@hostlink/nuxt-light 1.74.1 → 1.76.0
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.
- package/README.md +109 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +0 -1
- package/dist/runtime/components/L/Table.d.vue.ts +2 -0
- package/dist/runtime/components/L/Table.vue +19 -6
- package/dist/runtime/components/L/Table.vue.d.ts +2 -0
- package/dist/runtime/composables/collect.d.ts +1 -1
- package/dist/runtime/composables/collect.js +3 -4
- package/dist/runtime/composables/m.d.ts +1 -1
- package/dist/runtime/composables/m.js +3 -3
- package/dist/runtime/composables/model.d.ts +1 -1
- package/dist/runtime/composables/model.js +3 -3
- package/dist/runtime/composables/q.d.ts +2 -0
- package/dist/runtime/composables/q.js +4 -0
- package/dist/runtime/composables/useLightClient.d.ts +4 -0
- package/dist/runtime/composables/useLightClient.js +12 -0
- package/dist/runtime/plugin.js +14 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -55,6 +55,114 @@ export default defineNuxtConfig({
|
|
|
55
55
|
|
|
56
56
|
That's it! You can now use nuxt-light in your Nuxt app ✨
|
|
57
57
|
|
|
58
|
+
## API clients
|
|
59
|
+
|
|
60
|
+
`nuxt-light` supports multiple Light API endpoints. The client named `auth` is
|
|
61
|
+
always the default: when a component or composable does not specify a client,
|
|
62
|
+
the request is sent to `auth`.
|
|
63
|
+
|
|
64
|
+
Configure named clients in `nuxt.config.ts`:
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
export default defineNuxtConfig({
|
|
68
|
+
runtimeConfig: {
|
|
69
|
+
public: {
|
|
70
|
+
light: {
|
|
71
|
+
clients: {
|
|
72
|
+
auth: {
|
|
73
|
+
baseURL: 'https://auth.example.com/graphql',
|
|
74
|
+
},
|
|
75
|
+
business: {
|
|
76
|
+
baseURL: 'https://business.example.com/graphql',
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
modules: [
|
|
83
|
+
'@hostlink/nuxt-light',
|
|
84
|
+
],
|
|
85
|
+
})
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
A client can also be configured with a URL string:
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
clients: {
|
|
92
|
+
auth: '/auth-api/',
|
|
93
|
+
business: '/business-api/',
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Backwards-compatible single endpoint
|
|
98
|
+
|
|
99
|
+
The existing `public.apiBase` setting is still supported. When no named
|
|
100
|
+
`auth` client is configured, `apiBase` is registered as the `auth` client:
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
export default defineNuxtConfig({
|
|
104
|
+
runtimeConfig: {
|
|
105
|
+
public: {
|
|
106
|
+
apiBase: '/api/',
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
})
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
If neither setting is provided, the default Auth API URL is `/api/`.
|
|
113
|
+
|
|
114
|
+
### Selecting a client
|
|
115
|
+
|
|
116
|
+
Use `useLightClient()` without an argument to get the Auth API client:
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
const auth = useLightClient()
|
|
120
|
+
const business = useLightClient('business')
|
|
121
|
+
|
|
122
|
+
await auth.auth.login(username, password)
|
|
123
|
+
await business.query({
|
|
124
|
+
app: {
|
|
125
|
+
orders: {
|
|
126
|
+
order_id: true,
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
})
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
The standard composables also default to `auth`:
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
await q(query) // auth
|
|
136
|
+
await q(query, 'business') // business
|
|
137
|
+
|
|
138
|
+
model('User') // auth
|
|
139
|
+
model('Order', 'business') // business
|
|
140
|
+
|
|
141
|
+
collect('User', fields) // auth
|
|
142
|
+
collect('Order', fields, 'business') // business
|
|
143
|
+
|
|
144
|
+
await m('updateUser', args, fields) // auth
|
|
145
|
+
await m('updateOrder', args, fields, 'business') // business
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
`<L-Table>` uses `auth` unless its `client` prop is provided:
|
|
149
|
+
|
|
150
|
+
```vue
|
|
151
|
+
<template>
|
|
152
|
+
<!-- Uses the default auth client -->
|
|
153
|
+
<L-Table model-name="User" />
|
|
154
|
+
|
|
155
|
+
<!-- Uses the business client -->
|
|
156
|
+
<L-Table
|
|
157
|
+
client="business"
|
|
158
|
+
model-name="Order"
|
|
159
|
+
/>
|
|
160
|
+
</template>
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
An unknown client name throws an explicit configuration error instead of
|
|
164
|
+
silently sending the request to another endpoint.
|
|
165
|
+
|
|
58
166
|
## Development
|
|
59
167
|
|
|
60
168
|
```bash
|
|
@@ -119,4 +227,4 @@ nuxt.config.ts
|
|
|
119
227
|
]
|
|
120
228
|
}
|
|
121
229
|
}
|
|
122
|
-
```
|
|
230
|
+
```
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -220,7 +220,6 @@ const module$1 = defineNuxtModule({
|
|
|
220
220
|
});
|
|
221
221
|
addImports({ name: "isGranted", from: "@hostlink/light" });
|
|
222
222
|
addImports({ name: "getGrantedRights", from: "@hostlink/light" });
|
|
223
|
-
addImports({ name: "query", as: "q", from: "@hostlink/light" });
|
|
224
223
|
addImports({ name: "mutation", from: "@hostlink/light" });
|
|
225
224
|
addImports({ name: "query", from: "@hostlink/light" });
|
|
226
225
|
await addComponentsDir({
|
|
@@ -27,6 +27,7 @@ export type LTableColumn = QTableColumn & {
|
|
|
27
27
|
autoWidth?: boolean;
|
|
28
28
|
};
|
|
29
29
|
export type LTableProps = QTableProps & {
|
|
30
|
+
client?: string;
|
|
30
31
|
columns?: Array<LTableColumn>;
|
|
31
32
|
actions?: Array<'view' | 'edit' | 'delete' | 'update'>;
|
|
32
33
|
sortBy?: string;
|
|
@@ -127,6 +128,7 @@ declare const __VLS_base: import("vue").DefineComponent<LTableProps, {
|
|
|
127
128
|
rowsPerPageLabel: string;
|
|
128
129
|
rowsPerPageOptions: readonly any[];
|
|
129
130
|
selection: "none" | "single" | "multiple";
|
|
131
|
+
client: string;
|
|
130
132
|
searchable: boolean;
|
|
131
133
|
canExpandRow: (row: any) => boolean;
|
|
132
134
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -5,8 +5,9 @@ import { ref, computed, onMounted, useSlots, watch, useAttrs } from "vue";
|
|
|
5
5
|
import useLight from "../../composables/useLight";
|
|
6
6
|
import { useLightTableDefaults } from "../../composables/useLightProps";
|
|
7
7
|
import model from "../../composables/model";
|
|
8
|
+
import useLightClient from "../../composables/useLightClient";
|
|
8
9
|
import { toQuery } from "@hostlink/light";
|
|
9
|
-
import {
|
|
10
|
+
import { navigateTo } from "#imports";
|
|
10
11
|
import { useI18n } from "vue-i18n";
|
|
11
12
|
import { useStorage, useSessionStorage } from "@vueuse/core";
|
|
12
13
|
import { useRoute } from "#imports";
|
|
@@ -98,6 +99,7 @@ const props = defineProps({
|
|
|
98
99
|
"onUpdate:selected": { type: Function, required: false },
|
|
99
100
|
"onUpdate:expanded": { type: Function, required: false },
|
|
100
101
|
onVirtualScroll: { type: Function, required: false },
|
|
102
|
+
client: { type: String, required: false, default: "auth" },
|
|
101
103
|
actions: { type: Array, required: false, default: () => [] },
|
|
102
104
|
sortBy: { type: String, required: false },
|
|
103
105
|
modelName: { type: null, required: false },
|
|
@@ -138,7 +140,7 @@ if (!saveFilters.value) {
|
|
|
138
140
|
defineOptions({ inheritAttrs: false });
|
|
139
141
|
const light = useLight();
|
|
140
142
|
const vAttrs = useAttrs();
|
|
141
|
-
const L_KEYS = ["actions", "sortBy", "modelName", "searchable", "onRequestData", "addComponent", "addComponentProps", "name", "searchStyle", "canExpandRow"];
|
|
143
|
+
const L_KEYS = ["client", "actions", "sortBy", "modelName", "searchable", "onRequestData", "addComponent", "addComponentProps", "name", "searchStyle", "canExpandRow"];
|
|
142
144
|
const base = useLightTableDefaults(props, vAttrs, L_KEYS);
|
|
143
145
|
const pagination = ref(props.pagination);
|
|
144
146
|
if (props.rowsPerPageOptions[0] == 0) {
|
|
@@ -195,6 +197,17 @@ const resolveColumnOptions = async (col) => {
|
|
|
195
197
|
} catch {
|
|
196
198
|
}
|
|
197
199
|
};
|
|
200
|
+
const autoWidthSelectStyle = (col) => {
|
|
201
|
+
if (!col.autoWidth) return {};
|
|
202
|
+
const options = localSearchOptions.value[col.name] ?? [];
|
|
203
|
+
const labelWidth = (option) => {
|
|
204
|
+
const label = String(option.label ?? option.value ?? "");
|
|
205
|
+
return Array.from(label).reduce((width2, character) => width2 + (character.charCodeAt(0) > 255 ? 2 : 1), 0);
|
|
206
|
+
};
|
|
207
|
+
const longestLabel = Math.max(0, ...options.map(labelWidth));
|
|
208
|
+
const width = Math.min(36, Math.max(12, longestLabel + 4));
|
|
209
|
+
return { width: `${width}ch`, minWidth: `${width}ch` };
|
|
210
|
+
};
|
|
198
211
|
onMounted(async () => {
|
|
199
212
|
await Promise.all(
|
|
200
213
|
(props.columns ?? []).map((col) => resolveColumnOptions(col))
|
|
@@ -331,7 +344,7 @@ const onLocalRequest = async (p) => {
|
|
|
331
344
|
}
|
|
332
345
|
loading.value = true;
|
|
333
346
|
try {
|
|
334
|
-
let l = list(model2, localFields);
|
|
347
|
+
let l = useLightClient(props.client).list(model2, localFields);
|
|
335
348
|
l = l.filters(localFilters);
|
|
336
349
|
if (sort) {
|
|
337
350
|
l = l.sort(sort);
|
|
@@ -420,7 +433,7 @@ const ss = computed(() => Object.keys(slots));
|
|
|
420
433
|
const onDelete = async (id) => {
|
|
421
434
|
if (modelName.value == null) return;
|
|
422
435
|
try {
|
|
423
|
-
await model(modelName.value).delete(id);
|
|
436
|
+
await model(modelName.value, props.client).delete(id);
|
|
424
437
|
} catch (e) {
|
|
425
438
|
$q.notify({
|
|
426
439
|
message: e.message,
|
|
@@ -700,7 +713,7 @@ const hasFilters = computed(() => {
|
|
|
700
713
|
<q-td v-if="selection != 'none'" auto-width />
|
|
701
714
|
<q-td v-if="hasRowExpand" auto-width />
|
|
702
715
|
<q-td v-if="hasActions" auto-width />
|
|
703
|
-
<q-td v-for="col in props.cols" :key="col.name" :style="col.style">
|
|
716
|
+
<q-td v-for="col in props.cols" :key="col.name" :auto-width="col.autoWidth ?? false" :style="col.style">
|
|
704
717
|
|
|
705
718
|
<template v-if="col.searchable">
|
|
706
719
|
|
|
@@ -724,7 +737,7 @@ const hasFilters = computed(() => {
|
|
|
724
737
|
:options="localSearchOptions[col.name]" emit-value map-options
|
|
725
738
|
:multiple="col.searchMultiple" use-input input-debounce="0" @filter="(val, update) => {
|
|
726
739
|
searchSelectFilter(val, update, col.name);
|
|
727
|
-
}" :style="col.searchStyle" :placeholder="col.searchPlaceholder" />
|
|
740
|
+
}" :style="[autoWidthSelectStyle(col), col.searchStyle]" :placeholder="col.searchPlaceholder" />
|
|
728
741
|
</template>
|
|
729
742
|
|
|
730
743
|
<template v-if="col.searchType == 'date'">
|
|
@@ -27,6 +27,7 @@ export type LTableColumn = QTableColumn & {
|
|
|
27
27
|
autoWidth?: boolean;
|
|
28
28
|
};
|
|
29
29
|
export type LTableProps = QTableProps & {
|
|
30
|
+
client?: string;
|
|
30
31
|
columns?: Array<LTableColumn>;
|
|
31
32
|
actions?: Array<'view' | 'edit' | 'delete' | 'update'>;
|
|
32
33
|
sortBy?: string;
|
|
@@ -127,6 +128,7 @@ declare const __VLS_base: import("vue").DefineComponent<LTableProps, {
|
|
|
127
128
|
rowsPerPageLabel: string;
|
|
128
129
|
rowsPerPageOptions: readonly any[];
|
|
129
130
|
selection: "none" | "single" | "multiple";
|
|
131
|
+
client: string;
|
|
130
132
|
searchable: boolean;
|
|
131
133
|
canExpandRow: (row: any) => boolean;
|
|
132
134
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: (name: string, fields: Object) => any;
|
|
1
|
+
declare const _default: (name: string, fields: Object, client?: string) => any;
|
|
2
2
|
export default _default;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
export default (name, fields) => {
|
|
3
|
-
|
|
4
|
-
return client.collect(name, fields);
|
|
1
|
+
import useLightClient from "./useLightClient.js";
|
|
2
|
+
export default (name, fields, client = "auth") => {
|
|
3
|
+
return useLightClient(client).collect(name, fields);
|
|
5
4
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import useLightClient from "./useLightClient.js";
|
|
2
2
|
const removeUndefinedValues = (obj) => {
|
|
3
3
|
for (const key in obj) {
|
|
4
4
|
if (obj[key] instanceof File) {
|
|
@@ -13,7 +13,7 @@ const removeUndefinedValues = (obj) => {
|
|
|
13
13
|
}
|
|
14
14
|
return obj;
|
|
15
15
|
};
|
|
16
|
-
export default function(operation, args, fields = []) {
|
|
16
|
+
export default function(operation, args, fields = [], client = "auth") {
|
|
17
17
|
if (args) {
|
|
18
18
|
args = removeUndefinedValues(args);
|
|
19
19
|
}
|
|
@@ -29,7 +29,7 @@ export default function(operation, args, fields = []) {
|
|
|
29
29
|
if (Object.keys(q[operation]).length === 0) {
|
|
30
30
|
q[operation] = true;
|
|
31
31
|
}
|
|
32
|
-
return mutation(q).then((res) => {
|
|
32
|
+
return useLightClient(client).mutation(q).then((res) => {
|
|
33
33
|
return res[operation];
|
|
34
34
|
});
|
|
35
35
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { LTableColumn } from "../components/L/Table.vue.js";
|
|
2
|
-
declare const _default: (name: string) => Omit<{
|
|
2
|
+
declare const _default: (name: string, client?: string) => Omit<{
|
|
3
3
|
field: (f: string) => import("@hostlink/light").Field | null;
|
|
4
4
|
$fields: Record<string, import("@hostlink/light").Field>;
|
|
5
5
|
setDataPath(path: string): string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import useLightClient from "./useLightClient.js";
|
|
2
2
|
import defu from "defu";
|
|
3
|
-
export default (name) => {
|
|
4
|
-
const m =
|
|
3
|
+
export default (name, client = "auth") => {
|
|
4
|
+
const m = useLightClient(client).model(name);
|
|
5
5
|
return defu(m, {
|
|
6
6
|
columns(fields) {
|
|
7
7
|
let columns = [];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const clients = /* @__PURE__ */ new Map();
|
|
2
|
+
export function registerLightClient(name, client) {
|
|
3
|
+
clients.set(name, client);
|
|
4
|
+
}
|
|
5
|
+
export function clearLightClients() {
|
|
6
|
+
clients.clear();
|
|
7
|
+
}
|
|
8
|
+
export default function useLightClient(name = "auth") {
|
|
9
|
+
const client = clients.get(name);
|
|
10
|
+
if (!client) throw new Error(`Light client "${name}" is not configured`);
|
|
11
|
+
return client;
|
|
12
|
+
}
|
package/dist/runtime/plugin.js
CHANGED
|
@@ -12,10 +12,22 @@ import { createLightPlugin } from "./formkit/index.js";
|
|
|
12
12
|
import { plugin, defaultConfig } from "@formkit/vue";
|
|
13
13
|
import getApiBase from "./composables/getApiBase.js";
|
|
14
14
|
import useLight from "./composables/useLight.js";
|
|
15
|
+
import useLightClient, { clearLightClients, registerLightClient } from "./composables/useLightClient.js";
|
|
15
16
|
import { zhTW } from "@formkit/i18n";
|
|
16
17
|
export default defineNuxtPlugin((nuxtApp) => {
|
|
17
|
-
const
|
|
18
|
-
|
|
18
|
+
const runtimeConfig = useRuntimeConfig();
|
|
19
|
+
const lightConfig = runtimeConfig.public.light;
|
|
20
|
+
const configuredClients = lightConfig?.clients ?? {};
|
|
21
|
+
clearLightClients();
|
|
22
|
+
for (const [name, config] of Object.entries(configuredClients)) {
|
|
23
|
+
const baseURL = typeof config === "string" ? config : config.baseURL;
|
|
24
|
+
if (!baseURL) throw new Error(`Light client "${name}" requires a baseURL`);
|
|
25
|
+
registerLightClient(name, createClient(baseURL));
|
|
26
|
+
}
|
|
27
|
+
if (!configuredClients.auth) {
|
|
28
|
+
registerLightClient("auth", createClient(getApiBase()));
|
|
29
|
+
}
|
|
30
|
+
setApiClient(useLightClient());
|
|
19
31
|
defineModel("Permission", {}).setDataPath("app.listPermission");
|
|
20
32
|
defineModel("SystemValue", {}).setDataPath("app.listSystemValue");
|
|
21
33
|
defineModel("Config", {}).setDataPath("app.listConfig");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hostlink/nuxt-light",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.76.0",
|
|
4
4
|
"description": "HostLink Nuxt Light Framework",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"@formkit/inputs": "^2.1.2",
|
|
39
39
|
"@formkit/validation": "^2.1.2",
|
|
40
40
|
"@formkit/vue": "^2.1.2",
|
|
41
|
-
"@hostlink/light": "^3.
|
|
41
|
+
"@hostlink/light": "^3.3.1",
|
|
42
42
|
"@nuxt/module-builder": "^1.0.1",
|
|
43
43
|
"@quasar/extras": "^2.0.2",
|
|
44
44
|
"@quasar/quasar-ui-qmarkdown": "^3.0.1",
|