From 47c2d8e6de46c7bc2d2bcc1fc52a5ac0c768d5dd Mon Sep 17 00:00:00 2001 From: Gregor Vostrak Date: Fri, 9 Jan 2026 03:15:32 +0100 Subject: [PATCH 01/28] upgrade inertia v2; add prefetching; migrate queries to tanstack query vue --- docker-compose.yml | 2 +- e2e/clients.spec.ts | 3 +- e2e/project-members.spec.ts | 5 +- e2e/projects.spec.ts | 3 +- e2e/reporting.spec.ts | 3 +- e2e/tags.spec.ts | 3 +- e2e/tasks.spec.ts | 3 +- e2e/time.spec.ts | 3 +- e2e/timetracker.spec.ts | 2 +- e2e/utils/currentTimeEntry.ts | 3 +- e2e/utils/money.ts | 2 +- e2e/utils/tags.ts | 2 +- package-lock.json | 118 ++++---- package.json | 2 +- .../Client/ClientMultiselectDropdown.vue | 6 +- .../Common/Member/MemberCombobox.vue | 6 +- .../Common/Member/MemberDeleteModal.vue | 6 +- .../Member/MemberMakePlaceholderModal.vue | 6 +- .../Member/MemberMultiselectDropdown.vue | 6 +- .../Components/Common/Member/MemberTable.vue | 10 +- .../Common/Member/MemberTableRow.vue | 3 - resources/js/Components/Common/PageTitle.vue | 2 +- .../Common/Project/ProjectEditModal.vue | 6 +- .../Common/Project/ProjectTable.vue | 4 +- .../Common/Project/ProjectTableRow.vue | 9 +- .../ProjectMemberMoreOptionsDropdown.vue | 5 +- .../ProjectMember/ProjectMemberTableRow.vue | 5 +- .../Common/Reporting/ReportingOverview.vue | 12 +- .../js/Components/Common/Tag/TagTable.vue | 5 +- .../Common/Task/TaskMultiselectDropdown.vue | 6 +- .../RecentlyTrackedTasksCardEntry.vue | 10 +- resources/js/Components/DropdownLink.vue | 1 + resources/js/Components/NavLink.vue | 2 +- .../js/Components/NavigationSidebarLink.vue | 2 +- resources/js/Components/ResponsiveNavLink.vue | 2 +- resources/js/Components/TimeTracker.vue | 18 +- resources/js/Layouts/AppLayout.vue | 10 +- resources/js/Pages/Calendar.vue | 18 +- resources/js/Pages/Clients.vue | 11 +- resources/js/Pages/ProjectShow.vue | 25 +- resources/js/Pages/Projects.vue | 6 +- resources/js/Pages/ReportingDetailed.vue | 20 +- resources/js/Pages/Time.vue | 23 +- resources/js/app.ts | 9 +- .../ui/src/GroupedItemsCountButton.vue | 4 +- resources/js/utils/init.ts | 21 +- resources/js/utils/prefetch.ts | 283 ++++++++++++++++++ resources/js/utils/useClients.ts | 42 +-- resources/js/utils/useClientsQuery.ts | 35 +++ resources/js/utils/useMembers.ts | 32 +- resources/js/utils/useMembersQuery.ts | 34 +++ resources/js/utils/useProjectMembers.ts | 42 +-- resources/js/utils/useProjectMembersQuery.ts | 39 +++ resources/js/utils/useProjectsQuery.ts | 1 + resources/js/utils/useReporting.ts | 29 +- resources/js/utils/useTags.ts | 32 +- resources/js/utils/useTagsQuery.ts | 34 +++ resources/js/utils/useTasks.ts | 33 +- resources/js/utils/useTasksQuery.ts | 35 +++ 59 files changed, 712 insertions(+), 392 deletions(-) create mode 100644 resources/js/utils/prefetch.ts create mode 100644 resources/js/utils/useClientsQuery.ts create mode 100644 resources/js/utils/useMembersQuery.ts create mode 100644 resources/js/utils/useProjectMembersQuery.ts create mode 100644 resources/js/utils/useTagsQuery.ts create mode 100644 resources/js/utils/useTasksQuery.ts diff --git a/docker-compose.yml b/docker-compose.yml index 6974efb1..53d73ed4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -107,7 +107,7 @@ services: - sail - reverse-proxy playwright: - image: mcr.microsoft.com/playwright:v1.57.0-jammy + image: mcr.microsoft.com/playwright:v1.51.1-jammy command: ['npx', 'playwright', 'test', '--ui-port=8080', '--ui-host=0.0.0.0'] working_dir: /src extra_hosts: diff --git a/e2e/clients.spec.ts b/e2e/clients.spec.ts index dab9c81f..dc6ed8cc 100644 --- a/e2e/clients.spec.ts +++ b/e2e/clients.spec.ts @@ -1,4 +1,5 @@ -import { expect, Page } from '@playwright/test'; +import { expect } from '@playwright/test'; +import type { Page } from '@playwright/test'; import { PLAYWRIGHT_BASE_URL } from '../playwright/config'; import { test } from '../playwright/fixtures'; diff --git a/e2e/project-members.spec.ts b/e2e/project-members.spec.ts index 36ee7f2b..958014ac 100644 --- a/e2e/project-members.spec.ts +++ b/e2e/project-members.spec.ts @@ -1,9 +1,8 @@ -import { expect, Page } from '@playwright/test'; +import { expect } from '@playwright/test'; +import type { Page } from '@playwright/test'; import { PLAYWRIGHT_BASE_URL } from '../playwright/config'; import { test } from '../playwright/fixtures'; import { formatCentsWithOrganizationDefaults } from './utils/money'; -import type { CurrencyFormat } from '../resources/js/packages/ui/src/utils/money'; -import { NumberFormat } from '@/packages/ui/src/utils/number'; async function goToProjectsOverview(page: Page) { await page.goto(PLAYWRIGHT_BASE_URL + '/projects'); diff --git a/e2e/projects.spec.ts b/e2e/projects.spec.ts index b052baed..1c953a95 100644 --- a/e2e/projects.spec.ts +++ b/e2e/projects.spec.ts @@ -1,4 +1,5 @@ -import { expect, Page } from '@playwright/test'; +import { expect } from '@playwright/test'; +import type { Page } from '@playwright/test'; import { PLAYWRIGHT_BASE_URL } from '../playwright/config'; import { test } from '../playwright/fixtures'; import { formatCentsWithOrganizationDefaults } from './utils/money'; diff --git a/e2e/reporting.spec.ts b/e2e/reporting.spec.ts index 4c3a777d..93815265 100644 --- a/e2e/reporting.spec.ts +++ b/e2e/reporting.spec.ts @@ -1,4 +1,5 @@ -import { expect, Page } from '@playwright/test'; +import { expect } from '@playwright/test'; +import type { Page } from '@playwright/test'; import { PLAYWRIGHT_BASE_URL } from '../playwright/config'; import { test } from '../playwright/fixtures'; diff --git a/e2e/tags.spec.ts b/e2e/tags.spec.ts index 8b89aa2b..36b8defd 100644 --- a/e2e/tags.spec.ts +++ b/e2e/tags.spec.ts @@ -1,4 +1,5 @@ -import { expect, Page } from '@playwright/test'; +import { expect } from '@playwright/test'; +import type { Page } from '@playwright/test'; import { PLAYWRIGHT_BASE_URL } from '../playwright/config'; import { test } from '../playwright/fixtures'; diff --git a/e2e/tasks.spec.ts b/e2e/tasks.spec.ts index 8e2073db..646f618c 100644 --- a/e2e/tasks.spec.ts +++ b/e2e/tasks.spec.ts @@ -1,4 +1,5 @@ -import { expect, Page } from '@playwright/test'; +import { expect } from '@playwright/test'; +import type { Page } from '@playwright/test'; import { PLAYWRIGHT_BASE_URL } from '../playwright/config'; import { test } from '../playwright/fixtures'; diff --git a/e2e/time.spec.ts b/e2e/time.spec.ts index 2b01ddfb..fbcb500d 100644 --- a/e2e/time.spec.ts +++ b/e2e/time.spec.ts @@ -1,6 +1,7 @@ import { PLAYWRIGHT_BASE_URL } from '../playwright/config'; import { test } from '../playwright/fixtures'; -import { expect, Locator, Page } from '@playwright/test'; +import { expect } from '@playwright/test'; +import type { Locator, Page } from '@playwright/test'; import { assertThatTimerHasStarted, assertThatTimerIsStopped, diff --git a/e2e/timetracker.spec.ts b/e2e/timetracker.spec.ts index c7896ca1..2696acfc 100644 --- a/e2e/timetracker.spec.ts +++ b/e2e/timetracker.spec.ts @@ -7,7 +7,7 @@ import { startOrStopTimerWithButton, stoppedTimeEntryResponse, } from './utils/currentTimeEntry'; -import { Page } from '@playwright/test'; +import type { Page } from '@playwright/test'; import { newTagResponse } from './utils/tags'; async function goToDashboard(page: Page) { diff --git a/e2e/utils/currentTimeEntry.ts b/e2e/utils/currentTimeEntry.ts index 162975ec..908da317 100644 --- a/e2e/utils/currentTimeEntry.ts +++ b/e2e/utils/currentTimeEntry.ts @@ -1,4 +1,5 @@ -import { expect, Page } from '@playwright/test'; +import { expect } from '@playwright/test'; +import type { Page } from '@playwright/test'; export async function startOrStopTimerWithButton(page: Page) { await page.locator('[data-testid="dashboard_timer"] [data-testid="timer_button"]').click(); diff --git a/e2e/utils/money.ts b/e2e/utils/money.ts index aed8176c..5a2f3c66 100644 --- a/e2e/utils/money.ts +++ b/e2e/utils/money.ts @@ -1,6 +1,6 @@ import { formatCents } from '../../resources/js/packages/ui/src/utils/money'; import type { CurrencyFormat } from '../../resources/js/packages/ui/src/utils/money'; -import { NumberFormat } from '../../resources/js/packages/ui/src/utils/number'; +import type { NumberFormat } from '../../resources/js/packages/ui/src/utils/number'; export function formatCentsWithOrganizationDefaults( cents: number, diff --git a/e2e/utils/tags.ts b/e2e/utils/tags.ts index 888d6794..f3d0e86e 100644 --- a/e2e/utils/tags.ts +++ b/e2e/utils/tags.ts @@ -1,4 +1,4 @@ -import { Page } from '@playwright/test'; +import type { Page } from '@playwright/test'; export function newTagResponse(page: Page, { name = '' } = {}) { return page.waitForResponse(async (response) => { diff --git a/package-lock.json b/package-lock.json index a481c98a..9d7b0f9f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,7 +41,7 @@ "devDependencies": { "@eslint/eslintrc": "^3.2.0", "@eslint/js": "^9.19.0", - "@inertiajs/vue3": "^1.0.0", + "@inertiajs/vue3": "^2.0.0", "@playwright/test": "^1.41.1", "@tailwindcss/forms": "^0.5.9", "@tailwindcss/typography": "^0.5.15", @@ -1159,28 +1159,30 @@ } }, "node_modules/@inertiajs/core": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@inertiajs/core/-/core-1.3.0.tgz", - "integrity": "sha512-TJ8R1eUYY473m9DaKlCPRdHTdznFWTDuy5VvEzXg3t/hohbDQedLj46yn/uAqziJPEUZJrSftZzPI2NMzL9tQA==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/@inertiajs/core/-/core-2.3.7.tgz", + "integrity": "sha512-gBu2m71KoAu3kyaBDeszYiInkPqR0lIe+mRpI1JQyOlX1CT+Hwn+Tk5O7Dsr3dRMphEkRj6H9oVmJ19jHSNTIA==", "dev": true, "license": "MIT", "dependencies": { - "axios": "^1.6.0", - "deepmerge": "^4.0.0", - "nprogress": "^0.2.0", - "qs": "^6.9.0" + "@types/lodash-es": "^4.17.12", + "axios": "^1.13.2", + "laravel-precognition": "^1.0.0", + "lodash-es": "^4.17.21", + "qs": "^6.14.1" } }, "node_modules/@inertiajs/vue3": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@inertiajs/vue3/-/vue3-1.3.0.tgz", - "integrity": "sha512-GizqdCM3u4JWunit3uUbW4fEmTLKQTi1W7VvPRdrNy8XDt4Qy2cCmfFjq+aH5tHBSS3fI/ngYuhN7XvwqNaKvw==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/@inertiajs/vue3/-/vue3-2.3.7.tgz", + "integrity": "sha512-jaJtOPjulmLy4uKHL8BlYRjXGKk5FMccjczCePJzKS1JJYaF0aixpY046HzlKDtbnU9xn2h2tZRwu4kQ1uoTTg==", "dev": true, "license": "MIT", "dependencies": { - "@inertiajs/core": "1.3.0", - "lodash.clonedeep": "^4.5.0", - "lodash.isequal": "^4.5.0" + "@inertiajs/core": "2.3.7", + "@types/lodash-es": "^4.17.12", + "laravel-precognition": "^1.0.0", + "lodash-es": "^4.17.21" }, "peerDependencies": { "vue": "^3.0.0" @@ -1927,6 +1929,23 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "license": "MIT" }, + "node_modules/@types/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/lodash-es": { + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/lodash": "*" + } + }, "node_modules/@types/node": { "version": "22.14.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.1.tgz", @@ -2710,14 +2729,14 @@ } }, "node_modules/axios": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz", - "integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", + "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", "devOptional": true, "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", + "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, @@ -3089,16 +3108,6 @@ "license": "MIT", "peer": true }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/defu": { "version": "6.1.4", "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", @@ -3766,15 +3775,16 @@ } }, "node_modules/form-data": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", - "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", "devOptional": true, "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" }, "engines": { @@ -4277,6 +4287,17 @@ "json-buffer": "3.0.1" } }, + "node_modules/laravel-precognition": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/laravel-precognition/-/laravel-precognition-1.0.0.tgz", + "integrity": "sha512-hvXPT7dayCQAidxnsY0hab9Q+Y2rsh7xRpH9uiFtXN8Dekc3tIZt+NrxrOZ9N5SwHBmRBze/Bv+ElfXac0kD6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "axios": "^1.4.0", + "lodash-es": "^4.17.21" + } + }, "node_modules/laravel-vite-plugin": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-1.2.0.tgz", @@ -4351,6 +4372,13 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "license": "MIT" }, + "node_modules/lodash-es": { + "version": "4.17.22", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.22.tgz", + "integrity": "sha512-XEawp1t0gxSi9x01glktRZ5HDy0HXqrM0x5pXQM98EaI0NxO6jVM7omDOxsuEo5UIASAnm2bRp1Jt/e0a2XU8Q==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.castarray": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", @@ -4358,21 +4386,6 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", - "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", @@ -4604,13 +4617,6 @@ "node": ">=8" } }, - "node_modules/nprogress": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", - "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==", - "devOptional": true, - "license": "MIT" - }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -5274,9 +5280,9 @@ } }, "node_modules/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", "dev": true, "license": "BSD-3-Clause", "dependencies": { diff --git a/package.json b/package.json index f133c166..d9bd3652 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "devDependencies": { "@eslint/eslintrc": "^3.2.0", "@eslint/js": "^9.19.0", - "@inertiajs/vue3": "^1.0.0", + "@inertiajs/vue3": "^2.0.0", "@playwright/test": "^1.41.1", "@tailwindcss/forms": "^0.5.9", "@tailwindcss/typography": "^0.5.15", diff --git a/resources/js/Components/Common/Client/ClientMultiselectDropdown.vue b/resources/js/Components/Common/Client/ClientMultiselectDropdown.vue index c5e381c3..29c37824 100644 --- a/resources/js/Components/Common/Client/ClientMultiselectDropdown.vue +++ b/resources/js/Components/Common/Client/ClientMultiselectDropdown.vue @@ -1,11 +1,9 @@