@hostlink/nuxt-light 0.0.90 → 0.0.92

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 (41) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +0 -1
  3. package/dist/runtime/components/l-app.vue +11 -4
  4. package/dist/runtime/components/l-date-picker.vue +13 -4
  5. package/dist/runtime/components/l-field.vue +8 -0
  6. package/dist/runtime/components/l-item.vue +0 -1
  7. package/dist/runtime/components/l-link.vue +2 -9
  8. package/dist/runtime/components/l-list.vue +19 -3
  9. package/dist/runtime/components/l-table.vue +31 -8
  10. package/dist/runtime/index.d.ts +2 -0
  11. package/dist/runtime/index.mjs +14 -0
  12. package/dist/runtime/lib/getGQLFields.mjs +5 -1
  13. package/dist/runtime/lib/getID.d.ts +1 -1
  14. package/dist/runtime/lib/getID.mjs +2 -10
  15. package/dist/runtime/lib/index.d.ts +1 -2
  16. package/dist/runtime/lib/index.mjs +0 -2
  17. package/dist/runtime/lib/list.d.ts +7 -1
  18. package/dist/runtime/lib/list.mjs +35 -32
  19. package/dist/runtime/lib/listObject.d.ts +2 -1
  20. package/dist/runtime/lib/listObject.mjs +8 -17
  21. package/dist/runtime/lib/loadObject.mjs +2 -2
  22. package/dist/runtime/locales/zh-hk.json +1 -0
  23. package/dist/runtime/pages/EventLog/index.vue +2 -38
  24. package/dist/runtime/pages/MailLog/index.vue +33 -32
  25. package/dist/runtime/pages/Permission/add.vue +2 -2
  26. package/dist/runtime/pages/Permission/export.vue +2 -2
  27. package/dist/runtime/pages/System/view_as.vue +1 -6
  28. package/dist/runtime/pages/Translate/index.vue +1 -1
  29. package/dist/runtime/pages/User/_user_id/update-role.vue +2 -3
  30. package/dist/runtime/pages/User/add.vue +2 -2
  31. package/dist/runtime/pages/User/index.vue +1 -1
  32. package/dist/runtime/pages/User/profile.vue +72 -14
  33. package/dist/runtime/plugin.mjs +4 -0
  34. package/dist/runtime/types/EventLog.d.ts +33 -0
  35. package/dist/runtime/types/EventLog.mjs +32 -0
  36. package/dist/runtime/types/MailLog.d.ts +30 -0
  37. package/dist/runtime/types/MailLog.mjs +29 -0
  38. package/dist/runtime/types/User.mjs +8 -0
  39. package/package.json +1 -1
  40. package/dist/runtime/lib/listData.d.ts +0 -1
  41. package/dist/runtime/lib/listData.mjs +0 -33
package/dist/module.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "light",
3
3
  "configKey": "light",
4
- "version": "0.0.90"
4
+ "version": "0.0.92"
5
5
  }
package/dist/module.mjs CHANGED
@@ -45,7 +45,6 @@ const module = defineNuxtModule({
45
45
  { name: "getObject", from },
46
46
  { name: "loadObject", from },
47
47
  { name: "list", from },
48
- { name: "listData", from },
49
48
  { name: "m", from },
50
49
  { name: "q", from },
51
50
  { name: "removeObject", from },
@@ -1,15 +1,22 @@
1
1
  <script setup>
2
- import { useLight } from "#imports";
2
+ import { useLight, watch } from "#imports";
3
3
  import { useRuntimeConfig } from 'nuxt/app'
4
4
  import { setApiUrl } from '@hostlink/light'
5
5
  import { Dialog } from 'quasar'
6
6
  import { q } from '../'
7
+ import { useRoute } from "#vue-router";
7
8
  const config = useRuntimeConfig();
8
9
  setApiUrl(config?.public?.apiBase ?? '/api/');
9
10
 
11
+ const route = useRoute();
12
+ const light = useLight()
13
+
14
+ light.setCurrentRoute(route);
15
+ watch(route, (to, from) => {
16
+ light.setCurrentRoute(to);
17
+ });
10
18
 
11
19
  let app = null
12
- const light = useLight()
13
20
  try {
14
21
  app = (await q({ app: ['company', 'companyLogo', 'logged', 'twoFactorAuthentication', 'googleClientId'] })).app;
15
22
  light.setCompany(app.company);
@@ -30,13 +37,13 @@ try {
30
37
  <q-layout v-if="!app.logged">
31
38
  <q-page-container class="bg-grey-2" style="color:#1f1f1f">
32
39
  <q-page padding>
33
- <l-login :twoFactojrAuthentication="app.twoFactorAuthentication"
40
+ <l-login :two-factor-authentication="app.twoFactorAuthentication"
34
41
  :google-client-id="app.googleClientId"></l-login>
35
42
  </q-page>
36
43
  </q-page-container>
37
44
  </q-layout>
38
45
 
39
- <l-app-main>
46
+ <l-app-main v-else>
40
47
  <slot></slot>
41
48
  </l-app-main>
42
49
  </template>
@@ -45,14 +45,21 @@ const localValue = computed({
45
45
 
46
46
  const rules = [];
47
47
 
48
- if (props.required && !props.range) {
48
+ if (props.required) {
49
49
  rules.push((val) => {
50
50
  if (!val) {
51
51
  return "Required";
52
52
  }
53
+ })
54
+ }
55
+
56
+ if (!props.range) {
57
+ rules.push((val) => {
53
58
  //check val is YYYY-MM-DD
54
- if (!val.match(/^\d{4}-\d{2}-\d{2}$/)) {
55
- return "Invalid date format";
59
+ if (val) {
60
+ if (!val.match(/^\d{4}-\d{2}-\d{2}$/)) {
61
+ return "Invalid date format";
62
+ }
56
63
  }
57
64
  });
58
65
  }
@@ -70,9 +77,11 @@ const attrs = {
70
77
  ...useAttrs(),
71
78
  }
72
79
 
80
+ const mask = props.range ? "####-##-## - ####-##-##" : "####-##-##";
81
+
73
82
  </script>
74
83
  <template>
75
- <q-input v-bind="attrs" v-model="localValue" :rules="rules" :label="$t(label)" hide-bottom-space>
84
+ <q-input v-bind="attrs" v-model="localValue" :rules="rules" :label="$t(label)" hide-bottom-space :mask="mask">
76
85
  <template v-slot:prepend>
77
86
  <q-btn icon="sym_o_event" round dense flat>
78
87
  <q-popup-proxy cover transition-show="scale" transition-hide="scale" ref="popup">
@@ -0,0 +1,8 @@
1
+ <script setup>
2
+ const props = defineProps(['label']);
3
+ </script>
4
+ <template>
5
+ <q-field :label="$t(props.label ?? '')">
6
+ <slot></slot>
7
+ </q-field>
8
+ </template>
@@ -1,5 +1,4 @@
1
1
  <script setup>
2
- import { inject } from 'vue'
3
2
  const props = defineProps({
4
3
  label: {
5
4
  type: String,
@@ -1,5 +1,4 @@
1
1
  <script setup>
2
- import { useRouter } from "vue-router"
3
2
  const props = defineProps({
4
3
  to: {
5
4
  type: String,
@@ -11,15 +10,9 @@ const props = defineProps({
11
10
  default: "primary"
12
11
  },
13
12
  })
14
- const router = useRouter();
15
- const navigate = () => {
16
- if (props.to) {
17
- router.push(props.to);
18
- }
19
- }
20
13
  </script>
21
14
  <template>
22
- <a class="cursor-pointer" @click="navigate" style="text-decoration: underline; color:var(--q-primary)">
15
+ <router-link :to="props.to" style="text-decoration: underline; color:var(--q-primary)">
23
16
  <slot />
24
- </a>
17
+ </router-link>
25
18
  </template>
@@ -1,7 +1,5 @@
1
1
  <script setup>
2
2
 
3
-
4
-
5
3
  const props = defineProps({
6
4
  modelValue: {
7
5
  type: Object
@@ -11,11 +9,29 @@ const props = defineProps({
11
9
  }
12
10
  })
13
11
 
12
+ function getTo(field) {
13
+
14
+ const raw=field.getRaw();
15
+
16
+ if (raw.to) {
17
+ if (raw.to instanceof Function) {
18
+ return raw.to(props.modelValue);
19
+ }
20
+
21
+ if (typeof raw.to == 'string') {
22
+ return raw.to;
23
+ }
24
+ }
25
+
26
+ return null;
27
+ }
28
+
29
+
14
30
  </script>
15
31
  <template>
16
32
  <q-list bordered separator>
17
33
  <template v-if="fields">
18
- <l-item v-for="field in fields" :label="field.getRaw().label">
34
+ <l-item v-for="field in fields" :label="field.getRaw().label" :to="getTo(field)">
19
35
  {{ field.getFormattedValue(props.modelValue) }}
20
36
  </l-item>
21
37
 
@@ -1,8 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import { useQuasar, QTable } from 'quasar';
3
- import { ref, computed, onMounted, useSlots, reactive, useAttrs } from "vue";
4
- import { t, deleteObject, q, f, useLight, GQLFieldBuilder } from '../';
5
- import { toQuery } from '@hostlink/light'
3
+ import { ref, computed, onMounted, useSlots, useAttrs } from "vue";
4
+ import { t, deleteObject, q, useLight, GQLFieldBuilder } from '../';
6
5
 
7
6
  const errors = ref<InstanceType<any>>([]);
8
7
 
@@ -338,7 +337,9 @@ const getFilterValue = () => {
338
337
  if (col.searchable) {
339
338
  if (filters.value[col.name]) {
340
339
 
341
- if (col.searchType == "date") {
340
+ if (col.searchType == "number") {
341
+ f[col.name] = filters.value[col.name]
342
+ } else if (col.searchType == "date") {
342
343
  if (filters.value[col.name].from) {
343
344
  f[col.name] = {
344
345
  between: [filters.value[col.name].from, filters.value[col.name].to]
@@ -406,7 +407,18 @@ const attrs = {
406
407
  }
407
408
 
408
409
  const filter = ref('');
410
+
411
+ const toColumns = props.columns?.filter((col: any) => {
412
+ return col.to;
413
+ }).map((col: any) => {
414
+ col.slot_name = 'body-cell-' + col.name;
415
+ return col;
416
+
417
+ })
418
+
419
+ console.log(ss);
409
420
  </script>
421
+
410
422
  <template>
411
423
  <template v-if="errors.length > 0">
412
424
  <div class="q-gutter-sm">
@@ -415,7 +427,8 @@ const filter = ref('');
415
427
  </template>
416
428
 
417
429
  <template v-if="debug">
418
- <pre>primaryKey:{{ primaryKey }}
430
+ <pre>
431
+ primaryKey:{{ primaryKey }}
419
432
  modelName:{{ modelName }}
420
433
  filters:{{ filters }}
421
434
  pagination:{{ pagination }}
@@ -428,6 +441,7 @@ const filter = ref('');
428
441
  rows:{{ props.rows }}
429
442
  </template>
430
443
 
444
+
431
445
  <q-table v-bind="attrs" :row-key="rowKey" :loading="loading" :rows="rows" ref="table" @request="onRequest"
432
446
  :rows-per-page-label="$t(props.rowsPerPageLabel)" :columns="renderColumns"
433
447
  :rows-per-page-options="rowsPerPageOptions" :selection="selection" v-model:pagination="pagination" :filter="filter">
@@ -441,15 +455,19 @@ const filter = ref('');
441
455
 
442
456
  <q-btn v-if="fullscreen" flat round dense :icon="props.inFullscreen ? 'fullscreen_exit' : 'fullscreen'"
443
457
  @click="props.toggleFullscreen" class="q-ml-md" />
444
-
445
-
446
458
  </template>
447
459
 
448
-
449
460
  <template v-for="s in ss" v-slot:[s]="props">
450
461
  <slot :name="s" v-bind="props"></slot>
451
462
  </template>
452
463
 
464
+ <template v-for="col in toColumns" v-slot:[col.slot_name]="props">
465
+ <q-td :props="props">
466
+ <l-link :to="col.to(props.row)">
467
+ {{ col.field(props.row) }}
468
+ </l-link>
469
+ </q-td>
470
+ </template>
453
471
 
454
472
  <template #body-cell-_actions="props">
455
473
  <q-td :props="props" auto-width>
@@ -479,6 +497,11 @@ const filter = ref('');
479
497
  <q-td v-for="col in props.cols">
480
498
  <template v-if="col.searchable">
481
499
 
500
+ <template v-if="col.searchType == 'number'">
501
+ <q-input dense clearable v-model.number="filters[col.name]" @keydown.enter.prevent="onFilters"
502
+ @clear="onFilters" mask="##########"></q-input>
503
+ </template>
504
+
482
505
  <template v-if="col.searchType == 'select'">
483
506
  <q-select dense v-model="filters[col.name]" @update:model-value="onFilters" clearable
484
507
  :options="col.searchOptions" @clear="onFilters" emit-value />
@@ -9,6 +9,8 @@ interface Light {
9
9
  setCompany(company: string): void;
10
10
  getCompanyLogo(): string;
11
11
  setCompanyLogo(logo: string): void;
12
+ setCurrentRoute(to: any, from: any): void;
13
+ getID(): Number | null;
12
14
  }
13
15
  export declare const useLight: () => Light;
14
16
  export * from "./lib";
@@ -5,6 +5,7 @@ const app = {
5
5
  company: "",
6
6
  companyLogo: ""
7
7
  };
8
+ let currentRoute = null;
8
9
  export const useLight = () => {
9
10
  return {
10
11
  setCompany: (company) => {
@@ -42,6 +43,19 @@ export const useLight = () => {
42
43
  },
43
44
  setStyles(s) {
44
45
  styles = s;
46
+ },
47
+ setCurrentRoute(to, from) {
48
+ currentRoute = to;
49
+ },
50
+ getID() {
51
+ if (currentRoute == null)
52
+ return null;
53
+ let name = currentRoute.name?.toString();
54
+ if (name == void 0)
55
+ return 0;
56
+ let parts = name.split("-");
57
+ const keyname = parts[1];
58
+ return parseInt(currentRoute.params[keyname]);
45
59
  }
46
60
  };
47
61
  };
@@ -1,8 +1,12 @@
1
1
  import GQLFieldBuilder from "./GQLFieldBuilder.mjs";
2
+ import { getModelField } from "@hostlink/light";
2
3
  export default (name, fields) => {
3
4
  const builder = GQLFieldBuilder();
4
5
  fields.forEach((field) => {
5
- builder.add(getObjectField(name, field).getGQLField());
6
+ const modelField = getModelField(name, field);
7
+ if (modelField) {
8
+ builder.add(modelField.getGQLField());
9
+ }
6
10
  });
7
11
  return builder.get();
8
12
  };
@@ -1,2 +1,2 @@
1
- declare const _default: () => Number;
1
+ declare const _default: () => Number | null;
2
2
  export default _default;
@@ -1,12 +1,4 @@
1
- import { useRoute } from "vue-router";
2
- const route = useRoute();
1
+ import { useLight } from "../index.mjs";
3
2
  export default () => {
4
- let name = route.name?.toString();
5
- if (name == void 0)
6
- return 0;
7
- let parts = name.split("-");
8
- const module = parts[0];
9
- const moduleLower = module.charAt(0).toLowerCase() + module.slice(1);
10
- const keyname = parts[1];
11
- return parseInt(route.params[keyname]);
3
+ return useLight().getID();
12
4
  };
@@ -4,7 +4,6 @@ import getApiUrl from "./getApiUrl";
4
4
  import getCurrentUser from "./getCurrentUser";
5
5
  import getObject from "./getObject";
6
6
  import list from "./list";
7
- import listData from "./listData";
8
7
  import m from "./m";
9
8
  import q from "./q";
10
9
  import removeObject from "./removeObject";
@@ -22,4 +21,4 @@ declare const notify: (message: string, color?: string) => void;
22
21
  import getID from "./getID";
23
22
  declare const getApiBase: () => {};
24
23
  import { getGQLFields } from '@hostlink/light';
25
- export { addObject, f, getApiUrl, getCurrentUser, getObject, list, listData, m, q, removeObject, t, updateObject, notify, getID, deleteObject, listObject, isGranted, getApiBase, loadObject, GQLFieldBuilder, getModelField, getModelFields, getModelColumns, getGQLFields };
24
+ export { addObject, f, getApiUrl, getCurrentUser, getObject, list, m, q, removeObject, t, updateObject, notify, getID, deleteObject, listObject, isGranted, getApiBase, loadObject, GQLFieldBuilder, getModelField, getModelFields, getModelColumns, getGQLFields };
@@ -6,7 +6,6 @@ import getApiUrl from "./getApiUrl.mjs";
6
6
  import getCurrentUser from "./getCurrentUser.mjs";
7
7
  import getObject from "./getObject.mjs";
8
8
  import list from "./list.mjs";
9
- import listData from "./listData.mjs";
10
9
  import m from "./m.mjs";
11
10
  import q from "./q.mjs";
12
11
  import removeObject from "./removeObject.mjs";
@@ -40,7 +39,6 @@ export {
40
39
  getCurrentUser,
41
40
  getObject,
42
41
  list,
43
- listData,
44
42
  m,
45
43
  q,
46
44
  removeObject,
@@ -1 +1,7 @@
1
- export default function list(name: string, props?: any, fields?: Array<string>): Promise<any>;
1
+ import { Fields } from "@hostlink/light";
2
+ export default function list(name: string, props?: {
3
+ sort?: string;
4
+ filters?: object;
5
+ offset?: number;
6
+ limit?: number;
7
+ } | null, fields?: Fields): Promise<any>;
@@ -1,35 +1,38 @@
1
- import q from "./q.mjs";
2
- import f from "./f.mjs";
3
- export default async function list(name, props = {}, fields = []) {
4
- let v = {};
5
- if (props.sort) {
6
- v.sort = props.sort;
1
+ import { query, toQuery } from "@hostlink/light";
2
+ export default async function list(name, props = null, fields = []) {
3
+ let q = {};
4
+ if (props) {
5
+ if (props.sort) {
6
+ q.__args = q.__args || {};
7
+ q.__args.sort = props.sort;
8
+ }
9
+ if (props.filters) {
10
+ q.__args = q.__args || {};
11
+ q.__args.filters = props.filters;
12
+ }
7
13
  }
8
- if (props.filters) {
9
- v.filters = {
10
- value: props.filters,
11
- type: "mixed"
12
- };
14
+ q.data = {};
15
+ if (props) {
16
+ if (props.offset) {
17
+ q.data.__args = q.data.__args || {};
18
+ q.data.__args.offset = props.offset;
19
+ }
20
+ if (props.limit) {
21
+ q.data.__args = q.data.__args || {};
22
+ q.data.__args.limit = props.limit;
23
+ }
13
24
  }
14
- let offset_limit = {};
15
- if (props.offset) {
16
- offset_limit.offset = props.offset;
17
- }
18
- if (props.limit) {
19
- offset_limit.limit = props.limit;
20
- }
21
- const fs = fields;
22
- if (props.fields) {
23
- fs.push(...props.fields);
24
- }
25
- let data = await q(`list${name}`, v, [f("data", offset_limit, fs), f("meta", ["total", "key", "name"])]);
26
- if (props.done) {
27
- props.done({
28
- rows: data.data,
29
- total: data.meta.total,
30
- key: data.meta.key,
31
- name: data.meta.name
32
- });
33
- }
34
- return data.data;
25
+ q.data = {
26
+ ...q.data,
27
+ ...toQuery(fields)
28
+ };
29
+ q.meta = {
30
+ total: true,
31
+ key: true,
32
+ name: true
33
+ };
34
+ const resp = await query({
35
+ [`list${name}`]: q
36
+ });
37
+ return resp[`list${name}`];
35
38
  }
@@ -1 +1,2 @@
1
- export default function listObject(name: string, filters: {} | undefined, sort: String, offset: number, limit: number, fields?: Array<string>): Promise<any>;
1
+ import { Fields } from "@hostlink/light";
2
+ export default function listObject(name: string, filters: {} | undefined, sort: string, offset: number, limit: number, fields?: Fields): Promise<any>;
@@ -1,19 +1,10 @@
1
- import q from "./q.mjs";
2
- import f from "./f.mjs";
1
+ import list from "./list.mjs";
3
2
  export default async function listObject(name, filters = {}, sort, offset, limit, fields = []) {
4
- let offset_limit = {};
5
- if (offset) {
6
- offset_limit.offset = offset;
7
- }
8
- if (limit) {
9
- offset_limit.limit = limit;
10
- }
11
- let params = {};
12
- if (sort) {
13
- params.sort = sort;
14
- }
15
- if (filters) {
16
- params.filters = filters;
17
- }
18
- return await q(`list${name}`, params, [f("data", offset_limit, fields), f("meta", ["total", "key", "name"])]);
3
+ const resp = await list(name, {
4
+ filters,
5
+ sort,
6
+ offset,
7
+ limit
8
+ }, fields);
9
+ return resp.data;
19
10
  }
@@ -1,6 +1,6 @@
1
- import listData from "./listData.mjs";
1
+ import list from "./list.mjs";
2
2
  export default async function(module, filters, fields = []) {
3
- let { data } = await listData(module, {
3
+ let { data } = await list(module, {
4
4
  filters
5
5
  }, fields);
6
6
  if (data.length > 0) {
@@ -157,4 +157,5 @@
157
157
  "Event Log": "事件紀錄",
158
158
  "Mail Log": "郵件紀錄",
159
159
  "User Log": "使用者紀錄"
160
+
160
161
  }
@@ -1,42 +1,6 @@
1
1
  <script setup>
2
- const columns = [
3
- {
4
- label: "EventLog ID",
5
- name: "eventlog_id",
6
- sortable: true,
7
- searchable: true,
8
- },
9
-
10
- {
11
- label: "Class",
12
- name: "class",
13
- sortable: true,
14
- searchable: true,
15
- },
16
-
17
- {
18
- label: "ID",
19
- name: "id",
20
- sortable: true,
21
- searchable: true,
22
- },
23
- {
24
- label: "Action",
25
- name: "action",
26
- sortable: true,
27
- searchable: true,
28
- }, {
29
- label: "Created time",
30
- name: "created_time",
31
- sortable: true,
32
- searchable: true,
33
- }, {
34
- label: "Username",
35
- name: "username",
36
- sortable: true,
37
- searchable: true,
38
- }
39
- ]
2
+ import { getModelColumns } from "#imports"
3
+ const columns = getModelColumns('EventLog', ['eventlog_id', 'class', 'id', 'action', 'created_time', 'username'])
40
4
 
41
5
  </script>
42
6
 
@@ -1,40 +1,41 @@
1
1
  <script setup>
2
- const columns = [
3
- {
4
- label: "ID",
5
- name: "maillog_id",
6
- sortable: true,
7
- searchable: true,
8
- }, {
9
- label: "From",
10
- name: "from",
11
- sortable: true,
12
- searchable: true,
13
- }, {
14
- label: "To",
15
- name: "to",
16
- sortable: true,
17
- searchable: true,
18
- },
19
- {
20
- label: "Subject",
21
- name: "subject",
22
- sortable: true,
23
- searchable: true,
24
- },
25
- {
26
- label: "Created time",
27
- name: "created_time",
28
- sortable: true,
29
- searchable: true,
30
- searchType: "date",
31
- }
32
- ]
2
+ import { getModelColumns } from "#imports"
3
+ import { ref } from 'vue'
4
+ const columns = getModelColumns("MailLog", ["maillog_id", "from", "to", "subject", "created_time"])
33
5
 
6
+
7
+ columns.push({
8
+ label: "Content",
9
+ name: "_act",
10
+ gqlField: ["body"]
11
+ })
12
+ const show = ref(false)
13
+ const content = ref("")
34
14
  </script>
35
15
 
36
16
  <template>
37
17
  <l-page>
38
- <l-table @request="$event.loadObjects('MailLog')" :columns="columns" sort-by="maillog_id:desc" />
18
+ <q-dialog v-model="show" full-width>
19
+ <l-card>
20
+ <q-card-section>
21
+ <iframe width="100%" height="500px" :srcdoc="content" frameborder="0"></iframe>
22
+ </q-card-section>
23
+ </l-card>
24
+ </q-dialog>
25
+ <l-table row-key="maillog_id" @request="$event.loadObjects('MailLog')" :columns="columns" sort-by="maillog_id:desc">
26
+
27
+ <template #body-cell-_act="props">
28
+ <q-td :props="props">
29
+ <l-btn @click="
30
+ content = props.row.body;
31
+ show = true" label="Show" icon="sym_o_visibility">
32
+ </l-btn>
33
+
34
+
35
+ </q-td>
36
+
37
+ </template>
38
+
39
+ </l-table>
39
40
  </l-page>
40
41
  </template>
@@ -31,10 +31,10 @@ const onSave = async () => {
31
31
 
32
32
  <l-input label="Permission name" v-model="obj.value" required></l-input>
33
33
 
34
- <q-field label="Roles" stack-label>
34
+ <l-field label="Roles" stack-label>
35
35
  <q-option-group type="checkbox" :options="roles" v-model="obj.roles" inline>
36
36
  </q-option-group>
37
- </q-field>
37
+ </l-field>
38
38
 
39
39
  </l-form>
40
40
 
@@ -62,10 +62,10 @@ const submit = () => {
62
62
  <template>
63
63
  <l-page>
64
64
  <l-form submit-label="Export" submit-icon="sym_o_download" @submit="submit">
65
- <q-field label="Roles" stack-label>
65
+ <l-field label="Roles" stack-label>
66
66
  <q-option-group type="checkbox" :options="roles" v-model="obj.roles" inline>
67
67
  </q-option-group>
68
- </q-field>
68
+ </l-field>
69
69
  </l-form>
70
70
 
71
71
 
@@ -2,11 +2,7 @@
2
2
  import { list, m } from '../../'
3
3
  import { useRouter } from "vue-router"
4
4
 
5
- let users = await list("User", {
6
- fields: [
7
- "user_id", "username", "name", "roles"
8
- ]
9
- });
5
+ let { data: users } = await list("User", null, ["user_id", "username", "name", "roles"]);
10
6
 
11
7
  let columns = [
12
8
  {
@@ -44,7 +40,6 @@ const onCickView = async (id) => {
44
40
  </script>
45
41
  <template>
46
42
  <l-page>
47
-
48
43
  <q-table flat :columns="columns" :rows="users">
49
44
  <template #body-cell-view="props">
50
45
  <q-td :props="props">
@@ -1,5 +1,5 @@
1
1
  <script setup>
2
- import { ref, computed, inject, reactive } from 'vue';
2
+ import { ref, reactive } from 'vue';
3
3
  import { m, q } from '../../'
4
4
  import { Notify } from 'quasar';
5
5
  const app = await q("app", ["languages"])
@@ -42,11 +42,10 @@ const submit = async () => {
42
42
  <template>
43
43
  <l-page>
44
44
  <l-form @submit="submit">
45
- <q-field label="Roles" stack-label>
45
+ <l-field label="Roles" stack-label>
46
46
  <q-option-group type="checkbox" :options="roles" v-model="obj.roles" inline>
47
47
  </q-option-group>
48
- </q-field>
49
-
48
+ </l-field>
50
49
  </l-form>
51
50
 
52
51
  </l-page>
@@ -58,10 +58,10 @@ roles = roles.map((role) => {
58
58
 
59
59
  <l-input label="Default page" v-model="obj.default_page"></l-input>
60
60
 
61
- <q-field label="Roles" stack-label>
61
+ <l-field label="Roles" stack-label>
62
62
  <q-option-group type="checkbox" :options="roles" v-model="obj.roles" inline>
63
63
  </q-option-group>
64
- </q-field>
64
+ </l-field>
65
65
  </l-col>
66
66
  </l-row>
67
67
  </l-form>
@@ -4,7 +4,7 @@ import getModelColumns from "../../lib/getModelColumns";
4
4
  const onRequest = async (request) => {
5
5
  request.loadObjects("User", { status: status.value });
6
6
  };
7
- const columns = getModelColumns("User", ["username", "first_name", "label_name", "email", "phone", "join_date", "status"]);
7
+ const columns = getModelColumns("User", [ "username", "first_name", "label_name", "email", "phone", "join_date", "status"]);
8
8
  const status = ref("0");
9
9
  </script>
10
10
 
@@ -1,6 +1,50 @@
1
1
  <script setup>
2
- import { q } from '../../'
3
- const my = await q("my", ["user_id", "username", "first_name", "last_name", "email", "phone", "roles", "addr1", "addr2", "addr3", "join_date"])
2
+ import { q, getModelColumns } from '../../'
3
+ import { getGQLFields } from '#imports'
4
+ import { toQuery } from '@hostlink/light';
5
+
6
+ const { my } = await q(
7
+ {
8
+ my: ["user_id", "username", "first_name", "last_name", "email", "phone", "roles", "addr1", "addr2", "addr3", "join_date", {
9
+ userLog: {
10
+ __args: {
11
+ sort: "userlog_id:desc"
12
+ },
13
+ data: {
14
+ __args: {
15
+ limit: 10
16
+ },
17
+ ...toQuery(getGQLFields('UserLog', ['login_dt', 'result', "user_agent"]))
18
+ }
19
+ },
20
+ eventLog: {
21
+ __args: {
22
+ sort: "eventlog_id:desc"
23
+ },
24
+ data: {
25
+ __args: {
26
+ limit: 10
27
+ },
28
+ ...toQuery(getGQLFields('EventLog', ['class', 'id', 'action', "created_time"]))
29
+ }
30
+ }
31
+ }]
32
+ }
33
+ )
34
+
35
+ const userlogColumns = getModelColumns('UserLog', ['login_dt', 'result', 'user_agent']);
36
+ //remove all searchable
37
+ userlogColumns.forEach(col => {
38
+ col.searchable = false;
39
+ })
40
+
41
+
42
+ const eventLogCols = getModelColumns('EventLog', ['class', 'action', 'created_time']);
43
+ //remove all searchable
44
+ eventLogCols.forEach(col => {
45
+ col.searchable = false;
46
+ })
47
+
4
48
  </script>
5
49
  <template>
6
50
  <l-page title="User profile">
@@ -8,18 +52,32 @@ const my = await q("my", ["user_id", "username", "first_name", "last_name", "ema
8
52
  <l-btn icon="sym_o_key" to="update-password" label="Update password" />
9
53
  <l-btn icon="sym_o_key" to="two-factor-auth" label="Two factor auth" />
10
54
  </template>
11
- <l-card>
12
- <l-list>
13
- <l-item label="Username">{{ my.username }}</l-item>
14
- <l-item label="First name">{{ my.first_name }}</l-item>
15
- <l-item label="Last name">{{ my.last_name }}</l-item>
16
- <l-item label="Email">{{ my.email }}</l-item>
17
- <l-item label="Phone">{{ my.phone }}</l-item>
18
- <l-item label="Address">{{ my.addr1 }} {{ my.addr2 }} {{ my.addr3 }}</l-item>
19
- <l-item label="Join date">{{ my.join_date }}</l-item>
20
- <l-item label="Roles">{{ my.roles.join(",") }}</l-item>
21
- </l-list>
22
- </l-card>
55
+
56
+ <div class="q-gutter-md q-mt-md">
57
+ <l-card>
58
+ <l-list>
59
+ <l-item label="Username">{{ my.username }}</l-item>
60
+ <l-item label="First name">{{ my.first_name }}</l-item>
61
+ <l-item label="Last name">{{ my.last_name }}</l-item>
62
+ <l-item label="Email">{{ my.email }}</l-item>
63
+ <l-item label="Phone">{{ my.phone }}</l-item>
64
+ <l-item label="Address">{{ my.addr1 }} {{ my.addr2 }} {{ my.addr3 }}</l-item>
65
+ <l-item label="Join date">{{ my.join_date }}</l-item>
66
+ <l-item label="Roles">{{ my.roles.join(",") }}</l-item>
67
+ </l-list>
68
+ </l-card>
69
+
70
+ <l-card title="User Log">
71
+ <l-table :rows="my.userLog.data" :columns="userlogColumns" searchable :rows-per-page-options="[0]">
72
+ </l-table>
73
+ </l-card>
74
+
75
+ <l-card title="Event Log">
76
+ <l-table :rows="my.eventLog.data" :columns="eventLogCols" searchable :rows-per-page-options="[0]">
77
+ </l-table>
78
+ </l-card>
79
+ </div>
80
+
23
81
 
24
82
  </l-page>
25
83
  </template>
@@ -12,10 +12,14 @@ import { useLight } from "./index.mjs";
12
12
  import TypeUser from "./types/User.mjs";
13
13
  import TypeUserLog from "./types/UserLog.mjs";
14
14
  import TypeSystemValue from "./types/SystemValue.mjs";
15
+ import TypeMailLog from "./types/MailLog.mjs";
16
+ import TypeEventLog from "./types/EventLog.mjs";
15
17
  export default defineNuxtPlugin((nuxtApp) => {
16
18
  defineModel("User", TypeUser);
17
19
  defineModel("UserLog", TypeUserLog);
18
20
  defineModel("SystemValue", TypeSystemValue);
21
+ defineModel("MailLog", TypeMailLog);
22
+ defineModel("EventLog", TypeEventLog);
19
23
  nuxtApp.vueApp.config.errorHandler = (error) => {
20
24
  console.log(error);
21
25
  const light = useLight();
@@ -0,0 +1,33 @@
1
+ declare const _default: {
2
+ eventlog_id: {
3
+ label: string;
4
+ sortable: boolean;
5
+ searchable: boolean;
6
+ };
7
+ class: {
8
+ label: string;
9
+ sortable: boolean;
10
+ searchable: boolean;
11
+ };
12
+ id: {
13
+ label: string;
14
+ sortable: boolean;
15
+ searchable: boolean;
16
+ };
17
+ action: {
18
+ label: string;
19
+ sortable: boolean;
20
+ searchable: boolean;
21
+ };
22
+ created_time: {
23
+ label: string;
24
+ sortable: boolean;
25
+ searchable: boolean;
26
+ };
27
+ username: {
28
+ label: string;
29
+ sortable: boolean;
30
+ searchable: boolean;
31
+ };
32
+ };
33
+ export default _default;
@@ -0,0 +1,32 @@
1
+ export default {
2
+ eventlog_id: {
3
+ label: "EventLog ID",
4
+ sortable: true,
5
+ searchable: true
6
+ },
7
+ class: {
8
+ label: "Class",
9
+ sortable: true,
10
+ searchable: true
11
+ },
12
+ id: {
13
+ label: "ID",
14
+ sortable: true,
15
+ searchable: true
16
+ },
17
+ action: {
18
+ label: "Action",
19
+ sortable: true,
20
+ searchable: true
21
+ },
22
+ created_time: {
23
+ label: "Created time",
24
+ sortable: true,
25
+ searchable: true
26
+ },
27
+ username: {
28
+ label: "Username",
29
+ sortable: true,
30
+ searchable: true
31
+ }
32
+ };
@@ -0,0 +1,30 @@
1
+ declare const _default: {
2
+ maillog_id: {
3
+ label: string;
4
+ sortable: boolean;
5
+ searchable: boolean;
6
+ searchType: string;
7
+ };
8
+ from: {
9
+ label: string;
10
+ sortable: boolean;
11
+ searchable: boolean;
12
+ };
13
+ to: {
14
+ label: string;
15
+ sortable: boolean;
16
+ searchable: boolean;
17
+ };
18
+ subject: {
19
+ label: string;
20
+ sortable: boolean;
21
+ searchable: boolean;
22
+ };
23
+ created_time: {
24
+ label: string;
25
+ sortable: boolean;
26
+ searchable: boolean;
27
+ searchType: string;
28
+ };
29
+ };
30
+ export default _default;
@@ -0,0 +1,29 @@
1
+ export default {
2
+ maillog_id: {
3
+ label: "ID",
4
+ sortable: true,
5
+ searchable: true,
6
+ searchType: "number"
7
+ },
8
+ from: {
9
+ label: "From",
10
+ sortable: true,
11
+ searchable: true
12
+ },
13
+ to: {
14
+ label: "To",
15
+ sortable: true,
16
+ searchable: true
17
+ },
18
+ subject: {
19
+ label: "Subject",
20
+ sortable: true,
21
+ searchable: true
22
+ },
23
+ created_time: {
24
+ label: "Created time",
25
+ sortable: true,
26
+ searchable: true,
27
+ searchType: "date"
28
+ }
29
+ };
@@ -40,4 +40,12 @@ export default {
40
40
  return ["Active", "Inactive"][value];
41
41
  }
42
42
  }
43
+ /* ,
44
+ test: {
45
+ label: "Test",
46
+ name: "_test",
47
+ to: (row: any) => `/User/${row.user_id}/view`,
48
+ gqlField: ["user_id", "first_name"],
49
+ field: (row: any) => row.first_name,
50
+ } */
43
51
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hostlink/nuxt-light",
3
- "version": "0.0.90",
3
+ "version": "0.0.92",
4
4
  "description": "HostLink Nuxt Light Framework",
5
5
  "repository": "@hostlink/nuxt-light",
6
6
  "license": "MIT",
@@ -1 +0,0 @@
1
- export default function listData(name: string, props?: any, fields?: Array<string | Object> | Object): Promise<any>;
@@ -1,33 +0,0 @@
1
- import { query, toQuery } from "@hostlink/light";
2
- export default async function listData(name, props = {}, fields = []) {
3
- let json = {};
4
- if (props.sort) {
5
- json.__args = json.__args || {};
6
- json.__args.sort = props.sort;
7
- }
8
- if (props.filters) {
9
- json.__args = json.__args || {};
10
- json.__args.filters = props.filters;
11
- }
12
- json.data = {};
13
- if (props.offset) {
14
- json.data.__args = json.data.__args || {};
15
- json.data.__args.offset = props.offset;
16
- }
17
- if (props.limit) {
18
- json.data.__args = json.data.__args || {};
19
- json.data.__args.limit = props.limit;
20
- }
21
- Object.entries(toQuery(fields)).forEach(([key, value]) => {
22
- json.data[key] = value;
23
- });
24
- json.meta = {
25
- total: true,
26
- key: true,
27
- name: true
28
- };
29
- const q = {};
30
- q[`list${name}`] = json;
31
- let data = await query(q);
32
- return data[`list${name}`];
33
- }