From e3d00d91918198335b69069f9de672626b5995c6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 11 Nov 2025 11:51:46 +0000 Subject: [PATCH 1/2] Initial plan From a01764d9d883908dbc98f9244842ba007fdfded1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 11 Nov 2025 12:36:06 +0000 Subject: [PATCH 2/2] Replace lodash/lodash-es with native code and alternative packages - Add fast-deep-equal and rfdc packages for isEqual and cloneDeep - Replace lodash functions with native alternatives - Use VueUse for throttle and debounce where available - All tests pass, linting and type-check successful --- eslint-suppressions.json | 5 - package.json | 7 +- packages/components/package.json | 3 +- .../FileExplorer/components/FileExplorer.vue | 8 +- .../components/__tests__/FileExplorer.test.ts | 10 +- .../components/ResizeHandle/ResizeHandle.vue | 4 +- .../components/src/components/Tag/TagList.vue | 4 +- .../src/components/Toast/toastService.ts | 7 +- .../src/components/Toast/useAnimation.ts | 10 +- .../base/MenuItem/BaseMenuItems.vue | 18 ++- .../forms/DateTimeInput/DateTimeInput.vue | 3 +- .../components/forms/Dropdown/Dropdown.vue | 3 +- .../forms/Dropdown/__tests__/Dropdown.test.js | 6 +- .../components/forms/SortList/SortList.vue | 24 ++-- packages/hub-features/package.json | 3 +- .../hub-features/src/common/ofetchClient.ts | 13 +- .../versions/components/LabelList.vue | 4 +- .../versions/components/ManageVersions.vue | 13 +- .../versions/components/VersionItem.vue | 11 +- .../components/__tests__/CurrentState.test.ts | 11 +- .../components/__tests__/VersionItem.test.ts | 4 +- packages/jsonforms/package.json | 3 +- .../control/validation/useCustomValidation.ts | 15 +- .../control/validation/useValidation.ts | 14 +- .../src/uiComponents/SortListControl.vue | 3 +- packages/jsonforms/testUtils/renderer.ts | 24 ++-- pnpm-lock.yaml | 132 +++++------------- pnpm-workspace.yaml | 2 - 28 files changed, 170 insertions(+), 194 deletions(-) diff --git a/eslint-suppressions.json b/eslint-suppressions.json index 1c2f7c8219..66111351e4 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -24,11 +24,6 @@ "count": 1 } }, - "packages/components/src/components/FileExplorer/components/FileExplorer.vue": { - "depend/ban-dependencies": { - "count": 1 - } - }, "packages/components/src/components/FileExplorer/components/FileExplorerItem.vue": { "@typescript-eslint/no-floating-promises": { "count": 3 diff --git a/package.json b/package.json index f6612dc2e6..c7a1a1ad25 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,6 @@ "@knime/licenses": "workspace:*", "@tsconfig/node22": "22.0.0", "@types/jsdom": "^21.1.7", - "@types/lodash-es": "4.17.12", "@types/node": "22.12.0", "@vitest/coverage-v8": "catalog:", "@vue/tsconfig": "^0.5.1", @@ -84,5 +83,9 @@ "engines": { "node": "22.x" }, - "packageManager": "pnpm@10.18.1" + "packageManager": "pnpm@10.18.1", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "rfdc": "^1.4.1" + } } diff --git a/packages/components/package.json b/packages/components/package.json index ab410e9bc3..6dc9c443d4 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -47,10 +47,11 @@ "color-hash": "2.0.2", "date-fns": "2.30.0", "date-fns-tz": "2.0.0", + "fast-deep-equal": "^3.1.3", "filesize": "10.0.6", "focus-trap-vue": "4.0.2", - "lodash-es": "catalog:", "motion": "^12.23.12", + "rfdc": "^1.4.1", "typescript": "catalog:", "uuid": "11.1.0", "v-calendar": "catalog:patch" diff --git a/packages/components/src/components/FileExplorer/components/FileExplorer.vue b/packages/components/src/components/FileExplorer/components/FileExplorer.vue index 0475c1987d..3fc43117d1 100644 --- a/packages/components/src/components/FileExplorer/components/FileExplorer.vue +++ b/packages/components/src/components/FileExplorer/components/FileExplorer.vue @@ -4,9 +4,9 @@ import { computed, nextTick, ref, toRef, toRefs, watch } from "vue"; import { type MaybeElementRef, onClickOutside, + useDebounceFn, useResizeObserver, } from "@vueuse/core"; -import { debounce } from "lodash-es"; import OptionsIcon from "@knime/styles/img/icons/menu-options.svg"; import { getMetaOrCtrlKey } from "@knime/utils"; @@ -202,13 +202,15 @@ const scrollIntoView = ( // wait 50ms for DOM changes (e.g. changes in table ref) to take effect before scrolling const scrollDebounceMs = 50; - const debouncedScroll = debounce(() => { + const debouncedScroll = useDebounceFn(() => { containerProps.ref.value?.scrollTo({ top: virtualSizeManager.toOffset(index), behavior, }); }, scrollDebounceMs); - debouncedScroll(); + debouncedScroll().catch(() => { + // Ignore debounce errors + }); }; /** MULTISELECTION */ diff --git a/packages/components/src/components/FileExplorer/components/__tests__/FileExplorer.test.ts b/packages/components/src/components/FileExplorer/components/__tests__/FileExplorer.test.ts index 1f1215d764..13834536f0 100644 --- a/packages/components/src/components/FileExplorer/components/__tests__/FileExplorer.test.ts +++ b/packages/components/src/components/FileExplorer/components/__tests__/FileExplorer.test.ts @@ -23,14 +23,6 @@ vi.mock("motion", () => ({ }, })); -vi.mock("lodash-es", async (importOriginal) => { - const original = await importOriginal(); - return { - ...original, - debounce: (fn: (...args: never[]) => unknown) => fn, // bypass debounce - }; -}); - type Props = InstanceType["$props"]; describe("FileExplorer", () => { @@ -265,6 +257,7 @@ describe("FileExplorer", () => { const { wrapper } = doMount({ props: { mode: "mini" } }); await wrapper.setProps({ selectedItemIds: ["2", "3"] }); + await sleep(60); // wait for debounce (50ms + buffer) expect(getRenderedItems(wrapper).at(2)?.classes()).toContain("selected"); expect(getRenderedItems(wrapper).at(3)?.classes()).toContain("selected"); @@ -282,6 +275,7 @@ describe("FileExplorer", () => { { ...MOCK_DATA[0], id: "6", name: "Some new Folder" }, ], }); + await sleep(60); // wait for debounce (50ms + buffer) expect(getRenderedItems(wrapper).at(6)?.classes()).toContain("selected"); expect(scrollTo).toHaveBeenCalled(); diff --git a/packages/components/src/components/ResizeHandle/ResizeHandle.vue b/packages/components/src/components/ResizeHandle/ResizeHandle.vue index 850cdfe5b2..58a97c813e 100644 --- a/packages/components/src/components/ResizeHandle/ResizeHandle.vue +++ b/packages/components/src/components/ResizeHandle/ResizeHandle.vue @@ -1,6 +1,6 @@