Merge pull request #1146 from frappe/mergify/bp/main-hotfix/pr-1143

fixes to incorporate latest frappe-ui version  (backport #1143)
This commit is contained in:
Shariq Ansari 2025-08-18 22:47:46 +05:30 committed by GitHub
commit 30fed5f6ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
74 changed files with 855 additions and 1183 deletions

View File

@ -26,8 +26,9 @@ def create_default_manager_dashboard(force=False):
doc.title = "Manager Dashboard" doc.title = "Manager Dashboard"
doc.layout = default_manager_dashboard_layout() doc.layout = default_manager_dashboard_layout()
doc.insert(ignore_permissions=True) doc.insert(ignore_permissions=True)
elif force: else:
doc = frappe.get_doc("CRM Dashboard", "Manager Dashboard") doc = frappe.get_doc("CRM Dashboard", "Manager Dashboard")
doc.layout = default_manager_dashboard_layout() if force:
doc.save(ignore_permissions=True) doc.layout = default_manager_dashboard_layout()
doc.save(ignore_permissions=True)
return doc.layout return doc.layout

View File

@ -171,9 +171,6 @@ declare module 'vue' {
LostReasonModal: typeof import('./src/components/Modals/LostReasonModal.vue')['default'] LostReasonModal: typeof import('./src/components/Modals/LostReasonModal.vue')['default']
LucideCalendar: typeof import('~icons/lucide/calendar')['default'] LucideCalendar: typeof import('~icons/lucide/calendar')['default']
LucideChevronRight: typeof import('~icons/lucide/chevron-right')['default'] LucideChevronRight: typeof import('~icons/lucide/chevron-right')['default']
LucidePenLine: typeof import('~icons/lucide/pen-line')['default']
LucideRefreshCcw: typeof import('~icons/lucide/refresh-ccw')['default']
LucideX: typeof import('~icons/lucide/x')['default']
MarkAsDoneIcon: typeof import('./src/components/Icons/MarkAsDoneIcon.vue')['default'] MarkAsDoneIcon: typeof import('./src/components/Icons/MarkAsDoneIcon.vue')['default']
MaximizeIcon: typeof import('./src/components/Icons/MaximizeIcon.vue')['default'] MaximizeIcon: typeof import('./src/components/Icons/MaximizeIcon.vue')['default']
MenuIcon: typeof import('./src/components/Icons/MenuIcon.vue')['default'] MenuIcon: typeof import('./src/components/Icons/MenuIcon.vue')['default']
@ -188,7 +185,6 @@ declare module 'vue' {
MultiSelectEmailInput: typeof import('./src/components/Controls/MultiSelectEmailInput.vue')['default'] MultiSelectEmailInput: typeof import('./src/components/Controls/MultiSelectEmailInput.vue')['default']
MultiSelectUserInput: typeof import('./src/components/Controls/MultiSelectUserInput.vue')['default'] MultiSelectUserInput: typeof import('./src/components/Controls/MultiSelectUserInput.vue')['default']
MuteIcon: typeof import('./src/components/Icons/MuteIcon.vue')['default'] MuteIcon: typeof import('./src/components/Icons/MuteIcon.vue')['default']
NestedPopover: typeof import('./src/components/NestedPopover.vue')['default']
NewEmailTemplate: typeof import('./src/components/Settings/EmailTemplate/NewEmailTemplate.vue')['default'] NewEmailTemplate: typeof import('./src/components/Settings/EmailTemplate/NewEmailTemplate.vue')['default']
NoteArea: typeof import('./src/components/Activities/NoteArea.vue')['default'] NoteArea: typeof import('./src/components/Activities/NoteArea.vue')['default']
NoteIcon: typeof import('./src/components/Icons/NoteIcon.vue')['default'] NoteIcon: typeof import('./src/components/Icons/NoteIcon.vue')['default']

View File

@ -238,12 +238,9 @@
<Button <Button
class="!size-4" class="!size-4"
variant="ghost" variant="ghost"
:icon="SelectIcon"
@click="activity.show_others = !activity.show_others" @click="activity.show_others = !activity.show_others"
> />
<template #icon>
<SelectIcon />
</template>
</Button>
</div> </div>
<div <div
v-else v-else

View File

@ -9,23 +9,17 @@
<Button <Button
v-if="title == 'Emails'" v-if="title == 'Emails'"
variant="solid" variant="solid"
:label="__('New Email')"
iconLeft="plus"
@click="emailBox.show = true" @click="emailBox.show = true"
> />
<template #prefix>
<FeatherIcon name="plus" class="h-4 w-4" />
</template>
<span>{{ __('New Email') }}</span>
</Button>
<Button <Button
v-else-if="title == 'Comments'" v-else-if="title == 'Comments'"
variant="solid" variant="solid"
:label="__('New Comment')"
iconLeft="plus"
@click="emailBox.showComment = true" @click="emailBox.showComment = true"
> />
<template #prefix>
<FeatherIcon name="plus" class="h-4 w-4" />
</template>
<span>{{ __('New Comment') }}</span>
</Button>
<MultiActionButton <MultiActionButton
v-else-if="title == 'Calls'" v-else-if="title == 'Calls'"
variant="solid" variant="solid"
@ -34,59 +28,45 @@
<Button <Button
v-else-if="title == 'Notes'" v-else-if="title == 'Notes'"
variant="solid" variant="solid"
:label="__('New Note')"
iconLeft="plus"
@click="modalRef.showNote()" @click="modalRef.showNote()"
> />
<template #prefix>
<FeatherIcon name="plus" class="h-4 w-4" />
</template>
<span>{{ __('New Note') }}</span>
</Button>
<Button <Button
v-else-if="title == 'Tasks'" v-else-if="title == 'Tasks'"
variant="solid" variant="solid"
:label="__('New Task')"
iconLeft="plus"
@click="modalRef.showTask()" @click="modalRef.showTask()"
> />
<template #prefix>
<FeatherIcon name="plus" class="h-4 w-4" />
</template>
<span>{{ __('New Task') }}</span>
</Button>
<Button <Button
v-else-if="title == 'Attachments'" v-else-if="title == 'Attachments'"
variant="solid" variant="solid"
:label="__('Upload Attachment')"
iconLeft="plus"
@click="showFilesUploader = true" @click="showFilesUploader = true"
> />
<template #prefix>
<FeatherIcon name="plus" class="h-4 w-4" />
</template>
<span>{{ __('Upload Attachment') }}</span>
</Button>
<div class="flex gap-2 shrink-0" v-else-if="title == 'WhatsApp'"> <div class="flex gap-2 shrink-0" v-else-if="title == 'WhatsApp'">
<Button <Button
:label="__('Send Template')" :label="__('Send Template')"
@click="showWhatsappTemplates = true" @click="showWhatsappTemplates = true"
/> />
<Button variant="solid" @click="whatsappBox.show()"> <Button
<template #prefix> variant="solid"
<FeatherIcon name="plus" class="h-4 w-4" /> :label="__('New Message')"
</template> iconLeft="plus"
<span>{{ __('New Message') }}</span> @click="whatsappBox.show()"
</Button> />
</div> </div>
<Dropdown v-else :options="defaultActions" @click.stop> <Dropdown v-else :options="defaultActions" @click.stop>
<template v-slot="{ open }"> <template v-slot="{ open }">
<Button variant="solid" class="flex items-center gap-1"> <Button
<template #prefix> variant="solid"
<FeatherIcon name="plus" class="h-4 w-4" /> class="flex items-center gap-1"
</template> :label="__('New')"
<span>{{ __('New') }}</span> iconLeft="plus"
<template #suffix> :iconRight="open ? 'chevron-up' : 'chevron-down'"
<FeatherIcon />
:name="open ? 'chevron-up' : 'chevron-down'"
class="h-4 w-4"
/>
</template>
</Button>
</template> </template>
</Dropdown> </Dropdown>
</div> </div>

View File

@ -38,42 +38,31 @@
</div> </div>
</Tooltip> </Tooltip>
<div class="flex gap-1"> <div class="flex gap-1">
<Tooltip <Button
:text=" :tooltip="
attachment.is_private ? __('Make public') : __('Make private') attachment.is_private ? __('Make public') : __('Make private')
" "
class="!size-5"
@click.stop="
togglePrivate(attachment.name, attachment.is_private)
"
> >
<div> <template #icon>
<Button <FeatherIcon
class="!size-5" :name="attachment.is_private ? 'lock' : 'unlock'"
@click.stop=" class="size-3 text-ink-gray-7"
togglePrivate(attachment.name, attachment.is_private) />
" </template>
> </Button>
<template #icon> <Button
<FeatherIcon :tooltip="__('Delete attachment')"
:name="attachment.is_private ? 'lock' : 'unlock'" class="!size-5"
class="size-3 text-ink-gray-7" @click.stop="() => deleteAttachment(attachment.name)"
/> >
</template> <template #icon>
</Button> <FeatherIcon name="trash-2" class="size-3 text-ink-gray-7" />
</div> </template>
</Tooltip> </Button>
<Tooltip :text="__('Delete attachment')">
<div>
<Button
class="!size-5"
@click.stop="() => deleteAttachment(attachment.name)"
>
<template #icon>
<FeatherIcon
name="trash-2"
class="size-3 text-ink-gray-7"
/>
</template>
</Button>
</div>
</Tooltip>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,12 +1,12 @@
<template> <template>
<div class="w-full text-sm text-ink-gray-5"> <div class="w-full text-sm text-ink-gray-5">
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<Button variant="ghost" @click="playPause"> <Button
<template #icon> variant="ghost"
<PlayIcon v-if="isPaused" class="size-4 text-ink-gray-5" /> class="text-ink-gray-5"
<PauseIcon v-else class="size-4 text-ink-gray-5" /> :icon="isPaused ? PlayIcon : PauseIcon"
</template> @click="playPause"
</Button> />
<div class="flex gap-2 items-center justify-between flex-1"> <div class="flex gap-2 items-center justify-between flex-1">
<input <input
class="w-full slider !h-[0.5] bg-surface-gray-3 [&::-webkit-slider-thumb]:shadow [&::-webkit-slider-thumb:hover]:outline [&::-webkit-slider-thumb:hover]:outline-[0.5px]" class="w-full slider !h-[0.5] bg-surface-gray-3 [&::-webkit-slider-thumb]:shadow [&::-webkit-slider-thumb:hover]:outline [&::-webkit-slider-thumb:hover]:outline-[0.5px]"
@ -61,11 +61,11 @@
</Button> </Button>
</div> </div>
<Dropdown :options="options"> <Dropdown :options="options">
<Button variant="ghost" @click="showPlaybackSpeed = false"> <Button
<template #icon> icon="more-horizontal"
<FeatherIcon class="size-4" name="more-horizontal" /> variant="ghost"
</template> @click="showPlaybackSpeed = false"
</Button> />
</Dropdown> </Dropdown>
</div> </div>
</div> </div>

View File

@ -14,12 +14,10 @@
<div class="flex gap-1"> <div class="flex gap-1">
<Button <Button
v-if="isManager() && !isMobileView" v-if="isManager() && !isMobileView"
:tooltip="__('Edit fields layout')"
:icon="EditIcon"
@click="showDataFieldsModal = true" @click="showDataFieldsModal = true"
> />
<template #icon>
<EditIcon />
</template>
</Button>
<Button <Button
label="Save" label="Save"
:disabled="!document.isDirty" :disabled="!document.isDirty"

View File

@ -2,7 +2,9 @@
<div <div
class="cursor-pointer flex flex-col rounded-md shadow bg-surface-cards px-3 py-1.5 text-base transition-all duration-300 ease-in-out" class="cursor-pointer flex flex-col rounded-md shadow bg-surface-cards px-3 py-1.5 text-base transition-all duration-300 ease-in-out"
> >
<div class="-mb-0.5 flex items-center justify-between gap-2 truncate text-ink-gray-9"> <div
class="-mb-0.5 flex items-center justify-between gap-2 truncate text-ink-gray-9"
>
<div class="flex items-center gap-2 truncate"> <div class="flex items-center gap-2 truncate">
<span>{{ activity.data.sender_full_name }}</span> <span>{{ activity.data.sender_full_name }}</span>
<span class="sm:flex hidden text-sm text-ink-gray-5"> <span class="sm:flex hidden text-sm text-ink-gray-5">
@ -28,32 +30,20 @@
</div> </div>
</Tooltip> </Tooltip>
<div class="flex gap-0.5"> <div class="flex gap-0.5">
<Tooltip :text="__('Reply')"> <Button
<div> :tooltip="__('Reply')"
<Button variant="ghost"
variant="ghost" class="text-ink-gray-7"
class="text-ink-gray-7" :icon="ReplyIcon"
@click="reply(activity.data)" @click="reply(activity.data)"
> />
<template #icon> <Button
<ReplyIcon /> :tooltip="__('Reply All')"
</template> variant="ghost"
</Button> :icon="ReplyAllIcon"
</div> class="text-ink-gray-7"
</Tooltip> @click="reply(activity.data, true)"
<Tooltip :text="__('Reply All')"> />
<div>
<Button
variant="ghost"
class="text-ink-gray-7"
@click="reply(activity.data, true)"
>
<template #icon>
<ReplyAllIcon />
</template>
</Button>
</div>
</Tooltip>
</div> </div>
</div> </div>
</div> </div>

View File

@ -41,13 +41,13 @@
:options="taskStatusOptions(modalRef.updateTaskStatus, task)" :options="taskStatusOptions(modalRef.updateTaskStatus, task)"
@click.stop @click.stop
> >
<Tooltip :text="__('Change Status')"> <Button
<div> :tooltip="__('Change status')"
<Button variant="ghosted" class="hover:bg-surface-gray-4"> variant="ghosted"
<TaskStatusIcon :status="task.status" /> class="hover:bg-surface-gray-4"
</Button> >
</div> <TaskStatusIcon :status="task.status" />
</Tooltip> </Button>
</Dropdown> </Dropdown>
<Dropdown <Dropdown
:options="[ :options="[

View File

@ -1,7 +1,7 @@
<template> <template>
<NestedPopover> <Popover placement="bottom-end">
<template #target> <template #target="{ togglePopover }">
<div class="flex items-center"> <div class="flex items-center" @click="togglePopover">
<component <component
v-if="assignees?.length" v-if="assignees?.length"
:is="assignees?.length == 1 ? 'Button' : 'div'" :is="assignees?.length == 1 ? 'Button' : 'div'"
@ -11,24 +11,23 @@
<Button v-else :label="__('Assign to')" /> <Button v-else :label="__('Assign to')" />
</div> </div>
</template> </template>
<template #body="{ open }"> <template #body="{ isOpen }">
<AssignToBody <AssignToBody
v-show="open" v-show="isOpen"
v-model="assignees" v-model="assignees"
:docname="docname" :docname="docname"
:doctype="doctype" :doctype="doctype"
:open="open" :open="isOpen"
:onUpdate="ownerField && saveAssignees" :onUpdate="ownerField && saveAssignees"
/> />
</template> </template>
</NestedPopover> </Popover>
</template> </template>
<script setup> <script setup>
import NestedPopover from '@/components/NestedPopover.vue'
import MultipleAvatar from '@/components/MultipleAvatar.vue' import MultipleAvatar from '@/components/MultipleAvatar.vue'
import AssignToBody from '@/components/AssignToBody.vue' import AssignToBody from '@/components/AssignToBody.vue'
import { useDocument } from '@/data/document' import { useDocument } from '@/data/document'
import { toast } from 'frappe-ui' import { toast, Popover } from 'frappe-ui'
import { computed } from 'vue' import { computed } from 'vue'
const props = defineProps({ const props = defineProps({

View File

@ -25,23 +25,21 @@
:key="assignee.name" :key="assignee.name"
@click.stop @click.stop
> >
<div> <div
<div class="flex items-center text-sm p-0.5 text-ink-gray-6 border border-outline-gray-1 bg-surface-modal rounded-full cursor-pointer"
class="flex items-center text-sm p-0.5 text-ink-gray-6 border border-outline-gray-1 bg-surface-modal rounded-full cursor-pointer" @click.stop
@click.stop >
<UserAvatar :user="assignee.name" size="sm" />
<div class="ml-1">{{ getUser(assignee.name).full_name }}</div>
<Button
variant="ghost"
class="rounded-full !size-4 m-1"
@click.stop="removeValue(assignee.name)"
> >
<UserAvatar :user="assignee.name" size="sm" /> <template #icon>
<div class="ml-1">{{ getUser(assignee.name).full_name }}</div> <FeatherIcon name="x" class="h-3 w-3 text-ink-gray-6" />
<Button </template>
variant="ghost" </Button>
class="rounded-full !size-4 m-1"
@click.stop="removeValue(assignee.name)"
>
<template #icon>
<FeatherIcon name="x" class="h-3 w-3 text-ink-gray-6" />
</template>
</Button>
</div>
</div> </div>
</Tooltip> </Tooltip>
</div> </div>
@ -74,7 +72,7 @@ import UserAvatar from '@/components/UserAvatar.vue'
import Link from '@/components/Controls/Link.vue' import Link from '@/components/Controls/Link.vue'
import { usersStore } from '@/stores/users' import { usersStore } from '@/stores/users'
import { capture } from '@/telemetry' import { capture } from '@/telemetry'
import { Tooltip, Switch, toast, createResource } from 'frappe-ui' import { Tooltip, Switch, createResource } from 'frappe-ui'
import { ref, watch } from 'vue' import { ref, watch } from 'vue'
const props = defineProps({ const props = defineProps({

View File

@ -5,11 +5,9 @@
:label="label" :label="label"
theme="gray" theme="gray"
variant="outline" variant="outline"
:iconLeft="getIcon()"
@click="toggleDialog()" @click="toggleDialog()"
> >
<template #prefix>
<component :is="getIcon()" class="h-4 w-4" />
</template>
<template #suffix> <template #suffix>
<slot name="suffix" /> <slot name="suffix" />
</template> </template>

View File

@ -1,7 +1,7 @@
<template> <template>
<NestedPopover> <Popover placement="bottom-end">
<template #target> <template #target="{ togglePopover }">
<Button :label="__('Columns')"> <Button :label="__('Columns')" @click="togglePopover">
<template v-if="hideLabel"> <template v-if="hideLabel">
<ColumnsIcon class="h-4" /> <ColumnsIcon class="h-4" />
</template> </template>
@ -65,37 +65,28 @@
<Button <Button
class="w-full !justify-start !text-ink-gray-5" class="w-full !justify-start !text-ink-gray-5"
variant="ghost" variant="ghost"
@click="togglePopover()"
:label="__('Add Column')" :label="__('Add Column')"
> iconLeft="plus"
<template #prefix> @click="togglePopover"
<FeatherIcon name="plus" class="h-4" /> />
</template>
</Button>
</template> </template>
</Autocomplete> </Autocomplete>
<Button <Button
v-if="columnsUpdated" v-if="columnsUpdated"
class="w-full !justify-start !text-ink-gray-5" class="w-full !justify-start !text-ink-gray-5"
variant="ghost" variant="ghost"
@click="reset(close)"
:label="__('Reset Changes')" :label="__('Reset Changes')"
> :iconLeft="ReloadIcon"
<template #prefix> @click="reset(close)"
<ReloadIcon class="h-4" /> />
</template>
</Button>
<Button <Button
v-if="!is_default" v-if="!is_default"
class="w-full !justify-start !text-ink-gray-5" class="w-full !justify-start !text-ink-gray-5"
variant="ghost" variant="ghost"
@click="resetToDefault(close)"
:label="__('Reset to Default')" :label="__('Reset to Default')"
> :iconLeft="ReloadIcon"
<template #prefix> @click="resetToDefault(close)"
<ReloadIcon class="h-4" /> />
</template>
</Button>
</div> </div>
</div> </div>
<div v-else> <div v-else>
@ -144,7 +135,7 @@
</div> </div>
</div> </div>
</template> </template>
</NestedPopover> </Popover>
</template> </template>
<script setup> <script setup>
@ -152,9 +143,8 @@ import ColumnsIcon from '@/components/Icons/ColumnsIcon.vue'
import EditIcon from '@/components/Icons/EditIcon.vue' import EditIcon from '@/components/Icons/EditIcon.vue'
import DragIcon from '@/components/Icons/DragIcon.vue' import DragIcon from '@/components/Icons/DragIcon.vue'
import ReloadIcon from '@/components/Icons/ReloadIcon.vue' import ReloadIcon from '@/components/Icons/ReloadIcon.vue'
import NestedPopover from '@/components/NestedPopover.vue'
import Autocomplete from '@/components/frappe-ui/Autocomplete.vue'
import { isTouchScreenDevice } from '@/utils' import { isTouchScreenDevice } from '@/utils'
import { Autocomplete, Popover } from 'frappe-ui'
import Draggable from 'vuedraggable' import Draggable from 'vuedraggable'
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
import { watchOnce } from '@vueuse/core' import { watchOnce } from '@vueuse/core'

View File

@ -45,11 +45,12 @@
v-slot="{ togglePopover }" v-slot="{ togglePopover }"
@update:modelValue="() => appendEmoji()" @update:modelValue="() => appendEmoji()"
> >
<Button variant="ghost" @click="togglePopover()"> <Button
<template #icon> :tooltip="__('Insert Emoji')"
<SmileIcon class="h-4" /> :icon="SmileIcon"
</template> variant="ghost"
</Button> @click="togglePopover()"
/>
</IconPicker> </IconPicker>
<FileUploader <FileUploader
:upload-args="{ :upload-args="{
@ -61,14 +62,11 @@
> >
<template #default="{ openFileSelector }"> <template #default="{ openFileSelector }">
<Button <Button
theme="gray" :tooltip="__('Attach a file')"
variant="ghost" variant="ghost"
:icon="AttachmentIcon"
@click="openFileSelector()" @click="openFileSelector()"
> />
<template #icon>
<AttachmentIcon class="h-4" />
</template>
</Button>
</template> </template>
</FileUploader> </FileUploader>
</div> </div>

View File

@ -8,24 +8,18 @@
showEmailBox ? '!bg-surface-gray-4 hover:!bg-surface-gray-3' : '', showEmailBox ? '!bg-surface-gray-4 hover:!bg-surface-gray-3' : '',
]" ]"
:label="__('Reply')" :label="__('Reply')"
:iconLeft="Email2Icon"
@click="toggleEmailBox()" @click="toggleEmailBox()"
> />
<template #prefix>
<Email2Icon class="h-4" />
</template>
</Button>
<Button <Button
variant="ghost" variant="ghost"
:label="__('Comment')" :label="__('Comment')"
:class="[ :class="[
showCommentBox ? '!bg-surface-gray-4 hover:!bg-surface-gray-3' : '', showCommentBox ? '!bg-surface-gray-4 hover:!bg-surface-gray-3' : '',
]" ]"
:iconLeft="CommentIcon"
@click="toggleCommentBox()" @click="toggleCommentBox()"
> />
<template #prefix>
<CommentIcon class="h-4" />
</template>
</Button>
</div> </div>
</div> </div>
<div <div

View File

@ -54,14 +54,12 @@
</div> </div>
<div class="w-12"> <div class="w-12">
<Button <Button
class="flex w-full items-center justify-center rounded !bg-surface-gray-2 border-0" :tooltip="__('Edit grid fields')"
class="flex w-full items-center justify-center rounded !bg-surface-gray-2 border-0 !text-ink-gray-5"
variant="outline" variant="outline"
icon="settings"
@click="showGridFieldsEditorModal = true" @click="showGridFieldsEditorModal = true"
> />
<template #icon>
<FeatherIcon name="settings" class="size-4 text-ink-gray-7" />
</template>
</Button>
</div> </div>
</div> </div>
<!-- Rows --> <!-- Rows -->
@ -279,14 +277,12 @@
</div> </div>
<div class="edit-row w-12"> <div class="edit-row w-12">
<Button <Button
class="flex w-full items-center justify-center rounded border-0" :tooltip="__('Edit row')"
class="flex w-full items-center justify-center rounded border-0 !text-ink-gray-7"
variant="outline" variant="outline"
:icon="EditIcon"
@click="showRowList[index] = true" @click="showRowList[index] = true"
> />
<template #icon>
<EditIcon class="text-ink-gray-7" />
</template>
</Button>
</div> </div>
<GridRowModal <GridRowModal
v-if="showRowList[index]" v-if="showRowList[index]"

View File

@ -54,13 +54,10 @@
<template #target="{ togglePopover }"> <template #target="{ togglePopover }">
<Button <Button
class="w-full mt-2" class="w-full mt-2"
@click="togglePopover()"
:label="__('Add Field')" :label="__('Add Field')"
> iconLeft="plus"
<template #prefix> @click="togglePopover()"
<FeatherIcon name="plus" class="h-4" /> />
</template>
</Button>
</template> </template>
<template #item-label="{ option }"> <template #item-label="{ option }">
<div class="flex flex-col gap-1 text-ink-gray-9"> <div class="flex flex-col gap-1 text-ink-gray-9">

View File

@ -11,19 +11,18 @@
<div class="flex items-center gap-1"> <div class="flex items-center gap-1">
<Button <Button
v-if="isManager()" v-if="isManager()"
:tooltip="__('Edit fields layout')"
variant="ghost" variant="ghost"
class="w-7" class="w-7"
:icon="EditIcon"
@click="openGridRowFieldsModal" @click="openGridRowFieldsModal"
> />
<template #icon> <Button
<EditIcon /> icon="x"
</template> variant="ghost"
</Button> class="w-7"
<Button variant="ghost" class="w-7" @click="show = false"> @click="show = false"
<template #icon> />
<FeatherIcon name="x" class="size-4" />
</template>
</Button>
</div> </div>
</div> </div>
<div> <div>

View File

@ -48,24 +48,18 @@
variant="ghost" variant="ghost"
class="w-full !justify-start" class="w-full !justify-start"
:label="__('Create New')" :label="__('Create New')"
iconLeft="plus"
@click="() => attrs.onCreate(value, close)" @click="() => attrs.onCreate(value, close)"
> />
<template #prefix>
<FeatherIcon name="plus" class="h-4" />
</template>
</Button>
</div> </div>
<div> <div>
<Button <Button
variant="ghost" variant="ghost"
class="w-full !justify-start" class="w-full !justify-start"
:label="__('Clear')" :label="__('Clear')"
iconLeft="x"
@click="() => clearValue(close)" @click="() => clearValue(close)"
> />
<template #prefix>
<FeatherIcon name="x" class="h-4" />
</template>
</Button>
</div> </div>
</template> </template>
</Autocomplete> </Autocomplete>

View File

@ -18,14 +18,10 @@
:key="g.label" :key="g.label"
> >
<Dropdown :options="g.action" v-slot="{ open }"> <Dropdown :options="g.action" v-slot="{ open }">
<Button :label="g.label"> <Button
<template #suffix> :label="g.label"
<FeatherIcon :iconRight="open ? 'chevron-up' : 'chevron-down'"
:name="open ? 'chevron-up' : 'chevron-down'" />
class="h-4"
/>
</template>
</Button>
</Dropdown> </Dropdown>
</div> </div>
</template> </template>

View File

@ -19,53 +19,36 @@
v-if="editMode" v-if="editMode"
variant="ghost" variant="ghost"
:label="__('Save')" :label="__('Save')"
size="sm"
class="opacity-0 hover:bg-surface-gray-4 group-hover:opacity-100" class="opacity-0 hover:bg-surface-gray-4 group-hover:opacity-100"
@click="saveOption" @click="saveOption"
/> />
<Tooltip text="Set As Primary" v-if="!isNew && !option.selected"> <Button
<div> v-if="!isNew && !option.selected"
<Button :tooltip="__('Set As Primary')"
variant="ghost" variant="ghost"
size="sm" :icon="SuccessIcon"
class="opacity-0 hover:bg-surface-gray-4 group-hover:opacity-100" class="opacity-0 hover:bg-surface-gray-4 group-hover:opacity-100"
@click="option.onClick" @click="option.onClick"
> />
<template #icon> <Button
<SuccessIcon /> v-if="!editMode"
</template> :tooltip="__('Edit')"
</Button> variant="ghost"
</div> :icon="EditIcon"
</Tooltip> class="opacity-0 hover:bg-surface-gray-4 group-hover:opacity-100"
<Tooltip v-if="!editMode" text="Edit"> @click="toggleEditMode"
<div> />
<Button <Button
variant="ghost" :tooltip="__('Delete')"
size="sm" variant="ghost"
class="opacity-0 hover:bg-surface-gray-4 group-hover:opacity-100" icon="x"
@click="toggleEditMode" class="opacity-0 hover:bg-surface-gray-4 group-hover:opacity-100"
> @click="() => option.onDelete(option, isNew)"
<template #icon> />
<EditIcon />
</template>
</Button>
</div>
</Tooltip>
<Tooltip text="Delete">
<div>
<Button
variant="ghost"
icon="x"
size="sm"
class="opacity-0 hover:bg-surface-gray-4 group-hover:opacity-100"
@click="() => option.onDelete(option, isNew)"
/>
</div>
</Tooltip>
</div> </div>
</div> </div>
<div v-if="option.selected"> <div v-if="option.selected">
<FeatherIcon name="check" class="text-ink-gray-5 h-4 w-6" size="sm" /> <FeatherIcon name="check" class="text-ink-gray-5 h-4 w-6" />
</div> </div>
</div> </div>
</template> </template>

View File

@ -123,11 +123,12 @@
v-slot="{ togglePopover }" v-slot="{ togglePopover }"
@update:modelValue="() => appendEmoji()" @update:modelValue="() => appendEmoji()"
> >
<Button variant="ghost" @click="togglePopover()"> <Button
<template #icon> :tooltip="__('Insert Emoji')"
<SmileIcon class="h-4" /> :icon="SmileIcon"
</template> variant="ghost"
</Button> @click="togglePopover()"
/>
</IconPicker> </IconPicker>
<FileUploader <FileUploader
:upload-args="{ :upload-args="{
@ -138,21 +139,20 @@
@success="(f) => attachments.push(f)" @success="(f) => attachments.push(f)"
> >
<template #default="{ openFileSelector }"> <template #default="{ openFileSelector }">
<Button variant="ghost" @click="openFileSelector()"> <Button
<template #icon> :tooltip="__('Attach a file')"
<AttachmentIcon class="h-4" /> :icon="AttachmentIcon"
</template> variant="ghost"
</Button> @click="openFileSelector()"
/>
</template> </template>
</FileUploader> </FileUploader>
<Button <Button
:tooltip="__('Insert Email Template')"
variant="ghost" variant="ghost"
:icon="EmailTemplateIcon"
@click="showEmailTemplateSelectorModal = true" @click="showEmailTemplateSelectorModal = true"
> />
<template #icon>
<EmailTemplateIcon class="h-4" />
</template>
</Button>
</div> </div>
<div class="mt-2 flex items-center justify-end space-x-2 sm:mt-0"> <div class="mt-2 flex items-center justify-end space-x-2 sm:mt-0">
<Button v-bind="discardButtonProps || {}" :label="__('Discard')" /> <Button v-bind="discardButtonProps || {}" :label="__('Discard')" />

View File

@ -89,12 +89,9 @@
v-if="data[field.fieldname] && field.edit" v-if="data[field.fieldname] && field.edit"
class="shrink-0" class="shrink-0"
:label="__('Edit')" :label="__('Edit')"
:iconLeft="EditIcon"
@click="field.edit(data[field.fieldname])" @click="field.edit(data[field.fieldname])"
> />
<template #prefix>
<EditIcon class="h-4 w-4" />
</template>
</Button>
</div> </div>
<TableMultiselectInput <TableMultiselectInput

View File

@ -169,13 +169,10 @@
<Button <Button
class="w-full !h-8 !bg-surface-modal" class="w-full !h-8 !bg-surface-modal"
variant="outline" variant="outline"
@click="togglePopover()"
:label="__('Add Field')" :label="__('Add Field')"
> iconLeft="plus"
<template #prefix> @click="togglePopover()"
<FeatherIcon name="plus" class="h-4" /> />
</template>
</Button>
</div> </div>
</template> </template>
<template #item-label="{ option }"> <template #item-label="{ option }">
@ -198,6 +195,7 @@
class="w-full h-8" class="w-full h-8"
variant="subtle" variant="subtle"
:label="__('Add Section')" :label="__('Add Section')"
iconLeft="plus"
@click=" @click="
tabs[tabIndex].sections.push({ tabs[tabIndex].sections.push({
label: __('New Section'), label: __('New Section'),
@ -206,11 +204,7 @@
columns: [{ name: 'column_' + getRandom(), fields: [] }], columns: [{ name: 'column_' + getRandom(), fields: [] }],
}) })
" "
> />
<template #prefix>
<FeatherIcon name="plus" class="h-4" />
</template>
</Button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -29,6 +29,7 @@
filesUploaderArea?.showWebLink || filesUploaderArea?.showCamera filesUploaderArea?.showWebLink || filesUploaderArea?.showCamera
" "
:label="isMobileView ? __('Back') : __('Back to file upload')" :label="isMobileView ? __('Back') : __('Back to file upload')"
iconLeft="arrow-left"
@click=" @click="
() => { () => {
filesUploaderArea.showWebLink = false filesUploaderArea.showWebLink = false
@ -37,11 +38,7 @@
filesUploaderArea.cameraImage = null filesUploaderArea.cameraImage = null
} }
" "
> />
<template #prefix>
<FeatherIcon name="arrow-left" class="size-4" />
</template>
</Button>
<Button <Button
v-if=" v-if="
filesUploaderArea?.showCamera && !filesUploaderArea?.cameraImage filesUploaderArea?.showCamera && !filesUploaderArea?.cameraImage

View File

@ -1,12 +1,13 @@
<template> <template>
<NestedPopover> <Popover placement="bottom-end">
<template #target> <template #target="{ togglePopover, close }">
<div class="flex items-center"> <div class="flex items-center">
<Button <Button
:label="__('Filter')" :label="__('Filter')"
:class="filters?.size ? 'rounded-r-none' : ''" :class="filters?.size ? 'rounded-r-none' : ''"
:iconLeft="FilterIcon"
@click="togglePopover"
> >
<template #prefix><FilterIcon class="h-4" /></template>
<template v-if="filters?.size" #suffix> <template v-if="filters?.size" #suffix>
<div <div
class="flex h-5 w-5 items-center justify-center rounded-[5px] bg-surface-white pt-px text-xs font-medium text-ink-gray-8 shadow-sm" class="flex h-5 w-5 items-center justify-center rounded-[5px] bg-surface-white pt-px text-xs font-medium text-ink-gray-8 shadow-sm"
@ -15,15 +16,13 @@
</div> </div>
</template> </template>
</Button> </Button>
<Tooltip v-if="filters?.size" :text="__('Clear all Filter')"> <Button
<div> v-if="filters?.size"
<Button :tooltip="__('Clear all Filter')"
class="rounded-l-none border-l" class="rounded-l-none border-l"
icon="x" icon="x"
@click.stop="clearfilter(false)" @click.stop="clearfilter(close)"
/> />
</div>
</Tooltip>
</div> </div>
</template> </template>
<template #body="{ close }"> <template #body="{ close }">
@ -134,13 +133,10 @@
<Button <Button
class="!text-ink-gray-5" class="!text-ink-gray-5"
variant="ghost" variant="ghost"
@click="togglePopover()"
:label="__('Add Filter')" :label="__('Add Filter')"
> iconLeft="plus"
<template #prefix> @click="togglePopover()"
<FeatherIcon name="plus" class="h-4" /> />
</template>
</Button>
</template> </template>
</Autocomplete> </Autocomplete>
<Button <Button
@ -154,17 +150,16 @@
</div> </div>
</div> </div>
</template> </template>
</NestedPopover> </Popover>
</template> </template>
<script setup> <script setup>
import NestedPopover from '@/components/NestedPopover.vue'
import FilterIcon from '@/components/Icons/FilterIcon.vue' import FilterIcon from '@/components/Icons/FilterIcon.vue'
import Link from '@/components/Controls/Link.vue' import Link from '@/components/Controls/Link.vue'
import Autocomplete from '@/components/frappe-ui/Autocomplete.vue' import Autocomplete from '@/components/frappe-ui/Autocomplete.vue'
import { import {
FormControl, FormControl,
createResource, createResource,
Tooltip, Popover,
DatePicker, DatePicker,
DateTimePicker, DateTimePicker,
DateRangePicker, DateRangePicker,
@ -485,7 +480,7 @@ function removeFilter(index) {
function clearfilter(close) { function clearfilter(close) {
filters.value.clear() filters.value.clear()
apply() apply()
close && close() close()
} }
function updateValue(value, filter) { function updateValue(value, filter) {

View File

@ -7,18 +7,10 @@
? groupByValue?.label ? groupByValue?.label
: __('Group By: ') + groupByValue?.label : __('Group By: ') + groupByValue?.label
" "
:iconLeft="DetailsIcon"
:iconRight="isOpen ? 'chevron-up' : 'chevron-down'"
@click="togglePopover()" @click="togglePopover()"
> />
<template #prefix>
<DetailsIcon />
</template>
<template #suffix>
<FeatherIcon
:name="isOpen ? 'chevron-up' : 'chevron-down'"
class="h-4"
/>
</template>
</Button>
</template> </template>
</Autocomplete> </Autocomplete>
</template> </template>

View File

@ -69,7 +69,7 @@
</Popover> </Popover>
</template> </template>
<script setup> <script setup>
import Popover from '@/components/frappe-ui/Popover.vue' import { Popover } from 'frappe-ui'
import { gemoji } from 'gemoji' import { gemoji } from 'gemoji'
import { ref, computed } from 'vue' import { ref, computed } from 'vue'

View File

@ -3,11 +3,8 @@
:label="__('Kanban Settings')" :label="__('Kanban Settings')"
@click="showDialog = true" @click="showDialog = true"
v-bind="$attrs" v-bind="$attrs"
> :iconLeft="KanbanIcon"
<template #prefix> />
<KanbanIcon class="h-4" />
</template>
</Button>
<Dialog v-model="showDialog" :options="{ title: __('Kanban Settings') }"> <Dialog v-model="showDialog" :options="{ title: __('Kanban Settings') }">
<template #body-content> <template #body-content>
<div> <div>
@ -23,8 +20,8 @@
<template #target="{ togglePopover }"> <template #target="{ togglePopover }">
<Button <Button
class="w-full !justify-start" class="w-full !justify-start"
@click="togglePopover()"
:label="columnField.label" :label="columnField.label"
@click="togglePopover()"
/> />
</template> </template>
</Autocomplete> </Autocomplete>
@ -80,13 +77,10 @@
<template #target="{ togglePopover }"> <template #target="{ togglePopover }">
<Button <Button
class="w-full mt-2" class="w-full mt-2"
@click="togglePopover()"
:label="__('Add Field')" :label="__('Add Field')"
> iconLeft="plus"
<template #prefix> @click="togglePopover()"
<FeatherIcon name="plus" class="h-4" /> />
</template>
</Button>
</template> </template>
<template #item-label="{ option }"> <template #item-label="{ option }">
<div class="flex flex-col gap-1 text-ink-gray-9"> <div class="flex flex-col gap-1 text-ink-gray-9">

View File

@ -15,17 +15,18 @@
> >
<div class="flex gap-2 items-center group justify-between"> <div class="flex gap-2 items-center group justify-between">
<div class="flex items-center text-base"> <div class="flex items-center text-base">
<NestedPopover> <Popover>
<template #target> <template #target="{ togglePopover }">
<Button <Button
variant="ghost" variant="ghost"
size="sm" size="sm"
class="hover:!bg-surface-gray-2" class="hover:!bg-surface-gray-2"
@click="togglePopover"
> >
<IndicatorIcon :class="parseColor(column.column.color)" /> <IndicatorIcon :class="parseColor(column.column.color)" />
</Button> </Button>
</template> </template>
<template #body="{ close }"> <template #body>
<div <div
class="flex flex-col gap-3 px-3 py-2.5 min-w-40 rounded-lg bg-surface-modal shadow-2xl ring-1 ring-black ring-opacity-5 focus:outline-none" class="flex flex-col gap-3 px-3 py-2.5 min-w-40 rounded-lg bg-surface-modal shadow-2xl ring-1 ring-black ring-opacity-5 focus:outline-none"
> >
@ -48,7 +49,7 @@
</div> </div>
</div> </div>
</template> </template>
</NestedPopover> </Popover>
<div class="text-ink-gray-9">{{ column.column.name }}</div> <div class="text-ink-gray-9">{{ column.column.name }}</div>
</div> </div>
<div class="flex"> <div class="flex">
@ -153,13 +154,10 @@
<template #target="{ togglePopover }"> <template #target="{ togglePopover }">
<Button <Button
class="w-full mt-2.5 mb-1 mr-5" class="w-full mt-2.5 mb-1 mr-5"
@click="togglePopover()"
:label="__('Add Column')" :label="__('Add Column')"
> iconLeft="plus"
<template #prefix> @click="togglePopover()"
<FeatherIcon name="plus" class="h-4" /> />
</template>
</Button>
</template> </template>
</Autocomplete> </Autocomplete>
</div> </div>
@ -167,11 +165,10 @@
</template> </template>
<script setup> <script setup>
import Autocomplete from '@/components/frappe-ui/Autocomplete.vue' import Autocomplete from '@/components/frappe-ui/Autocomplete.vue'
import NestedPopover from '@/components/NestedPopover.vue'
import IndicatorIcon from '@/components/Icons/IndicatorIcon.vue' import IndicatorIcon from '@/components/Icons/IndicatorIcon.vue'
import { isTouchScreenDevice, colors, parseColor } from '@/utils' import { isTouchScreenDevice, colors, parseColor } from '@/utils'
import Draggable from 'vuedraggable' import Draggable from 'vuedraggable'
import { Dropdown } from 'frappe-ui' import { Dropdown, Popover } from 'frappe-ui'
import { computed } from 'vue' import { computed } from 'vue'
const props = defineProps({ const props = defineProps({

View File

@ -3,8 +3,8 @@
class="relative flex h-full flex-col justify-between transition-all duration-300 ease-in-out" class="relative flex h-full flex-col justify-between transition-all duration-300 ease-in-out"
:class="isSidebarCollapsed ? 'w-12' : 'w-[220px]'" :class="isSidebarCollapsed ? 'w-12' : 'w-[220px]'"
> >
<div> <div class="p-2">
<UserDropdown class="p-2" :isCollapsed="isSidebarCollapsed" /> <UserDropdown :isCollapsed="isSidebarCollapsed" />
</div> </div>
<div class="flex-1 overflow-y-auto"> <div class="flex-1 overflow-y-auto">
<div class="mb-3 flex flex-col"> <div class="mb-3 flex flex-col">
@ -197,51 +197,50 @@ const isSidebarCollapsed = useStorage('isSidebarCollapsed', false)
const isFCSite = ref(window.is_fc_site) const isFCSite = ref(window.is_fc_site)
const isDemoSite = ref(window.is_demo_site) const isDemoSite = ref(window.is_demo_site)
const allViews = computed(() => { const links = [
const links = [ {
{ label: 'Dashboard',
label: 'Dashboard', icon: LucideLayoutDashboard,
icon: LucideLayoutDashboard, to: 'Dashboard',
to: 'Dashboard', },
condition: () => isManager(), {
}, label: 'Leads',
{ icon: LeadsIcon,
label: 'Leads', to: 'Leads',
icon: LeadsIcon, },
to: 'Leads', {
}, label: 'Deals',
{ icon: DealsIcon,
label: 'Deals', to: 'Deals',
icon: DealsIcon, },
to: 'Deals', {
}, label: 'Contacts',
{ icon: ContactsIcon,
label: 'Contacts', to: 'Contacts',
icon: ContactsIcon, },
to: 'Contacts', {
}, label: 'Organizations',
{ icon: OrganizationsIcon,
label: 'Organizations', to: 'Organizations',
icon: OrganizationsIcon, },
to: 'Organizations', {
}, label: 'Notes',
{ icon: NoteIcon,
label: 'Notes', to: 'Notes',
icon: NoteIcon, },
to: 'Notes', {
}, label: 'Tasks',
{ icon: TaskIcon,
label: 'Tasks', to: 'Tasks',
icon: TaskIcon, },
to: 'Tasks', {
}, label: 'Call Logs',
{ icon: PhoneIcon,
label: 'Call Logs', to: 'Call Logs',
icon: PhoneIcon, },
to: 'Call Logs', ]
},
]
const allViews = computed(() => {
let _views = [ let _views = [
{ {
name: 'All Views', name: 'All Views',

View File

@ -11,19 +11,18 @@
<div class="flex items-center gap-1"> <div class="flex items-center gap-1">
<Button <Button
v-if="isManager() && !isMobileView" v-if="isManager() && !isMobileView"
:tooltip="__('Edit fields layout')"
variant="ghost" variant="ghost"
:icon="EditIcon"
class="w-7" class="w-7"
@click="openQuickEntryModal" @click="openQuickEntryModal"
> />
<template #icon> <Button
<EditIcon /> icon="x"
</template> variant="ghost"
</Button> class="w-7"
<Button variant="ghost" class="w-7" @click="show = false"> @click="show = false"
<template #icon> />
<FeatherIcon name="x" class="size-4" />
</template>
</Button>
</div> </div>
</div> </div>
<div v-if="tabs.data && _address.doc"> <div v-if="tabs.data && _address.doc">

View File

@ -36,18 +36,17 @@
<Button <Button
v-if="!isMobileView" v-if="!isMobileView"
variant="ghost" variant="ghost"
:tooltip="__('Edit call log')"
:icon="EditIcon"
class="w-7" class="w-7"
@click="openCallLogModal" @click="openCallLogModal"
> />
<template #icon> <Button
<EditIcon /> icon="x"
</template> variant="ghost"
</Button> class="w-7"
<Button variant="ghost" class="w-7" @click="show = false"> @click="show = false"
<template #icon> />
<FeatherIcon name="x" class="size-4" />
</template>
</Button>
</div> </div>
</div> </div>
<div class="flex flex-col gap-3.5"> <div class="flex flex-col gap-3.5">

View File

@ -13,18 +13,17 @@
<Button <Button
v-if="isManager() && !isMobileView" v-if="isManager() && !isMobileView"
variant="ghost" variant="ghost"
:tooltip="__('Edit fields layout')"
:icon="EditIcon"
class="w-7" class="w-7"
@click="openQuickEntryModal" @click="openQuickEntryModal"
> />
<template #icon> <Button
<EditIcon /> variant="ghost"
</template> class="w-7"
</Button> @click="show = false"
<Button variant="ghost" class="w-7" @click="show = false"> icon="x"
<template #icon> />
<FeatherIcon name="x" class="size-4" />
</template>
</Button>
</div> </div>
</div> </div>
<div v-if="tabs.data"> <div v-if="tabs.data">

View File

@ -13,17 +13,16 @@
v-if="isManager() && !isMobileView" v-if="isManager() && !isMobileView"
variant="ghost" variant="ghost"
class="w-7" class="w-7"
:tooltip="__('Edit fields layout')"
:icon="EditIcon"
@click="openQuickEntryModal" @click="openQuickEntryModal"
> />
<template #icon> <Button
<EditIcon /> variant="ghost"
</template> class="w-7"
</Button> @click="show = false"
<Button variant="ghost" class="w-7" @click="show = false"> icon="x"
<template #icon> />
<FeatherIcon name="x" class="size-4" />
</template>
</Button>
</div> </div>
</div> </div>
<FieldLayout <FieldLayout
@ -90,12 +89,16 @@ const { document: _contact, triggerOnBeforeCreate } = useDocument('Contact')
async function createContact() { async function createContact() {
if (_contact.doc.email_id) { if (_contact.doc.email_id) {
_contact.doc.email_ids = [{ email_id: _contact.doc.email_id, is_primary: 1 }] _contact.doc.email_ids = [
{ email_id: _contact.doc.email_id, is_primary: 1 },
]
delete _contact.doc.email_id delete _contact.doc.email_id
} }
if (_contact.doc.mobile_no) { if (_contact.doc.mobile_no) {
_contact.doc.phone_nos = [{ phone: _contact.doc.mobile_no, is_primary_mobile_no: 1 }] _contact.doc.phone_nos = [
{ phone: _contact.doc.mobile_no, is_primary_mobile_no: 1 },
]
delete _contact.doc.mobile_no delete _contact.doc.mobile_no
} }

View File

@ -23,12 +23,10 @@
<Button <Button
v-if="isManager() && !isMobileView" v-if="isManager() && !isMobileView"
variant="ghost" variant="ghost"
:tooltip="__('Edit deal\'s mandatory fields layout')"
:icon="EditIcon"
@click="openQuickEntryModal" @click="openQuickEntryModal"
> />
<template #icon>
<EditIcon class="h-4 w-4" />
</template>
</Button>
<Button icon="x" variant="ghost" @click="show = false" /> <Button icon="x" variant="ghost" @click="show = false" />
</div> </div>
</div> </div>

View File

@ -13,17 +13,16 @@
v-if="isManager() && !isMobileView" v-if="isManager() && !isMobileView"
variant="ghost" variant="ghost"
class="w-7" class="w-7"
:tooltip="__('Edit fields layout')"
:icon="EditIcon"
@click="openQuickEntryModal" @click="openQuickEntryModal"
> />
<template #icon> <Button
<EditIcon /> variant="ghost"
</template> class="w-7"
</Button> icon="x"
<Button variant="ghost" class="w-7" @click="show = false"> @click="show = false"
<template #icon> />
<FeatherIcon name="x" class="size-4" />
</template>
</Button>
</div> </div>
</div> </div>
<div v-if="tabs.data"> <div v-if="tabs.data">

View File

@ -13,17 +13,16 @@
v-if="isManager() && !isMobileView" v-if="isManager() && !isMobileView"
variant="ghost" variant="ghost"
class="w-7" class="w-7"
:tooltip="__('Edit fields layout')"
:icon="EditIcon"
@click="openQuickEntryModal" @click="openQuickEntryModal"
> />
<template #icon> <Button
<EditIcon /> variant="ghost"
</template> class="w-7"
</Button> icon="x"
<Button variant="ghost" class="w-7" @click="show = false"> @click="show = false"
<template #icon> />
<FeatherIcon name="x" class="size-4" />
</template>
</Button>
</div> </div>
</div> </div>
<div> <div>

View File

@ -13,17 +13,16 @@
v-if="isManager() && !isMobileView" v-if="isManager() && !isMobileView"
variant="ghost" variant="ghost"
class="w-7" class="w-7"
:tooltip="__('Edit fields layout')"
:icon="EditIcon"
@click="openQuickEntryModal" @click="openQuickEntryModal"
> />
<template #icon> <Button
<EditIcon /> variant="ghost"
</template> class="w-7"
</Button> @click="show = false"
<Button variant="ghost" class="w-7" @click="show = false"> icon="x"
<template #icon> />
<FeatherIcon name="x" class="size-4" />
</template>
</Button>
</div> </div>
</div> </div>
<div> <div>

View File

@ -1,41 +1,59 @@
<template> <template>
<Dialog v-model="show" :options="{ <Dialog
size: 'xl', v-model="show"
actions: [ :options="{
{ size: 'xl',
label: editMode ? __('Update') : __('Create'), actions: [
variant: 'solid', {
onClick: () => updateNote(), label: editMode ? __('Update') : __('Create'),
}, variant: 'solid',
], onClick: () => updateNote(),
}"> },
],
}"
>
<template #body-title> <template #body-title>
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<h3 class="text-2xl font-semibold leading-6 text-ink-gray-9"> <h3 class="text-2xl font-semibold leading-6 text-ink-gray-9">
{{ editMode ? __('Edit Note') : __('Create Note') }} {{ editMode ? __('Edit Note') : __('Create Note') }}
</h3> </h3>
<Button v-if="_note?.reference_docname" size="sm" :label="_note.reference_doctype == 'CRM Deal' <Button
? __('Open Deal') v-if="_note?.reference_docname"
: __('Open Lead') size="sm"
" @click="redirect()"> :label="
<template #suffix> _note.reference_doctype == 'CRM Deal'
<ArrowUpRightIcon class="w-4 h-4" /> ? __('Open Deal')
</template> : __('Open Lead')
</Button> "
:iconRight="ArrowUpRightIcon"
@click="redirect()"
/>
</div> </div>
</template> </template>
<template #body-content> <template #body-content>
<div class="flex flex-col gap-4"> <div class="flex flex-col gap-4">
<div> <div>
<FormControl ref="title" :label="__('Title')" v-model="_note.title" :placeholder="__('Call with John Doe')" <FormControl
required /> ref="title"
:label="__('Title')"
v-model="_note.title"
:placeholder="__('Call with John Doe')"
required
/>
</div> </div>
<div> <div>
<div class="mb-1.5 text-xs text-ink-gray-5">{{ __('Content') }}</div> <div class="mb-1.5 text-xs text-ink-gray-5">{{ __('Content') }}</div>
<TextEditor variant="outline" ref="content" <TextEditor
variant="outline"
ref="content"
editor-class="!prose-sm overflow-auto min-h-[180px] max-h-80 py-1.5 px-2 rounded border border-[--surface-gray-2] bg-surface-gray-2 placeholder-ink-gray-4 hover:border-outline-gray-modals hover:bg-surface-gray-3 hover:shadow-sm focus:bg-surface-white focus:border-outline-gray-4 focus:shadow-sm focus:ring-0 focus-visible:ring-2 focus-visible:ring-outline-gray-3 text-ink-gray-8 transition-colors" editor-class="!prose-sm overflow-auto min-h-[180px] max-h-80 py-1.5 px-2 rounded border border-[--surface-gray-2] bg-surface-gray-2 placeholder-ink-gray-4 hover:border-outline-gray-modals hover:bg-surface-gray-3 hover:shadow-sm focus:bg-surface-white focus:border-outline-gray-4 focus:shadow-sm focus:ring-0 focus-visible:ring-2 focus-visible:ring-outline-gray-3 text-ink-gray-8 transition-colors"
:bubbleMenu="true" :content="_note.content" @change="(val) => (_note.content = val)" :placeholder="__('Took a call with John Doe and discussed the new project.') :bubbleMenu="true"
" /> :content="_note.content"
@change="(val) => (_note.content = val)"
:placeholder="
__('Took a call with John Doe and discussed the new project.')
"
/>
</div> </div>
<ErrorMessage class="mt-4" v-if="error" :message="__(error)" /> <ErrorMessage class="mt-4" v-if="error" :message="__(error)" />
</div> </div>
@ -92,21 +110,25 @@ async function updateNote() {
emit('after', d) emit('after', d)
} }
} else { } else {
let d = await call('frappe.client.insert', { let d = await call(
doc: { 'frappe.client.insert',
doctype: 'FCRM Note', {
title: _note.value.title, doc: {
content: _note.value.content, doctype: 'FCRM Note',
reference_doctype: props.doctype, title: _note.value.title,
reference_docname: props.doc || '', content: _note.value.content,
reference_doctype: props.doctype,
reference_docname: props.doc || '',
},
}, },
}, { {
onError: (err) => { onError: (err) => {
if (err.error.exc_type == 'MandatoryError') { if (err.error.exc_type == 'MandatoryError') {
error.value = "Title is mandatory" error.value = 'Title is mandatory'
} }
} },
}) },
)
if (d.name) { if (d.name) {
updateOnboardingStep('create_first_note') updateOnboardingStep('create_first_note')
capture('note_created') capture('note_created')

View File

@ -13,17 +13,16 @@
v-if="isManager() && !isMobileView" v-if="isManager() && !isMobileView"
variant="ghost" variant="ghost"
class="w-7" class="w-7"
:tooltip="__('Edit fields layout')"
:icon="EditIcon"
@click="openQuickEntryModal" @click="openQuickEntryModal"
> />
<template #icon> <Button
<EditIcon /> variant="ghost"
</template> class="w-7"
</Button> @click="show = false"
<Button variant="ghost" class="w-7" @click="show = false"> icon="x"
<template #icon> />
<FeatherIcon name="x" class="size-4" />
</template>
</Button>
</div> </div>
</div> </div>
<FieldLayout <FieldLayout

View File

@ -25,12 +25,9 @@
? __('Open Deal') ? __('Open Deal')
: __('Open Lead') : __('Open Lead')
" "
:iconRight="ArrowUpRightIcon"
@click="redirect()" @click="redirect()"
> />
<template #suffix>
<ArrowUpRightIcon class="w-4 h-4" />
</template>
</Button>
</div> </div>
</template> </template>
<template #body-content> <template #body-content>

View File

@ -7,17 +7,6 @@
: duplicateMode : duplicateMode
? __('Duplicate View') ? __('Duplicate View')
: __('Create View'), : __('Create View'),
actions: [
{
label: editMode
? __('Save Changes')
: duplicateMode
? __('Duplicate')
: __('Create'),
variant: 'solid',
onClick: () => (editMode ? update() : create()),
},
],
}" }"
> >
<template #body-content> <template #body-content>
@ -42,6 +31,21 @@
/> />
</div> </div>
</template> </template>
<template #actions>
<div class="flex justify-end">
<Button
variant="solid"
:label="
editMode
? __('Save Changes')
: duplicateMode
? __('Duplicate')
: __('Create')
"
@click="() => (editMode ? update() : create())"
/>
</div>
</template>
</Dialog> </Dialog>
</template> </template>

View File

@ -9,21 +9,9 @@
$attrs.class, $attrs.class,
showDropdown ? 'rounded-br-none rounded-tr-none' : '', showDropdown ? 'rounded-br-none rounded-tr-none' : '',
]" ]"
:iconLeft="activeButton.icon"
@click="() => activeButton.onClick()" @click="() => activeButton.onClick()"
> />
<template #prefix>
<FeatherIcon
v-if="activeButton.icon && typeof activeButton.icon === 'string'"
:name="activeButton.icon"
class="h-4 w-4"
/>
<component
v-else-if="activeButton.icon"
:is="activeButton.icon"
class="h-4 w-4"
/>
</template>
</Button>
<Dropdown <Dropdown
v-if="showDropdown" v-if="showDropdown"
:options="parsedOptions" :options="parsedOptions"

View File

@ -1,60 +0,0 @@
<template>
<Popover v-slot="{ open }">
<PopoverButton
as="div"
ref="reference"
@click="updatePosition"
@focusin="updatePosition"
@keydown="updatePosition"
v-slot="{ open }"
>
<slot name="target" v-bind="{ open }" />
</PopoverButton>
<div v-show="open">
<PopoverPanel
v-slot="{ open, close }"
ref="popover"
static
class="z-[100]"
>
<slot name="body" v-bind="{ open, close }" />
</PopoverPanel>
</div>
</Popover>
</template>
<script setup>
import { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue'
import { createPopper } from '@popperjs/core'
import { nextTick, ref, onBeforeUnmount } from 'vue'
const props = defineProps({
placement: {
type: String,
default: 'bottom-start',
},
})
const reference = ref(null)
const popover = ref(null)
let popper = ref(null)
function setupPopper() {
if (!popper.value) {
popper.value = createPopper(reference.value.el, popover.value.el, {
placement: props.placement,
})
} else {
popper.value.update()
}
}
function updatePosition() {
nextTick(() => setupPopper())
}
onBeforeUnmount(() => {
popper.value?.destroy()
})
</script>

View File

@ -16,24 +16,18 @@
> >
<div class="text-base font-medium">{{ __('Notifications') }}</div> <div class="text-base font-medium">{{ __('Notifications') }}</div>
<div class="flex gap-1"> <div class="flex gap-1">
<Tooltip :text="__('Mark all as read')"> <Button
<div> :tooltip="__('Mark all as read')"
<Button variant="ghost" @click="() => markAllAsRead()"> :icon="MarkAsDoneIcon"
<template #icon> variant="ghost"
<MarkAsDoneIcon class="h-4 w-4" /> @click="markAllAsRead"
</template> />
</Button> <Button
</div> :tooltip="__('Close')"
</Tooltip> icon="x"
<Tooltip :text="__('Close')"> variant="ghost"
<div> @click="() => toggle()"
<Button variant="ghost" @click="() => toggle()"> />
<template #icon>
<FeatherIcon name="x" class="h-4 w-4" />
</template>
</Button>
</div>
</Tooltip>
</div> </div>
</div> </div>
<div <div
@ -100,7 +94,6 @@ import { globalStore } from '@/stores/global'
import { timeAgo } from '@/utils' import { timeAgo } from '@/utils'
import { onClickOutside } from '@vueuse/core' import { onClickOutside } from '@vueuse/core'
import { capture } from '@/telemetry' import { capture } from '@/telemetry'
import { Tooltip } from 'frappe-ui'
import { ref, onMounted, onBeforeUnmount } from 'vue' import { ref, onMounted, onBeforeUnmount } from 'vue'
const { $socket } = globalStore() const { $socket } = globalStore()

View File

@ -27,14 +27,10 @@
:options="s.options" :options="s.options"
> >
<template #default="{ open }"> <template #default="{ open }">
<Button :label="s.value"> <Button
<template #suffix> :label="s.value"
<FeatherIcon :iconRight="open ? 'chevron-up' : 'chevron-down'"
:name="open ? 'chevron-up' : 'chevron-down'" />
class="h-4"
/>
</template>
</Button>
</template> </template>
</Dropdown> </Dropdown>
</div> </div>

View File

@ -131,7 +131,7 @@
</div> </div>
</template> </template>
<script setup> <script setup>
import { ErrorMessage } from 'frappe-ui' import { ErrorMessage, toast } from 'frappe-ui'
import { getSettings } from '@/stores/settings' import { getSettings } from '@/stores/settings'
import { globalStore } from '@/stores/global' import { globalStore } from '@/stores/global'
import { showSettings } from '@/composables/settings' import { showSettings } from '@/composables/settings'

View File

@ -80,19 +80,16 @@
</span> </span>
</div> </div>
<div> <div>
<Tooltip text="Delete Invitation"> <Button
<div> :tooltip="__('Delete invitation')"
<Button icon="x"
icon="x" variant="ghost"
variant="ghost" :loading="
:loading=" pendingInvitations.delete.loading &&
pendingInvitations.delete.loading && pendingInvitations.delete.params.name === user.name
pendingInvitations.delete.params.name === user.name "
" @click="pendingInvitations.delete.submit(user.name)"
@click="pendingInvitations.delete.submit(user.name)" />
/>
</div>
</Tooltip>
</div> </div>
</li> </li>
</ul> </ul>

View File

@ -20,12 +20,9 @@
v-if="section.showEditButton" v-if="section.showEditButton"
variant="ghost" variant="ghost"
class="w-7 mr-2" class="w-7 mr-2"
:icon="EditIcon"
@click="showSidePanelModal = true" @click="showSidePanelModal = true"
> />
<template #icon>
<EditIcon />
</template>
</Button>
</slot> </slot>
</template> </template>
<slot v-bind="{ section }"> <slot v-bind="{ section }">
@ -83,11 +80,12 @@
</Tooltip> </Tooltip>
</div> </div>
<div v-else-if="field.fieldtype === 'Dropdown'"> <div v-else-if="field.fieldtype === 'Dropdown'">
<NestedPopover> <Popover>
<template #target="{ open }"> <template #target="{ isOpen, togglePopover }">
<Button <Button
:label="doc[field.fieldname]" :label="doc[field.fieldname]"
class="dropdown-button flex w-full items-center justify-between rounded border border-gray-100 bg-surface-gray-2 px-2 py-1.5 text-base text-ink-gray-8 placeholder-ink-gray-4 transition-colors hover:border-outline-gray-modals hover:bg-surface-gray-3 focus:border-outline-gray-4 focus:bg-surface-white focus:shadow-sm focus:outline-none focus:ring-0 focus-visible:ring-2 focus-visible:ring-outline-gray-3" class="dropdown-button flex w-full items-center justify-between rounded border border-gray-100 bg-surface-gray-2 px-2 py-1.5 text-base text-ink-gray-8 placeholder-ink-gray-4 transition-colors hover:border-outline-gray-modals hover:bg-surface-gray-3 focus:border-outline-gray-4 focus:bg-surface-white focus:shadow-sm focus:outline-none focus:ring-0 focus-visible:ring-2 focus-visible:ring-outline-gray-3"
@click="togglePopover"
> >
<div <div
v-if="doc[field.fieldname]" v-if="doc[field.fieldname]"
@ -103,7 +101,9 @@
</div> </div>
<template #suffix> <template #suffix>
<FeatherIcon <FeatherIcon
:name="open ? 'chevron-up' : 'chevron-down'" :name="
isOpen ? 'chevron-up' : 'chevron-down'
"
class="h-4 text-ink-gray-5" class="h-4 text-ink-gray-5"
/> />
</template> </template>
@ -135,16 +135,13 @@
variant="ghost" variant="ghost"
class="w-full !justify-start" class="w-full !justify-start"
:label="__('Create New')" :label="__('Create New')"
iconLeft="plus"
@click="field.create()" @click="field.create()"
> />
<template #prefix>
<FeatherIcon name="plus" class="h-4" />
</template>
</Button>
</div> </div>
</div> </div>
</template> </template>
</NestedPopover> </Popover>
</div> </div>
<FormControl <FormControl
v-else-if="field.fieldtype == 'Check'" v-else-if="field.fieldtype == 'Check'"
@ -369,7 +366,6 @@
import Password from '@/components/Controls/Password.vue' import Password from '@/components/Controls/Password.vue'
import FormattedInput from '@/components/Controls/FormattedInput.vue' import FormattedInput from '@/components/Controls/FormattedInput.vue'
import Section from '@/components/Section.vue' import Section from '@/components/Section.vue'
import NestedPopover from '@/components/NestedPopover.vue'
import DropdownItem from '@/components/DropdownItem.vue' import DropdownItem from '@/components/DropdownItem.vue'
import FadedScrollableDiv from '@/components/FadedScrollableDiv.vue' import FadedScrollableDiv from '@/components/FadedScrollableDiv.vue'
import ArrowUpRightIcon from '@/components/Icons/ArrowUpRightIcon.vue' import ArrowUpRightIcon from '@/components/Icons/ArrowUpRightIcon.vue'
@ -382,7 +378,7 @@ import { usersStore } from '@/stores/users'
import { isMobileView } from '@/composables/settings' import { isMobileView } from '@/composables/settings'
import { getFormat, evaluateDependsOnValue } from '@/utils' import { getFormat, evaluateDependsOnValue } from '@/utils'
import { flt } from '@/utils/numberFormat.js' import { flt } from '@/utils/numberFormat.js'
import { Tooltip, DateTimePicker, DatePicker } from 'frappe-ui' import { Tooltip, DateTimePicker, DatePicker, Popover } from 'frappe-ui'
import { useDocument } from '@/data/document' import { useDocument } from '@/data/document'
import { ref, computed, getCurrentInstance } from 'vue' import { ref, computed, getCurrentInstance } from 'vue'

View File

@ -94,13 +94,10 @@
<Button <Button
class="w-full h-8 mt-1.5 !bg-surface-gray-1" class="w-full h-8 mt-1.5 !bg-surface-gray-1"
variant="outline" variant="outline"
@click="togglePopover()"
:label="__('Add Field')" :label="__('Add Field')"
> iconLeft="plus"
<template #prefix> @click="togglePopover()"
<FeatherIcon name="plus" class="h-4" /> />
</template>
</Button>
</template> </template>
<template #item-label="{ option }"> <template #item-label="{ option }">
<div class="flex flex-col gap-1 text-ink-gray-9"> <div class="flex flex-col gap-1 text-ink-gray-9">
@ -128,6 +125,7 @@
class="w-full h-8" class="w-full h-8"
variant="subtle" variant="subtle"
:label="__('Add Section')" :label="__('Add Section')"
iconLeft="plus"
@click=" @click="
sections.push({ sections.push({
label: __('New Section'), label: __('New Section'),
@ -136,11 +134,7 @@
columns: [{ name: 'column_' + getRandom(), fields: [] }], columns: [{ name: 'column_' + getRandom(), fields: [] }],
}) })
" "
> />
<template #prefix>
<FeatherIcon name="plus" class="h-4" />
</template>
</Button>
</div> </div>
</div> </div>
</template> </template>

View File

@ -17,13 +17,15 @@
</Button> </Button>
</template> </template>
</Autocomplete> </Autocomplete>
<NestedPopover v-else> <Popover placement="bottom-end" v-else>
<template #target="{ open }"> <template #target="{ isOpen, togglePopover }">
<Button v-if="sortValues.size > 1" :label="__('Sort')"> <Button
<template v-if="hideLabel"> v-if="sortValues.size > 1"
<SortIcon class="h-4" /> :label="__('Sort')"
</template> :icon="hideLabel && SortIcon"
<template v-if="!hideLabel" #prefix><SortIcon class="h-4" /></template> :iconLeft="!hideLabel && SortIcon"
@click="togglePopover"
>
<template v-if="sortValues?.size" #suffix> <template v-if="sortValues?.size" #suffix>
<div <div
class="flex h-5 w-5 items-center justify-center rounded-[5px] bg-surface-white pt-px text-xs font-medium text-ink-gray-8 shadow-sm" class="flex h-5 w-5 items-center justify-center rounded-[5px] bg-surface-white pt-px text-xs font-medium text-ink-gray-8 shadow-sm"
@ -36,6 +38,11 @@
<Button <Button
v-if="sortValues.size" v-if="sortValues.size"
class="rounded-r-none border-r" class="rounded-r-none border-r"
:icon="
Array.from(sortValues)[0].direction == 'asc'
? AscendingIcon
: DesendingIcon
"
@click.stop=" @click.stop="
() => { () => {
Array.from(sortValues)[0].direction = Array.from(sortValues)[0].direction =
@ -43,28 +50,17 @@
apply() apply()
} }
" "
> />
<AscendingIcon
v-if="Array.from(sortValues)[0].direction == 'asc'"
class="h-4"
/>
<DesendingIcon v-else class="h-4" />
</Button>
<Button <Button
:label="getSortLabel()" :label="getSortLabel()"
class="shrink-0" class="shrink-0 [&_svg]:text-ink-gray-5"
:iconLeft="!hideLabel && !sortValues?.size && SortIcon"
:iconRight="
sortValues?.size && (isOpen ? 'chevron-up' : 'chevron-down')
"
:class="sortValues.size ? 'rounded-l-none' : ''" :class="sortValues.size ? 'rounded-l-none' : ''"
> @click.stop="togglePopover"
<template v-if="!hideLabel && !sortValues?.size" #prefix> />
<SortIcon class="h-4" />
</template>
<template v-if="sortValues?.size" #suffix>
<FeatherIcon
:name="open ? 'chevron-up' : 'chevron-down'"
class="h-4 text-ink-gray-5"
/>
</template>
</Button>
</div> </div>
</template> </template>
<template #body="{ close }"> <template #body="{ close }">
@ -85,42 +81,42 @@
<div class="handle flex h-7 w-7 items-center justify-center"> <div class="handle flex h-7 w-7 items-center justify-center">
<DragIcon class="h-4 w-4 cursor-grab text-ink-gray-5" /> <DragIcon class="h-4 w-4 cursor-grab text-ink-gray-5" />
</div> </div>
<div class="flex flex-1 [&>_div]:w-full"> <div class="flex flex-1">
<Button <Button
size="md" size="md"
class="rounded-r-none border-r" class="rounded-r-none border-r"
:icon="
sort.direction == 'asc' ? AscendingIcon : DesendingIcon
"
@click=" @click="
() => { () => {
sort.direction = sort.direction == 'asc' ? 'desc' : 'asc' sort.direction = sort.direction == 'asc' ? 'desc' : 'asc'
apply() apply()
} }
" "
> />
<AscendingIcon v-if="sort.direction == 'asc'" class="h-4" />
<DesendingIcon v-else class="h-4" />
</Button>
<Autocomplete <Autocomplete
class="[&>_div]:w-full"
:value="sort.fieldname" :value="sort.fieldname"
:options="sortOptions.data" :options="sortOptions.data"
@change="(e) => updateSort(e, i)" @change="(e) => updateSort(e, i)"
:placeholder="__('First Name')" :placeholder="__('First Name')"
> >
<template <template
#target="{ togglePopover, selectedValue, displayValue }" #target="{
open,
togglePopover,
selectedValue,
displayValue,
}"
> >
<Button <Button
class="flex w-full items-center justify-between rounded-l-none !text-ink-gray-5" class="flex w-full items-center justify-between rounded-l-none !text-ink-gray-5"
size="md" size="md"
:label="displayValue(selectedValue)"
:iconRight="open ? 'chevron-down' : 'chevron-up'"
@click="togglePopover()" @click="togglePopover()"
> />
{{ displayValue(selectedValue) }}
<template #suffix>
<FeatherIcon
name="chevron-down"
class="h-4 text-ink-gray-5"
/>
</template>
</Button>
</template> </template>
</Autocomplete> </Autocomplete>
</div> </div>
@ -143,14 +139,11 @@
<template #target="{ togglePopover }"> <template #target="{ togglePopover }">
<Button <Button
class="!text-ink-gray-5" class="!text-ink-gray-5"
variant="ghost"
@click="togglePopover()"
:label="__('Add Sort')" :label="__('Add Sort')"
> variant="ghost"
<template #prefix> iconLeft="plus"
<FeatherIcon name="plus" class="h-4" /> @click="togglePopover()"
</template> />
</Button>
</template> </template>
</Autocomplete> </Autocomplete>
<Button <Button
@ -164,18 +157,17 @@
</div> </div>
</div> </div>
</template> </template>
</NestedPopover> </Popover>
</template> </template>
<script setup> <script setup>
import AscendingIcon from '@/components/Icons/AscendingIcon.vue' import AscendingIcon from '@/components/Icons/AscendingIcon.vue'
import DesendingIcon from '@/components/Icons/DesendingIcon.vue' import DesendingIcon from '@/components/Icons/DesendingIcon.vue'
import NestedPopover from '@/components/NestedPopover.vue'
import SortIcon from '@/components/Icons/SortIcon.vue' import SortIcon from '@/components/Icons/SortIcon.vue'
import DragIcon from '@/components/Icons/DragIcon.vue' import DragIcon from '@/components/Icons/DragIcon.vue'
import Autocomplete from '@/components/frappe-ui/Autocomplete.vue' import Autocomplete from '@/components/frappe-ui/Autocomplete.vue'
import { useSortable } from '@vueuse/integrations/useSortable' import { useSortable } from '@vueuse/integrations/useSortable'
import { createResource } from 'frappe-ui' import { createResource, Popover } from 'frappe-ui'
import { computed, nextTick, onMounted } from 'vue' import { computed, nextTick, onMounted } from 'vue'
const props = defineProps({ const props = defineProps({

View File

@ -123,13 +123,11 @@
<div class="flex"> <div class="flex">
<Button <Button
@click="toggleCallPopup" @click="toggleCallPopup"
class="bg-surface-gray-7 text-ink-white hover:bg-surface-gray-6 shrink-0" class="bg-surface-gray-7 text-ink-white hover:bg-surface-gray-6 shrink-0 cursor-pointer"
:tooltip="__('Minimize')"
:icon="MinimizeIcon"
size="md" size="md"
> />
<template #icon>
<MinimizeIcon class="h-4 w-4 cursor-pointer" />
</template>
</Button>
<Button <Button
v-if="callStatus == 'Call ended' || callStatus == 'No answer'" v-if="callStatus == 'Call ended' || callStatus == 'No answer'"
@click="closeCallPopup" @click="closeCallPopup"
@ -182,33 +180,26 @@
<div class="flex gap-2"> <div class="flex gap-2">
<Button <Button
class="bg-surface-gray-6 text-ink-white hover:bg-surface-gray-5" class="bg-surface-gray-6 text-ink-white hover:bg-surface-gray-5"
:tooltip="__('Add a note')"
size="md" size="md"
:icon="NoteIcon"
@click="showNoteWindow" @click="showNoteWindow"
> />
<template #icon>
<NoteIcon class="w-4 h-4" />
</template>
</Button>
<Button <Button
class="bg-surface-gray-6 text-ink-white hover:bg-surface-gray-5" class="bg-surface-gray-6 text-ink-white hover:bg-surface-gray-5"
size="md" size="md"
:tooltip="__('Add a task')"
:icon="TaskIcon"
@click="showTaskWindow" @click="showTaskWindow"
> />
<template #icon>
<TaskIcon class="w-4 h-4" />
</template>
</Button>
<Button <Button
v-if="contact.deal || contact.lead" v-if="contact.deal || contact.lead"
class="bg-surface-gray-6 text-ink-white hover:bg-surface-gray-5" class="bg-surface-gray-6 text-ink-white hover:bg-surface-gray-5"
size="md" size="md"
:iconRight="ArrowUpRightIcon"
:label="contact.deal ? __('Deal') : __('Lead')" :label="contact.deal ? __('Deal') : __('Lead')"
@click="openDealOrLead" @click="openDealOrLead"
> />
<template #suffix>
<ArrowUpRightIcon class="w-4 h-4" />
</template>
</Button>
</div> </div>
<Button <Button

View File

@ -52,22 +52,18 @@
<DialpadIcon class="cursor-pointer rounded-full" /> <DialpadIcon class="cursor-pointer rounded-full" />
</template> </template>
</Button> --> </Button> -->
<Button class="rounded-full"> <Button
<template #icon> class="cursor-pointer rounded-full"
<NoteIcon :tooltip="__('Add a note')"
class="h-4 w-4 cursor-pointer rounded-full text-ink-gray-9" :icon="NoteIcon"
@click="showNoteModal = true" @click="showNoteModal = true"
/> />
</template> <Button
</Button> class="rounded-full bg-surface-red-5 hover:bg-surface-red-6 rotate-[135deg] text-ink-white"
<Button class="rounded-full bg-surface-red-5 hover:bg-surface-red-6"> :tooltip="__('Hang up')"
<template #icon> :icon="PhoneIcon"
<PhoneIcon @click="hangUpCall"
class="h-4 w-4 rotate-[135deg] fill-white text-ink-white" />
@click="hangUpCall"
/>
</template>
</Button>
</div> </div>
<div v-else-if="calling || callStatus == 'initiating'"> <div v-else-if="calling || callStatus == 'initiating'">
<Button <Button
@ -76,13 +72,10 @@
theme="red" theme="red"
:label="__('Cancel')" :label="__('Cancel')"
@click="cancelCall" @click="cancelCall"
class="rounded-lg" class="rounded-lg rotate-[135deg] text-ink-white"
:disabled="callStatus == 'initiating'" :disabled="callStatus == 'initiating'"
> :iconLeft="PhoneIcon"
<template #prefix> />
<PhoneIcon class="h-4 w-4 rotate-[135deg] fill-white" />
</template>
</Button>
</div> </div>
<div v-else class="flex gap-2"> <div v-else class="flex gap-2">
<Button <Button
@ -90,25 +83,19 @@
variant="solid" variant="solid"
theme="green" theme="green"
:label="__('Accept')" :label="__('Accept')"
class="rounded-lg" class="rounded-lg text-ink-white"
:iconLeft="PhoneIcon"
@click="acceptIncomingCall" @click="acceptIncomingCall"
> />
<template #prefix>
<PhoneIcon class="h-4 w-4 fill-white" />
</template>
</Button>
<Button <Button
size="md" size="md"
variant="solid" variant="solid"
theme="red" theme="red"
:label="__('Reject')" :label="__('Reject')"
class="rounded-lg" class="rounded-lg rotate-[135deg] text-ink-white"
:iconLeft="PhoneIcon"
@click="rejectIncomingCall" @click="rejectIncomingCall"
> />
<template #prefix>
<PhoneIcon class="h-4 w-4 rotate-[135deg] fill-white" />
</template>
</Button>
</div> </div>
</div> </div>
</div> </div>
@ -134,14 +121,13 @@
<div class="my-1 min-w-[40px] text-center"> <div class="my-1 min-w-[40px] text-center">
{{ counterUp?.updatedTime }} {{ counterUp?.updatedTime }}
</div> </div>
<Button variant="solid" theme="red" class="!h-6 !w-6 rounded-full"> <Button
<template #icon> variant="solid"
<PhoneIcon theme="red"
class="h-4 w-4 rotate-[135deg] fill-white" class="!h-6 !w-6 rounded-full rotate-[135deg] text-ink-white"
@click.stop="hangUpCall" :icon="PhoneIcon"
/> @click.stop="hangUpCall"
</template> />
</Button>
</div> </div>
<div v-else-if="calling" class="flex items-center gap-3"> <div v-else-if="calling" class="flex items-center gap-3">
<div class="my-1"> <div class="my-1">
@ -150,35 +136,28 @@
<Button <Button
variant="solid" variant="solid"
theme="red" theme="red"
class="!h-6 !w-6 rounded-full" class="!h-6 !w-6 rounded-full rotate-[135deg] text-ink-white"
:icon="PhoneIcon"
@click.stop="cancelCall" @click.stop="cancelCall"
> />
<template #icon>
<PhoneIcon class="h-4 w-4 rotate-[135deg] fill-white" />
</template>
</Button>
</div> </div>
<div v-else class="flex items-center gap-2"> <div v-else class="flex items-center gap-2">
<Button <Button
variant="solid" variant="solid"
theme="green" theme="green"
class="pulse relative !h-6 !w-6 rounded-full" class="pulse relative !h-6 !w-6 rounded-full animate-pulse text-ink-white"
:tooltip="__('Accept call')"
:icon="PhoneIcon"
@click.stop="acceptIncomingCall" @click.stop="acceptIncomingCall"
> />
<template #icon>
<PhoneIcon class="h-4 w-4 animate-pulse fill-white" />
</template>
</Button>
<Button <Button
variant="solid" variant="solid"
theme="red" theme="red"
class="!h-6 !w-6 rounded-full" class="!h-6 !w-6 rounded-full rotate-[135deg] text-ink-white"
:tooltip="__('Reject call')"
:icon="PhoneIcon"
@click.stop="rejectIncomingCall" @click.stop="rejectIncomingCall"
> />
<template #icon>
<PhoneIcon class="h-4 w-4 rotate-[135deg] fill-white" />
</template>
</Button>
</div> </div>
</div> </div>
<NoteModal <NoteModal

View File

@ -18,28 +18,25 @@
> >
/ /
</span> </span>
<Dropdown v-if="viewControls" :options="viewControls.viewsDropdownOptions"> <Dropdown
v-if="viewControls"
:options="viewControls.viewsDropdownOptions"
>
<template #default="{ open }"> <template #default="{ open }">
<Button <Button
variant="ghost" variant="ghost"
class="text-lg font-medium text-nowrap" class="text-lg font-medium text-nowrap"
:label="__(viewControls.currentView.label)" :label="__(viewControls.currentView.label)"
:iconRight="open ? 'chevron-up' : 'chevron-down'"
> >
<template #prefix> <template #prefix>
<Icon :icon="viewControls.currentView.icon" class="h-4" /> <Icon :icon="viewControls.currentView.icon" class="h-4" />
</template> </template>
<template #suffix>
<FeatherIcon
:name="open ? 'chevron-up' : 'chevron-down'"
class="h-4 text-ink-gray-8"
/>
</template>
</Button> </Button>
</template> </template>
<template #item="{ item, active }"> <template #item="{ item, close }">
<button <button
class="group flex text-ink-gray-6 gap-4 h-7 w-full justify-between items-center rounded px-2 text-base" class="group flex text-ink-gray-6 gap-4 h-7 w-full justify-between items-center rounded px-2 text-base hover:bg-surface-gray-3"
:class="{ 'bg-surface-gray-3': active }"
@click="item.onClick" @click="item.onClick"
> >
<div class="flex items-center"> <div class="flex items-center">
@ -63,16 +60,15 @@
class="flex flex-row-reverse gap-2 items-center min-w-11" class="flex flex-row-reverse gap-2 items-center min-w-11"
> >
<Dropdown <Dropdown
:class="active ? 'block' : 'hidden'"
placement="right-start" placement="right-start"
:options="viewControls.viewActions(item)" :options="viewControls.viewActions(item, close)"
> >
<template #default="{ togglePopover }"> <template #default>
<Button <Button
variant="ghost" variant="ghost"
class="!size-5" class="!size-5 hidden group-hover:block"
icon="more-horizontal" icon="more-horizontal"
@click.stop="togglePopover()" @click.stop
/> />
</template> </template>
</Dropdown> </Dropdown>
@ -89,7 +85,7 @@
</template> </template>
<script setup> <script setup>
import Icon from '@/components/Icon.vue' import Icon from '@/components/Icon.vue'
import Dropdown from '@/components/frappe-ui/Dropdown.vue' import { Dropdown } from 'frappe-ui'
const props = defineProps({ const props = defineProps({
routeName: { routeName: {

View File

@ -22,11 +22,12 @@
</div> </div>
<div class="flex gap-2"> <div class="flex gap-2">
<Button :label="__('Refresh')" @click="reload()" :loading="isLoading"> <Button
<template #icon> :tooltip="__('Refresh')"
<RefreshIcon class="h-4 w-4" /> :icon="RefreshIcon"
</template> :loading="isLoading"
</Button> @click="reload()"
/>
<SortBy <SortBy
v-if="route.params.viewType !== 'kanban'" v-if="route.params.viewType !== 'kanban'"
v-model="list" v-model="list"
@ -100,13 +101,10 @@
<Button <Button
class="whitespace-nowrap mr-2" class="whitespace-nowrap mr-2"
variant="ghost" variant="ghost"
@click="togglePopover()"
:label="__('Add filter')" :label="__('Add filter')"
> iconLeft="plus"
<template #prefix> @click="togglePopover()"
<FeatherIcon name="plus" class="h-4" /> />
</template>
</Button>
</template> </template>
<template #item-label="{ option }"> <template #item-label="{ option }">
<Tooltip :text="option.value" :hover-delay="1"> <Tooltip :text="option.value" :hover-delay="1">
@ -124,11 +122,7 @@
:loading="updateQuickFilters.loading" :loading="updateQuickFilters.loading"
@click="saveQuickFilters" @click="saveQuickFilters"
/> />
<Button @click="customizeQuickFilter = false"> <Button icon="x" @click="customizeQuickFilter = false" />
<template #icon>
<FeatherIcon name="x" class="h-4 w-4" />
</template>
</Button>
</div> </div>
</div> </div>
<div v-else class="flex items-center justify-between gap-2 px-5 py-4"> <div v-else class="flex items-center justify-between gap-2 px-5 py-4">
@ -157,11 +151,12 @@
<Button :label="__('Save Changes')" @click="saveView" /> <Button :label="__('Save Changes')" @click="saveView" />
</div> </div>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<Button :label="__('Refresh')" @click="reload()" :loading="isLoading"> <Button
<template #icon> :tooltip="__('Refresh')"
<RefreshIcon class="h-4 w-4" /> :icon="RefreshIcon"
</template> :loading="isLoading"
</Button> @click="reload()"
/>
<GroupBy <GroupBy
v-if="route.params.viewType === 'group_by'" v-if="route.params.viewType === 'group_by'"
v-model="list" v-model="list"
@ -194,6 +189,7 @@
/> />
<Dropdown <Dropdown
v-if="route.params.viewType !== 'kanban' || isManager()" v-if="route.params.viewType !== 'kanban' || isManager()"
placement="right"
:options="[ :options="[
{ {
group: __('Options'), group: __('Options'),
@ -218,7 +214,7 @@
]" ]"
> >
<template #default> <template #default>
<Button icon="more-horizontal" /> <Button :tooltip="__('More Options')" icon="more-horizontal" />
</template> </template>
</Dropdown> </Dropdown>
</div> </div>
@ -1088,7 +1084,7 @@ function updatePageLength(value, loadMore = false) {
} }
// View Actions // View Actions
const viewActions = (view) => { const viewActions = (view, close) => {
let isStandard = typeof view.name === 'string' let isStandard = typeof view.name === 'string'
let _view = getView(view.name) let _view = getView(view.name)
@ -1112,7 +1108,7 @@ const viewActions = (view) => {
{ {
label: __('Duplicate'), label: __('Duplicate'),
icon: () => h(DuplicateIcon, { class: 'h-4 w-4' }), icon: () => h(DuplicateIcon, { class: 'h-4 w-4' }),
onClick: () => duplicateView(_view), onClick: () => duplicateView(_view, close),
}, },
], ],
}, },
@ -1130,7 +1126,7 @@ const viewActions = (view) => {
actions[0].items.push({ actions[0].items.push({
label: __('Edit'), label: __('Edit'),
icon: () => h(EditIcon, { class: 'h-4 w-4' }), icon: () => h(EditIcon, { class: 'h-4 w-4' }),
onClick: () => editView(_view), onClick: () => editView(_view, close),
}) })
if (!_view.public) { if (!_view.public) {
@ -1213,17 +1209,19 @@ function setAsDefault(v) {
}) })
} }
function duplicateView(v) { function duplicateView(v, close) {
v.label = v.label + __(' (New)') v.label = v.label + __(' (New)')
viewModalObj.value = v viewModalObj.value = v
viewModalObj.value.mode = 'duplicate' viewModalObj.value.mode = 'duplicate'
showViewModal.value = true showViewModal.value = true
close()
} }
function editView(v) { function editView(v, close) {
viewModalObj.value = v viewModalObj.value = v
viewModalObj.value.mode = 'edit' viewModalObj.value.mode = 'edit'
showViewModal.value = true showViewModal.value = true
close()
} }
function publicView(v) { function publicView(v) {

View File

@ -8,9 +8,12 @@
v-if="callLogsListView?.customListActions" v-if="callLogsListView?.customListActions"
:actions="callLogsListView.customListActions" :actions="callLogsListView.customListActions"
/> />
<Button variant="solid" :label="__('Create')" @click="createCallLog"> <Button
<template #prefix><FeatherIcon name="plus" class="h-4" /></template> variant="solid"
</Button> :label="__('Create')"
iconLeft="plus"
@click="createCallLog"
/>
</template> </template>
</LayoutHeader> </LayoutHeader>
<ViewControls <ViewControls

View File

@ -93,17 +93,14 @@
v-if="callEnabled && contact.doc.mobile_no" v-if="callEnabled && contact.doc.mobile_no"
:label="__('Make Call')" :label="__('Make Call')"
size="sm" size="sm"
:iconLeft="PhoneIcon"
@click="callEnabled && makeCall(contact.doc.mobile_no)" @click="callEnabled && makeCall(contact.doc.mobile_no)"
> />
<template #prefix>
<PhoneIcon class="h-4 w-4" />
</template>
</Button>
<Button <Button
:label="__('Delete')" :label="__('Delete')"
theme="red" theme="red"
size="sm" size="sm"
icon-left="trash-2" iconLeft="trash-2"
@click="deleteContact()" @click="deleteContact()"
/> />
</div> </div>

View File

@ -11,10 +11,9 @@
<Button <Button
variant="solid" variant="solid"
:label="__('Create')" :label="__('Create')"
iconLeft="plus"
@click="showContactModal = true" @click="showContactModal = true"
> />
<template #prefix><FeatherIcon name="plus" class="h-4" /></template>
</Button>
</template> </template>
</LayoutHeader> </LayoutHeader>
<ViewControls <ViewControls
@ -57,9 +56,11 @@
> >
<ContactsIcon class="h-10 w-10" /> <ContactsIcon class="h-10 w-10" />
<span>{{ __('No {0} Found', [__('Contacts')]) }}</span> <span>{{ __('No {0} Found', [__('Contacts')]) }}</span>
<Button :label="__('Create')" @click="showContactModal = true"> <Button
<template #prefix><FeatherIcon name="plus" class="h-4" /></template> :label="__('Create')"
</Button> iconLeft="plus"
@click="showContactModal = true"
/>
</div> </div>
</div> </div>
<ContactModal <ContactModal

View File

@ -8,36 +8,27 @@
<Button <Button
v-if="!editing" v-if="!editing"
:label="__('Refresh')" :label="__('Refresh')"
:iconLeft="LucideRefreshCcw"
@click="dashboardItems.reload" @click="dashboardItems.reload"
> />
<template #prefix>
<LucideRefreshCcw class="size-4" />
</template>
</Button>
<Button <Button
v-if="!editing && isAdmin()" v-if="!editing && isAdmin()"
:label="__('Edit')" :label="__('Edit')"
:iconLeft="LucidePenLine"
@click="enableEditing" @click="enableEditing"
> />
<template #prefix>
<LucidePenLine class="size-4" />
</template>
</Button>
<Button <Button
v-if="editing" v-if="editing"
:label="__('Chart')" :label="__('Chart')"
icon-left="plus" iconLeft="plus"
@click="showAddChartModal = true" @click="showAddChartModal = true"
/> />
<Button <Button
v-if="editing && isAdmin()" v-if="editing && isAdmin()"
:label="__('Reset to default')" :label="__('Reset to default')"
:iconLeft="LucideUndo2"
@click="resetToDefault" @click="resetToDefault"
> />
<template #prefix>
<LucideUndo2 class="size-4" />
</template>
</Button>
<Button v-if="editing" :label="__('Cancel')" @click="cancel" /> <Button v-if="editing" :label="__('Cancel')" @click="cancel" />
<Button <Button
v-if="editing" v-if="editing"
@ -65,11 +56,7 @@
iconRight: 'chevron-down', iconRight: 'chevron-down',
iconLeft: 'calendar', iconLeft: 'calendar',
}" }"
> />
<template #prefix>
<LucideCalendar class="size-4 text-ink-gray-5 mr-2" />
</template>
</Dropdown>
<DateRangePicker <DateRangePicker
v-else v-else
class="!w-48" class="!w-48"

View File

@ -18,26 +18,19 @@
/> />
<AssignTo v-model="assignees.data" doctype="CRM Deal" :docname="dealId" /> <AssignTo v-model="assignees.data" doctype="CRM Deal" :docname="dealId" />
<Dropdown <Dropdown
v-if="doc" v-if="doc && document.statuses"
:options=" :options="statuses"
statusOptions( placement="right"
'deal',
document.statuses?.length ? document.statuses : document._statuses,
triggerStatusChange,
)
"
> >
<template #default="{ open }"> <template #default="{ open }">
<Button v-if="doc.status" :label="doc.status"> <Button
v-if="doc.status"
:label="doc.status"
:iconRight="open ? 'chevron-up' : 'chevron-down'"
>
<template #prefix> <template #prefix>
<IndicatorIcon :class="getDealStatus(doc.status).color" /> <IndicatorIcon :class="getDealStatus(doc.status).color" />
</template> </template>
<template #suffix>
<FeatherIcon
:name="open ? 'chevron-up' : 'chevron-down'"
class="h-4"
/>
</template>
</Button> </Button>
</template> </template>
</Dropdown> </Dropdown>
@ -83,54 +76,44 @@
</div> </div>
</Tooltip> </Tooltip>
<div class="flex gap-1.5"> <div class="flex gap-1.5">
<Tooltip v-if="callEnabled" :text="__('Make a call')"> <Button
<div> v-if="callEnabled"
<Button @click="triggerCall"> :tooltip="__('Make a call')"
<template #icon><PhoneIcon /></template> :icon="PhoneIcon"
</Button> @click="triggerCall"
</div> />
</Tooltip>
<Tooltip :text="__('Send an email')"> <Button
<div> :tooltip="__('Send an email')"
<Button :icon="Email2Icon"
@click=" @click="
doc.email ? openEmailBox() : toast.error(__('No email set')) doc.email ? openEmailBox() : toast.error(__('No email set'))
" "
> />
<template #icon><Email2Icon /></template>
</Button> <Button
</div> :tooltip="__('Go to website')"
</Tooltip> :icon="LinkIcon"
<Tooltip :text="__('Go to website')"> @click="
<div> doc.website
<Button ? openWebsite(doc.website)
@click=" : toast.error(__('No website set'))
doc.website "
? openWebsite(doc.website) />
: toast.error(__('No website set'))
" <Button
> :tooltip="__('Attach a file')"
<template #icon><LinkIcon /></template> :icon="AttachmentIcon"
</Button> @click="showFilesUploader = true"
</div> />
</Tooltip>
<Tooltip :text="__('Attach a file')"> <Button
<div> :tooltip="__('Delete')"
<Button @click="showFilesUploader = true"> variant="subtle"
<template #icon><AttachmentIcon /></template> icon="trash-2"
</Button> theme="red"
</div> @click="deleteDeal"
</Tooltip> />
<Tooltip :text="__('Delete')">
<div>
<Button
@click="deleteDeal"
variant="subtle"
icon="trash-2"
theme="red"
/>
</div>
</Tooltip>
</div> </div>
</div> </div>
</div> </div>
@ -233,26 +216,22 @@
</Dropdown> </Dropdown>
<Button <Button
variant="ghost" variant="ghost"
:tooltip="__('View contact')"
:icon="ArrowUpRightIcon"
@click=" @click="
router.push({ router.push({
name: 'Contact', name: 'Contact',
params: { contactId: contact.name }, params: { contactId: contact.name },
}) })
" "
> />
<template #icon> <Button
<ArrowUpRightIcon class="h-4 w-4" /> variant="ghost"
</template> class="transition-all duration-300 ease-in-out"
</Button> :class="{ 'rotate-90': opened }"
<Button variant="ghost" @click="toggle()"> icon="chevron-right"
<template #icon> @click="toggle()"
<FeatherIcon />
name="chevron-right"
class="h-4 w-4 text-ink-gray-9 transition-all duration-300 ease-in-out"
:class="{ 'rotate-90': opened }"
/>
</template>
</Button>
</div> </div>
</div> </div>
</template> </template>
@ -526,6 +505,13 @@ const title = computed(() => {
return doc.value?.[t] || props.dealId return doc.value?.[t] || props.dealId
}) })
const statuses = computed(() => {
let customStatuses = document.statuses?.length
? document.statuses
: document._statuses || []
return statusOptions('deal', customStatuses, triggerStatusChange)
})
usePageMeta(() => { usePageMeta(() => {
return { return {
title: title.value, title: title.value,

View File

@ -11,10 +11,9 @@
<Button <Button
variant="solid" variant="solid"
:label="__('Create')" :label="__('Create')"
iconLeft="plus"
@click="showDealModal = true" @click="showDealModal = true"
> />
<template #prefix><FeatherIcon name="plus" class="h-4" /></template>
</Button>
</template> </template>
</LayoutHeader> </LayoutHeader>
<ViewControls <ViewControls
@ -233,9 +232,11 @@
> >
<DealsIcon class="h-10 w-10" /> <DealsIcon class="h-10 w-10" />
<span>{{ __('No {0} Found', [__('Deals')]) }}</span> <span>{{ __('No {0} Found', [__('Deals')]) }}</span>
<Button :label="__('Create')" @click="showDealModal = true"> <Button
<template #prefix><FeatherIcon name="plus" class="h-4" /></template> :label="__('Create')"
</Button> iconLeft="plus"
@click="showDealModal = true"
/>
</div> </div>
</div> </div>
<DealModal <DealModal

View File

@ -3,11 +3,12 @@
class="grid h-full place-items-center px-4 py-20 text-center text-lg text-ink-gray-5" class="grid h-full place-items-center px-4 py-20 text-center text-lg text-ink-gray-5"
> >
<div class="space-y-2"> <div class="space-y-2">
<div>Invalid page or not permitted to access</div> <div>{{ __('Invalid page or not permitted to access') }}</div>
<Button :route="{ name: 'Leads' }"> <Button
<template #prefix><LeadsIcon class="w-4" /></template> :route="{ name: 'Leads' }"
Leads :label="__('Leads')"
</Button> :iconLeft="LeadsIcon"
/>
</div> </div>
</div> </div>
</template> </template>

View File

@ -18,26 +18,19 @@
/> />
<AssignTo v-model="assignees.data" doctype="CRM Lead" :docname="leadId" /> <AssignTo v-model="assignees.data" doctype="CRM Lead" :docname="leadId" />
<Dropdown <Dropdown
v-if="doc" v-if="doc && document.statuses"
:options=" :options="statuses"
statusOptions( placement="right"
'lead',
document.statuses?.length ? document.statuses : document._statuses,
triggerStatusChange,
)
"
> >
<template #default="{ open }"> <template #default="{ open }">
<Button v-if="doc.status" :label="doc.status"> <Button
v-if="doc.status"
:label="doc.status"
:iconRight="open ? 'chevron-up' : 'chevron-down'"
>
<template #prefix> <template #prefix>
<IndicatorIcon :class="getLeadStatus(doc.status).color" /> <IndicatorIcon :class="getLeadStatus(doc.status).color" />
</template> </template>
<template #suffix>
<FeatherIcon
:name="open ? 'chevron-up' : 'chevron-down'"
class="h-4"
/>
</template>
</Button> </Button>
</template> </template>
</Dropdown> </Dropdown>
@ -125,71 +118,48 @@
</div> </div>
</Tooltip> </Tooltip>
<div class="flex gap-1.5"> <div class="flex gap-1.5">
<Tooltip v-if="callEnabled" :text="__('Make a call')"> <Button
<div> v-if="callEnabled"
<Button :tooltip="__('Make a call')"
@click=" :icon="PhoneIcon"
() => @click="
doc.mobile_no () =>
? makeCall(doc.mobile_no) doc.mobile_no
: toast.error(__('No phone number set')) ? makeCall(doc.mobile_no)
" : toast.error(__('No phone number set'))
> "
<template #icon> />
<PhoneIcon />
</template> <Button
</Button> :tooltip="__('Send an email')"
</div> :icon="Email2Icon"
</Tooltip> @click="
<Tooltip :text="__('Send an email')"> doc.email ? openEmailBox() : toast.error(__('No email set'))
<div> "
<Button />
@click=" <Button
doc.email :tooltip="__('Go to website')"
? openEmailBox() :icon="LinkIcon"
: toast.error(__('No email set')) @click="
" doc.website
> ? openWebsite(doc.website)
<template #icon> : toast.error(__('No website set'))
<Email2Icon /> "
</template> />
</Button>
</div> <Button
</Tooltip> :tooltip="__('Attach a file')"
<Tooltip :text="__('Go to website')"> :icon="AttachmentIcon"
<div> @click="showFilesUploader = true"
<Button />
@click="
doc.website <Button
? openWebsite(doc.website) :tooltip="__('Delete')"
: toast.error(__('No website set')) variant="subtle"
" theme="red"
> icon="trash-2"
<template #icon> @click="deleteLead"
<LinkIcon /> />
</template>
</Button>
</div>
</Tooltip>
<Tooltip :text="__('Attach a file')">
<div>
<Button @click="showFilesUploader = true">
<template #icon>
<AttachmentIcon />
</template>
</Button>
</div>
</Tooltip>
<Tooltip :text="__('Delete')">
<div>
<Button
@click="deleteLead"
variant="subtle"
theme="red"
icon="trash-2"
/>
</div>
</Tooltip>
</div> </div>
<ErrorMessage :message="__(error)" /> <ErrorMessage :message="__(error)" />
</div> </div>
@ -395,6 +365,13 @@ const title = computed(() => {
return doc?.[t] || props.leadId return doc?.[t] || props.leadId
}) })
const statuses = computed(() => {
let customStatuses = document.statuses?.length
? document.statuses
: document._statuses || []
return statusOptions('lead', customStatuses, triggerStatusChange)
})
usePageMeta(() => { usePageMeta(() => {
return { title: title.value, icon: brand.favicon } return { title: title.value, icon: brand.favicon }
}) })

View File

@ -11,10 +11,9 @@
<Button <Button
variant="solid" variant="solid"
:label="__('Create')" :label="__('Create')"
iconLeft="plus"
@click="showLeadModal = true" @click="showLeadModal = true"
> />
<template #prefix><FeatherIcon name="plus" class="h-4" /></template>
</Button>
</template> </template>
</LayoutHeader> </LayoutHeader>
<ViewControls <ViewControls
@ -259,9 +258,11 @@
> >
<LeadsIcon class="h-10 w-10" /> <LeadsIcon class="h-10 w-10" />
<span>{{ __('No {0} Found', [__('Leads')]) }}</span> <span>{{ __('No {0} Found', [__('Leads')]) }}</span>
<Button :label="__('Create')" @click="showLeadModal = true"> <Button
<template #prefix><FeatherIcon name="plus" class="h-4" /></template> :label="__('Create')"
</Button> iconLeft="plus"
@click="showLeadModal = true"
/>
</div> </div>
</div> </div>
<LeadModal <LeadModal

View File

@ -72,12 +72,9 @@
v-if="callEnabled && contact.doc.mobile_no" v-if="callEnabled && contact.doc.mobile_no"
:label="__('Make Call')" :label="__('Make Call')"
size="sm" size="sm"
:iconLeft="PhoneIcon"
@click="callEnabled && makeCall(contact.doc.mobile_no)" @click="callEnabled && makeCall(contact.doc.mobile_no)"
> />
<template #prefix>
<PhoneIcon class="h-4 w-4" />
</template>
</Button>
<Button <Button
:label="__('Delete')" :label="__('Delete')"
theme="red" theme="red"

View File

@ -22,16 +22,14 @@
" "
> >
<template #default="{ open }"> <template #default="{ open }">
<Button v-if="doc.status" :label="doc.status"> <Button
v-if="doc.status"
:label="doc.status"
:iconRight="open ? 'chevron-up' : 'chevron-down'"
>
<template #prefix> <template #prefix>
<IndicatorIcon :class="getDealStatus(doc.status).color" /> <IndicatorIcon :class="getDealStatus(doc.status).color" />
</template> </template>
<template #suffix>
<FeatherIcon
:name="open ? 'chevron-up' : 'chevron-down'"
class="h-4"
/>
</template>
</Button> </Button>
</template> </template>
</Dropdown> </Dropdown>

View File

@ -22,16 +22,14 @@
" "
> >
<template #default="{ open }"> <template #default="{ open }">
<Button v-if="doc.status" :label="doc.status"> <Button
v-if="doc.status"
:label="doc.status"
:iconRight="open ? 'chevron-up' : 'chevron-down'"
>
<template #prefix> <template #prefix>
<IndicatorIcon :class="getLeadStatus(doc.status).color" /> <IndicatorIcon :class="getLeadStatus(doc.status).color" />
</template> </template>
<template #suffix>
<FeatherIcon
:name="open ? 'chevron-up' : 'chevron-down'"
class="h-4"
/>
</template>
</Button> </Button>
</template> </template>
</Dropdown> </Dropdown>

View File

@ -8,18 +8,12 @@
/> />
</template> </template>
<template #right-header> <template #right-header>
<Tooltip :text="__('Mark all as read')"> <Button
<div> :tooltip="__('Mark all as read')"
<Button :label="__('Mark all as read')"
:label="__('Mark all as read')" :iconLeft="MarkAsDoneIcon"
@click="() => mark_as_read.reload()" @click="() => mark_as_read.reload()"
> />
<template #prefix>
<MarkAsDoneIcon class="h-4 w-4" />
</template>
</Button>
</div>
</Tooltip>
</template> </template>
</LayoutHeader> </LayoutHeader>
<div class="flex flex-col overflow-hidden text-ink-gray-9"> <div class="flex flex-col overflow-hidden text-ink-gray-9">

View File

@ -72,12 +72,9 @@
:label="__('Delete')" :label="__('Delete')"
theme="red" theme="red"
size="sm" size="sm"
iconLeft="trash-2"
@click="deleteOrganization" @click="deleteOrganization"
> />
<template #prefix>
<FeatherIcon name="trash-2" class="h-4 w-4" />
</template>
</Button>
</div> </div>
<ErrorMessage :message="__(error)" /> <ErrorMessage :message="__(error)" />
</div> </div>

View File

@ -4,9 +4,12 @@
<ViewBreadcrumbs v-model="viewControls" routeName="Notes" /> <ViewBreadcrumbs v-model="viewControls" routeName="Notes" />
</template> </template>
<template #right-header> <template #right-header>
<Button variant="solid" :label="__('Create')" @click="createNote"> <Button
<template #prefix><FeatherIcon name="plus" class="h-4" /></template> variant="solid"
</Button> :label="__('Create')"
iconLeft="plus"
@click="createNote"
/>
</template> </template>
</LayoutHeader> </LayoutHeader>
<ViewControls <ViewControls
@ -90,9 +93,7 @@
> >
<NoteIcon class="h-10 w-10" /> <NoteIcon class="h-10 w-10" />
<span>{{ __('No {0} Found', [__('Notes')]) }}</span> <span>{{ __('No {0} Found', [__('Notes')]) }}</span>
<Button :label="__('Create')" @click="createNote"> <Button :label="__('Create')" iconLeft="plus" @click="createNote" />
<template #prefix><FeatherIcon name="plus" class="h-4" /></template>
</Button>
</div> </div>
</div> </div>
<NoteModal <NoteModal

View File

@ -83,19 +83,14 @@
:label="__('Delete')" :label="__('Delete')"
theme="red" theme="red"
size="sm" size="sm"
iconLeft="trash-2"
@click="deleteOrganization()" @click="deleteOrganization()"
> />
<template #prefix> <Button
<FeatherIcon name="trash-2" class="h-4 w-4" /> :tooltip="__('Open website')"
</template> icon="link"
</Button> @click="openWebsite"
<Tooltip :text="__('Open website')"> />
<div>
<Button @click="openWebsite">
<FeatherIcon name="link" class="h-4 w-4" />
</Button>
</div>
</Tooltip>
</div> </div>
</div> </div>
</template> </template>

View File

@ -11,10 +11,9 @@
<Button <Button
variant="solid" variant="solid"
:label="__('Create')" :label="__('Create')"
iconLeft="plus"
@click="showOrganizationModal = true" @click="showOrganizationModal = true"
> />
<template #prefix><FeatherIcon name="plus" class="h-4" /></template>
</Button>
</template> </template>
</LayoutHeader> </LayoutHeader>
<ViewControls <ViewControls
@ -57,9 +56,11 @@
> >
<OrganizationsIcon class="h-10 w-10" /> <OrganizationsIcon class="h-10 w-10" />
<span>{{ __('No {0} Found', [__('Organizations')]) }}</span> <span>{{ __('No {0} Found', [__('Organizations')]) }}</span>
<Button :label="__('Create')" @click="showOrganizationModal = true"> <Button
<template #prefix><FeatherIcon name="plus" class="h-4" /></template> :label="__('Create')"
</Button> iconLeft="plus"
@click="showOrganizationModal = true"
/>
</div> </div>
</div> </div>
<OrganizationModal <OrganizationModal

View File

@ -8,9 +8,12 @@
v-if="tasksListView?.customListActions" v-if="tasksListView?.customListActions"
:actions="tasksListView.customListActions" :actions="tasksListView.customListActions"
/> />
<Button variant="solid" :label="__('Create')" @click="createTask"> <Button
<template #prefix><FeatherIcon name="plus" class="h-4" /></template> variant="solid"
</Button> :label="__('Create')"
iconLeft="plus"
@click="createTask"
/>
</template> </template>
</LayoutHeader> </LayoutHeader>
<ViewControls <ViewControls
@ -120,8 +123,8 @@
<div class="flex gap-2 items-center justify-between"> <div class="flex gap-2 items-center justify-between">
<div> <div>
<Button <Button
class="-ml-2"
v-if="getRow(itemName, 'reference_docname').label" v-if="getRow(itemName, 'reference_docname').label"
class="-ml-2"
variant="ghost" variant="ghost"
size="sm" size="sm"
:label=" :label="
@ -129,17 +132,14 @@
? __('Deal') ? __('Deal')
: __('Lead') : __('Lead')
" "
:iconRight="ArrowUpRightIcon"
@click.stop=" @click.stop="
redirect( redirect(
getRow(itemName, 'reference_doctype').label, getRow(itemName, 'reference_doctype').label,
getRow(itemName, 'reference_docname').label, getRow(itemName, 'reference_docname').label,
) )
" "
> />
<template #suffix>
<ArrowUpRightIcon class="h-4 w-4" />
</template>
</Button>
</div> </div>
<Dropdown <Dropdown
class="flex items-center gap-2" class="flex items-center gap-2"
@ -182,9 +182,11 @@
> >
<Email2Icon class="h-10 w-10" /> <Email2Icon class="h-10 w-10" />
<span>{{ __('No {0} Found', [__('Tasks')]) }}</span> <span>{{ __('No {0} Found', [__('Tasks')]) }}</span>
<Button :label="__('Create')" @click="showTaskModal = true"> <Button
<template #prefix><FeatherIcon name="plus" class="h-4" /></template> :label="__('Create')"
</Button> iconLeft="plus"
@click="showTaskModal = true"
/>
</div> </div>
</div> </div>
<TaskModal <TaskModal