fix: replace toast.create, prefix lucide icon names and dedupe prosemirror

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013qR2bFcCSBEXQXtXws8oas
This commit is contained in:
Ritvik Sardana
2026-09-11 22:47:20 +05:30
parent 938de94638
commit c65b1aee20
31 changed files with 84 additions and 76 deletions

View File

@@ -25,6 +25,7 @@
"@vueuse/core": "^14.1.0",
"@vueuse/integrations": "^14.1.0",
"dayjs": "^1.11.7",
"echarts": "^6.1.0",
"grid-layout-plus": "^1.1.0",
"frappe-ui": "1.0.0-beta.63",
"mime": "^3.0.0",
@@ -51,6 +52,9 @@
},
"resolutions": {
"cheerio": "1.0.0-rc.12",
"prosemirror-model": "1.25.7"
"prosemirror-model": "1.25.7",
"prosemirror-state": "1.4.4",
"prosemirror-view": "1.41.8",
"prosemirror-transform": "1.12.0"
}
}

View File

@@ -29,16 +29,14 @@ useColorScheme();
onMounted(() => {
window.addEventListener("online", () => {
toast.create({
message: __("You are now online."),
icon: h(Wifi, { class: "text-ink-base" }),
toast(__("You are now online."), {
icon: () => h(Wifi, { class: "text-ink-base" }),
});
});
window.addEventListener("offline", () => {
toast.create({
message: __("You are now offline."),
icon: h(WifiOff, { class: "text-ink-base" }),
toast(__("You are now offline."), {
icon: () => h(WifiOff, { class: "text-ink-base" }),
});
});
!isCustomerPortal.value && setConfig("localTimezone", window.timezone?.user);

View File

@@ -16,7 +16,7 @@
<Button
variant="solid"
theme="red"
icon-left="trash-2"
icon-left="lucide-trash-2"
:label="__('Delete')"
:loading="isDeleting"
@click="confirmDelete"

View File

@@ -36,7 +36,7 @@ function handleDiscard() {
{
label: "Delete",
theme: "red",
iconLeft: "trash-2",
iconLeft: "lucide-trash-2",
variant: "solid",
onClick(close: Function) {
emit("discard");

View File

@@ -256,7 +256,7 @@ const defaultOptions = reactive({
label: __("Delete"),
variant: "solid",
theme: "red",
iconLeft: "trash-2",
iconLeft: "lucide-trash-2",
onClick({ close }) {
handleBulkDelete(close, selections);
},

View File

@@ -138,7 +138,7 @@
:label="getUserRole(agent.name)"
:button="{
label: getUserRole(agent.name),
iconRight: 'chevron-down',
iconRight: 'lucide-chevron-down',
iconLeft:
getUserRole(agent.name) === 'Agent'
? 'user'

View File

@@ -388,9 +388,8 @@ function buildUpdatePayload() {
function pullEmails() {
loadingPull.value = true;
toast.create({
message: __("Pulling emails, this may take a few minutes."),
icon: h(CircleAlert, { class: "text-ink-blue-5" }),
toast(__("Pulling emails, this may take a few minutes."), {
icon: () => h(CircleAlert, { class: "text-ink-blue-5" }),
});
call("frappe.email.doctype.email_account.email_account.pull_emails", {

View File

@@ -14,7 +14,7 @@
theme="amber"
/>
</div>
<Button icon="x" variant="ghost" @click="open = false" />
<Button icon="lucide-x" variant="ghost" @click="open = false" />
</div>
<div class="space-y-4">

View File

@@ -79,7 +79,7 @@
<Button
:loading="feedbackListResource.loading"
:label="__('Load More')"
icon-left="refresh-cw"
icon-left="lucide-refresh-cw"
@click="feedbackListResource.next()"
/>
</div>

View File

@@ -146,7 +146,7 @@ const dropdownOptions = computed(() => {
if (!props.contact.is_primary) {
primaryActions.push({
label: __("Set as Primary"),
icon: "star",
icon: "lucide-star",
onClick: () => {
updatePrimaryContact();
},
@@ -155,7 +155,7 @@ const dropdownOptions = computed(() => {
const roleActions = [
{
label: __("Role"),
icon: "briefcase",
icon: "lucide-briefcase",
submenu: [
{
label: __("Customer"),
@@ -180,7 +180,7 @@ const dropdownOptions = computed(() => {
const destructiveActions = [
{
label: __("Remove Contact"),
icon: "x",
icon: "lucide-x",
theme: "red" as const,
onClick: () => {
removeContact();

View File

@@ -20,7 +20,7 @@
theme="amber"
/>
</div>
<Button icon="x" @click="model = false" variant="ghost" />
<Button icon="lucide-x" @click="model = false" variant="ghost" />
</div>
<div class="space-y-4">
<!-- Image section -->

View File

@@ -6,8 +6,8 @@
<Button
:variant="confirming ? 'subtle' : 'ghost'"
:theme="confirming ? 'red' : 'gray'"
:icon="!confirming && 'trash-2'"
:icon-left="confirming && 'trash-2'"
:icon="!confirming && 'lucide-trash-2'"
:icon-left="confirming && 'lucide-trash-2'"
:label="confirming && __('Confirm')"
:tooltip="__('Revoke Invite')"
:loading="cancelInviteResource.loading"

View File

@@ -140,7 +140,7 @@
<Button
:loading="ticketsListResource.loading"
:label="__('Load More')"
icon-left="refresh-cw"
icon-left="lucide-refresh-cw"
@click="
() => {
ticketsListResource.next();

View File

@@ -84,7 +84,10 @@ import { MultipleAvatar } from "@/components";
import LayoutHeader from "@/components/LayoutHeader.vue";
import TicketMergeModal from "@/components/ticket/TicketMergeModal.vue";
import { showMergeModal } from "@/pages/ticket/modalStates";
import { setupCustomizations } from "@/composables/formCustomisation";
import {
createToast,
setupCustomizations,
} from "@/composables/formCustomisation";
import { useNotifyTicketUpdate } from "@/composables/realtime";
import { useShortcut } from "@/composables/shortcuts";
import { useView } from "@/composables/useView";
@@ -194,7 +197,7 @@ function handleDeleteTicket() {
{
label: __("Delete"),
theme: "red",
iconLeft: "trash-2",
iconLeft: "lucide-trash-2",
variant: "solid",
onClick({ close }) {
call("helpdesk.api.ticket.delete_ticket", {
@@ -314,7 +317,7 @@ const customizationCtx = computed(() => ({
toast,
$dialog: globalStore().$dialog,
updateField,
createToast: toast.create,
createToast,
}));
// to manage the correct customization context for actions, happens because of navigation between tickets using buttons

View File

@@ -1,4 +1,26 @@
import { Field } from "@/types";
import { toast } from "frappe-ui";
type ToastType = "success" | "error" | "warning" | "info";
/**
* `toast.create({ message, ... })` shape kept alive for customer-written form
* scripts. frappe-ui v1 dropped `toast.create` for `toast(message, options)`.
*/
export function createToast({
message,
type,
icon,
...options
}: {
message: string;
type?: ToastType;
icon?: unknown;
[key: string]: unknown;
}) {
const data = icon ? { ...options, icon: () => icon } : options;
return type ? toast[type](message, data) : toast(message, data);
}
export async function setupCustomizations(doc, obj) {
// Supporting old format, will have to refactor later

View File

@@ -305,7 +305,7 @@ export function useView(dt: string = null) {
{
label: __("Confirm"),
variant: "solid",
iconLeft: "trash-2",
iconLeft: "lucide-trash-2",
theme: "red",
onClick({ close }: any) {
if (route.query.view === _view.name) {

View File

@@ -45,9 +45,8 @@ setConfig("serverMessagesHandler", (msgs) => {
toast.success(msg.message);
return;
}
toast.create({
message: msg.message,
icon: h(CircleAlert, { class: "text-ink-blue-5" }),
toast(msg.message, {
icon: () => h(CircleAlert, { class: "text-ink-blue-5" }),
});
});
});

View File

@@ -229,7 +229,7 @@ function getCallLogDetail(row, log, columns = []) {
} else if (row === "type") {
return {
label: log.type,
icon: incoming ? "phone-incoming" : "phone-outgoing",
icon: incoming ? "lucide-phone-incoming" : "lucide-phone-outgoing",
};
} else if (row === "status") {
return {

View File

@@ -38,7 +38,7 @@
align="end"
v-if="hasPermission()"
>
<Button icon="more-horizontal" variant="subtle" />
<Button icon="lucide-more-horizontal" variant="subtle" />
</Dropdown>
</div>
</template>
@@ -269,7 +269,7 @@ const dropdownActions = computed(() => {
if (!contact.doc?.user && !invitation.value?.name) {
baseActions.push({
label: __("Invite as User"),
icon: "user-plus",
icon: "lucide-user-plus",
onClick: async () => {
await inviteAsUser(props.id, contact.doc?.email_id);
contactInfoResource.reload();
@@ -279,7 +279,7 @@ const dropdownActions = computed(() => {
if (invitation.value?.name) {
baseActions.push({
label: __("Resend Invite"),
icon: "mail",
icon: "lucide-mail",
onClick: async () => {
await resendInvite(
invitation.value!.name,
@@ -294,7 +294,7 @@ const dropdownActions = computed(() => {
if (contact.doc?.user) {
baseActions.push({
label: __("Send reset password email"),
icon: "mail",
icon: "lucide-mail",
onClick: () => {
resetPassword();
},

View File

@@ -29,7 +29,7 @@
</div>
</Button>
<Dropdown :options="dropdownActions" align="end">
<Button icon="more-horizontal" variant="subtle" />
<Button icon="lucide-more-horizontal" variant="subtle" />
</Dropdown>
</div>
</template>

View File

@@ -73,7 +73,7 @@
<div
v-for="idx in 5"
:key="idx"
class="border-t border-dashed border-surface-gray-2 w-full"
class="border-t border-dashed border-outline-gray-2 w-full"
/>
</div>
<div

View File

@@ -250,7 +250,7 @@
<div class="flex items-center gap-1 py-1">
<div class="w-64 h-4 bg-surface-gray-1 rounded-1" />
</div>
<hr class="my-2 border-surface-gray-2" />
<hr class="my-2 border-outline-gray-2" />
<div class="flex items-center gap-2 mb-3 mt-1">
<div class="w-12 h-5 bg-surface-gray-1 rounded-1" />
<div class="w-56 h-5 bg-surface-gray-1 rounded-1" />

View File

@@ -206,7 +206,7 @@ const selectBannerActions = [
{
label: __("Delete"),
theme: "red",
iconLeft: "trash-2",
iconLeft: "lucide-trash-2",
variant: "solid",
onClick({ close }) {
handleDeleteArticles();

View File

@@ -259,6 +259,7 @@ import SetContactPhoneModal from "@/components/ticket/SetContactPhoneModal.vue";
import TicketSLA from "@/components/ticket-agent/TicketSLA.vue";
import TicketAgentFields from "@/components/ticket/TicketAgentFields.vue";
import {
createToast,
parseField,
setupCustomizations,
} from "@/composables/formCustomisation";
@@ -337,7 +338,7 @@ const customizationCtx = computed(() => ({
toast,
$dialog,
updateField,
createToast: toast.create,
createToast,
}));
watchEffect(async () => {

View File

@@ -96,7 +96,10 @@
<script setup lang="ts">
import { LayoutHeader } from "@/components";
import TicketCustomerSidebar from "@/components/ticket/TicketCustomerSidebar.vue";
import { setupCustomizations } from "@/composables/formCustomisation";
import {
createToast,
setupCustomizations,
} from "@/composables/formCustomisation";
import { useActiveViewers } from "@/composables/realtime";
import { useScreenSize } from "@/composables/screen";
@@ -157,7 +160,7 @@ const ticket = createResource({
toast,
$dialog,
updateField,
createToast: toast.create,
createToast,
});
},
onError: () => {

View File

@@ -21,7 +21,7 @@ interface AvailabilityEvent {
// Maps an HD Agent Status `color` value to a solid presence-dot background.
const dotColorMap: Record<string, string> = {
black: "bg-ink-gray-9",
black: "bg-surface-gray-9",
gray: "bg-surface-gray-6",
blue: "bg-surface-blue-6",
green: "bg-surface-green-6",

View File

@@ -479,7 +479,7 @@ export function TemplateOption({ active, option, variant, icon, onClick }) {
class: [
active ? "bg-surface-gray-2" : "text-ink-gray-8",
"group flex w-full gap-2 items-center rounded-5 px-2 py-2 text-base hover:bg-surface-gray-3",
variant == "danger" ? "text-ink-red-6 hover:bg-ink-red-1" : "",
variant == "danger" ? "text-ink-red-6 hover:bg-surface-red-1" : "",
],
onClick: onClick,
},

View File

@@ -47,13 +47,6 @@ export function getLocalFrappeUIDevConfig({
"src",
"style.css"
),
"frappe-ui/editor-style.css": path.resolve(
localFrappeUIPath,
"src",
"molecules",
"editor",
"style.css"
),
// The `frappe-ui/editor` subpath maps to src/molecules/editor via the
// package's exports map, which the bare `frappe-ui` directory alias
// bypasses. Map it explicitly (same pattern as `frappe-ui/style.css`)

View File

@@ -141,7 +141,6 @@ export default defineConfig(async ({ mode }) => {
},
optimizeDeps: {
include: [
"feather-icons",
"tailwind.config.js",
"prosemirror-state",
"prosemirror-view",

View File

@@ -4347,7 +4347,7 @@ prosemirror-keymap@^1.0.0, prosemirror-keymap@^1.2.3:
prosemirror-state "^1.0.0"
w3c-keyname "^2.2.0"
prosemirror-model@1.25.7, prosemirror-model@^1.0.0, prosemirror-model@^1.20.0, prosemirror-model@^1.21.0, prosemirror-model@^1.25.4, prosemirror-model@^1.25.8, prosemirror-model@^1.25.9:
prosemirror-model@1.25.7, prosemirror-model@^1.0.0, prosemirror-model@^1.20.0, prosemirror-model@^1.21.0, prosemirror-model@^1.25.4, prosemirror-model@^1.25.9:
version "1.25.7"
resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.25.7.tgz#0ef150e8098a9037703b48b623d668218f355b9c"
integrity sha512-A79aN8QEFUwI6cax8Yq4Rpcx1TJZ3Kagn+ii7qLo4/V8H3mMiHrhFyhTyHHvpSnOgMPpWiDGSwM3etwrxE50ug==
@@ -4363,7 +4363,7 @@ prosemirror-schema-list@^1.5.1:
prosemirror-state "^1.0.0"
prosemirror-transform "^1.7.3"
prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.4.4:
prosemirror-state@1.4.4, prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.4.4:
version "1.4.4"
resolved "https://registry.yarnpkg.com/prosemirror-state/-/prosemirror-state-1.4.4.tgz#72b5e926f9e92dcee12b62a05fcc8a2de3bf5b39"
integrity sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==
@@ -4383,38 +4383,22 @@ prosemirror-tables@^1.8.1, prosemirror-tables@^1.8.5:
prosemirror-transform "^1.10.5"
prosemirror-view "^1.41.4"
prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transform@^1.10.2, prosemirror-transform@^1.10.5, prosemirror-transform@^1.7.3:
version "1.11.0"
resolved "https://registry.yarnpkg.com/prosemirror-transform/-/prosemirror-transform-1.11.0.tgz#f5c5050354423dc83c6b083f6f1959ec86a3f9ba"
integrity sha512-4I7Ce4KpygXb9bkiPS3hTEk4dSHorfRw8uI0pE8IhxlK2GXsqv5tIA7JUSxtSu7u8APVOTtbUBxTmnHIxVkIJw==
dependencies:
prosemirror-model "^1.21.0"
prosemirror-transform@^1.12.0:
prosemirror-transform@1.12.0, prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transform@^1.10.2, prosemirror-transform@^1.10.5, prosemirror-transform@^1.12.0, prosemirror-transform@^1.7.3:
version "1.12.0"
resolved "https://registry.yarnpkg.com/prosemirror-transform/-/prosemirror-transform-1.12.0.tgz#0239288d0e98d91e6af3dd269a8968466be406d7"
integrity sha512-GxboyN4AMIsoHNtz5uf2r2Ru551i5hWeCMD6E2Ib4Eogqoub0NflniaBPVQ4MrGE5yZ8JV9tUHg9qcZTTrcN4w==
dependencies:
prosemirror-model "^1.21.0"
prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.27.0, prosemirror-view@^1.31.0, prosemirror-view@^1.41.4:
version "1.41.7"
resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.41.7.tgz#61e6f44ac160795c913ead92a282247df9d468f6"
integrity sha512-jUwKNCEIGiqdvhlS91/2QAg21e4dfU5bH2iwmSDQeosXJgKF7smG0YSplOWK0cjSNgIqXe7VXqo7EIfUFJdt3w==
prosemirror-view@1.41.8, prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.27.0, prosemirror-view@^1.31.0, prosemirror-view@^1.41.4, prosemirror-view@^1.41.9:
version "1.41.8"
resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.41.8.tgz#bfb48d9dc328f1aa2a0eea1600b0828818be03f1"
integrity sha512-TnKDdohEatgyZNGCDWIdccOHXhYloJwbwU+phw/a23KBvJIR9lWQWW7WHHK3vBdOLDNuF7TaX98GObUZOWkOnA==
dependencies:
prosemirror-model "^1.20.0"
prosemirror-state "^1.0.0"
prosemirror-transform "^1.1.0"
prosemirror-view@^1.41.9:
version "1.42.1"
resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.42.1.tgz#7d8dae19a757de11b918760ba094a68a293dbb87"
integrity sha512-rRqzZnRgkyh69XoOMrfFJHwauHscLBmHbq772kwbic1ymQAM8gXjzEbJse5j1ep2UO2HRIAQL0bY3kZ/RoqjVw==
dependencies:
prosemirror-model "^1.25.8"
prosemirror-state "^1.0.0"
prosemirror-transform "^1.1.0"
punycode@^2.1.0:
version "2.3.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"

View File

@@ -7,6 +7,9 @@
},
"resolutions": {
"cheerio": "1.0.0-rc.12",
"prosemirror-model": "1.25.7"
"prosemirror-model": "1.25.7",
"prosemirror-state": "1.4.4",
"prosemirror-view": "1.41.8",
"prosemirror-transform": "1.12.0"
}
}