@hostlink/nuxt-light 0.0.109 → 0.0.111
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-input.vue +56 -6
- package/dist/runtime/locales/en.json +3 -2
- package/dist/runtime/locales/zh-hk.json +2 -2
- package/dist/runtime/pages/System/view_as.vue +1 -1
- package/dist/runtime/pages/SystemValue/index.vue +2 -2
- package/dist/runtime/pages/User/_user_id/change-password.vue +9 -24
- package/dist/runtime/pages/User/_user_id/view.vue +3 -12
- package/dist/runtime/pages/User/add.vue +3 -1
- package/dist/runtime/pages/User/profile.vue +3 -7
- package/dist/runtime/pages/User/setting/password.vue +15 -5
- package/dist/runtime/types/EventLog.d.ts +1 -0
- package/dist/runtime/types/EventLog.mjs +2 -1
- package/package.json +1 -1
package/dist/module.json
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { computed, ref,
|
|
2
|
+
import { computed, ref, useAttrs } from "vue";
|
|
3
3
|
import { useI18n } from 'vue-i18n';
|
|
4
4
|
import tc2sc from "../lib/tc2sc";
|
|
5
5
|
import { useLight } from '../';
|
|
6
6
|
|
|
7
7
|
const i18n = useI18n();
|
|
8
8
|
const light = useLight();
|
|
9
|
-
const slots = useSlots();
|
|
10
9
|
|
|
11
10
|
const props = defineProps({
|
|
12
11
|
modelValue: {
|
|
@@ -38,11 +37,13 @@ const props = defineProps({
|
|
|
38
37
|
});
|
|
39
38
|
const emit = defineEmits(["update:modelValue"]);
|
|
40
39
|
|
|
40
|
+
//clone rules to new_rules
|
|
41
41
|
const new_rules = props.rules || [];
|
|
42
42
|
|
|
43
|
+
|
|
43
44
|
//has required prop (in properties)
|
|
44
|
-
if (props.required) {
|
|
45
|
-
new_rules.push(val => !!val || i18n.t('input_required',[i18n.t(props.label)]));
|
|
45
|
+
if (props.required || (new_rules.indexOf("required") >= 0)) {
|
|
46
|
+
new_rules.push(val => !!val || i18n.t('input_required', [i18n.t(props.label)]));
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
if (props.type == "email") {
|
|
@@ -53,6 +54,57 @@ if (props.type == "email") {
|
|
|
53
54
|
});
|
|
54
55
|
}
|
|
55
56
|
|
|
57
|
+
if (new_rules.indexOf("containUpper") >= 0) {
|
|
58
|
+
new_rules.push(val => {
|
|
59
|
+
if (val && !val.match(/[A-Z]/)) {
|
|
60
|
+
return i18n.t("Must contain at least one uppercase letter");
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (new_rules.indexOf("containLower") >= 0) {
|
|
66
|
+
new_rules.push(val => {
|
|
67
|
+
if (val && !val.match(/[a-z]/)) {
|
|
68
|
+
return i18n.t("Must contain at least one lowercase letter");
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (new_rules.indexOf("containNumber") >= 0) {
|
|
74
|
+
new_rules.push(val => {
|
|
75
|
+
if (val && !val.match(/[0-9]/)) {
|
|
76
|
+
return i18n.t("Must contain at least one number");
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (new_rules.indexOf("containSpecial") >= 0) {
|
|
82
|
+
new_rules.push(val => {
|
|
83
|
+
if (val && !val.match(/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/)) {
|
|
84
|
+
return i18n.t("Must contain at least one symbol");
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
//find mniLength:x in rules
|
|
90
|
+
const minLength = new_rules.find(rule => {
|
|
91
|
+
if (typeof rule != "string") return false;
|
|
92
|
+
return rule.startsWith("minLength:")
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
if (minLength) {
|
|
96
|
+
const min = parseInt(minLength.replace("minLength:", ""));
|
|
97
|
+
new_rules.push(val => {
|
|
98
|
+
if (val && val.length < min) {
|
|
99
|
+
return i18n.t("input_min", [min]);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
56
108
|
|
|
57
109
|
const localValue = computed({
|
|
58
110
|
get: () => props.modelValue,
|
|
@@ -100,8 +152,6 @@ const onClickTc2Sc = () => {
|
|
|
100
152
|
localValue.value = tc2sc(localValue.value);
|
|
101
153
|
}
|
|
102
154
|
|
|
103
|
-
|
|
104
|
-
|
|
105
155
|
const attrs = {
|
|
106
156
|
...{
|
|
107
157
|
filled: light.getStyle("inputFilled", false),
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"Theme Customizer": "Theme Customizer",
|
|
12
12
|
"Customize & Preview in Real Time": "Customize & Preview in Real Time",
|
|
13
13
|
"Permission": "Permission",
|
|
14
|
-
"storage_usage":"{0} free of {1}",
|
|
15
|
-
"input_required": "Please input {0}"
|
|
14
|
+
"storage_usage": "{0} free of {1}",
|
|
15
|
+
"input_required": "Please input {0}",
|
|
16
|
+
"input_min": "Please input at least {0} characters"
|
|
16
17
|
}
|
|
@@ -40,7 +40,7 @@ const onCickView = async (id) => {
|
|
|
40
40
|
</script>
|
|
41
41
|
<template>
|
|
42
42
|
<l-page>
|
|
43
|
-
<q-table flat :columns="columns" :rows="users">
|
|
43
|
+
<q-table flat :columns="columns" :rows="users" :rows-per-page-options="[0]">
|
|
44
44
|
<template #body-cell-view="props">
|
|
45
45
|
<q-td :props="props">
|
|
46
46
|
<q-btn rounded outline color="primary" @click="onCickView(props.row.user_id)" label="view"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import {
|
|
3
|
-
const columns =
|
|
2
|
+
import { model } from "#imports"
|
|
3
|
+
const columns = model("SystemValue").columns(["name", "value"]);
|
|
4
4
|
</script>
|
|
5
5
|
<template>
|
|
6
6
|
<l-page>
|
|
@@ -1,35 +1,20 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { q } from '../../../'
|
|
2
|
+
import { q, m } from '../../../'
|
|
3
3
|
import { useRouter, useRoute } from "vue-router"
|
|
4
4
|
import { reactive } from "vue"
|
|
5
5
|
const system = await q("system", ["passwordPolicy"]);
|
|
6
|
-
const rules = system.passwordPolicy.map((rule) => {
|
|
7
|
-
let s = rule.split(":");
|
|
8
|
-
|
|
9
|
-
switch (s[0]) {
|
|
10
|
-
case "required":
|
|
11
|
-
return (v) => !!v || "Required";
|
|
12
|
-
case "containUpper":
|
|
13
|
-
return (v) => /[A-Z]/.test(v) || "Must contain at least one uppercase letter";
|
|
14
|
-
case "containLower":
|
|
15
|
-
return (v) => /[a-z]/.test(v) || "Must contain at least one lowercase letter";
|
|
16
|
-
case "containNumber":
|
|
17
|
-
return (v) => /[0-9]/.test(v) || "Must contain at least one number";
|
|
18
|
-
case "containSpecial":
|
|
19
|
-
return (v) => /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(v) || "Must contain at least one special character";
|
|
20
|
-
case "minLength":
|
|
21
|
-
return (v) => v.length >= parseInt(s[1]) || `Must be at least ${s[1]} characters`;
|
|
22
|
-
}
|
|
23
|
-
})
|
|
24
6
|
const router = useRouter();
|
|
25
7
|
const route = useRoute();
|
|
26
|
-
const obj = reactive({
|
|
27
|
-
id: parseInt(route.params.user_id)
|
|
28
|
-
})
|
|
29
8
|
|
|
9
|
+
const obj = reactive({
|
|
10
|
+
password: "",
|
|
11
|
+
});
|
|
30
12
|
|
|
31
13
|
const onUpdatePassword = async () => {
|
|
32
|
-
if (await m("
|
|
14
|
+
if (await m("updateUserPassword", {
|
|
15
|
+
id: route.params.user_id,
|
|
16
|
+
password: obj.password
|
|
17
|
+
})) {
|
|
33
18
|
router.push("/User");
|
|
34
19
|
}
|
|
35
20
|
}
|
|
@@ -38,7 +23,7 @@ const onUpdatePassword = async () => {
|
|
|
38
23
|
<template>
|
|
39
24
|
<l-page>
|
|
40
25
|
<l-form @save="onUpdatePassword">
|
|
41
|
-
<l-input type="password" label="New password"
|
|
26
|
+
<l-input type="password" label="New password" v-model="obj.password" :rules="system.passwordPolicy">
|
|
42
27
|
</l-input>
|
|
43
28
|
</l-form>
|
|
44
29
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { getObject, getModelFields, q
|
|
2
|
+
import { model, getObject, getModelFields, q } from '../../../';
|
|
3
|
+
|
|
3
4
|
const obj = await getObject(["user_id", "username", "first_name", "last_name", "email", "phone", "roles", 'status', 'join_date']);
|
|
4
5
|
|
|
5
6
|
</script>
|
|
@@ -25,16 +26,10 @@ const obj = await getObject(["user_id", "username", "first_name", "last_name", "
|
|
|
25
26
|
</l-list>
|
|
26
27
|
</l-card>
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
29
|
<l-tabs>
|
|
31
|
-
|
|
32
30
|
<l-tab label="Event log">
|
|
33
31
|
<l-table row-key="eventlog_id" sort-by="eventlog_id:desc"
|
|
34
|
-
:columns="
|
|
35
|
-
@request="async (req) => {
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
:columns="model('EventLog').columns(['eventlog_id', 'class', 'id', 'action', 'created_time'])" @request="async (req) => {
|
|
38
33
|
const a = {
|
|
39
34
|
listUser: {
|
|
40
35
|
__args: {
|
|
@@ -53,12 +48,8 @@ const obj = await getObject(["user_id", "username", "first_name", "last_name", "
|
|
|
53
48
|
|
|
54
49
|
let resp = await q(a);
|
|
55
50
|
req.setData(resp.listUser.data[0].eventLog)
|
|
56
|
-
|
|
57
|
-
|
|
58
51
|
}" />
|
|
59
52
|
</l-tab>
|
|
60
|
-
|
|
61
53
|
</l-tabs>
|
|
62
|
-
|
|
63
54
|
</l-page>
|
|
64
55
|
</template>
|
|
@@ -18,6 +18,7 @@ roles = roles.map((role) => {
|
|
|
18
18
|
};
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
+
const system = await q("system", ["passwordPolicy"]);
|
|
21
22
|
</script>
|
|
22
23
|
<template>
|
|
23
24
|
<l-page>
|
|
@@ -25,7 +26,8 @@ roles = roles.map((role) => {
|
|
|
25
26
|
<l-row>
|
|
26
27
|
<l-col md="6" gutter="md">
|
|
27
28
|
<l-input label="Username" v-model="obj.username" required />
|
|
28
|
-
<l-input label="Password" v-model="obj.password" required type="password"
|
|
29
|
+
<l-input label="Password" v-model="obj.password" required type="password"
|
|
30
|
+
:rules="system.passwordPolicy" />
|
|
29
31
|
<l-input label="First name" v-model="obj.first_name" required />
|
|
30
32
|
<l-input label="Last name" v-model="obj.last_name" />
|
|
31
33
|
<l-input label="Email" v-model="obj.email" required type="email" />
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { q,
|
|
3
|
-
import { getGQLFields } from '#imports'
|
|
2
|
+
import { q, getGQLFields, model } from '#imports'
|
|
4
3
|
import { toQuery } from '@hostlink/light';
|
|
5
4
|
|
|
6
5
|
const { my } = await q(
|
|
@@ -32,14 +31,14 @@ const { my } = await q(
|
|
|
32
31
|
}
|
|
33
32
|
)
|
|
34
33
|
|
|
35
|
-
const userlogColumns =
|
|
34
|
+
const userlogColumns = model('UserLog').columns(['login_dt', 'result', 'user_agent']);
|
|
36
35
|
//remove all searchable
|
|
37
36
|
userlogColumns.forEach(col => {
|
|
38
37
|
col.searchable = false;
|
|
39
38
|
})
|
|
40
39
|
|
|
41
40
|
|
|
42
|
-
const eventLogCols =
|
|
41
|
+
const eventLogCols = model('EventLog').columns(['class', 'action', 'created_time']);
|
|
43
42
|
//remove all searchable
|
|
44
43
|
eventLogCols.forEach(col => {
|
|
45
44
|
col.searchable = false;
|
|
@@ -52,7 +51,6 @@ eventLogCols.forEach(col => {
|
|
|
52
51
|
<l-btn icon="sym_o_key" to="update-password" label="Update password" />
|
|
53
52
|
<l-btn icon="sym_o_key" to="two-factor-auth" label="Two factor auth" />
|
|
54
53
|
</template>
|
|
55
|
-
|
|
56
54
|
<div class="q-gutter-md q-mt-md">
|
|
57
55
|
<l-card>
|
|
58
56
|
<l-list>
|
|
@@ -77,7 +75,5 @@ eventLogCols.forEach(col => {
|
|
|
77
75
|
</l-table>
|
|
78
76
|
</l-card>
|
|
79
77
|
</div>
|
|
80
|
-
|
|
81
|
-
|
|
82
78
|
</l-page>
|
|
83
79
|
</template>
|
|
@@ -3,6 +3,8 @@ import { reactive } from "vue"
|
|
|
3
3
|
import { notify } from '../../../'
|
|
4
4
|
import { updatePassword } from "@hostlink/light"
|
|
5
5
|
|
|
6
|
+
import { q } from "#imports"
|
|
7
|
+
|
|
6
8
|
const obj = reactive({
|
|
7
9
|
old_password: "",
|
|
8
10
|
new_password: "",
|
|
@@ -17,16 +19,24 @@ const onSave = async () => {
|
|
|
17
19
|
}
|
|
18
20
|
}
|
|
19
21
|
|
|
22
|
+
const system = await q("system", ["passwordPolicy"])
|
|
23
|
+
|
|
20
24
|
</script>
|
|
21
25
|
<template>
|
|
22
26
|
<l-form @save="onSave" :bordered="false">
|
|
23
|
-
<l-input label="Old password" v-model="obj.old_password" type="password"
|
|
24
|
-
|
|
25
|
-
<l-input label="New password" v-model="obj.new_password" type="password"
|
|
26
|
-
:rules="[v => !!v || 'New password is required']" />
|
|
27
|
+
<l-input label="Old password" v-model="obj.old_password" type="password" required />
|
|
28
|
+
<l-input label="New password" v-model="obj.new_password" type="password" :rules="system.passwordPolicy" />
|
|
27
29
|
<l-input label="Confirm password" v-model="obj.confirm_password" type="password" :rules="[
|
|
28
|
-
v => !!v || 'Confirm password is required',
|
|
29
30
|
v => v == obj.new_password || 'Confirm password does not match'
|
|
30
31
|
]" />
|
|
31
32
|
</l-form>
|
|
33
|
+
|
|
34
|
+
<div>
|
|
35
|
+
<div>Password policy</div>
|
|
36
|
+
<ul>
|
|
37
|
+
<li v-for="rule in system.passwordPolicy" :key="rule">
|
|
38
|
+
{{ rule }}
|
|
39
|
+
</li>
|
|
40
|
+
</ul>
|
|
41
|
+
</div>
|
|
32
42
|
</template>
|