@hostlink/nuxt-light 1.73.2 → 1.74.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.
Files changed (50) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/runtime/components/L/App.vue +0 -19
  3. package/dist/runtime/components/L/AppMain.d.vue.ts +3 -3
  4. package/dist/runtime/components/L/AppMain.vue +43 -10
  5. package/dist/runtime/components/L/AppMain.vue.d.ts +3 -3
  6. package/dist/runtime/components/L/FacebookButton.d.vue.ts +19 -3
  7. package/dist/runtime/components/L/FacebookButton.vue +73 -12
  8. package/dist/runtime/components/L/FacebookButton.vue.d.ts +19 -3
  9. package/dist/runtime/components/L/FavMenu.d.vue.ts +2 -0
  10. package/dist/runtime/components/L/FavMenu.vue +10 -2
  11. package/dist/runtime/components/L/FavMenu.vue.d.ts +2 -0
  12. package/dist/runtime/components/L/Form.d.vue.ts +29 -56
  13. package/dist/runtime/components/L/Form.vue +70 -80
  14. package/dist/runtime/components/L/Form.vue.d.ts +29 -56
  15. package/dist/runtime/components/L/FormLayout.d.vue.ts +36 -0
  16. package/dist/runtime/components/L/FormLayout.vue +36 -0
  17. package/dist/runtime/components/L/FormLayout.vue.d.ts +36 -0
  18. package/dist/runtime/components/L/Login.vue +1 -1
  19. package/dist/runtime/components/L/Menu.d.vue.ts +2 -0
  20. package/dist/runtime/components/L/Menu.vue +4 -4
  21. package/dist/runtime/components/L/Menu.vue.d.ts +2 -0
  22. package/dist/runtime/composables/useLight.d.ts +0 -4
  23. package/dist/runtime/formkit/Form.d.vue.ts +2 -2
  24. package/dist/runtime/formkit/Form.vue +15 -18
  25. package/dist/runtime/formkit/Form.vue.d.ts +2 -2
  26. package/dist/runtime/formkit/index.js +2 -0
  27. package/dist/runtime/locales/en.json +8 -2
  28. package/dist/runtime/locales/zh-hk.json +8 -2
  29. package/dist/runtime/pages/Role/[name]/update-child.vue +4 -1
  30. package/dist/runtime/pages/System/fs.vue +116 -15
  31. package/dist/runtime/pages/User/setting/index.vue +29 -12
  32. package/dist/runtime/pages/User/setting/information.vue +4 -28
  33. package/dist/runtime/pages/User/setting/open_id.vue +132 -91
  34. package/dist/runtime/pages/User/setting/two-factor-auth.vue +388 -143
  35. package/dist/runtime/pages/User/setting.vue +3 -4
  36. package/dist/runtime/types/form.d.ts +2 -0
  37. package/dist/runtime/types/form.js +0 -0
  38. package/dist/runtime/utils/filterMenuItems.d.ts +10 -0
  39. package/dist/runtime/utils/filterMenuItems.js +34 -0
  40. package/dist/runtime/utils/formLayout.d.ts +2 -0
  41. package/dist/runtime/utils/formLayout.js +7 -0
  42. package/dist/runtime/utils/socialSdk.d.ts +2 -0
  43. package/dist/runtime/utils/socialSdk.js +127 -0
  44. package/package.json +14 -14
  45. package/dist/runtime/pages/Role/add2.d.vue.ts +0 -3
  46. package/dist/runtime/pages/Role/add2.vue +0 -57
  47. package/dist/runtime/pages/Role/add2.vue.d.ts +0 -3
  48. package/dist/runtime/pages/System/test.d.vue.ts +0 -3
  49. package/dist/runtime/pages/System/test.vue +0 -13
  50. package/dist/runtime/pages/System/test.vue.d.ts +0 -3
@@ -1,70 +1,43 @@
1
- declare var __VLS_23: {};
1
+ import type { LFormGutter, LFormLayout } from "../../types/form.js";
2
+ type __VLS_Props = {
3
+ actions?: boolean;
4
+ bordered?: boolean;
5
+ gutter?: LFormGutter;
6
+ layout?: LFormLayout;
7
+ modelValue?: Record<string, unknown>;
8
+ noRedirect?: boolean;
9
+ submitIcon?: string;
10
+ submitLabel?: string;
11
+ };
12
+ declare var __VLS_17: {}, __VLS_20: {
13
+ loading: boolean;
14
+ }, __VLS_22: {
15
+ loading: boolean;
16
+ };
2
17
  type __VLS_Slots = {} & {
3
- default?: (props: typeof __VLS_23) => any;
18
+ default?: (props: typeof __VLS_17) => any;
19
+ } & {
20
+ actions?: (props: typeof __VLS_20) => any;
21
+ } & {
22
+ buttons?: (props: typeof __VLS_22) => any;
4
23
  };
5
- declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
6
- modelValue: {
7
- type: ObjectConstructor;
8
- };
9
- bordered: {
10
- type: BooleanConstructor;
11
- default: boolean;
12
- };
13
- gutter: {
14
- type: StringConstructor;
15
- default: string;
16
- };
17
- submitLabel: {
18
- type: StringConstructor;
19
- default: string;
20
- };
21
- submitIcon: {
22
- type: StringConstructor;
23
- default: string;
24
- };
25
- noRedirect: {
26
- type: BooleanConstructor;
27
- default: boolean;
28
- };
29
- }>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
24
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
30
25
  submit: (...args: any[]) => void;
31
26
  save: (...args: any[]) => void;
32
27
  submitted: (...args: any[]) => void;
33
- }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
34
- modelValue: {
35
- type: ObjectConstructor;
36
- };
37
- bordered: {
38
- type: BooleanConstructor;
39
- default: boolean;
40
- };
41
- gutter: {
42
- type: StringConstructor;
43
- default: string;
44
- };
45
- submitLabel: {
46
- type: StringConstructor;
47
- default: string;
48
- };
49
- submitIcon: {
50
- type: StringConstructor;
51
- default: string;
52
- };
53
- noRedirect: {
54
- type: BooleanConstructor;
55
- default: boolean;
56
- };
57
- }>> & Readonly<{
28
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
58
29
  onSubmit?: ((...args: any[]) => any) | undefined;
59
30
  onSave?: ((...args: any[]) => any) | undefined;
60
31
  onSubmitted?: ((...args: any[]) => any) | undefined;
61
32
  }>, {
33
+ actions: boolean;
62
34
  bordered: boolean;
63
- gutter: string;
64
- submitLabel: string;
65
- submitIcon: string;
35
+ gutter: LFormGutter;
36
+ layout: LFormLayout;
66
37
  noRedirect: boolean;
67
- }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
38
+ submitIcon: string;
39
+ submitLabel: string;
40
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
68
41
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
69
42
  declare const _default: typeof __VLS_export;
70
43
  export default _default;
@@ -0,0 +1,36 @@
1
+ import type { LFormGutter, LFormLayout } from "../../types/form.js";
2
+ type __VLS_Props = {
3
+ actions?: boolean;
4
+ bordered?: boolean;
5
+ contentClass?: string | string[] | Record<string, boolean>;
6
+ gutter?: LFormGutter;
7
+ layout?: LFormLayout;
8
+ submitDisable?: boolean;
9
+ submitIcon?: string;
10
+ submitLabel?: string;
11
+ submitLoading?: boolean;
12
+ };
13
+ declare var __VLS_14: {}, __VLS_22: {};
14
+ type __VLS_Slots = {} & {
15
+ default?: (props: typeof __VLS_14) => any;
16
+ } & {
17
+ actions?: (props: typeof __VLS_22) => any;
18
+ };
19
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
20
+ actions: boolean;
21
+ bordered: boolean;
22
+ gutter: LFormGutter;
23
+ layout: LFormLayout;
24
+ submitIcon: string;
25
+ submitLabel: string;
26
+ submitDisable: boolean;
27
+ submitLoading: boolean;
28
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
29
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
30
+ declare const _default: typeof __VLS_export;
31
+ export default _default;
32
+ type __VLS_WithSlots<T, S> = T & {
33
+ new (): {
34
+ $slots: S;
35
+ };
36
+ };
@@ -0,0 +1,36 @@
1
+ <script setup>
2
+ import { computed } from "vue";
3
+ import { getFormLayoutClasses } from "../../utils/formLayout";
4
+ const props = defineProps({
5
+ actions: { type: Boolean, required: false, default: true },
6
+ bordered: { type: Boolean, required: false, default: true },
7
+ contentClass: { type: [String, Array, Object], required: false },
8
+ gutter: { type: String, required: false, default: "md" },
9
+ layout: { type: String, required: false, default: "grid" },
10
+ submitDisable: { type: Boolean, required: false, default: false },
11
+ submitIcon: { type: String, required: false, default: "sym_o_save" },
12
+ submitLabel: { type: String, required: false, default: "Save" },
13
+ submitLoading: { type: Boolean, required: false, default: false }
14
+ });
15
+ const layoutClass = computed(() => getFormLayoutClasses(props.layout, props.gutter));
16
+ </script>
17
+
18
+ <template>
19
+ <l-card :bordered="bordered">
20
+ <q-card-section :class="[layoutClass, contentClass]">
21
+ <slot />
22
+ </q-card-section>
23
+
24
+ <q-card-actions v-if="actions" align="right">
25
+ <slot name="actions">
26
+ <l-btn
27
+ type="submit"
28
+ :icon="submitIcon"
29
+ :label="submitLabel"
30
+ :loading="submitLoading"
31
+ :disable="submitDisable"
32
+ />
33
+ </slot>
34
+ </q-card-actions>
35
+ </l-card>
36
+ </template>
@@ -0,0 +1,36 @@
1
+ import type { LFormGutter, LFormLayout } from "../../types/form.js";
2
+ type __VLS_Props = {
3
+ actions?: boolean;
4
+ bordered?: boolean;
5
+ contentClass?: string | string[] | Record<string, boolean>;
6
+ gutter?: LFormGutter;
7
+ layout?: LFormLayout;
8
+ submitDisable?: boolean;
9
+ submitIcon?: string;
10
+ submitLabel?: string;
11
+ submitLoading?: boolean;
12
+ };
13
+ declare var __VLS_14: {}, __VLS_22: {};
14
+ type __VLS_Slots = {} & {
15
+ default?: (props: typeof __VLS_14) => any;
16
+ } & {
17
+ actions?: (props: typeof __VLS_22) => any;
18
+ };
19
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
20
+ actions: boolean;
21
+ bordered: boolean;
22
+ gutter: LFormGutter;
23
+ layout: LFormLayout;
24
+ submitIcon: string;
25
+ submitLabel: string;
26
+ submitDisable: boolean;
27
+ submitLoading: boolean;
28
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
29
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
30
+ declare const _default: typeof __VLS_export;
31
+ export default _default;
32
+ type __VLS_WithSlots<T, S> = T & {
33
+ new (): {
34
+ $slots: S;
35
+ };
36
+ };
@@ -305,7 +305,7 @@ const facebookLogin = (accessToken) => {
305
305
  </q-card-actions>
306
306
 
307
307
  <q-card-actions v-if="facebookAppId">
308
- <l-facebook-button @login="facebookLogin" />
308
+ <l-facebook-button :app-id="facebookAppId" @login="facebookLogin" />
309
309
  </q-card-actions>
310
310
  </q-card>
311
311
  </template>
@@ -3,7 +3,9 @@ export default _default;
3
3
  declare const __VLS_export: import("vue").DefineComponent<{
4
4
  value?: any;
5
5
  dense?: any;
6
+ expandAll?: any;
6
7
  }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{
7
8
  value?: any;
8
9
  dense?: any;
10
+ expandAll?: any;
9
11
  }> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -2,7 +2,7 @@
2
2
  import { useRoute } from "vue-router";
3
3
  import { ref, computed } from "vue";
4
4
  import { useLight } from "#imports";
5
- const props = defineProps(["value", "dense"]);
5
+ const props = defineProps(["value", "dense", "expandAll"]);
6
6
  const light = useLight();
7
7
  const isShowExpansionItem = (menu) => {
8
8
  if (menu.children && menu.children.length > 0) {
@@ -47,9 +47,9 @@ const hasChildLink = () => {
47
47
  <q-list class="menu-list" :dense="dense">
48
48
  <template v-for="menu in value">
49
49
 
50
- <q-expansion-item :default-opened="hasLink(menu)" :label="$t(menu.label)" :icon="menu.icon" :dense="dense"
51
- v-if="isShowExpansionItem(menu)" :group="group">
52
- <l-menu class="q-pl-md" :value="menu.children" :dense="dense"></l-menu>
50
+ <q-expansion-item :default-opened="expandAll || hasLink(menu)" :label="$t(menu.label)" :icon="menu.icon" :dense="dense"
51
+ v-if="isShowExpansionItem(menu)" :group="expandAll ? undefined : group">
52
+ <l-menu class="q-pl-md" :value="menu.children" :dense="dense" :expand-all="expandAll"></l-menu>
53
53
  </q-expansion-item>
54
54
 
55
55
  <template v-else>
@@ -3,7 +3,9 @@ export default _default;
3
3
  declare const __VLS_export: import("vue").DefineComponent<{
4
4
  value?: any;
5
5
  dense?: any;
6
+ expandAll?: any;
6
7
  }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{
7
8
  value?: any;
8
9
  dense?: any;
10
+ expandAll?: any;
9
11
  }> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -135,8 +135,6 @@ declare const light: {
135
135
  ipod: boolean;
136
136
  kindle: boolean;
137
137
  winphone: boolean;
138
- blackberry: boolean;
139
- playbook: boolean;
140
138
  silk: boolean;
141
139
  };
142
140
  has: {
@@ -732,8 +730,6 @@ declare const _default: () => {
732
730
  ipod: boolean;
733
731
  kindle: boolean;
734
732
  winphone: boolean;
735
- blackberry: boolean;
736
- playbook: boolean;
737
733
  silk: boolean;
738
734
  };
739
735
  has: {
@@ -1,8 +1,8 @@
1
- declare var __VLS_14: {
1
+ declare var __VLS_7: {
2
2
  [x: string]: any;
3
3
  };
4
4
  type __VLS_Slots = {} & {
5
- default?: (props: typeof __VLS_14) => any;
5
+ default?: (props: typeof __VLS_7) => any;
6
6
  };
7
7
  declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
8
8
  context: {
@@ -14,7 +14,6 @@ let props = defineProps({
14
14
  let onSubmit = async () => {
15
15
  props.context?.handlers.submit(new Event("submit"));
16
16
  };
17
- const gutter = props.context?.gutter ?? "md";
18
17
  let bordered = true;
19
18
  if (props.context.bordered !== void 0) {
20
19
  bordered = props.context.bordered;
@@ -89,24 +88,22 @@ if (!props.context.onSubmit) {
89
88
  const isNoDirtyCheck = computed(() => {
90
89
  return props.context.attrs["no-dirty-check"] !== void 0;
91
90
  });
92
- const localClass = computed(() => {
93
- if (props.context.attrs.class) {
94
- return props.context.attrs.class;
95
- }
96
- return "row q-col-gutter-md";
97
- });
98
91
  </script>
99
92
 
100
93
  <template>
101
- <l-card :bordered="bordered">
102
- <form @submit.prevent="onSubmit">
103
- <q-card-section :class="localClass">
104
- <slot v-bind="context"></slot>
105
- </q-card-section>
106
- <q-card-actions align="right" v-if="context.actions">
107
- <l-btn type="submit" icon="sym_o_check" :label="context.submitLabel ?? 'Submit'"
108
- :disabled="!isNoDirtyCheck && !context.state.dirty" :loading="context.state.loading"></l-btn>
109
- </q-card-actions>
110
- </form>
111
- </l-card>
94
+ <form @submit.prevent="onSubmit">
95
+ <l-form-layout
96
+ :actions="context.actions"
97
+ :bordered="bordered"
98
+ :content-class="context.attrs.class"
99
+ :gutter="context.gutter ?? 'md'"
100
+ :layout="context.layout ?? 'grid'"
101
+ :submit-disable="!isNoDirtyCheck && !context.state.dirty"
102
+ :submit-icon="context.submitIcon ?? 'sym_o_check'"
103
+ :submit-label="context.submitLabel ?? 'Submit'"
104
+ :submit-loading="context.state.loading"
105
+ >
106
+ <slot v-bind="context" />
107
+ </l-form-layout>
108
+ </form>
112
109
  </template>
@@ -1,8 +1,8 @@
1
- declare var __VLS_14: {
1
+ declare var __VLS_7: {
2
2
  [x: string]: any;
3
3
  };
4
4
  type __VLS_Slots = {} & {
5
- default?: (props: typeof __VLS_14) => any;
5
+ default?: (props: typeof __VLS_7) => any;
6
6
  };
7
7
  declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
8
8
  context: {
@@ -110,9 +110,11 @@ export const createLightPlugin = () => {
110
110
  props: [
111
111
  "actions",
112
112
  "submitLabel",
113
+ "submitIcon",
113
114
  "submit",
114
115
  "onSubmit",
115
116
  "gutter",
117
+ "layout",
116
118
  "bordered",
117
119
  "modelName",
118
120
  "modelId"
@@ -6,5 +6,11 @@
6
6
  "contains_symbol": "Must contain at least one special character",
7
7
  "storage_usage": "{0} free of {1}",
8
8
  "input_required": "Please input {0}",
9
- "input_min": "Please input at least {0} characters"
10
- }
9
+ "input_min": "Please input at least {0} characters",
10
+ "Filesystem decorators": "Filesystem decorators",
11
+ "Decorators are applied in order to every file operation.": "Decorators are applied in order to every file operation.",
12
+ "Add decorator": "Add decorator",
13
+ "Decorator": "Decorator",
14
+ "Search menu": "Search menu",
15
+ "No matching menu": "No matching menu"
16
+ }
@@ -126,6 +126,8 @@
126
126
  "File": "檔案",
127
127
  "Folder": "資料夾",
128
128
  "Search": "搜尋",
129
+ "Search menu": "搜尋選單",
130
+ "No matching menu": "找不到符合的選單",
129
131
  "Reset": "重設",
130
132
  "Reload": "重新載入",
131
133
  "Rename": "重新命名",
@@ -210,5 +212,9 @@
210
212
  "Are you sure you want to reset 2FA?" : "您確定要重置雙重認證嗎?",
211
213
  "Update role": "更新角色",
212
214
  "Overview": "概覽",
213
- "Click the button below to link your Google account.": "點擊下面的按鈕連接您的Google帳戶。"
214
- }
215
+ "Click the button below to link your Google account.": "點擊下面的按鈕連接您的Google帳戶。",
216
+ "Filesystem decorators": "檔案系統路徑處理器",
217
+ "Decorators are applied in order to every file operation.": "路徑處理器會按顯示次序套用到每個檔案操作。",
218
+ "Add decorator": "新增路徑處理器",
219
+ "Decorator": "路徑處理器"
220
+ }
@@ -1,6 +1,9 @@
1
1
  <script setup>
2
2
  import { useRoute } from "vue-router";
3
- import { q } from "#imports";
3
+ import { definePageMeta, q } from "#imports";
4
+ definePageMeta({
5
+ permission: "role.update-child"
6
+ });
4
7
  const route = useRoute();
5
8
  const name = route.params.name;
6
9
  const role = await q("getRole", {
@@ -6,17 +6,34 @@ const $q = useQuasar();
6
6
  const { data: app, refresh } = await useAsyncData(async () => {
7
7
  return await q({
8
8
  app: {
9
+ listFileSystem: true,
9
10
  fs: {
10
- list: true,
11
- types: true
11
+ types: true,
12
+ decoratorTypes: true
12
13
  },
13
14
  driveTypes: true
14
15
  }
15
16
  }).then((res) => res.app);
16
17
  });
17
- const items = computed(() => app.value.fs.list);
18
+ const items = computed(() => app.value?.listFileSystem ?? []);
18
19
  const dialog = ref(false);
19
20
  const value = ref({});
21
+ const clone = (data) => JSON.parse(JSON.stringify(data));
22
+ const openAdd = () => {
23
+ value.value = {
24
+ data: {},
25
+ decorators: []
26
+ };
27
+ dialog.value = true;
28
+ };
29
+ const openEdit = (row) => {
30
+ value.value = clone({
31
+ ...row,
32
+ data: row.data ?? {},
33
+ decorators: row.decorators ?? []
34
+ });
35
+ dialog.value = true;
36
+ };
20
37
  const onSubmit = async (data) => {
21
38
  loading.value = true;
22
39
  try {
@@ -39,19 +56,19 @@ const onSubmit = async (data) => {
39
56
  }
40
57
  loading.value = false;
41
58
  };
42
- const onRemove = async (selected2) => {
59
+ const onRemove = async (rows) => {
43
60
  $q.dialog({
44
61
  title: "Confirm",
45
62
  message: "Are you sure you want to delete this file system?",
46
63
  ok: "Yes",
47
64
  cancel: "No"
48
65
  }).onOk(async () => {
49
- for (let row of selected2) {
66
+ for (let row of rows) {
50
67
  await m("lightFSdelete", {
51
68
  uuid: row.uuid
52
69
  });
53
70
  }
54
- selected2.value = [];
71
+ selected.value = [];
55
72
  refresh();
56
73
  });
57
74
  };
@@ -88,6 +105,11 @@ const columns = [
88
105
  name: "data",
89
106
  label: "Data",
90
107
  align: "left"
108
+ },
109
+ {
110
+ name: "decorators",
111
+ label: "Decorators",
112
+ align: "left"
91
113
  }
92
114
  ];
93
115
  const selected = ref([]);
@@ -96,12 +118,28 @@ const getType = (type) => {
96
118
  if (!type) return null;
97
119
  return app.value.fs.types.find((t) => t.name == type);
98
120
  };
121
+ const getDecoratorType = (type) => {
122
+ if (!type) return null;
123
+ return app.value.fs.decoratorTypes.find((t) => t.name == type);
124
+ };
125
+ const isSecret = (key) => [
126
+ "secret_key",
127
+ "secretKey",
128
+ "password",
129
+ "token",
130
+ "access_key_secret"
131
+ ].includes(key);
132
+ const displayValue = (key, optionValue) => {
133
+ if (isSecret(key) && optionValue) return "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
134
+ if (typeof optionValue === "boolean") return optionValue ? "Yes" : "No";
135
+ return optionValue;
136
+ };
99
137
  </script>
100
138
 
101
139
  <template>
102
140
  <l-page title="File system">
103
141
  <q-dialog v-model="dialog" persistent>
104
- <q-card style="width: 500px;">
142
+ <q-card style="width: 720px; max-width: 90vw;">
105
143
 
106
144
  <q-toolbar>
107
145
  <q-toolbar-title v-if="value.uuid">{{ $t('Edit File System') }}</q-toolbar-title>
@@ -116,15 +154,60 @@ const getType = (type) => {
116
154
  option-value="name"></form-kit>
117
155
 
118
156
  <form-kit type="group" name="data" v-if="value.type">
119
- <template v-for="(option, name) in getType(value.type).options">
120
- <form-kit type="l-input" :name="name" :label="name"
157
+ <template v-for="(option, name) in getType(value.type)?.options" :key="name">
158
+ <form-kit v-if="option.type === 'select'" type="l-select" :name="name" :label="name"
159
+ :options="option.options" :validation="option.required ? 'required' : ''"
160
+ :help="option.description"></form-kit>
161
+
162
+ <form-kit v-else-if="option.type === 'boolean'" type="l-toggle" :name="name" :label="name"
163
+ :help="option.description"></form-kit>
164
+
165
+ <form-kit v-else type="l-input" :name="name" :label="name"
121
166
  :validation="option.required ? 'required' : ''" :help="option.description"
122
- :placeholder="option.placeholder"></form-kit>
167
+ :placeholder="option.placeholder" :input-type="option.type === 'password' ? 'password' : 'text'"
168
+ :number="option.type === 'int' ? 'integer' : undefined"></form-kit>
123
169
 
124
170
  </template>
125
171
 
126
172
  </form-kit>
127
173
 
174
+ <div class="col-12">
175
+ <q-separator class="q-mb-md"></q-separator>
176
+ <div class="text-subtitle2">{{ $t('Filesystem decorators') }}</div>
177
+ <div class="text-caption text-grey-7 q-mb-sm">
178
+ {{ $t('Decorators are applied in order to every file operation.') }}
179
+ </div>
180
+
181
+ <form-kit type="l-repeater" name="decorators" :sortable="true"
182
+ :add-label="$t('Add decorator')" #default="{ value: decorator }">
183
+ <div class="row q-col-gutter-sm">
184
+ <form-kit class="col-12" type="l-select" label="Decorator" name="type"
185
+ validation="required" :options="app.fs.decoratorTypes"
186
+ option-value="name"></form-kit>
187
+
188
+ <form-kit class="col-12" type="group" name="data" v-if="decorator.type">
189
+ <template
190
+ v-for="(option, name) in getDecoratorType(decorator.type)?.options"
191
+ :key="name">
192
+ <form-kit v-if="option.type === 'select'" type="l-select" :name="name"
193
+ :label="name" :options="option.options"
194
+ :validation="option.required ? 'required' : ''"
195
+ :help="option.description"></form-kit>
196
+
197
+ <form-kit v-else-if="option.type === 'boolean'" type="l-toggle" :name="name"
198
+ :label="name" :help="option.description"></form-kit>
199
+
200
+ <form-kit v-else type="l-input" :name="name" :label="name"
201
+ :validation="option.required ? 'required' : ''"
202
+ :help="option.description" :placeholder="option.placeholder"
203
+ :input-type="option.type === 'password' ? 'password' : 'text'"
204
+ :number="option.type === 'int' ? 'integer' : undefined"></form-kit>
205
+ </template>
206
+ </form-kit>
207
+ </div>
208
+ </form-kit>
209
+ </div>
210
+
128
211
  </form-kit>
129
212
 
130
213
  </q-card>
@@ -133,9 +216,7 @@ const getType = (type) => {
133
216
  <q-table :rows="items" :columns="columns" selection="multiple" flat bordered dense separator="cell"
134
217
  v-model:selected="selected" row-key="uuid" :loading="loading">
135
218
  <template #top-left>
136
- <q-btn icon="sym_o_add" @click="value = {
137
- data: {}
138
- }; dialog = true" flat round dense>
219
+ <q-btn icon="sym_o_add" @click="openAdd" flat round dense>
139
220
  <q-tooltip>Add File System</q-tooltip>
140
221
  </q-btn>
141
222
  </template>
@@ -152,16 +233,36 @@ const getType = (type) => {
152
233
  <q-item v-for="(value, key) in props.row.data" :key="key">
153
234
  <q-item-section>
154
235
  <q-item-label caption>{{ key }}</q-item-label>
155
- <q-item-label>{{ value }}</q-item-label>
236
+ <q-item-label>{{ displayValue(key, value) }}</q-item-label>
237
+ </q-item-section>
238
+ </q-item>
239
+ </q-list>
240
+ </q-td>
241
+ </template>
242
+
243
+ <template #body-cell-decorators="props">
244
+ <q-td>
245
+ <q-list v-if="props.row.decorators?.length" flat dense>
246
+ <q-item v-for="(decorator, index) in props.row.decorators"
247
+ :key="`${decorator.type}-${index}`">
248
+ <q-item-section>
249
+ <q-item-label>{{ getDecoratorType(decorator.type)?.label ?? decorator.type }}</q-item-label>
250
+ <q-item-label caption>
251
+ <span v-if="decorator.data?.prefix">
252
+ {{ decorator.data.prefix }} /
253
+ </span>
254
+ {{ decorator.data?.scope ?? 'fixed' }}
255
+ </q-item-label>
156
256
  </q-item-section>
157
257
  </q-item>
158
258
  </q-list>
259
+ <span v-else class="text-grey-6">—</span>
159
260
  </q-td>
160
261
  </template>
161
262
 
162
263
  <template #body-cell-action="props">
163
264
  <q-td auto-width>
164
- <q-btn icon="sym_o_edit" @click="value = props.row; dialog = true" flat round dense>
265
+ <q-btn icon="sym_o_edit" @click="openEdit(props.row)" flat round dense>
165
266
  <q-tooltip>Edit</q-tooltip>
166
267
  </q-btn>
167
268
  </q-td>