@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 CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "light",
3
3
  "configKey": "light",
4
- "version": "0.0.109"
4
+ "version": "0.0.111"
5
5
  }
@@ -1,12 +1,11 @@
1
1
  <script setup>
2
- import { computed, ref, useSlots, useAttrs } from "vue";
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
  }
@@ -160,6 +160,6 @@
160
160
  "input_required": "{0}為必填",
161
161
  "Invalid email format": "電郵格式錯誤",
162
162
  "No data available": "沒有資料",
163
- "Loading...": "載入中..."
164
-
163
+ "Loading...": "載入中...",
164
+ "input_min": "最少{0}個字"
165
165
  }
@@ -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 { getModelColumns } from '../../lib';
3
- const columns = getModelColumns("SystemValue", ["name", "value"]);
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("changeUserPassword", obj)) {
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" :rules="rules" v-model="obj.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, getModelColumns } from '../../../';
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="getModelColumns('EventLog', ['eventlog_id', 'class', 'id', 'action', 'created_time'])"
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, getModelColumns } from '../../'
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 = getModelColumns('UserLog', ['login_dt', 'result', 'user_agent']);
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 = getModelColumns('EventLog', ['class', 'action', 'created_time']);
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
- :rules="[v => !!v || 'Old password is required']" />
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>
@@ -24,6 +24,7 @@ declare const _default: {
24
24
  label: string;
25
25
  sortable: boolean;
26
26
  searchable: boolean;
27
+ searchType: string;
27
28
  };
28
29
  username: {
29
30
  label: string;
@@ -23,7 +23,8 @@ export default {
23
23
  created_time: {
24
24
  label: "Created time",
25
25
  sortable: true,
26
- searchable: true
26
+ searchable: true,
27
+ searchType: "date"
27
28
  },
28
29
  username: {
29
30
  label: "Username",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hostlink/nuxt-light",
3
- "version": "0.0.109",
3
+ "version": "0.0.111",
4
4
  "description": "HostLink Nuxt Light Framework",
5
5
  "repository": "@hostlink/nuxt-light",
6
6
  "license": "MIT",