@hostlink/nuxt-light 1.7.1 → 1.8.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.json +1 -1
- package/dist/runtime/components/L/Revision.vue +232 -0
- package/dist/runtime/components/L/Storage.vue +36 -0
- package/dist/runtime/components/l-app-main.vue +50 -61
- package/dist/runtime/components/l-app.vue +7 -1
- package/dist/runtime/components/l-login.vue +3 -1
- package/dist/runtime/pages/System/setting.vue +38 -29
- package/dist/runtime/pages/User/_user_id/view.vue +2 -3
- package/dist/runtime/pages/User/index.vue +1 -2
- package/dist/runtime/types/User.d.ts +5 -0
- package/dist/runtime/types/User.mjs +7 -0
- package/package.json +2 -1
package/dist/module.json
CHANGED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { Dialog, Notify } from "quasar"
|
|
3
|
+
import { computed, ref, reactive } from "vue";
|
|
4
|
+
import { q, m } from "#imports";
|
|
5
|
+
|
|
6
|
+
import * as Diff2Html from 'diff2html';
|
|
7
|
+
import 'diff2html/bundles/css/diff2html.min.css';
|
|
8
|
+
|
|
9
|
+
/* const diffs = '--- a/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n+++ b/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n@@ -1035,6 +1035,17 @@ func Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (\n \n // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n \n+func Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) {\n+\tr0, _, e1 := Syscall6(SYS_PSELECT6, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)))\n+\tn = int(r0)\n+\tif e1 != 0 {\n+\t\terr = errnoErr(e1)\n+\t}\n+\treturn\n+}\n+\n+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n+\n func read(fd int, p []byte) (n int, err error) {\n \tvar _p0 unsafe.Pointer\n \tif len(p) > 0 {\n';
|
|
10
|
+
const html = Diff2Html.html(diffs, {
|
|
11
|
+
drawFileList: true,
|
|
12
|
+
matching: 'lines',
|
|
13
|
+
outputFormat: 'side-by-side',
|
|
14
|
+
});
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const props = defineProps({
|
|
18
|
+
modelId: {
|
|
19
|
+
type: String,
|
|
20
|
+
required: true
|
|
21
|
+
},
|
|
22
|
+
modelClass: {
|
|
23
|
+
type: String,
|
|
24
|
+
required: true
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
const { revisionsByModel } = await q({
|
|
30
|
+
"revisionsByModel": {
|
|
31
|
+
__args: {
|
|
32
|
+
model_id: parseInt(props.modelId),
|
|
33
|
+
model_class: props.modelClass
|
|
34
|
+
},
|
|
35
|
+
revision_id: true,
|
|
36
|
+
revisionBy: true,
|
|
37
|
+
createdTime: true,
|
|
38
|
+
content: true,
|
|
39
|
+
delta: true,
|
|
40
|
+
diff: true
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
const num_of_revisions = computed(() => {
|
|
46
|
+
return revisionsByModel.length;
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
const showDialog = ref(false);
|
|
50
|
+
|
|
51
|
+
const selectedRevision = ref(null);
|
|
52
|
+
const onClick = (revision) => {
|
|
53
|
+
selectedRevision.value = revision;
|
|
54
|
+
|
|
55
|
+
showDialog.value = true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const onRestore = () => {
|
|
59
|
+
//confirm restore
|
|
60
|
+
Dialog.create({
|
|
61
|
+
title: 'Restore',
|
|
62
|
+
message: 'Are you sure you want to restore selected fields?',
|
|
63
|
+
ok: 'Yes',
|
|
64
|
+
cancel: 'No'
|
|
65
|
+
}).onOk(async () => {
|
|
66
|
+
//restore
|
|
67
|
+
if (await m("restoreRevision", {
|
|
68
|
+
revision_id: selectedRevision.value.revision_id,
|
|
69
|
+
fields: restore_fields.value
|
|
70
|
+
})) {
|
|
71
|
+
Notify.create({
|
|
72
|
+
message: 'Restored successfully',
|
|
73
|
+
color: 'positive'
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
//reload
|
|
77
|
+
window.location.reload();
|
|
78
|
+
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const restore_fields = ref([]);
|
|
87
|
+
|
|
88
|
+
const onToggleAll = () => {
|
|
89
|
+
if (restore_fields.value.length === 0) {
|
|
90
|
+
restore_fields.value = Object.keys(getFilteredContent.value);
|
|
91
|
+
} else {
|
|
92
|
+
restore_fields.value = [];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const isCheckedAll = computed(() => {
|
|
97
|
+
return restore_fields.value.length === Object.keys(getFilteredContent.value).length;
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
const isAllowRestore = computed(() => {
|
|
101
|
+
return restore_fields.value.length > 0;
|
|
102
|
+
})
|
|
103
|
+
const showOnlyDelta = ref(false);
|
|
104
|
+
|
|
105
|
+
const getFilteredContent = computed(() => {
|
|
106
|
+
if (showOnlyDelta.value) {
|
|
107
|
+
const contents = {};
|
|
108
|
+
|
|
109
|
+
for (const key in selectedRevision.value.delta) {
|
|
110
|
+
contents[key] = selectedRevision.value.content[key];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return contents;
|
|
114
|
+
} else {
|
|
115
|
+
return selectedRevision.value.content;
|
|
116
|
+
}
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
const outputFormat = ref('side-by-side');
|
|
120
|
+
const getDiffHtml = (diffs) => {
|
|
121
|
+
if (!diffs) {
|
|
122
|
+
return '';
|
|
123
|
+
}
|
|
124
|
+
return Diff2Html.html(diffs, {
|
|
125
|
+
drawFileList: false,
|
|
126
|
+
matching: 'lines',
|
|
127
|
+
outputFormat: outputFormat.value,
|
|
128
|
+
highlight: true
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
</script>
|
|
134
|
+
|
|
135
|
+
<template>
|
|
136
|
+
<div>
|
|
137
|
+
|
|
138
|
+
<div v-html="html"></div>
|
|
139
|
+
<q-dialog v-model="showDialog" full-height full-width>
|
|
140
|
+
<q-card>
|
|
141
|
+
<q-toolbar>
|
|
142
|
+
<l-btn label="Restore" icon="sym_o_restore" permission="revision.restore" @click="onRestore"
|
|
143
|
+
:disabled="!isAllowRestore" />
|
|
144
|
+
|
|
145
|
+
<q-checkbox label="Show changed only" v-model="showOnlyDelta" :color="$light.color"></q-checkbox>
|
|
146
|
+
|
|
147
|
+
<q-btn-toggle class="q-mx-md" v-model="outputFormat" :toggle-color="$light.color" :options="[
|
|
148
|
+
{ label: 'side-by-side', value: 'side-by-side' }, { label: 'line-by-line', value: 'line-by-line' }
|
|
149
|
+
]" />
|
|
150
|
+
<q-space />
|
|
151
|
+
<q-btn flat round dense icon="close" @click="showDialog = false" />
|
|
152
|
+
</q-toolbar>
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
<div class="q-pa-md">
|
|
156
|
+
|
|
157
|
+
<div class="text-h6 q-mb-md">
|
|
158
|
+
Revision by: {{ selectedRevision.revisionBy }} <br>
|
|
159
|
+
Created at: {{ selectedRevision.createdTime }}
|
|
160
|
+
|
|
161
|
+
</div>
|
|
162
|
+
|
|
163
|
+
<q-markup-table dense separator="cell" flat bordered>
|
|
164
|
+
<thead>
|
|
165
|
+
<tr>
|
|
166
|
+
<th width="48px">
|
|
167
|
+
<q-checkbox @click="onToggleAll" v-model="isCheckedAll"
|
|
168
|
+
:color="$light.color"></q-checkbox>
|
|
169
|
+
</th>
|
|
170
|
+
<th>Field</th>
|
|
171
|
+
<th>Value</th>
|
|
172
|
+
<th>Changed</th>
|
|
173
|
+
</tr>
|
|
174
|
+
</thead>
|
|
175
|
+
<tbody>
|
|
176
|
+
<template v-for="(value, key) in getFilteredContent" :key="key">
|
|
177
|
+
|
|
178
|
+
<tr>
|
|
179
|
+
|
|
180
|
+
<td><q-checkbox v-model="restore_fields" :val="key"
|
|
181
|
+
:color="$light.color"></q-checkbox>
|
|
182
|
+
</td>
|
|
183
|
+
<td :class="{ 'bg-yellow-3': selectedRevision.delta[key] != undefined }">{{ key }}
|
|
184
|
+
</td>
|
|
185
|
+
<td>
|
|
186
|
+
<pre>{{ value }}</pre>
|
|
187
|
+
</td>
|
|
188
|
+
<td>
|
|
189
|
+
<pre>{{ selectedRevision.delta[key] }}</pre>
|
|
190
|
+
</td>
|
|
191
|
+
|
|
192
|
+
</tr>
|
|
193
|
+
|
|
194
|
+
<tr v-if="getDiffHtml(selectedRevision.diff[key])">
|
|
195
|
+
<td colspan="4">
|
|
196
|
+
<div v-html="getDiffHtml(selectedRevision.diff[key])"></div>
|
|
197
|
+
</td>
|
|
198
|
+
</tr>
|
|
199
|
+
</template>
|
|
200
|
+
</tbody>
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
</q-markup-table>
|
|
204
|
+
|
|
205
|
+
</div>
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
</q-card>
|
|
210
|
+
</q-dialog>
|
|
211
|
+
|
|
212
|
+
<l-card>
|
|
213
|
+
<q-list>
|
|
214
|
+
<q-expansion-item :label="`Revisions: ${num_of_revisions}`" icon="sym_o_history" expand-separator>
|
|
215
|
+
|
|
216
|
+
<q-list>
|
|
217
|
+
<q-item v-for="revision in revisionsByModel" :key="revision.revision_id"
|
|
218
|
+
@click="onClick(revision)" clickable>
|
|
219
|
+
<q-item-section>
|
|
220
|
+
<q-item-label>Revision by: {{ revision.revisionBy }}</q-item-label>
|
|
221
|
+
<q-item-label caption>{{ revision.createdTime }}</q-item-label>
|
|
222
|
+
|
|
223
|
+
</q-item-section>
|
|
224
|
+
</q-item>
|
|
225
|
+
</q-list>
|
|
226
|
+
|
|
227
|
+
</q-expansion-item>
|
|
228
|
+
|
|
229
|
+
</q-list>
|
|
230
|
+
</l-card>
|
|
231
|
+
</div>
|
|
232
|
+
</template>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed } from 'vue';
|
|
3
|
+
import { format } from "quasar"
|
|
4
|
+
const { humanStorageSize } = format
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
storage: {
|
|
7
|
+
type: Object,
|
|
8
|
+
required: true
|
|
9
|
+
},
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
const usagePercent = computed(() => {
|
|
14
|
+
return Math.round((props.storage.totalSpace - props.storage.freeSpace) / props.storage.totalSpace)
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const progressColor = computed(() => {
|
|
18
|
+
if (usagePercent.value > 0.95) {
|
|
19
|
+
return "negative"
|
|
20
|
+
}
|
|
21
|
+
if (usagePercent.value > 0.9) {
|
|
22
|
+
return "warning"
|
|
23
|
+
}
|
|
24
|
+
return "primary"
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
</script>
|
|
28
|
+
<template>
|
|
29
|
+
<q-card>
|
|
30
|
+
<q-card-section>
|
|
31
|
+
{{ $t("Storage") }}
|
|
32
|
+
<q-linear-progress rounded size="20px" :value="usagePercent" :color="progressColor" class="q-mt-sm" />
|
|
33
|
+
{{ $t('storage_usage', [humanStorageSize(storage.freeSpace), humanStorageSize(storage.totalSpace)]) }}
|
|
34
|
+
</q-card-section>
|
|
35
|
+
</q-card>
|
|
36
|
+
</template>
|
|
@@ -3,29 +3,56 @@ import { useRoute, useRouter } from 'vue-router';
|
|
|
3
3
|
import { useLight, q, m } from "#imports";
|
|
4
4
|
import { useQuasar, Loading, Dialog } from 'quasar';
|
|
5
5
|
import { useI18n } from 'vue-i18n';
|
|
6
|
-
import { ref, computed, reactive, provide, watch, toRaw
|
|
6
|
+
import { ref, computed, reactive, provide, watch, toRaw } from 'vue';
|
|
7
7
|
import { useRuntimeConfig } from 'nuxt/app';
|
|
8
8
|
|
|
9
9
|
Loading.show()
|
|
10
|
-
|
|
11
|
-
/* import { download } from './../lib/SystemValue'
|
|
12
|
-
await download();
|
|
13
|
-
*/
|
|
10
|
+
|
|
14
11
|
const config = useRuntimeConfig();
|
|
15
12
|
|
|
16
13
|
const appVersion = config.public.appVersion ?? '0.0.1';
|
|
17
14
|
|
|
18
15
|
const quasar = useQuasar();
|
|
19
16
|
const tt = await q({
|
|
20
|
-
system:
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
17
|
+
system: {
|
|
18
|
+
devMode: true,
|
|
19
|
+
time: true,
|
|
20
|
+
storage: {
|
|
21
|
+
freeSpace: true,
|
|
22
|
+
usageSpace: true,
|
|
23
|
+
totalSpace: true,
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
app: {
|
|
27
|
+
menus: true,
|
|
28
|
+
viewAsMode: true,
|
|
29
|
+
languages: true,
|
|
30
|
+
copyrightName: true,
|
|
31
|
+
copyrightYear: true,
|
|
32
|
+
hasFavorite: true,
|
|
33
|
+
i18nMessages: {
|
|
34
|
+
name: true,
|
|
35
|
+
value: true
|
|
36
|
+
}
|
|
37
|
+
}, my: {
|
|
38
|
+
username: true,
|
|
39
|
+
first_name: true,
|
|
40
|
+
last_name: true,
|
|
41
|
+
roles: true,
|
|
42
|
+
styles: true,
|
|
43
|
+
language: true,
|
|
44
|
+
permissions: true,
|
|
45
|
+
default_page: true,
|
|
46
|
+
myFavorites: {
|
|
47
|
+
my_favorite_id: true,
|
|
48
|
+
label: true,
|
|
49
|
+
path: true,
|
|
50
|
+
icon: true
|
|
51
|
+
}
|
|
52
|
+
}
|
|
27
53
|
})
|
|
28
54
|
|
|
55
|
+
|
|
29
56
|
let app = tt.app
|
|
30
57
|
let my = reactive(tt.my)
|
|
31
58
|
|
|
@@ -54,13 +81,6 @@ i18n.locale = my.language || 'en';
|
|
|
54
81
|
|
|
55
82
|
let system = tt.system;
|
|
56
83
|
|
|
57
|
-
if (light.isGranted("system.storage")) {
|
|
58
|
-
let s = await q("system", ["diskFreeSpace", "diskUsageSpace", "diskTotalSpace", "diskFreeSpacePercent"]);
|
|
59
|
-
//merge system value
|
|
60
|
-
system = { ...system, ...s };
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
84
|
// message
|
|
65
85
|
let messages = i18n.messages.value[i18n.locale];
|
|
66
86
|
for (let t of app.i18nMessages) {
|
|
@@ -168,35 +188,17 @@ const exitViewAs = async () => {
|
|
|
168
188
|
}
|
|
169
189
|
|
|
170
190
|
const storageColor = computed(() => {
|
|
171
|
-
if (system) {
|
|
172
|
-
|
|
191
|
+
if (system.storage) {
|
|
192
|
+
const percent = system.storage.freeSpace / system.storage.totalSpace;
|
|
193
|
+
if (percent < 0.05) {
|
|
173
194
|
return "negative"
|
|
174
195
|
}
|
|
175
|
-
if (
|
|
196
|
+
if (percent < 0.1) {
|
|
176
197
|
return "warning"
|
|
177
198
|
}
|
|
178
199
|
}
|
|
179
200
|
})
|
|
180
201
|
|
|
181
|
-
const storageProgressColor = computed(() => {
|
|
182
|
-
if (system) {
|
|
183
|
-
if (system.diskFreeSpacePercent < 0.05) {
|
|
184
|
-
return "negative"
|
|
185
|
-
}
|
|
186
|
-
if (system.diskFreeSpacePercent < 0.1) {
|
|
187
|
-
return "warning"
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
return "primary"
|
|
191
|
-
})
|
|
192
|
-
|
|
193
|
-
const storageUsagePercent = computed(() => {
|
|
194
|
-
if (system) {
|
|
195
|
-
return 1 - system.diskFreeSpacePercent;
|
|
196
|
-
}
|
|
197
|
-
return 0;
|
|
198
|
-
})
|
|
199
|
-
|
|
200
202
|
const containerClass = computed(() => {
|
|
201
203
|
return (light.theme == 'dark') ? {} : { 'bg-grey-2': true }
|
|
202
204
|
})
|
|
@@ -223,8 +225,6 @@ const onToggleFav = async () => {
|
|
|
223
225
|
|
|
224
226
|
//reload my.myFavorites
|
|
225
227
|
light.reloadMyFavorites();
|
|
226
|
-
|
|
227
|
-
|
|
228
228
|
return;
|
|
229
229
|
}
|
|
230
230
|
|
|
@@ -320,24 +320,13 @@ if (route.fullPath == "/" && my.default_page) {
|
|
|
320
320
|
</q-item>
|
|
321
321
|
</q-list>
|
|
322
322
|
</q-menu>
|
|
323
|
-
|
|
324
|
-
|
|
325
323
|
</q-btn>
|
|
326
324
|
|
|
327
|
-
<q-btn icon="sym_o_storage" flat round dense class="q-mr-sm" v-if="system"
|
|
325
|
+
<q-btn icon="sym_o_storage" flat round dense class="q-mr-sm" v-if="system.storage"
|
|
326
|
+
:color="storageColor">
|
|
328
327
|
<q-menu>
|
|
329
|
-
<
|
|
330
|
-
<q-card-section>
|
|
331
|
-
{{ $t("Storage") }}
|
|
332
|
-
<q-linear-progress rounded size="20px" :value="storageUsagePercent"
|
|
333
|
-
:color="storageProgressColor" class="q-mt-sm" />
|
|
334
|
-
{{ $t('storage_usage', [system.diskFreeSpace, system.diskTotalSpace]) }}
|
|
335
|
-
</q-card-section>
|
|
336
|
-
|
|
337
|
-
</q-card>
|
|
328
|
+
<l-storage :storage="system.storage" style="width:250px" />
|
|
338
329
|
</q-menu>
|
|
339
|
-
|
|
340
|
-
|
|
341
330
|
</q-btn>
|
|
342
331
|
|
|
343
332
|
<div class="q-mx-sm" v-if="$q.screen.gt.xs">
|
|
@@ -422,7 +411,8 @@ if (route.fullPath == "/" && my.default_page) {
|
|
|
422
411
|
</q-scroll-area>
|
|
423
412
|
</q-drawer>
|
|
424
413
|
|
|
425
|
-
<q-page-container :class="containerClass" :style="containerStyle">
|
|
414
|
+
<q-page-container :class="containerClass" :style="containerStyle"> <!-- Error message -->
|
|
415
|
+
<slot name="header"></slot>
|
|
426
416
|
<q-banner dense inline-actions class="bg-grey-4 q-ma-md" v-for=" error in errors " rounded>
|
|
427
417
|
{{ error }}
|
|
428
418
|
|
|
@@ -448,9 +438,8 @@ if (route.fullPath == "/" && my.default_page) {
|
|
|
448
438
|
<q-item>
|
|
449
439
|
<q-item-section>
|
|
450
440
|
{{ light.getCompany() }} {{ appVersion }} - Copyright {{ app.copyrightYear }} {{ app.copyrightName
|
|
451
|
-
}}.
|
|
452
|
-
|
|
453
|
-
light.getVersion() }}
|
|
441
|
+
}}. Build
|
|
442
|
+
{{ light.getVersion() }}
|
|
454
443
|
</q-item-section>
|
|
455
444
|
</q-item>
|
|
456
445
|
</q-footer>
|
|
@@ -157,8 +157,10 @@ onMounted(() => {
|
|
|
157
157
|
google.accounts.id.initialize({
|
|
158
158
|
client_id: props.googleClientId,
|
|
159
159
|
callback: handleGoogleCredentialResponse,
|
|
160
|
-
|
|
160
|
+
use_fedcm_for_prompt: true
|
|
161
161
|
|
|
162
|
+
});
|
|
163
|
+
google.accounts.id.prompt();
|
|
162
164
|
google.accounts.id.renderButton(
|
|
163
165
|
document.getElementById('g_id_signin'),
|
|
164
166
|
{
|
|
@@ -23,9 +23,12 @@ const fields = ["company", "company_logo",
|
|
|
23
23
|
"auth_lockout_attempts",
|
|
24
24
|
"access_token_expire",
|
|
25
25
|
"copyright_year",
|
|
26
|
-
"copyright_name"
|
|
26
|
+
"copyright_name",
|
|
27
|
+
"revision"
|
|
27
28
|
];
|
|
28
29
|
|
|
30
|
+
obj.revision = obj.revision ? obj.revision.split(',') : []
|
|
31
|
+
|
|
29
32
|
//filter out fields that are not in the app.config table
|
|
30
33
|
Object.keys(obj).forEach((key) => {
|
|
31
34
|
if (!fields.includes(key)) {
|
|
@@ -80,11 +83,11 @@ const tab = ref('general')
|
|
|
80
83
|
</template>
|
|
81
84
|
<template #after>
|
|
82
85
|
<FormKit type="l-form" :bordered="false" :value="{
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
company: obj.company,
|
|
87
|
+
company_logo: obj.company_logo,
|
|
88
|
+
copyright_name: obj.copyright_name,
|
|
89
|
+
copyright_year: obj.copyright_year
|
|
90
|
+
}" v-if="tab == 'general'" @submit="onSubmit">
|
|
88
91
|
<FormKit type="l-input" label="Company" name="company" validation="required"></FormKit>
|
|
89
92
|
<FormKit type="l-input" label="Company logo" name="company_logo"></FormKit>
|
|
90
93
|
|
|
@@ -94,21 +97,21 @@ const tab = ref('general')
|
|
|
94
97
|
</FormKit>
|
|
95
98
|
|
|
96
99
|
<FormKit type="l-form" :bordered="false" :value="{
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
100
|
+
password_contains_uppercase: obj.password_contains_uppercase,
|
|
101
|
+
password_contains_lowercase: obj.password_contains_lowercase,
|
|
102
|
+
password_contains_numeric: obj.password_contains_numeric,
|
|
103
|
+
password_contains_symbol: obj.password_contains_symbol,
|
|
104
|
+
password_min_length: obj.password_min_length,
|
|
105
|
+
two_factor_authentication: obj.two_factor_authentication,
|
|
106
|
+
auth_lockout_duration: obj.auth_lockout_duration,
|
|
107
|
+
auth_lockout_attempts: obj.auth_lockout_attempts,
|
|
108
|
+
access_token_expire: obj.access_token_expire,
|
|
109
|
+
}" v-if="tab == 'security'" @submit="onSubmit">
|
|
107
110
|
<q-field label="Password policy" stack-label>
|
|
108
|
-
<FormKit type="l-checkbox" label="Upper Case" name="password_contains_uppercase"
|
|
109
|
-
false-value="0" />
|
|
110
|
-
<FormKit type="l-checkbox" label="Lower Case" name="password_contains_lowercase"
|
|
111
|
-
false-value="0" />
|
|
111
|
+
<FormKit type="l-checkbox" label="Upper Case" name="password_contains_uppercase"
|
|
112
|
+
true-value="1" false-value="0" />
|
|
113
|
+
<FormKit type="l-checkbox" label="Lower Case" name="password_contains_lowercase"
|
|
114
|
+
true-value="1" false-value="0" />
|
|
112
115
|
<FormKit type="l-checkbox" label="Number" name="password_contains_numeric" true-value="1"
|
|
113
116
|
false-value="0" />
|
|
114
117
|
<FormKit type="l-checkbox" label="Special Character" name="password_contains_symbol"
|
|
@@ -139,23 +142,29 @@ const tab = ref('general')
|
|
|
139
142
|
</FormKit>
|
|
140
143
|
|
|
141
144
|
<FormKit type="l-form" :bordered="false" :value="{
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
+
file_manager: obj.file_manager,
|
|
146
|
+
revision: obj.revision
|
|
147
|
+
}" v-if="tab == 'Modules'" @submit="onSubmit">
|
|
145
148
|
<q-field label="File manager" stack-label>
|
|
146
|
-
<FormKit type="l-checkbox" label="Show" name="file_manager" true-value="1"
|
|
149
|
+
<FormKit type="l-checkbox" label="Show" name="file_manager" true-value="1"
|
|
150
|
+
false-value="0" />
|
|
147
151
|
</q-field>
|
|
152
|
+
|
|
153
|
+
<FormKit type="q-select" label="Revision" name="revision" use-input use-chips multiple
|
|
154
|
+
hide-dropdown-icon input-debounce="0" new-value-mode="add-unique" />
|
|
155
|
+
|
|
156
|
+
|
|
148
157
|
</FormKit>
|
|
149
158
|
|
|
150
159
|
<FormKit type="l-form" :bordered="false" :value="{
|
|
151
|
-
|
|
160
|
+
mode: obj.mode,
|
|
152
161
|
|
|
153
|
-
|
|
162
|
+
}" v-if="tab == 'Developer'" @submit="onSubmit">
|
|
154
163
|
<FormKit label="Mode" type="l-select" :options="[
|
|
155
|
-
|
|
156
|
-
|
|
164
|
+
{ label: 'Production', value: 'prod' },
|
|
165
|
+
{ label: 'Development', value: 'dev' },
|
|
157
166
|
|
|
158
|
-
|
|
167
|
+
]" name="mode" validation="required">
|
|
159
168
|
</FormKit>
|
|
160
169
|
</FormKit>
|
|
161
170
|
</template>
|
|
@@ -7,18 +7,17 @@ const route = useRoute();
|
|
|
7
7
|
const light = useLight();
|
|
8
8
|
|
|
9
9
|
const tab = ref('overview');
|
|
10
|
-
const splitter = ref(10);
|
|
11
10
|
const id = route.params.user_id;
|
|
12
11
|
</script>
|
|
13
12
|
|
|
14
13
|
<template>
|
|
15
14
|
<l-page edit-btn>
|
|
16
15
|
<template #header>
|
|
17
|
-
<l-btn to="change-password" icon="sym_o_key" permission="user.changePassword"
|
|
16
|
+
<l-btn to="change-password" icon="sym_o_key" permission="user.changePassword"
|
|
17
|
+
label="Change password"></l-btn>
|
|
18
18
|
<l-btn to="update-role" icon="sym_o_people" permission="user.role.add" label="Update role"></l-btn>
|
|
19
19
|
</template>
|
|
20
20
|
|
|
21
|
-
|
|
22
21
|
<q-card flat bordered>
|
|
23
22
|
<q-tabs v-model="tab" :active-color="$light.color" inline-label align="justify">
|
|
24
23
|
<q-tab name="overview" icon="sym_o_person" label="Overview" />
|
|
@@ -5,7 +5,7 @@ const onRequest = async (request) => {
|
|
|
5
5
|
request.loadObjects("User", { status: status.value });
|
|
6
6
|
//request.loadObjects("User");
|
|
7
7
|
};
|
|
8
|
-
const columns = model("User").columns(["username", "first_name", "label_name", "email", "phone", "join_date", "status"]);
|
|
8
|
+
const columns = model("User").columns(["username", "first_name", "label_name", "email", "phone", "join_date", "status","has2FA"]);
|
|
9
9
|
const status = ref("0");
|
|
10
10
|
const selected = ref([]);
|
|
11
11
|
</script>
|
|
@@ -13,7 +13,6 @@ const selected = ref([]);
|
|
|
13
13
|
<template>
|
|
14
14
|
<l-page>
|
|
15
15
|
|
|
16
|
-
|
|
17
16
|
<l-tabs v-model="status">
|
|
18
17
|
<l-tab label="Active" name="0">
|
|
19
18
|
<l-table row-key="user_id" @request="onRequest" :columns="columns"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hostlink/nuxt-light",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.1",
|
|
4
4
|
"description": "HostLink Nuxt Light Framework",
|
|
5
5
|
"repository": "@hostlink/nuxt-light",
|
|
6
6
|
"license": "MIT",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"@nuxt/module-builder": "^0.5.2",
|
|
41
41
|
"@quasar/extras": "^1.16.6",
|
|
42
42
|
"axios": "^1.5.0",
|
|
43
|
+
"diff2html": "^3.4.47",
|
|
43
44
|
"formkit-quasar": "^0.0.15",
|
|
44
45
|
"json-to-graphql-query": "^2.2.5",
|
|
45
46
|
"quasar": "^2.12.5",
|