Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Admin Dashboard #68

Merged
merged 73 commits into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
1fcf2b0
feat: add Domains page
krantheman Jan 27, 2025
26428ec
feat: redirect non admins out of dashboard
krantheman Jan 28, 2025
008e7ee
chore: clean up redundant 'computed's
krantheman Jan 28, 2025
d97c68f
chore: move admin methods to different file
krantheman Jan 28, 2025
c9b0ae3
feat: add Add Domain dialog
krantheman Jan 28, 2025
101f02c
feat: add domain listview
krantheman Jan 28, 2025
d7271cd
chore: merge with develop
krantheman Jan 29, 2025
ab0db9b
fix: domain request apis
krantheman Jan 29, 2025
6ef7293
feat: add single domain view
krantheman Jan 29, 2025
a86fa83
chore: bump frappe-ui to v0.1.108
krantheman Jan 29, 2025
933712c
feat(Mail Domain): add tenant name
krantheman Jan 29, 2025
ff6b934
feat: show mail domain doc fields
krantheman Jan 29, 2025
4147c16
fix(Signup): account request value
krantheman Jan 30, 2025
5fb2947
chore: add frappe-ui.diff
krantheman Jan 30, 2025
1580b81
chore: downgrade vite to v5
krantheman Jan 30, 2025
a47f505
feat(Domains): add styling to listview
krantheman Jan 30, 2025
7679110
feat(Domain): show error on setvalue failure
krantheman Jan 30, 2025
dd34fca
feat(Domain): add labels
krantheman Jan 30, 2025
d383bf4
refactor(Domain): save doc using button
krantheman Jan 30, 2025
65889e2
feat(Domain): add actions resources
krantheman Jan 30, 2025
34433a6
feat(Domain): add confirmation dialog
krantheman Jan 30, 2025
3d0753e
fix(Domain): rewrite of dns records on save
krantheman Jan 31, 2025
c4cb545
fix(Domain): column widths
krantheman Jan 31, 2025
787c19f
fix(Domain): isDirty Save disable
krantheman Jan 31, 2025
e4cc3f8
chore: fix return types
krantheman Jan 31, 2025
81fe1a7
chore: fix type checking
krantheman Jan 31, 2025
45a77d4
chore: merge with develop
krantheman Jan 31, 2025
f2f7dcd
feat: add Members page
krantheman Jan 31, 2025
f0b3cd5
chore(Mail Domain): set_only_once as 1
krantheman Jan 31, 2025
bf44c7b
feat: add Invite User
krantheman Jan 31, 2025
3cf1b77
feat: add Invite User functionality
krantheman Feb 3, 2025
cafb7aa
feat: show tenant members
krantheman Feb 3, 2025
3cd86e2
chore: rename Invite User as Add Member
krantheman Feb 3, 2025
6cbc573
feat: show if admin in members list view
krantheman Feb 4, 2025
921f3fb
chore: merge with develop
krantheman Feb 4, 2025
426357d
feat(Members): add actions
krantheman Feb 4, 2025
bfb5ca2
feat(Members): add non invite based account creation
krantheman Feb 4, 2025
4cc57fc
fix: reset state on opening modals
krantheman Feb 4, 2025
7b755b1
refactor: multiple
krantheman Feb 4, 2025
d310be5
fix: multiple
krantheman Feb 4, 2025
2e55cbe
refactor: add validation for email address when needed
krantheman Feb 4, 2025
b2dc1a3
refactor: create mail account
krantheman Feb 5, 2025
43cf7a8
fix: email css build
krantheman Feb 5, 2025
fd3bcec
feat(Mail Account Request): validate expired
krantheman Feb 5, 2025
1c23ae6
fix: validate email only when there is one
krantheman Feb 5, 2025
f97c470
refactor(Mail Domain): remove tenant_name field
krantheman Feb 5, 2025
6191277
Merge branch 'develop' into feat-admin-dashboard
krantheman Feb 5, 2025
89bccdf
fix: frappe-logo typo 💀
krantheman Feb 5, 2025
17a6874
refactor(Members): only show badge for admins
krantheman Feb 5, 2025
c908936
fix: multiple
krantheman Feb 6, 2025
349d9e8
fix: validate tenant admin for get_members
krantheman Feb 6, 2025
9ba1b57
chore: `linter`
s-aga-r Feb 6, 2025
6a3a650
refactor: make account email lowercase
s-aga-r Feb 6, 2025
2e7680e
chore: redirect `/login` to `/mail/login`
s-aga-r Feb 6, 2025
cd7c102
chore: redirect `/signup` to `/mail/signup`
s-aga-r Feb 6, 2025
18dd27a
fix(ux): use input type as `text`
s-aga-r Feb 6, 2025
da5441d
refactor: redirect admin to desk
krantheman Feb 6, 2025
5ffe298
fix: routing
krantheman Feb 6, 2025
9aca4b4
fix: routing
krantheman Feb 6, 2025
c9bf187
refactor: check if domain request already exists before creating new one
krantheman Feb 6, 2025
c9457e2
fix: check Mail Domain instead of Mail Domain Request for verified do…
krantheman Feb 6, 2025
53f477d
feat: make domain name in error message bold
krantheman Feb 6, 2025
c1e1f76
fix: hacky fix to redirect admin to app after setup wizard
krantheman Feb 6, 2025
a7167fa
fix: use remote url for frappe-logo
s-aga-r Feb 6, 2025
43800f4
refactor(Mail Account Request): role => is_admin
krantheman Feb 7, 2025
baf31fc
feat(Members): show owner
krantheman Feb 7, 2025
13086f1
fix(Copy): remove scrollbar
krantheman Feb 7, 2025
7ffb328
fix(Members): don't show remove admin/remove member for owner
krantheman Feb 7, 2025
dce7bca
chore: change is_admin type annotation from literal to bool
krantheman Feb 7, 2025
d6b7eef
refactor(Mail Account Request): clean up form flow
krantheman Feb 7, 2025
10986ea
fix: type for checkbox field
krantheman Feb 7, 2025
936a836
fix: do not explicit validate email
s-aga-r Feb 7, 2025
d0a39e4
fix: validate account email
s-aga-r Feb 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"@vueuse/core": "^10.4.1",
"dayjs": "^1.11.11",
"feather-icons": "^4.28.0",
"frappe-ui": "^0.1.60",
"frappe-ui": "^0.1.108",
"gemoji": "^8.1.0",
"lucide-vue-next": "^0.383.0",
"markdown-it": "^14.1.0",
Expand Down
11 changes: 9 additions & 2 deletions frontend/src/components/AppSidebar.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div
class="flex h-full flex-col justify-between transition-all duration-300 ease-in-out bg-gray-100"
class="flex h-full flex-col justify-between transition-all duration-300 ease-in-out bg-gray-50 border-r"
:class="isSidebarCollapsed ? 'w-14' : 'w-56'"
>
<div
Expand Down Expand Up @@ -40,14 +40,21 @@
</template>

<script setup>
import { useRoute } from 'vue-router'
import UserDropdown from '@/components/UserDropdown.vue'
import SidebarLink from '@/components/SidebarLink.vue'
import { useStorage } from '@vueuse/core'
import { ref, computed } from 'vue'
import { ArrowLeftFromLine } from 'lucide-vue-next'
import { getSidebarLinks } from '../utils'

const sidebarLinks = computed(() => getSidebarLinks())
const route = useRoute()

const sidebarLinks = computed(() =>
getSidebarLinks().filter((link) =>
route.meta.isDashboard ? link.forDashboard : !link.forDashboard
)
)

const getSidebarFromStorage = () => {
return useStorage('sidebar_is_collapsed', false)
Expand Down
20 changes: 12 additions & 8 deletions frontend/src/components/Controls/Copy.vue
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<template>
<label class="block pt-2 text-sm">
<div class="block pt-2 text-sm">
<span class="mb-2 block leading-4 text-gray-700">{{ props.label }}</span>
<button
class="border-2 rounded-lg bg-gray-100 p-2 w-full flex items-center"
@click="copyToClipBoard(props.value)"
>
<span class="text-gray-800">{{ props.value }}</span>
<span class="text-gray-800 text-nowrap overflow-x-scroll">{{ props.value }}</span>
<span class="border rounded bg-white p-1 text-gray-600 text-xs ml-auto">
{{ message }}
</span>
</button>
</label>
</div>
</template>
<script setup>
import { ref } from 'vue'
Expand All @@ -29,10 +29,14 @@ const props = defineProps({
})

const copyToClipBoard = async (text) => {
await navigator.clipboard.writeText(text)
message.value = 'Copied!'
setTimeout(() => {
message.value = 'Copy'
}, 2000)
try {
await navigator.clipboard.writeText(text)
message.value = 'Copied!'
setTimeout(() => {
message.value = 'Copy'
}, 2000)
} catch (e) {
alert('Failed to copy text. Please copy from here: ' + text)
}
}
</script>
86 changes: 86 additions & 0 deletions frontend/src/components/Modals/AddDomain.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<template>
<Dialog
v-model="show"
:options="{
title: __('Add Domain'),
actions: [
{
label: __(domainRequest?.data ? 'Verify DNS' : 'Add Domain'),
variant: 'solid',
onClick: domainRequest?.data ? verifyDNS.submit : domainRequest.submit,
},
],
}"
>
<template #body-content>
<div class="space-y-4">
<p class="text-p-base">
{{
__(
`To add a domain, you must already own it. If you don't have one, purchase one and return here.`
)
}}
</p>
<FormControl
type="text"
:label="__('Domain Name')"
placeholder="example.com"
v-model="domainName"
:readonly="!!domainRequest?.data"
autocomplete="off"
/>
<ErrorMessage :message="domainRequest.error?.messages[0]" />
<div v-if="domainRequest.data?.verification_key" class="space-y-4">
<p class="text-p-base">
{{
__(
`Add the following TXT record to your domain's DNS records to verify your ownership:`
)
}}
</p>
<Copy
:label="__('Verification Key')"
:value="domainRequest.data.verification_key"
/>
<ErrorMessage :message="verifyDNS.error?.messages[0] || verificationError" />
</div>
</div>
</template>
</Dialog>
</template>

<script setup>
import { ref, computed, inject } from 'vue'
import { Dialog, FormControl, ErrorMessage, createResource } from 'frappe-ui'
import Copy from '@/components/Controls/Copy.vue'
import { raiseToast } from '@/utils'

const show = defineModel()
const user = inject('$user')

const domainName = ref('')
const verificationError = ref('')

const emit = defineEmits(['reloadDomains'])

const domainRequest = createResource({
url: 'mail.api.admin.create_domain_request',
makeParams() {
return { domain_name: domainName.value, mail_tenant: user.data.tenant }
},
})

const verifyDNS = createResource({
url: 'mail.api.admin.verify_dns_record',
makeParams() {
return { domain_request: domainRequest?.data.name }
},
onSuccess(data) {
if (data) {
show.value = false
emit('reloadDomains')
raiseToast('Domain added successfully!')
} else verificationError.value = __('Failed to verify DNS record.')
},
})
</script>
1 change: 1 addition & 0 deletions frontend/src/components/Modals/Settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { Dialog, Button } from 'frappe-ui'
import { User, Mailbox } from 'lucide-vue-next'

const show = defineModel()

const tabs = [
{
label: 'User',
Expand Down
49 changes: 23 additions & 26 deletions frontend/src/components/UserDropdown.vue
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,14 @@

<script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import MailLogo from '@/components/Icons/MailLogo.vue'
import Settings from '@/components/Modals/Settings.vue'
import { sessionStore } from '@/stores/session'
import { Dropdown } from 'frappe-ui'
import {
Home,
LayoutDashboard,
ChevronDown,
LogIn,
LogOut,
Expand All @@ -74,9 +77,10 @@ import {
import { convertToTitleCase } from '../utils'
import { userStore } from '@/stores/user'

const { logout, branding } = sessionStore()
const { isLoggedIn, logout, branding } = sessionStore()
const { userResource } = userStore()
let { isLoggedIn } = sessionStore()
const router = useRouter()

const showSettings = ref(false)

const props = defineProps({
Expand All @@ -87,17 +91,28 @@ const props = defineProps({
})

const userDropdownOptions = [
{
icon: Home,
label: 'Home',
onClick: () => router.push('/'),
condition: () => userResource.data.roles.includes('Mail Admin'),
},
{
icon: LayoutDashboard,
label: 'Admin Dashboard',
onClick: () => router.push('/dashboard'),
condition: () => userResource.data.roles.includes('Mail Admin'),
},
{
icon: ArrowRightLeft,
label: 'Switch to Desk',
onClick: () => {
window.location.href = '/app'
},
condition: () => {
let cookies = new URLSearchParams(document.cookie.split('; ').join('&'))
let system_user = cookies.get('system_user')
if (system_user === 'yes') return true
else return false
const cookies = new URLSearchParams(document.cookie.split('; ').join('&'))
const system_user = cookies.get('system_user')
return system_user === 'yes'
},
},
{
Expand All @@ -106,29 +121,11 @@ const userDropdownOptions = [
onClick: () => {
showSettings.value = true
},
condition: () => {
return isLoggedIn
},
},
{
icon: LogOut,
label: 'Log out',
onClick: () => {
logout.submit()
},
condition: () => {
return isLoggedIn
},
},
{
icon: LogIn,
label: 'Log in',
onClick: () => {
window.location.href = '/login'
},
condition: () => {
return !isLoggedIn
},
label: 'Log Out',
onClick: logout.submit,
},
]
</script>
13 changes: 2 additions & 11 deletions frontend/src/pages/Drafts.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<header
class="sticky top-0 z-10 flex items-center justify-between border-b bg-white px-3 py-2.5 sm:px-5"
>
<Breadcrumbs :items="breadcrumbs">
<Breadcrumbs :items="[{ label: 'Drafts' }]">
<template #suffix>
<div v-if="draftMailsCount.data" class="self-end text-xs text-gray-600 ml-2">
{{
Expand Down Expand Up @@ -57,7 +57,7 @@
</template>
<script setup>
import { Breadcrumbs, createResource, createListResource } from 'frappe-ui'
import { ref, computed, inject, watch } from 'vue'
import { ref, inject, watch } from 'vue'
import HeaderActions from '@/components/HeaderActions.vue'
import { formatNumber, startResizing, singularize } from '@/utils'
import MailDetails from '@/components/MailDetails.vue'
Expand Down Expand Up @@ -105,13 +105,4 @@ const draftMailsCount = createResource({
const loadMoreEmails = useDebounceFn(() => {
if (draftMails.hasNextPage) draftMails.next()
}, 500)

const breadcrumbs = computed(() => {
return [
{
label: `Drafts`,
route: { name: 'Drafts' },
},
]
})
</script>
13 changes: 2 additions & 11 deletions frontend/src/pages/Inbox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<header
class="sticky top-0 z-10 flex items-center justify-between border-b bg-white px-3 py-2.5 sm:px-5"
>
<Breadcrumbs :items="breadcrumbs">
<Breadcrumbs :items="[{ label: 'Inbox' }]">
<template #suffix>
<div v-if="incomingMailCount.data" class="self-end text-xs text-gray-600 ml-2">
{{
Expand Down Expand Up @@ -52,7 +52,7 @@
</template>
<script setup>
import { Breadcrumbs, createListResource, createResource } from 'frappe-ui'
import { computed, inject, ref, onMounted } from 'vue'
import { inject, ref, onMounted } from 'vue'
import { formatNumber, startResizing, singularize } from '@/utils'
import HeaderActions from '@/components/HeaderActions.vue'
import MailDetails from '@/components/MailDetails.vue'
Expand Down Expand Up @@ -99,13 +99,4 @@ const incomingMailCount = createResource({
const loadMoreEmails = useDebounceFn(() => {
if (incomingMails.hasNextPage) incomingMails.next()
}, 500)

const breadcrumbs = computed(() => {
return [
{
label: `Inbox`,
route: { name: 'Inbox' },
},
]
})
</script>
13 changes: 2 additions & 11 deletions frontend/src/pages/Sent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<header
class="sticky top-0 z-10 flex items-center justify-between border-b bg-white px-3 py-2.5 sm:px-5"
>
<Breadcrumbs :items="breadcrumbs">
<Breadcrumbs :items="[{ label: 'Sent' }]">
<template #suffix>
<div v-if="sentMailsCount.data" class="self-end text-xs text-gray-600 ml-2">
{{
Expand Down Expand Up @@ -52,7 +52,7 @@
</template>
<script setup>
import { Breadcrumbs, createResource, createListResource } from 'frappe-ui'
import { computed, inject, ref, onMounted } from 'vue'
import { inject, ref, onMounted } from 'vue'
import HeaderActions from '@/components/HeaderActions.vue'
import { formatNumber, startResizing, singularize } from '@/utils'
import MailDetails from '@/components/MailDetails.vue'
Expand Down Expand Up @@ -100,13 +100,4 @@ const sentMailsCount = createResource({
const loadMoreEmails = useDebounceFn(() => {
if (sentMails.hasNextPage) sentMails.next()
}, 500)

const breadcrumbs = computed(() => {
return [
{
label: 'Sent',
route: { name: 'Sent' },
},
]
})
</script>
4 changes: 2 additions & 2 deletions frontend/src/pages/Setup.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<FormControl type="text" label="User" :value="user.data?.name" disabled class="mb-4" />
<FormControl type="text" label="User" :value="user.data?.name" readonly class="mb-4" />

<form
v-if="!user.data?.tenant"
Expand Down Expand Up @@ -33,7 +33,7 @@ const { logout } = sessionStore()
const tenantName = ref('')

const createTenant = createResource({
url: 'mail.api.account.create_tenant',
url: 'mail.api.admin.create_tenant',
makeParams() {
return { tenant_name: tenantName.value }
},
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/SignUp.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
placeholder="[email protected]"
autocomplete="email"
v-model="email"
:disabled="!!props.requestKey || isVerificationStep"
:readonly="!!props.requestKey || isVerificationStep"
required
/>
<FormControl
Expand Down
Loading
Loading