fg-devkit 1.17.1 → 1.17.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -49,6 +49,14 @@ alwaysApply: true
49
49
  - Centralize HTTP and endpoint wiring in a dedicated API layer (for example `src/api/endpoints/*` or the convention used in the repo).
50
50
  - Consume server state through query/mutation hooks (for example `src/queries/*` or equivalent), not ad-hoc fetches in UI code.
51
51
 
52
+ ## Query strings
53
+
54
+ - Build query strings with `URLSearchParams` (or a shared helper that wraps it).
55
+ - Do not concatenate `key=value` fragments with `&`.
56
+ - Let `URLSearchParams` encode values. Do not interpolate untrusted or user-entered values into URLs.
57
+ - `toString()` has no leading `?`. Prefix it when appending to a path, and skip empty values instead of emitting empty keys.
58
+ - For list views, derive the query string in the view from route filter state (`requestQueryParams` computed). The API layer should accept the query string, not reconstruct filters.
59
+
52
60
  ## State-management boundaries
53
61
 
54
62
  - Use TanStack Query for server state and caching. Do not add Vuex for new work.
@@ -67,6 +75,42 @@ alwaysApply: true
67
75
  - Set `staleTime` intentionally per resource; keep `refetchOnWindowFocus` off unless fresh-on-focus behavior is required.
68
76
  - On mutation success, update cache intentionally (`setQueryData`) and/or invalidate the narrowest matching keys.
69
77
  - Respect shared query client retry behavior and only override retries when endpoint-specific behavior is needed.
78
+
79
+ ### Query loading UI
80
+
81
+ TanStack Query v5 flags (do not treat them as interchangeable):
82
+
83
+ | Flag | Meaning |
84
+ | --- | --- |
85
+ | `isPending` | No cached data yet (`status === 'pending'`) |
86
+ | `isFetching` | Any in-flight request, including background refetch |
87
+ | `isLoading` | First fetch in flight (`isPending && isFetching`) |
88
+
89
+ Rules:
90
+
91
+ 1. **Content-blocking / full-page spinner** — use `isLoading` (or combine several `isLoading*` flags). Prefer `isLoading` over bare `isPending` when the query can be `enabled: false` (lazy/disabled queries stay `isPending` without fetching).
92
+ 2. **Do not use bare `isFetching` for blocking UI** — it re-shows the full loader on every background refetch. Use `isFetching` only for subtle “refreshing” indicators while keeping content visible.
93
+ 3. **Paginated / `keepPreviousData` lists** — show a hard loader only when there is nothing useful to render:
94
+
95
+ ```ts
96
+ const isLoading = computed(() => isPending.value || (isFetching.value && !data.value))
97
+ ```
98
+
99
+ 4. **Multiple queries for one screen** — combine with OR into one (or purpose-prefixed) computed:
100
+
101
+ ```ts
102
+ const isLoading = computed(() => isLoadingDetails.value || isLoadingList.value)
103
+ ```
104
+
105
+ 5. **No passthrough aliases** — do not wrap a single flag (`const loading = computed(() => isFetching.value)`). Destructure and rename instead:
106
+
107
+ ```ts
108
+ const { data, isLoading, error } = useGetDetails(id)
109
+ // template: v-show="isLoading"
110
+ ```
111
+
112
+ 6. **Naming** — local query-derived booleans use the `is*` prefix: `isLoading`, `isLoadingUnits`, `isLoadingHistory`. Keep FDS/component prop names as-is (`:loading="isLoading"`). Mutations: rename `isPending` to intent (`isSaving`, `isSubmitting`, `isUploading`).
113
+
70
114
  - TanStack Query boolean flags (`isPending`, `isSuccess`, `isError`) are typed `Ref<false> | Ref<true>`. `vue-tsc` unwraps that union in templates to `boolean`; the Vue language plugin may not.
71
115
  - Narrow in script (`const isPending = mutation.isPending as Ref<boolean>`), then bind without `.value` (`:loading="isPending"`). Do not use `.value` in templates (fails `vue-tsc`) and do not add a wrapping `computed` only to satisfy the editor.
72
116
 
@@ -85,6 +129,11 @@ alwaysApply: true
85
129
  - Prefer named-route navigation for internal flows (`{ name, params, query }`) and reserve raw path pushes for simple/static redirects.
86
130
  - Preserve existing query params intentionally when updating filters, pagination, or tab state.
87
131
  - Lazy-load route components with dynamic imports to keep initial bundles smaller.
132
+ - Name organisation route params by domain meaning, not generic `id`:
133
+ - top org: `:topClientNumber`
134
+ - unit/sub-org: `:unitClientNumber`
135
+ - Prefer `/organisations/:topClientNumber/units/:unitClientNumber` over `:id` / `:clino`.
136
+ - Keep route param names aligned with component props when using `props: true`.
88
137
 
89
138
  ## Vue and UI expectations
90
139
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "toolchain": {
3
- "packageManager": "pnpm@11.25.0",
3
+ "packageManager": "pnpm@12.4.2",
4
4
  "node": {
5
5
  "nvmrc": "22",
6
6
  "engines": ">=22.13.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fg-devkit",
3
- "version": "1.17.1",
3
+ "version": "1.17.3",
4
4
  "description": "Shared configs, scripts, and DX tooling for Vue / TypeScript frontend repos",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -0,0 +1,13 @@
1
+ .DS_Store
2
+ node_modules
3
+ /dist
4
+ pnpm-debug.log*
5
+
6
+ .env.local
7
+ .env.*.local
8
+ *env.local
9
+
10
+ .idea
11
+ *.sw?
12
+
13
+ tsconfig.tsbuildinfo
@@ -32,14 +32,14 @@
32
32
  "@intlify/unplugin-vue-i18n": "11.2.5",
33
33
  "@tanstack/vue-query-devtools": "6.1.48",
34
34
  "@types/node": "22.16.5",
35
- "fg-devkit": "1.17.1",
35
+ "fg-devkit": "1.17.3",
36
36
  "@vitejs/plugin-vue": "6.0.9",
37
37
  "tailwindcss": "4.3.3",
38
38
  "tsx": "4.23.13",
39
39
  "vite": "7.3.5",
40
40
  "vite-plugin-vue-inspector": "7.0.0"
41
41
  },
42
- "packageManager": "pnpm@11.25.0",
42
+ "packageManager": "pnpm@12.4.2",
43
43
  "engines": {
44
44
  "node": ">=22.13.0"
45
45
  }