@hostlink/nuxt-light 1.8.1 → 1.8.3

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": "1.8.1"
4
+ "version": "1.8.3"
5
5
  }
@@ -144,7 +144,7 @@ const getDiffHtml = (diffs) => {
144
144
 
145
145
  <q-checkbox label="Show changed only" v-model="showOnlyDelta" :color="$light.color"></q-checkbox>
146
146
 
147
- <q-btn-toggle class="q-mx-md" v-model="outputFormat" :toggle-color="$light.color" :options="[
147
+ <q-btn-toggle class="q-mx-md" v-model="outputFormat" :toggle-color="$light.color" :options="[
148
148
  { label: 'side-by-side', value: 'side-by-side' }, { label: 'line-by-line', value: 'line-by-line' }
149
149
  ]" />
150
150
  <q-space />
@@ -3,6 +3,9 @@ import { useLight, q, m } from '#imports'
3
3
  import { ref, computed } from 'vue'
4
4
  import { type QCardProps } from 'quasar';
5
5
 
6
+ const minimized = defineModel<boolean>("minimized", { default: false })
7
+ const maximized = defineModel<boolean>("maximized", { default: false })
8
+
6
9
  export interface LCardProps extends QCardProps {
7
10
  loading?: boolean;
8
11
  title?: string;
@@ -10,9 +13,9 @@ export interface LCardProps extends QCardProps {
10
13
  * Permission to access this card, if not granted, the card will not be shown, if the user is admin, a lock icon will be shown to allow the user to grant the permission
11
14
  */
12
15
  permission?: string
13
- fullscreenable?: boolean
14
16
  closeable?: boolean
15
- minimizable?: boolean
17
+ minimizable?: boolean,
18
+ maximizable?: boolean
16
19
 
17
20
  }
18
21
 
@@ -31,26 +34,16 @@ const attrs = computed(() => {
31
34
  return a;
32
35
  });
33
36
 
34
- const cl = computed(() => {
37
+ const barClass = computed(() => {
35
38
  const c = ["text-white"];
36
39
  const color = light.color;
37
40
  c.push(`bg-${color}`);
38
41
  return c;
39
42
  });
40
43
 
41
- const minimize = ref(false);
42
-
43
- const icon = computed(() => minimize.value ? "sym_o_add" : "sym_o_remove");
44
-
45
- const fullScreen = ref(false);
46
-
47
- const fullScreenIcon = computed(() => fullScreen.value ? "sym_o_fullscreen_exit" : "sym_o_fullscreen");
48
-
49
- const showBody = computed(() => !minimize.value || fullScreen.value);
50
-
51
44
  const showBar = computed(() => {
52
45
  if (props.closeable) return true;
53
- if (props.fullscreenable) return true;
46
+ if (props.maximizable) return true;
54
47
  if (props.minimizable) return true;
55
48
  if (props.title !== undefined) return true;
56
49
  if (showSecurity.value) return true;
@@ -115,9 +108,9 @@ const onUpdatePermission = async (role: any) => {
115
108
 
116
109
  </script>
117
110
  <template>
118
- <q-card v-bind="attrs" :class="{ 'fullscreen': fullScreen, 'no-margin': fullScreen }"
111
+ <q-card v-bind="attrs" :class="{ 'fullscreen': maximized, 'no-margin': maximized }"
119
112
  v-if="$light.isGranted(permission)" :dark="$q.dark.isActive">
120
- <q-bar :class="cl" v-if="showBar">
113
+ <q-bar :class="barClass" v-if="showBar">
121
114
  <div>{{ $t(title ?? "") }}</div>
122
115
  <q-space />
123
116
 
@@ -134,11 +127,13 @@ const onUpdatePermission = async (role: any) => {
134
127
  </q-menu>
135
128
  </q-btn>
136
129
 
137
- <q-btn dense flat :icon="icon" @click="minimize = !minimize" v-if="!fullScreen && minimizable" />
138
- <q-btn dense flat @click="fullScreen = !fullScreen" :icon="fullScreenIcon" v-if="fullscreenable" />
130
+ <q-btn dense flat :icon="minimized ? 'sym_o_add' : 'sym_o_remove'" @click="minimized = !minimized"
131
+ v-if="minimizable && !maximized" />
132
+ <q-btn dense flat @click="maximized = !maximized"
133
+ :icon="maximized ? 'sym_o_select_window_2' : 'sym_o_crop_square'" v-if="maximizable" />
139
134
  <q-btn dense flat icon="sym_o_close" v-close-popup v-if="closeable" />
140
135
  </q-bar>
141
- <template v-if="showBody">
136
+ <template v-if="!minimized || maximized">
142
137
  <slot></slot>
143
138
  </template>
144
139
 
@@ -6,6 +6,9 @@ import { t, q, useLight, GQLFieldBuilder, model } from '../';
6
6
  import { toQuery } from '@hostlink/light';
7
7
 
8
8
 
9
+ const minimized = defineModel<boolean>("minimized", { default: false })
10
+ const maximized = defineModel<boolean>("maximized", { default: false })
11
+
9
12
  // extends QTableColumn
10
13
  export interface LTableColumn extends QTableColumn {
11
14
  searchable?: boolean,
@@ -16,7 +19,8 @@ export interface LTableColumn extends QTableColumn {
16
19
  backgroundColor?: string | Function
17
20
  }
18
21
 
19
- const errors = ref<InstanceType<any>>([]);
22
+ const errors = ref<InstanceType<any>>([
23
+ ]);
20
24
 
21
25
  export interface LTableProps extends QTableProps {
22
26
  columns?: Array<LTableColumn>,
@@ -26,6 +30,8 @@ export interface LTableProps extends QTableProps {
26
30
  modelName?: string | null | undefined,
27
31
  searchable?: boolean | null | undefined,
28
32
  selected?: Array<any>,
33
+ maximizable?: boolean,
34
+ minimizable?: boolean,
29
35
  }
30
36
 
31
37
  const props = withDefaults(defineProps<LTableProps>(), {
@@ -43,6 +49,8 @@ const props = withDefaults(defineProps<LTableProps>(), {
43
49
  },
44
50
  fullscreen: false,
45
51
  searchable: false,
52
+ maximizable: false,
53
+ minimizable: false,
46
54
  selected: () => [],
47
55
  loadingLabel: "Loading...",
48
56
  noDataLabel: "No data available",
@@ -158,9 +166,6 @@ const validateData = () => {
158
166
 
159
167
  if (props.actions.includes("edit")) {
160
168
  if (rows.value.length > 0) {
161
-
162
-
163
-
164
169
  //get first row
165
170
  let row = rows.value[0];
166
171
  //check has primary key
@@ -375,7 +380,7 @@ const getFilterValue = () => {
375
380
 
376
381
 
377
382
  const onFilters = () => {
378
-
383
+
379
384
  //clone the filters
380
385
  onRequest({
381
386
  pagination: {
@@ -420,7 +425,6 @@ const attrs = computed(() => {
420
425
  bordered: light.getStyle("tableBorder"),
421
426
  separator: light.getStyle("tableSeparator"),
422
427
  },
423
- title: props.title,
424
428
  loadingLabel: t(props.loadingLabel),
425
429
  noDataLabel: t(props.noDataLabel),
426
430
  rowsPerPageOptions: props.rowsPerPageOptions,
@@ -496,93 +500,101 @@ const localSelected = computed({
496
500
  }
497
501
  });
498
502
 
503
+
499
504
  </script>
500
505
 
501
506
 
502
507
  <template>
503
- <template v-if="errors.length > 0">
504
- <div class="q-gutter-sm">
505
- <q-banner inline-actions v-for="e in errors" rounded class="bg-negative text-white">{{ e }}</q-banner>
506
- </div>
507
- </template>
508
-
509
- <q-table v-bind="attrs" :loading="loading" :rows="rows" ref="table" @request="onRequest" :columns="columns"
510
- v-model:pagination="pagination" :filter="filter" v-model:selected="localSelected">
511
-
512
- <template #header="props">
513
- <q-tr :props="props">
514
- <q-td v-if="selection != 'none'" auto-width>
515
- <q-checkbox v-model="props.selected" />
516
- </q-td>
517
- <q-th v-if="hasRowExpand" auto-width></q-th>
518
- <q-th v-if="hasActions" auto-width></q-th>
519
- <q-th v-for="col in props.cols" :key="col.name" :props="props">{{ col.label }}</q-th>
520
- </q-tr>
521
- </template>
508
+ <l-card flat bordered :maximizable="maximizable" :minimizable="minimizable" :title="title"
509
+ v-model:minimized="minimized" v-model:maximized="maximized">
522
510
 
523
- <template #body="props">
524
- <q-tr :props="props">
525
- <q-td v-if="selection != 'none'" auto-width>
526
- <q-checkbox v-model="props.selected" />
527
- </q-td>
528
- <q-td v-if="hasRowExpand" auto-width>
529
- <q-btn :class="{ 'text-grey-8': !isDark }" flat round dense
530
- :icon="props.expand ? 'sym_o_expand_more' : 'sym_o_expand_less'"
531
- @click="props.expand = !props.expand"></q-btn>
532
- </q-td>
533
511
 
534
- <q-td v-if="hasActions" auto-width>
535
- <div :class="{ 'text-grey-8': !isDark }" v-if="primaryKey">
536
-
537
- <l-view-btn v-if="actionView && props.row.canView"
538
- :to="`/${modelName}/${props.row[primaryKey]}/view`" />
539
-
540
- <l-edit-btn v-if="activeEdit && props.row.canUpdate"
541
- :to="`/${modelName}/${props.row[primaryKey]}/edit`" />
542
-
543
- <l-delete-btn v-if="actionDelete && props.row.canDelete"
544
- @submit="onDelete(props.row[primaryKey])"></l-delete-btn>
545
-
546
- <slot name="actions" v-bind="props"></slot>
547
- </div>
548
-
549
- </q-td>
512
+ <template v-if="errors.length > 0">
513
+ <div class="q-mb-sm">
514
+ <div class="q-gutter-sm">
515
+ <l-alert type="negative" v-for="e in errors">{{ e }}</l-alert>
516
+ </div>
517
+ </div>
518
+ </template>
550
519
 
551
- <template v-for="col in props.cols">
552
- <template v-if="ss.indexOf('body-cell-' + col.name) >= 0">
553
- <slot :name="'body-cell-' + col.name" v-bind="props"></slot>
520
+ <q-table v-bind="attrs" :loading="loading" :rows="rows" ref="table" @request="onRequest" :columns="columns"
521
+ v-model:pagination="pagination" :filter="filter" v-model:selected="localSelected">
522
+
523
+ <template #header="props">
524
+ <q-tr :props="props">
525
+ <q-td v-if="selection != 'none'" auto-width>
526
+ <q-checkbox v-model="props.selected" />
527
+ </q-td>
528
+ <q-th v-if="hasRowExpand" auto-width></q-th>
529
+ <q-th v-if="hasActions" auto-width></q-th>
530
+ <q-th v-for="col in props.cols" :key="col.name" :props="props">{{ col.label }}</q-th>
531
+ </q-tr>
532
+ </template>
533
+
534
+ <template #body="props">
535
+ <q-tr :props="props">
536
+ <q-td v-if="selection != 'none'" auto-width>
537
+ <q-checkbox v-model="props.selected" />
538
+ </q-td>
539
+ <q-td v-if="hasRowExpand" auto-width>
540
+ <q-btn :class="{ 'text-grey-8': !isDark }" flat round dense
541
+ :icon="props.expand ? 'sym_o_expand_more' : 'sym_o_expand_less'"
542
+ @click="props.expand = !props.expand"></q-btn>
543
+ </q-td>
544
+
545
+ <q-td v-if="hasActions" auto-width>
546
+ <div :class="{ 'text-grey-8': !isDark }" v-if="primaryKey">
547
+
548
+ <l-view-btn v-if="actionView && props.row.canView"
549
+ :to="`/${modelName}/${props.row[primaryKey]}/view`" />
550
+
551
+ <l-edit-btn v-if="activeEdit && props.row.canUpdate"
552
+ :to="`/${modelName}/${props.row[primaryKey]}/edit`" />
553
+
554
+ <l-delete-btn v-if="actionDelete && props.row.canDelete"
555
+ @submit="onDelete(props.row[primaryKey])"></l-delete-btn>
556
+
557
+ <slot name="actions" v-bind="props"></slot>
558
+ </div>
559
+
560
+ </q-td>
561
+
562
+ <template v-for="col in props.cols">
563
+ <template v-if="ss.indexOf('body-cell-' + col.name) >= 0">
564
+ <slot :name="'body-cell-' + col.name" v-bind="props"></slot>
565
+ </template>
566
+ <template v-else>
567
+ <q-td :key="col.name" :props="props" :auto-width="col.autoWidth ?? false"
568
+ :style="getCellStyle(col, props.row)" :class="getCellClass(col, props.row)"><template
569
+ v-if="col.to" class="bg-primary">
570
+ <l-link :to="col.to(props.row)">{{ col.value }}</l-link>
571
+ </template><template v-else>{{ col.value }}</template></q-td>
572
+ </template>
554
573
  </template>
555
- <template v-else>
556
- <q-td :key="col.name" :props="props" :auto-width="col.autoWidth ?? false"
557
- :style="getCellStyle(col, props.row)" :class="getCellClass(col, props.row)"><template
558
- v-if="col.to" class="bg-primary">
559
- <l-link :to="col.to(props.row)">{{ col.value }}</l-link>
560
- </template><template v-else>{{ col.value }}</template></q-td>
574
+ </q-tr>
575
+ <q-tr v-show="props.expand" :props="props">
576
+ <q-td colspan="100%">
577
+ <slot name="row-expand" v-bind="props"></slot>
578
+ </q-td>
579
+ </q-tr>
580
+ </template>
581
+
582
+
583
+ <template #top-right="props" v-if="searchable">
584
+ <q-input v-if="searchable" outlined dense debounce="300" v-model="filter" :placeholder="$t('Search')"
585
+ :color="$light.color">
586
+ <template v-slot:append>
587
+ <q-icon name="search" />
561
588
  </template>
562
- </template>
563
- </q-tr>
564
- <q-tr v-show="props.expand" :props="props">
565
- <q-td colspan="100%">
566
- <slot name="row-expand" v-bind="props"></slot>
567
- </q-td>
568
- </q-tr>
569
- </template>
589
+ </q-input>
570
590
 
571
591
 
572
- <template #top-right="props" v-if="fullscreen || searchable">
573
- <q-input v-if="searchable" outlined dense debounce="300" v-model="filter" :placeholder="$t('Search')"
574
- :color="$light.color">
575
- <template v-slot:append>
576
- <q-icon name="search" />
577
- </template>
578
- </q-input>
579
592
 
580
- <q-btn v-if="fullscreen" flat round dense :icon="props.inFullscreen ? 'fullscreen_exit' : 'fullscreen'"
581
- @click="props.toggleFullscreen" class="q-ml-md" />
582
- </template>
593
+
594
+ </template>
583
595
 
584
596
 
585
- <!-- template v-for="col in toColumns" v-slot:[col.slot_name]="props">
597
+ <!-- template v-for="col in toColumns" v-slot:[col.slot_name]="props">
586
598
  <q-td :props="props">
587
599
  <l-link :to="col.to(props.row)">
588
600
  {{ col.field(props.row) }}
@@ -591,44 +603,46 @@ const localSelected = computed({
591
603
  </template -->
592
604
 
593
605
 
594
- <template #top-row="props" v-if="hasSearch && isServerSide">
595
- <q-tr>
596
- <q-td v-if="selection != 'none'" auto-width />
597
- <q-td v-if="hasRowExpand" auto-width />
598
- <q-td v-if="hasActions" auto-width />
599
- <q-td v-for="col in props.cols">
600
- <template v-if="col.searchable">
606
+ <template #top-row="props" v-if="hasSearch && isServerSide">
607
+ <q-tr>
608
+ <q-td v-if="selection != 'none'" auto-width />
609
+ <q-td v-if="hasRowExpand" auto-width />
610
+ <q-td v-if="hasActions" auto-width />
611
+ <q-td v-for="col in props.cols">
612
+ <template v-if="col.searchable">
601
613
 
602
- <template v-if="col.searchType == 'number'">
603
- <q-input style="min-width: 80px;" dense clearable filled square
604
- v-model.number="filters[col.name]" @keydown.enter.prevent="onFilters" @clear="onFilters"
605
- mask="##########" enterkeyhint="search"></q-input>
606
- </template>
614
+ <template v-if="col.searchType == 'number'">
615
+ <q-input style="min-width: 80px;" dense clearable filled square
616
+ v-model.number="filters[col.name]" @keydown.enter.prevent="onFilters"
617
+ @clear="onFilters" mask="##########" enterkeyhint="search"></q-input>
618
+ </template>
607
619
 
608
- <template v-if="col.searchType == 'select'">
609
- <q-select dense clearable filled square v-model="filters[col.name]"
610
- @update:model-value="onFilters" options-dense :options="col.searchOptions" emit-value
611
- map-options :multiple="col.searchMultiple" :color="$light.color" />
620
+ <template v-if="col.searchType == 'select'">
621
+ <q-select dense clearable filled square v-model="filters[col.name]"
622
+ @update:model-value="onFilters" options-dense :options="col.searchOptions"
623
+ emit-value map-options :multiple="col.searchMultiple" :color="$light.color" />
612
624
 
613
- </template>
625
+ </template>
614
626
 
615
627
 
616
- <template v-if="col.searchType == 'date'">
617
- <l-date-picker dense clearable filled square :outlined="false" hide-bottom-space
618
- v-model="filters[col.name]" @update:model-value="onFilters" range @clear="onFilters" />
619
- </template>
628
+ <template v-if="col.searchType == 'date'">
629
+ <l-date-picker dense clearable filled square :outlined="false" hide-bottom-space
630
+ v-model="filters[col.name]" @update:model-value="onFilters" range
631
+ @clear="onFilters" />
632
+ </template>
620
633
 
621
- <template v-if="!col.searchType">
622
- <q-input style="min-width: 80px;" dense clearable filled square v-model="filters[col.name]"
623
- @keydown.enter.prevent="onFilters" @clear="onFilters" enterkeyhint="search"
624
- :color="$light.color"></q-input>
634
+ <template v-if="!col.searchType">
635
+ <q-input style="min-width: 80px;" dense clearable filled square
636
+ v-model="filters[col.name]" @keydown.enter.prevent="onFilters" @clear="onFilters"
637
+ enterkeyhint="search" :color="$light.color"></q-input>
625
638
 
626
- </template>
639
+ </template>
627
640
 
628
- </template>
629
- </q-td>
630
- </q-tr>
631
- </template>
641
+ </template>
642
+ </q-td>
643
+ </q-tr>
644
+ </template>
632
645
 
633
- </q-table>
646
+ </q-table>
647
+ </l-card>
634
648
  </template>
@@ -48,7 +48,7 @@ const localValue = computed({
48
48
  v-model="localValue">
49
49
  <q-tab v-for="tab in tabContents" :label="$t(tab.label)" :name="tab.name"></q-tab>
50
50
  </q-tabs>
51
- <q-tab-panels v-model="localValue">
51
+ <q-tab-panels v-model="localValue" keep-alive >
52
52
  <q-tab-panel v-for="tab in tabContents" :name="tab.name">
53
53
  <component :is="tab.content.default"></component>
54
54
  </q-tab-panel>
@@ -1,11 +1,13 @@
1
1
  <script setup>
2
2
  import { model } from "#imports"
3
+ import { ref } from 'vue'
3
4
  const columns = model('EventLog').columns(['eventlog_id', 'class', 'id', 'action', 'created_time', 'username'])
4
5
  </script>
5
6
  <template>
6
7
  <l-page>
7
- <l-table fullscreen @request="$event.loadObjects('EventLog')" :columns="columns" sort-by="eventlog_id:desc"
8
- :actions="['view']">
8
+
9
+ <l-table @request="$event.loadObjects('EventLog')" :columns="columns"
10
+ sort-by="eventlog_id:desc" :actions="['view']">
9
11
 
10
12
  </l-table>
11
13
  </l-page>
@@ -12,11 +12,10 @@ let columns = [
12
12
  name: "username",
13
13
  field: "username",
14
14
  align: "left",
15
-
16
15
  },
17
16
  {
18
17
  name: "name",
19
- label: "姓名",
18
+ label: "Name",
20
19
  field: "name",
21
20
  align: "left",
22
21
  }, {
@@ -35,7 +34,10 @@ const router = useRouter();
35
34
  const onCickView = async (id) => {
36
35
  try {
37
36
  if (await m("viewAs", { user_id: id })) {
38
- router.back();
37
+
38
+ //redirect to last path
39
+ window.location.reload();
40
+
39
41
  }
40
42
  } catch (e) {
41
43
  Dialog.create({
@@ -59,10 +61,10 @@ const filtered = computed(() => {
59
61
  })
60
62
  </script>
61
63
  <template>
62
- <l-page>
63
- <p>
64
+ <l-page class="q-gutter-md">
65
+ <q-banner >
64
66
  Use this page to view the system as another user. This is useful for testing permissions.
65
- </p>
67
+ </q-banner>
66
68
 
67
69
  <q-table flat :columns="columns" :rows="filtered" :rows-per-page-options="[0]" dense>
68
70
  <template v-slot:top-right>
@@ -3,11 +3,9 @@ import { ref } from 'vue'
3
3
  import { model } from "#imports"
4
4
  const onRequest = async (request) => {
5
5
  request.loadObjects("User", { status: status.value });
6
- //request.loadObjects("User");
7
6
  };
8
7
  const columns = model("User").columns(["username", "first_name", "label_name", "email", "phone", "join_date", "status","has2FA"]);
9
8
  const status = ref("0");
10
- const selected = ref([]);
11
9
  </script>
12
10
 
13
11
  <template>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hostlink/nuxt-light",
3
- "version": "1.8.1",
3
+ "version": "1.8.3",
4
4
  "description": "HostLink Nuxt Light Framework",
5
5
  "repository": "@hostlink/nuxt-light",
6
6
  "license": "MIT",