@hostlink/nuxt-light 1.66.2 → 1.67.1
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/dist/module.d.mts +5 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +10 -0
- package/dist/runtime/components/L/DatePicker.d.vue.ts +1 -1
- package/dist/runtime/components/L/DatePicker.vue.d.ts +1 -1
- package/dist/runtime/components/L/DeleteBtn.d.vue.ts +10 -1
- package/dist/runtime/components/L/DeleteBtn.vue +4 -2
- package/dist/runtime/components/L/DeleteBtn.vue.d.ts +10 -1
- package/dist/runtime/components/L/SearchNumber.d.vue.ts +16 -0
- package/dist/runtime/components/L/SearchNumber.vue +139 -0
- package/dist/runtime/components/L/SearchNumber.vue.d.ts +16 -0
- package/dist/runtime/components/L/Table.d.vue.ts +16 -8
- package/dist/runtime/components/L/Table.vue +76 -13
- package/dist/runtime/components/L/Table.vue.d.ts +16 -8
- package/dist/runtime/composables/useLight.d.ts +6 -6
- package/dist/runtime/composables/useLight.js +10 -1
- package/dist/runtime/models/EventLog.js +5 -1
- package/dist/runtime/models/User.js +1 -0
- package/dist/runtime/pages/Permission/all.vue +23 -14
- package/dist/runtime/plugin.js +13 -5
- package/package.json +1 -1
package/dist/module.d.mts
CHANGED
|
@@ -2,6 +2,11 @@ import * as _nuxt_schema from '@nuxt/schema';
|
|
|
2
2
|
|
|
3
3
|
interface ModuleOptions {
|
|
4
4
|
checkPagePermissions?: boolean;
|
|
5
|
+
tableActionIcons?: {
|
|
6
|
+
view?: string;
|
|
7
|
+
edit?: string;
|
|
8
|
+
delete?: string;
|
|
9
|
+
};
|
|
5
10
|
}
|
|
6
11
|
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
|
7
12
|
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -334,6 +334,16 @@ const module$1 = defineNuxtModule({
|
|
|
334
334
|
}, */
|
|
335
335
|
async setup(options, nuxt) {
|
|
336
336
|
const resolver = createResolver(import.meta.url);
|
|
337
|
+
nuxt.options.runtimeConfig = nuxt.options.runtimeConfig || {};
|
|
338
|
+
nuxt.options.runtimeConfig.public = nuxt.options.runtimeConfig.public || {};
|
|
339
|
+
nuxt.options.runtimeConfig.public.light = {
|
|
340
|
+
...nuxt.options.runtimeConfig.public.light || {},
|
|
341
|
+
tableActionIcons: {
|
|
342
|
+
view: options.tableActionIcons?.view,
|
|
343
|
+
edit: options.tableActionIcons?.edit,
|
|
344
|
+
delete: options.tableActionIcons?.delete
|
|
345
|
+
}
|
|
346
|
+
};
|
|
337
347
|
extendPages((pages) => {
|
|
338
348
|
for (const route of routes) {
|
|
339
349
|
if (route.children) {
|
|
@@ -19,13 +19,13 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
|
|
|
19
19
|
square: boolean;
|
|
20
20
|
dense: boolean;
|
|
21
21
|
disable: boolean;
|
|
22
|
+
range: boolean;
|
|
22
23
|
outlined: boolean;
|
|
23
24
|
filled: boolean;
|
|
24
25
|
stackLabel: boolean;
|
|
25
26
|
standout: string | boolean;
|
|
26
27
|
hideBottomSpace: boolean;
|
|
27
28
|
todayBtn: boolean;
|
|
28
|
-
range: boolean;
|
|
29
29
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
30
30
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
31
31
|
declare const _default: typeof __VLS_export;
|
|
@@ -19,13 +19,13 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
|
|
|
19
19
|
square: boolean;
|
|
20
20
|
dense: boolean;
|
|
21
21
|
disable: boolean;
|
|
22
|
+
range: boolean;
|
|
22
23
|
outlined: boolean;
|
|
23
24
|
filled: boolean;
|
|
24
25
|
stackLabel: boolean;
|
|
25
26
|
standout: string | boolean;
|
|
26
27
|
hideBottomSpace: boolean;
|
|
27
28
|
todayBtn: boolean;
|
|
28
|
-
range: boolean;
|
|
29
29
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
30
30
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
31
31
|
declare const _default: typeof __VLS_export;
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
declare const _default: typeof __VLS_export;
|
|
2
2
|
export default _default;
|
|
3
|
-
declare const __VLS_export:
|
|
3
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
4
|
+
type __VLS_WithSlots<T, S> = T & (new () => {
|
|
5
|
+
$slots: S;
|
|
6
|
+
});
|
|
7
|
+
declare const __VLS_base: import("vue").DefineComponent<{
|
|
8
|
+
icon?: any;
|
|
4
9
|
to?: any;
|
|
5
10
|
}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
6
11
|
submit: (...args: any[]) => void;
|
|
7
12
|
}, string, import("vue").PublicProps, Readonly<{
|
|
13
|
+
icon?: any;
|
|
8
14
|
to?: any;
|
|
9
15
|
}> & Readonly<{
|
|
10
16
|
onSubmit?: ((...args: any[]) => any) | undefined;
|
|
11
17
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
18
|
+
type __VLS_Slots = {
|
|
19
|
+
default?: ((props: {}) => any) | undefined;
|
|
20
|
+
};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { useQuasar } from "quasar";
|
|
3
3
|
import { useI18n } from "vue-i18n";
|
|
4
4
|
const { t } = useI18n();
|
|
5
|
-
const props = defineProps(["to"]);
|
|
5
|
+
const props = defineProps(["to", "icon"]);
|
|
6
6
|
const emit = defineEmits(["submit"]);
|
|
7
7
|
const qua = useQuasar();
|
|
8
8
|
const onDelete = () => {
|
|
@@ -19,5 +19,7 @@ const onDelete = () => {
|
|
|
19
19
|
</script>
|
|
20
20
|
|
|
21
21
|
<template>
|
|
22
|
-
<q-btn flat round icon="sym_o_delete" @click="onDelete"
|
|
22
|
+
<q-btn flat round :icon="icon || 'sym_o_delete'" @click="onDelete">
|
|
23
|
+
<slot></slot>
|
|
24
|
+
</q-btn>
|
|
23
25
|
</template>
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
declare const _default: typeof __VLS_export;
|
|
2
2
|
export default _default;
|
|
3
|
-
declare const __VLS_export:
|
|
3
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
4
|
+
type __VLS_WithSlots<T, S> = T & (new () => {
|
|
5
|
+
$slots: S;
|
|
6
|
+
});
|
|
7
|
+
declare const __VLS_base: import("vue").DefineComponent<{
|
|
8
|
+
icon?: any;
|
|
4
9
|
to?: any;
|
|
5
10
|
}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
6
11
|
submit: (...args: any[]) => void;
|
|
7
12
|
}, string, import("vue").PublicProps, Readonly<{
|
|
13
|
+
icon?: any;
|
|
8
14
|
to?: any;
|
|
9
15
|
}> & Readonly<{
|
|
10
16
|
onSubmit?: ((...args: any[]) => any) | undefined;
|
|
11
17
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
18
|
+
type __VLS_Slots = {
|
|
19
|
+
default?: ((props: {}) => any) | undefined;
|
|
20
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
modelValue?: number | string | {
|
|
3
|
+
min?: number | null;
|
|
4
|
+
max?: number | null;
|
|
5
|
+
} | null;
|
|
6
|
+
placeholder?: string;
|
|
7
|
+
};
|
|
8
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
9
|
+
change: (value: any) => any;
|
|
10
|
+
"update:modelValue": (value: any) => any;
|
|
11
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
12
|
+
onChange?: ((value: any) => any) | undefined;
|
|
13
|
+
"onUpdate:modelValue"?: ((value: any) => any) | undefined;
|
|
14
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
15
|
+
declare const _default: typeof __VLS_export;
|
|
16
|
+
export default _default;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref, watch, computed } from "vue";
|
|
3
|
+
import { useI18n } from "vue-i18n";
|
|
4
|
+
const props = defineProps({
|
|
5
|
+
modelValue: { type: [Number, String, Object, null], required: false },
|
|
6
|
+
placeholder: { type: String, required: false }
|
|
7
|
+
});
|
|
8
|
+
const emit = defineEmits(["update:modelValue", "change"]);
|
|
9
|
+
const { t } = useI18n();
|
|
10
|
+
const mode = ref("equals");
|
|
11
|
+
const equalsValue = ref(null);
|
|
12
|
+
const minValue = ref(null);
|
|
13
|
+
const maxValue = ref(null);
|
|
14
|
+
watch(() => props.modelValue, (val) => {
|
|
15
|
+
if (val == null || val === "") {
|
|
16
|
+
equalsValue.value = null;
|
|
17
|
+
minValue.value = null;
|
|
18
|
+
maxValue.value = null;
|
|
19
|
+
} else if (typeof val === "object") {
|
|
20
|
+
mode.value = "range";
|
|
21
|
+
equalsValue.value = null;
|
|
22
|
+
minValue.value = val.min ?? null;
|
|
23
|
+
maxValue.value = val.max ?? null;
|
|
24
|
+
} else {
|
|
25
|
+
mode.value = "equals";
|
|
26
|
+
equalsValue.value = Number(val);
|
|
27
|
+
minValue.value = null;
|
|
28
|
+
maxValue.value = null;
|
|
29
|
+
}
|
|
30
|
+
}, { immediate: true });
|
|
31
|
+
const hasValue = computed(() => {
|
|
32
|
+
if (props.modelValue == null || props.modelValue === "") return false;
|
|
33
|
+
if (typeof props.modelValue === "object") {
|
|
34
|
+
const { min, max } = props.modelValue;
|
|
35
|
+
return min != null || max != null;
|
|
36
|
+
}
|
|
37
|
+
return true;
|
|
38
|
+
});
|
|
39
|
+
const displayLabel = computed(() => {
|
|
40
|
+
if (!hasValue.value) return t("Search");
|
|
41
|
+
if (typeof props.modelValue === "object") {
|
|
42
|
+
const { min, max } = props.modelValue;
|
|
43
|
+
if (min != null && max != null) return `${min} \u2013 ${max}`;
|
|
44
|
+
if (min != null) return `\u2265 ${min}`;
|
|
45
|
+
if (max != null) return `\u2264 ${max}`;
|
|
46
|
+
}
|
|
47
|
+
return `= ${props.modelValue}`;
|
|
48
|
+
});
|
|
49
|
+
const apply = () => {
|
|
50
|
+
let out = null;
|
|
51
|
+
if (mode.value === "equals") {
|
|
52
|
+
out = equalsValue.value;
|
|
53
|
+
} else {
|
|
54
|
+
const outRange = {};
|
|
55
|
+
if (minValue.value != null) outRange.min = minValue.value;
|
|
56
|
+
if (maxValue.value != null) outRange.max = maxValue.value;
|
|
57
|
+
if (Object.keys(outRange).length > 0) out = outRange;
|
|
58
|
+
}
|
|
59
|
+
emit("update:modelValue", out);
|
|
60
|
+
emit("change", out);
|
|
61
|
+
};
|
|
62
|
+
const clear = () => {
|
|
63
|
+
equalsValue.value = null;
|
|
64
|
+
minValue.value = null;
|
|
65
|
+
maxValue.value = null;
|
|
66
|
+
emit("update:modelValue", null);
|
|
67
|
+
emit("change", null);
|
|
68
|
+
};
|
|
69
|
+
</script>
|
|
70
|
+
|
|
71
|
+
<template>
|
|
72
|
+
<q-btn-dropdown
|
|
73
|
+
dense flat square no-caps
|
|
74
|
+
:color="hasValue ? 'primary' : 'grey-7'"
|
|
75
|
+
:label="displayLabel"
|
|
76
|
+
:icon="hasValue ? 'sym_o_filter_alt' : 'sym_o_search'"
|
|
77
|
+
size="sm"
|
|
78
|
+
content-class="l-search-number-dropdown"
|
|
79
|
+
>
|
|
80
|
+
<div class="q-pa-md" style="min-width: 280px">
|
|
81
|
+
<q-tabs
|
|
82
|
+
v-model="mode"
|
|
83
|
+
dense
|
|
84
|
+
no-caps
|
|
85
|
+
align="left"
|
|
86
|
+
active-color="primary"
|
|
87
|
+
indicator-color="primary"
|
|
88
|
+
class="text-grey"
|
|
89
|
+
>
|
|
90
|
+
<q-tab name="equals" :label="t('Equals')" />
|
|
91
|
+
<q-tab name="range" :label="t('Range')" />
|
|
92
|
+
</q-tabs>
|
|
93
|
+
|
|
94
|
+
<q-separator class="q-mb-sm" />
|
|
95
|
+
|
|
96
|
+
<q-tab-panels v-model="mode" animated>
|
|
97
|
+
<q-tab-panel name="equals" class="q-pa-none">
|
|
98
|
+
<q-input
|
|
99
|
+
v-model.number="equalsValue"
|
|
100
|
+
dense filled square
|
|
101
|
+
type="number"
|
|
102
|
+
mask="##########"
|
|
103
|
+
:placeholder="placeholder || t('Enter a number')"
|
|
104
|
+
autofocus
|
|
105
|
+
@keydown.enter.prevent="apply"
|
|
106
|
+
/>
|
|
107
|
+
</q-tab-panel>
|
|
108
|
+
<q-tab-panel name="range" class="q-pa-none">
|
|
109
|
+
<div class="row q-gutter-sm items-center">
|
|
110
|
+
<q-input
|
|
111
|
+
v-model.number="minValue"
|
|
112
|
+
dense filled square
|
|
113
|
+
type="number"
|
|
114
|
+
mask="##########"
|
|
115
|
+
:placeholder="t('Min')"
|
|
116
|
+
class="col"
|
|
117
|
+
@keydown.enter.prevent="apply"
|
|
118
|
+
/>
|
|
119
|
+
<span class="text-grey">—</span>
|
|
120
|
+
<q-input
|
|
121
|
+
v-model.number="maxValue"
|
|
122
|
+
dense filled square
|
|
123
|
+
type="number"
|
|
124
|
+
mask="##########"
|
|
125
|
+
:placeholder="t('Max')"
|
|
126
|
+
class="col"
|
|
127
|
+
@keydown.enter.prevent="apply"
|
|
128
|
+
/>
|
|
129
|
+
</div>
|
|
130
|
+
</q-tab-panel>
|
|
131
|
+
</q-tab-panels>
|
|
132
|
+
|
|
133
|
+
<div class="row q-gutter-sm justify-end q-mt-md">
|
|
134
|
+
<q-btn flat dense :label="t('Clear')" color="negative" @click="clear" />
|
|
135
|
+
<q-btn flat dense :label="t('Apply')" color="primary" @click="apply" />
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
</q-btn-dropdown>
|
|
139
|
+
</template>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
modelValue?: number | string | {
|
|
3
|
+
min?: number | null;
|
|
4
|
+
max?: number | null;
|
|
5
|
+
} | null;
|
|
6
|
+
placeholder?: string;
|
|
7
|
+
};
|
|
8
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
9
|
+
change: (value: any) => any;
|
|
10
|
+
"update:modelValue": (value: any) => any;
|
|
11
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
12
|
+
onChange?: ((value: any) => any) | undefined;
|
|
13
|
+
"onUpdate:modelValue"?: ((value: any) => any) | undefined;
|
|
14
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
15
|
+
declare const _default: typeof __VLS_export;
|
|
16
|
+
export default _default;
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import type { Component } from "vue";
|
|
2
2
|
import { Dialog } from 'quasar';
|
|
3
3
|
import type { QTableColumn, QTableProps } from 'quasar';
|
|
4
|
+
export interface SearchOptionsContext {
|
|
5
|
+
filters: Record<string, any>;
|
|
6
|
+
columnValue: any;
|
|
7
|
+
column: LTableColumn;
|
|
8
|
+
}
|
|
9
|
+
export type SearchOptionsResolver = (ctx: SearchOptionsContext) => Promise<Record<string, any>[]>;
|
|
4
10
|
export type LTableColumn = QTableColumn & {
|
|
5
11
|
searchType?: "date" | "text" | "number" | "select" | "boolean";
|
|
6
12
|
searchable?: boolean;
|
|
7
|
-
|
|
13
|
+
searchPlaceholder?: string;
|
|
14
|
+
searchOptions?: Record<string, any>[] | SearchOptionsResolver;
|
|
15
|
+
searchDependsOn?: string[];
|
|
8
16
|
searchMultiple?: boolean;
|
|
9
17
|
searchIndex?: string;
|
|
10
18
|
component?: Component;
|
|
@@ -15,7 +23,7 @@ export type LTableColumn = QTableColumn & {
|
|
|
15
23
|
* @deprecated use gql instead
|
|
16
24
|
*/
|
|
17
25
|
gqlField?: string | Array<string> | Object;
|
|
18
|
-
searchMethod?: "equals" | "contains";
|
|
26
|
+
searchMethod?: "equals" | "contains" | "range";
|
|
19
27
|
autoWidth?: boolean;
|
|
20
28
|
};
|
|
21
29
|
export type LTableProps = QTableProps & {
|
|
@@ -71,17 +79,17 @@ export interface LTableRequest {
|
|
|
71
79
|
}) => void;
|
|
72
80
|
}
|
|
73
81
|
declare function requestServerInteraction(): void;
|
|
74
|
-
declare var
|
|
82
|
+
declare var __VLS_135: any, __VLS_138: string, __VLS_139: any, __VLS_170: any, __VLS_173: any, __VLS_343: string, __VLS_344: any;
|
|
75
83
|
type __VLS_Slots = {} & {
|
|
76
|
-
[K in NonNullable<typeof
|
|
84
|
+
[K in NonNullable<typeof __VLS_138>]?: (props: typeof __VLS_139) => any;
|
|
77
85
|
} & {
|
|
78
|
-
[K in NonNullable<typeof
|
|
86
|
+
[K in NonNullable<typeof __VLS_343>]?: (props: typeof __VLS_344) => any;
|
|
79
87
|
} & {
|
|
80
|
-
actions?: (props: typeof
|
|
88
|
+
actions?: (props: typeof __VLS_135) => any;
|
|
81
89
|
} & {
|
|
82
|
-
'row-expand'?: (props: typeof
|
|
90
|
+
'row-expand'?: (props: typeof __VLS_170) => any;
|
|
83
91
|
} & {
|
|
84
|
-
'top-right'?: (props: typeof
|
|
92
|
+
'top-right'?: (props: typeof __VLS_173) => any;
|
|
85
93
|
};
|
|
86
94
|
declare const __VLS_base: import("vue").DefineComponent<LTableProps, {
|
|
87
95
|
requestServerInteraction: typeof requestServerInteraction;
|
|
@@ -149,7 +149,8 @@ const localColumns = computed(
|
|
|
149
149
|
...col,
|
|
150
150
|
align: col.align ?? "left",
|
|
151
151
|
field: col.field ?? col.name,
|
|
152
|
-
label: t(col.label)
|
|
152
|
+
label: t(col.label),
|
|
153
|
+
searchPlaceholder: col.searchPlaceholder ? t(col.searchPlaceholder) : void 0
|
|
153
154
|
}))
|
|
154
155
|
);
|
|
155
156
|
const emits = defineEmits(["request-data", "update:selected", "delete"]);
|
|
@@ -171,15 +172,46 @@ const table = ref();
|
|
|
171
172
|
const rows = ref(props.rows ?? []);
|
|
172
173
|
const resolvedSearchOptions = ref({});
|
|
173
174
|
const localSearchOptions = ref({});
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
resolvedSearchOptions.value[col.name] =
|
|
179
|
-
localSearchOptions.value[col.name] =
|
|
175
|
+
const resolveSeqs = /* @__PURE__ */ new Map();
|
|
176
|
+
const resolveColumnOptions = async (col) => {
|
|
177
|
+
if (!col.searchOptions || !col.name) return;
|
|
178
|
+
if (Array.isArray(col.searchOptions)) {
|
|
179
|
+
resolvedSearchOptions.value[col.name] = col.searchOptions;
|
|
180
|
+
localSearchOptions.value[col.name] = col.searchOptions;
|
|
181
|
+
return;
|
|
180
182
|
}
|
|
183
|
+
const ctx = {
|
|
184
|
+
filters: { ...filters.value },
|
|
185
|
+
columnValue: filters.value[col.name],
|
|
186
|
+
column: col
|
|
187
|
+
};
|
|
188
|
+
const seq = (resolveSeqs.get(col.name) ?? 0) + 1;
|
|
189
|
+
resolveSeqs.set(col.name, seq);
|
|
190
|
+
try {
|
|
191
|
+
const result = await col.searchOptions(ctx);
|
|
192
|
+
if (seq !== resolveSeqs.get(col.name)) return;
|
|
193
|
+
resolvedSearchOptions.value[col.name] = result;
|
|
194
|
+
localSearchOptions.value[col.name] = result;
|
|
195
|
+
} catch {
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
onMounted(async () => {
|
|
199
|
+
await Promise.all(
|
|
200
|
+
(props.columns ?? []).map((col) => resolveColumnOptions(col))
|
|
201
|
+
);
|
|
181
202
|
table.value?.requestServerInteraction();
|
|
182
203
|
});
|
|
204
|
+
watch(filters, (newFilters, oldFilters) => {
|
|
205
|
+
if (!props.columns) return;
|
|
206
|
+
for (const col of props.columns) {
|
|
207
|
+
if (!col.searchDependsOn?.length) continue;
|
|
208
|
+
if (typeof col.searchOptions !== "function") continue;
|
|
209
|
+
if (!col.name) continue;
|
|
210
|
+
const deps = col.searchDependsOn;
|
|
211
|
+
const changed = deps.some((dep) => newFilters?.[dep] !== oldFilters?.[dep]);
|
|
212
|
+
if (changed) resolveColumnOptions(col);
|
|
213
|
+
}
|
|
214
|
+
}, { deep: true });
|
|
183
215
|
const primaryKey = ref(props.rowKey);
|
|
184
216
|
const modelName = ref(props.modelName);
|
|
185
217
|
const validateData = () => {
|
|
@@ -335,6 +367,18 @@ const getFilterValue = () => {
|
|
|
335
367
|
const k = col.searchIndex ?? col.name;
|
|
336
368
|
if (col.searchType == "boolean") {
|
|
337
369
|
f[k] = filters.value[col.name];
|
|
370
|
+
} else if (col.searchMethod == "range" && typeof filters.value[col.name] === "object") {
|
|
371
|
+
const rangeValue = filters.value[col.name];
|
|
372
|
+
const rangeFilter = {};
|
|
373
|
+
if (rangeValue.min !== null && rangeValue.min !== "" && rangeValue.min !== void 0) {
|
|
374
|
+
rangeFilter._gte = Number(rangeValue.min);
|
|
375
|
+
}
|
|
376
|
+
if (rangeValue.max !== null && rangeValue.max !== "" && rangeValue.max !== void 0) {
|
|
377
|
+
rangeFilter._lte = Number(rangeValue.max);
|
|
378
|
+
}
|
|
379
|
+
if (Object.keys(rangeFilter).length > 0) {
|
|
380
|
+
f[k] = rangeFilter;
|
|
381
|
+
}
|
|
338
382
|
} else if (col.searchType == "number") {
|
|
339
383
|
f[k] = filters.value[col.name];
|
|
340
384
|
} else if (col.searchType == "date") {
|
|
@@ -460,6 +504,9 @@ const localFilterMethod = (rows2, terms) => {
|
|
|
460
504
|
if (!String(cell ?? "").toLowerCase().includes(String(value.contains).toLowerCase())) return false;
|
|
461
505
|
} else if (typeof value === "object" && value !== null && "_between" in value) {
|
|
462
506
|
if (cell < value._between[0] || cell > value._between[1]) return false;
|
|
507
|
+
} else if (typeof value === "object" && value !== null && ("_gte" in value || "_lte" in value)) {
|
|
508
|
+
if ("_gte" in value && value._gte !== null && value._gte !== void 0 && cell < value._gte) return false;
|
|
509
|
+
if ("_lte" in value && value._lte !== null && value._lte !== void 0 && cell > value._lte) return false;
|
|
463
510
|
} else {
|
|
464
511
|
if (cell !== value) return false;
|
|
465
512
|
}
|
|
@@ -549,13 +596,22 @@ const hasFilters = computed(() => {
|
|
|
549
596
|
<div :class="{ 'text-grey-8': !isDark }" v-if="primaryKey">
|
|
550
597
|
|
|
551
598
|
<l-action-btn v-if="actionView && props.row.canView"
|
|
552
|
-
:to="`/${modelName}/${props.row[primaryKey]}/view`"
|
|
599
|
+
:to="`/${modelName}/${props.row[primaryKey]}/view`"
|
|
600
|
+
:icon="light.styles.table.actionIcons.view">
|
|
601
|
+
<q-tooltip>{{ $t("View") }}</q-tooltip>
|
|
602
|
+
</l-action-btn>
|
|
553
603
|
|
|
554
604
|
<l-action-btn v-if="activeEdit && props.row.canUpdate"
|
|
555
|
-
:to="`/${modelName}/${props.row[primaryKey]}/edit`"
|
|
605
|
+
:to="`/${modelName}/${props.row[primaryKey]}/edit`"
|
|
606
|
+
:icon="light.styles.table.actionIcons.edit">
|
|
607
|
+
<q-tooltip>{{ $t("Edit") }}</q-tooltip>
|
|
608
|
+
</l-action-btn>
|
|
556
609
|
|
|
557
610
|
<l-delete-btn v-if="actionDelete && props.row.canDelete"
|
|
558
|
-
|
|
611
|
+
:icon="light.styles.table.actionIcons.delete"
|
|
612
|
+
@submit="onDelete(props.row[primaryKey])" size="sm">
|
|
613
|
+
<q-tooltip>{{ $t("Delete") }}</q-tooltip>
|
|
614
|
+
</l-delete-btn>
|
|
559
615
|
|
|
560
616
|
<slot name="actions" v-bind="props"></slot>
|
|
561
617
|
</div>
|
|
@@ -648,7 +704,14 @@ const hasFilters = computed(() => {
|
|
|
648
704
|
|
|
649
705
|
<template v-if="col.searchable">
|
|
650
706
|
|
|
651
|
-
<template v-if="col.searchType == 'number'">
|
|
707
|
+
<template v-if="col.searchMethod == 'range' && (!col.searchType || col.searchType == 'number')">
|
|
708
|
+
<l-search-number
|
|
709
|
+
v-model="filters[col.name]"
|
|
710
|
+
@change="onFilters"
|
|
711
|
+
/>
|
|
712
|
+
</template>
|
|
713
|
+
|
|
714
|
+
<template v-else-if="col.searchType == 'number'">
|
|
652
715
|
<q-input style="min-width: 80px;" dense clearable filled square
|
|
653
716
|
v-model.number="tempFilters[col.name]"
|
|
654
717
|
@keydown.enter.prevent="filters[col.name] = tempFilters[col.name]"
|
|
@@ -677,9 +740,9 @@ const hasFilters = computed(() => {
|
|
|
677
740
|
|
|
678
741
|
</template>
|
|
679
742
|
|
|
680
|
-
<template v-if="!col.searchType || col.searchType == 'text'">
|
|
743
|
+
<template v-if="(!col.searchType || col.searchType == 'text') && col.searchMethod != 'range'">
|
|
681
744
|
<q-input style="min-width: 80px;" dense clearable filled square
|
|
682
|
-
v-model="tempFilters[col.name]" @keydown.enter.prevent="filters[col.name] = tempFilters[col.name]" @clear="delete filters[col.name]" :enterkeyhint="$t('search')" :style="col.searchStyle"></q-input>
|
|
745
|
+
v-model="tempFilters[col.name]" @keydown.enter.prevent="filters[col.name] = tempFilters[col.name]" @clear="delete filters[col.name]" :enterkeyhint="$t('search')" :placeholder="col.searchPlaceholder" :style="col.searchStyle"></q-input>
|
|
683
746
|
|
|
684
747
|
</template>
|
|
685
748
|
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import type { Component } from "vue";
|
|
2
2
|
import { Dialog } from 'quasar';
|
|
3
3
|
import type { QTableColumn, QTableProps } from 'quasar';
|
|
4
|
+
export interface SearchOptionsContext {
|
|
5
|
+
filters: Record<string, any>;
|
|
6
|
+
columnValue: any;
|
|
7
|
+
column: LTableColumn;
|
|
8
|
+
}
|
|
9
|
+
export type SearchOptionsResolver = (ctx: SearchOptionsContext) => Promise<Record<string, any>[]>;
|
|
4
10
|
export type LTableColumn = QTableColumn & {
|
|
5
11
|
searchType?: "date" | "text" | "number" | "select" | "boolean";
|
|
6
12
|
searchable?: boolean;
|
|
7
|
-
|
|
13
|
+
searchPlaceholder?: string;
|
|
14
|
+
searchOptions?: Record<string, any>[] | SearchOptionsResolver;
|
|
15
|
+
searchDependsOn?: string[];
|
|
8
16
|
searchMultiple?: boolean;
|
|
9
17
|
searchIndex?: string;
|
|
10
18
|
component?: Component;
|
|
@@ -15,7 +23,7 @@ export type LTableColumn = QTableColumn & {
|
|
|
15
23
|
* @deprecated use gql instead
|
|
16
24
|
*/
|
|
17
25
|
gqlField?: string | Array<string> | Object;
|
|
18
|
-
searchMethod?: "equals" | "contains";
|
|
26
|
+
searchMethod?: "equals" | "contains" | "range";
|
|
19
27
|
autoWidth?: boolean;
|
|
20
28
|
};
|
|
21
29
|
export type LTableProps = QTableProps & {
|
|
@@ -71,17 +79,17 @@ export interface LTableRequest {
|
|
|
71
79
|
}) => void;
|
|
72
80
|
}
|
|
73
81
|
declare function requestServerInteraction(): void;
|
|
74
|
-
declare var
|
|
82
|
+
declare var __VLS_135: any, __VLS_138: string, __VLS_139: any, __VLS_170: any, __VLS_173: any, __VLS_343: string, __VLS_344: any;
|
|
75
83
|
type __VLS_Slots = {} & {
|
|
76
|
-
[K in NonNullable<typeof
|
|
84
|
+
[K in NonNullable<typeof __VLS_138>]?: (props: typeof __VLS_139) => any;
|
|
77
85
|
} & {
|
|
78
|
-
[K in NonNullable<typeof
|
|
86
|
+
[K in NonNullable<typeof __VLS_343>]?: (props: typeof __VLS_344) => any;
|
|
79
87
|
} & {
|
|
80
|
-
actions?: (props: typeof
|
|
88
|
+
actions?: (props: typeof __VLS_135) => any;
|
|
81
89
|
} & {
|
|
82
|
-
'row-expand'?: (props: typeof
|
|
90
|
+
'row-expand'?: (props: typeof __VLS_170) => any;
|
|
83
91
|
} & {
|
|
84
|
-
'top-right'?: (props: typeof
|
|
92
|
+
'top-right'?: (props: typeof __VLS_173) => any;
|
|
85
93
|
};
|
|
86
94
|
declare const __VLS_base: import("vue").DefineComponent<LTableProps, {
|
|
87
95
|
requestServerInteraction: typeof requestServerInteraction;
|
|
@@ -226,7 +226,6 @@ declare const light: {
|
|
|
226
226
|
label: {
|
|
227
227
|
create: string;
|
|
228
228
|
set: string;
|
|
229
|
-
clear: string;
|
|
230
229
|
filter: string;
|
|
231
230
|
remove: string;
|
|
232
231
|
cancel: string;
|
|
@@ -234,6 +233,7 @@ declare const light: {
|
|
|
234
233
|
reset: string;
|
|
235
234
|
select: string;
|
|
236
235
|
search: string;
|
|
236
|
+
clear: string;
|
|
237
237
|
ok: string;
|
|
238
238
|
update: string;
|
|
239
239
|
refresh: string;
|
|
@@ -360,11 +360,11 @@ declare const light: {
|
|
|
360
360
|
today: string;
|
|
361
361
|
};
|
|
362
362
|
editor: {
|
|
363
|
-
size: string;
|
|
364
363
|
bold: string;
|
|
365
364
|
left: string;
|
|
366
365
|
right: string;
|
|
367
366
|
center: string;
|
|
367
|
+
size: string;
|
|
368
368
|
align: string;
|
|
369
369
|
italic: string;
|
|
370
370
|
strikethrough: string;
|
|
@@ -448,8 +448,8 @@ declare const light: {
|
|
|
448
448
|
icon: string;
|
|
449
449
|
};
|
|
450
450
|
uploader: {
|
|
451
|
-
clear: string;
|
|
452
451
|
done: string;
|
|
452
|
+
clear: string;
|
|
453
453
|
add: string;
|
|
454
454
|
upload: string;
|
|
455
455
|
removeQueue: string;
|
|
@@ -823,7 +823,6 @@ declare const _default: () => {
|
|
|
823
823
|
label: {
|
|
824
824
|
create: string;
|
|
825
825
|
set: string;
|
|
826
|
-
clear: string;
|
|
827
826
|
filter: string;
|
|
828
827
|
remove: string;
|
|
829
828
|
cancel: string;
|
|
@@ -831,6 +830,7 @@ declare const _default: () => {
|
|
|
831
830
|
reset: string;
|
|
832
831
|
select: string;
|
|
833
832
|
search: string;
|
|
833
|
+
clear: string;
|
|
834
834
|
ok: string;
|
|
835
835
|
update: string;
|
|
836
836
|
refresh: string;
|
|
@@ -957,11 +957,11 @@ declare const _default: () => {
|
|
|
957
957
|
today: string;
|
|
958
958
|
};
|
|
959
959
|
editor: {
|
|
960
|
-
size: string;
|
|
961
960
|
bold: string;
|
|
962
961
|
left: string;
|
|
963
962
|
right: string;
|
|
964
963
|
center: string;
|
|
964
|
+
size: string;
|
|
965
965
|
align: string;
|
|
966
966
|
italic: string;
|
|
967
967
|
strikethrough: string;
|
|
@@ -1045,8 +1045,8 @@ declare const _default: () => {
|
|
|
1045
1045
|
icon: string;
|
|
1046
1046
|
};
|
|
1047
1047
|
uploader: {
|
|
1048
|
-
clear: string;
|
|
1049
1048
|
done: string;
|
|
1049
|
+
clear: string;
|
|
1050
1050
|
add: string;
|
|
1051
1051
|
upload: string;
|
|
1052
1052
|
removeQueue: string;
|
|
@@ -40,7 +40,12 @@ const light = reactive({
|
|
|
40
40
|
dense: true,
|
|
41
41
|
flat: true,
|
|
42
42
|
bordered: true,
|
|
43
|
-
separator: "cell"
|
|
43
|
+
separator: "cell",
|
|
44
|
+
actionIcons: {
|
|
45
|
+
view: "sym_o_search",
|
|
46
|
+
edit: "sym_o_edit",
|
|
47
|
+
delete: "sym_o_delete"
|
|
48
|
+
}
|
|
44
49
|
},
|
|
45
50
|
card: {
|
|
46
51
|
flat: true,
|
|
@@ -220,6 +225,10 @@ const light = reactive({
|
|
|
220
225
|
light.styles.button = { ...light.styles.button, ...styles.button || {} };
|
|
221
226
|
light.styles.table = { ...light.styles.table, ...styles.table || {} };
|
|
222
227
|
light.styles.table.color = light.color;
|
|
228
|
+
light.styles.table.actionIcons = {
|
|
229
|
+
...light.styles.table.actionIcons,
|
|
230
|
+
...styles.table?.actionIcons || {}
|
|
231
|
+
};
|
|
223
232
|
watch(() => light.theme, async () => {
|
|
224
233
|
await light.setStyle("theme", light.theme);
|
|
225
234
|
});
|
|
@@ -60,27 +60,37 @@ const rows = computed(() => {
|
|
|
60
60
|
const onUpdate = async (value, role, permission) => {
|
|
61
61
|
const updateKey = `${role}-${permission}`;
|
|
62
62
|
updating.value.add(updateKey);
|
|
63
|
+
const roleObj = app.value?.roles.find((r) => r.name === role);
|
|
64
|
+
if (!roleObj) {
|
|
65
|
+
updating.value.delete(updateKey);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const originalPermissions = [...roleObj.permissions];
|
|
69
|
+
if (value) {
|
|
70
|
+
if (!roleObj.permissions.includes(permission)) {
|
|
71
|
+
roleObj.permissions = [...roleObj.permissions, permission];
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
if (roleObj.permissions.includes(permission)) {
|
|
75
|
+
roleObj.permissions = roleObj.permissions.filter((p) => p !== permission);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
63
78
|
try {
|
|
64
79
|
if (value) {
|
|
65
80
|
await m("addPermission", { value: permission, role });
|
|
66
|
-
$q.notify({
|
|
67
|
-
type: "positive",
|
|
68
|
-
message: t("Permission granted successfully")
|
|
69
|
-
});
|
|
70
81
|
} else {
|
|
71
82
|
await m("removePermission", { value: permission, role });
|
|
72
|
-
$q.notify({
|
|
73
|
-
type: "positive",
|
|
74
|
-
message: t("Permission removed successfully")
|
|
75
|
-
});
|
|
76
83
|
}
|
|
77
|
-
|
|
84
|
+
$q.notify({
|
|
85
|
+
type: "positive",
|
|
86
|
+
message: t(value ? "Permission granted successfully" : "Permission removed successfully")
|
|
87
|
+
});
|
|
78
88
|
} catch (error) {
|
|
89
|
+
roleObj.permissions = originalPermissions;
|
|
79
90
|
$q.notify({
|
|
80
91
|
type: "negative",
|
|
81
92
|
message: t("Failed to update permission")
|
|
82
93
|
});
|
|
83
|
-
app.value = await fetchApp();
|
|
84
94
|
} finally {
|
|
85
95
|
updating.value.delete(updateKey);
|
|
86
96
|
}
|
|
@@ -94,8 +104,9 @@ const toggleAllForRole = async (role, grant) => {
|
|
|
94
104
|
}
|
|
95
105
|
}
|
|
96
106
|
if (updates.length === 0) return;
|
|
107
|
+
const originalPermissions = [...role.permissions];
|
|
108
|
+
role.permissions = grant ? [...app.value.permissions] : [];
|
|
97
109
|
try {
|
|
98
|
-
loading.value = true;
|
|
99
110
|
for (const update of updates) {
|
|
100
111
|
if (update.grant) {
|
|
101
112
|
await m("addPermission", { value: update.permission, role: update.role });
|
|
@@ -103,18 +114,16 @@ const toggleAllForRole = async (role, grant) => {
|
|
|
103
114
|
await m("removePermission", { value: update.permission, role: update.role });
|
|
104
115
|
}
|
|
105
116
|
}
|
|
106
|
-
app.value = await fetchApp();
|
|
107
117
|
$q.notify({
|
|
108
118
|
type: "positive",
|
|
109
119
|
message: t(grant ? "All permissions granted" : "All permissions removed")
|
|
110
120
|
});
|
|
111
121
|
} catch (error) {
|
|
122
|
+
role.permissions = originalPermissions;
|
|
112
123
|
$q.notify({
|
|
113
124
|
type: "negative",
|
|
114
125
|
message: t("Failed to update permissions")
|
|
115
126
|
});
|
|
116
|
-
} finally {
|
|
117
|
-
loading.value = false;
|
|
118
127
|
}
|
|
119
128
|
};
|
|
120
129
|
const filter = ref("");
|
package/dist/runtime/plugin.js
CHANGED
|
@@ -3,7 +3,7 @@ import "@quasar/quasar-ui-qmarkdown/dist/index.css";
|
|
|
3
3
|
import { createClient, setApiClient, defineModel } from "@hostlink/light";
|
|
4
4
|
import { createI18n } from "vue-i18n";
|
|
5
5
|
import createLight from "./composables/createLight.js";
|
|
6
|
-
import { defineNuxtPlugin, useRoute } from "#app";
|
|
6
|
+
import { defineNuxtPlugin, useRoute, useRuntimeConfig } from "#app";
|
|
7
7
|
import "./assets/main.css";
|
|
8
8
|
import message_en from "./locales/en.json";
|
|
9
9
|
import message_zh from "./locales/zh-hk.json";
|
|
@@ -22,14 +22,14 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|
|
22
22
|
defineModel("Config", {}).setDataPath("app.listConfig");
|
|
23
23
|
nuxtApp.vueApp.config.errorHandler = (err, instance, info) => {
|
|
24
24
|
const $route = useRoute();
|
|
25
|
-
const
|
|
26
|
-
if (
|
|
25
|
+
const light2 = useLight();
|
|
26
|
+
if (light2.devMode) {
|
|
27
27
|
console.log(err);
|
|
28
28
|
}
|
|
29
29
|
if (err instanceof Error) {
|
|
30
|
-
|
|
30
|
+
light2.addError(err.message + " at " + $route.fullPath);
|
|
31
31
|
} else {
|
|
32
|
-
|
|
32
|
+
light2.addError(JSON.stringify(err) + " at " + $route.fullPath);
|
|
33
33
|
}
|
|
34
34
|
};
|
|
35
35
|
nuxtApp.vueApp.use(QMarkdownVuePlugin);
|
|
@@ -44,6 +44,14 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|
|
44
44
|
fallbackWarn: false,
|
|
45
45
|
missingWarn: false
|
|
46
46
|
});
|
|
47
|
+
const light = useLight();
|
|
48
|
+
const runtimeLight = useRuntimeConfig().public.light;
|
|
49
|
+
if (runtimeLight?.tableActionIcons) {
|
|
50
|
+
const t = runtimeLight.tableActionIcons;
|
|
51
|
+
if (t.view) light.styles.table.actionIcons.view = t.view;
|
|
52
|
+
if (t.edit) light.styles.table.actionIcons.edit = t.edit;
|
|
53
|
+
if (t.delete) light.styles.table.actionIcons.delete = t.delete;
|
|
54
|
+
}
|
|
47
55
|
nuxtApp.vueApp.use(createLight({
|
|
48
56
|
i18n
|
|
49
57
|
}));
|