@hostlink/nuxt-light 0.0.106 → 0.0.108

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.106"
4
+ "version": "0.0.108"
5
5
  }
@@ -10,6 +10,7 @@ const props = defineProps({
10
10
  type: String,
11
11
  default: null
12
12
  }
13
+
13
14
  });
14
15
 
15
16
 
@@ -174,7 +174,12 @@ onMounted(() => {
174
174
  <template>
175
175
  <q-card bordered flat style="min-width:360px;max-width: 400px;" class="fixed-center">
176
176
  <q-card-section>
177
- <q-img :src="light.getCompanyLogo()" class="full-width" />
177
+ <q-img :src="light.getCompanyLogo()" class="full-width">
178
+ <template v-slot:error>
179
+ <q-img src="https://raw.githubusercontent.com/HostLink/.github/master/profile/logo.webp" class="full-width" />
180
+ </template>
181
+ </q-img>
182
+
178
183
  <div class="text-h6">
179
184
  {{ light.getCompany() }}
180
185
  </div>
@@ -1,8 +1,19 @@
1
1
  <script setup lang="ts">
2
- import { useQuasar, QTable, is } from 'quasar';
2
+ import { useQuasar, QTable } from 'quasar';
3
3
  import { ref, computed, onMounted, useSlots, useAttrs } from "vue";
4
4
  import { t, q, useLight, GQLFieldBuilder, model } from '../';
5
5
  import { toQuery } from '@hostlink/light';
6
+ import { type QTableColumn } from 'quasar';
7
+
8
+ // extends QTableColumn
9
+ export interface LTableColumn extends QTableColumn {
10
+ searchable?: boolean,
11
+ searchType?: string,
12
+ searchOptions?: Array<any> | Function,
13
+ searchMultiple?: boolean,
14
+ gqlField?: string | Array<string> | Object,
15
+ backgroundColor?: string | Function
16
+ }
6
17
 
7
18
  const errors = ref<InstanceType<any>>([]);
8
19
 
@@ -13,18 +24,7 @@ const props = defineProps({
13
24
  default: false
14
25
  },
15
26
  columns: {
16
- type: Array<{
17
- label: string,
18
- name: string,
19
- align?: "left" | "right" | "center" | undefined,
20
- sortable?: boolean,
21
- searchable?: boolean,
22
- searchType?: string,
23
- searchOptions?: Array<any> | Function,
24
- searchMultiple?: boolean,
25
- field?: string | Object,
26
- gqlField?: string | Array<string> | Object,
27
- }>
27
+ type: Array<LTableColumn>
28
28
  },
29
29
  actions: {
30
30
  type: Array,
@@ -109,25 +109,7 @@ if (props.columns) {
109
109
  }
110
110
  }
111
111
 
112
- const renderColumns = computed(() => {
113
- if (props.columns == undefined) return undefined;
114
-
115
- let cols = [];
116
- if (props.actions.length > 0) {
117
- cols = [
118
- {
119
- name: "_actions",
120
- align: "left"
121
- },
122
- ...props.columns ?? []
123
- ]
124
- } else {
125
- cols = props.columns;
126
- }
127
- return cols;
128
- })
129
-
130
- interface LTableRequest {
112
+ export interface LTableRequest {
131
113
  sort: string,
132
114
  fields: Array<string>,
133
115
  gql: {
@@ -481,8 +463,44 @@ const isDark = computed(() => {
481
463
  return light.theme == "dark";
482
464
  })
483
465
 
466
+ const hasRowExpand = computed(() => {
467
+ return ss.indexOf("row-expand") >= 0;
468
+ })
469
+
470
+ const hasActions = computed(() => {
471
+ return props.actions.length > 0;
472
+ })
473
+
474
+ const getCellStyle = (col: any, row: any) => {
475
+ const style: any = {};
476
+ if (col.backgroundColor) {
477
+ if (typeof col.backgroundColor == "function") {
478
+ style.backgroundColor = col.backgroundColor(row);
479
+ } else {
480
+ style.backgroundColor = col.backgroundColor;
481
+ }
482
+
483
+ }
484
+ return style;
485
+ }
486
+
487
+ const getCellClass = (col: any, row: any) => {
488
+ const cl: any = [];
489
+
490
+ if (col.cellClass) {
491
+ if (typeof col.cellClass == "function") {
492
+ cl.push(col.cellClass(row));
493
+ } else {
494
+ cl.push(col.cellClass);
495
+ }
496
+
497
+ }
498
+ return cl;
499
+ }
500
+
484
501
  </script>
485
502
 
503
+
486
504
  <template>
487
505
  <template v-if="errors.length > 0">
488
506
  <div class="q-gutter-sm">
@@ -507,9 +525,68 @@ const isDark = computed(() => {
507
525
 
508
526
 
509
527
  <q-table v-bind="attrs" :row-key="rowKey" :loading="loading" :rows="rows" ref="table" @request="onRequest"
510
- :rows-per-page-label="$t(props.rowsPerPageLabel)" :columns="renderColumns"
511
- :rows-per-page-options="rowsPerPageOptions" :selection="selection" v-model:pagination="pagination" :filter="filter"
512
- :no-data-label="$t('No data available')" :loading-label="$t('Loading...')">
528
+ :rows-per-page-label="$t(props.rowsPerPageLabel)" :columns="columns" :rows-per-page-options="rowsPerPageOptions"
529
+ :selection="selection" v-model:pagination="pagination" :filter="filter" :no-data-label="$t('No data available')"
530
+ :loading-label="$t('Loading...')">
531
+
532
+
533
+ <!-- template v-for="s in ss" v-slot:[s]="props">
534
+ <slot :name="s" v-bind="props"></slot>
535
+ </template -->
536
+
537
+ <template #header="props">
538
+ <q-tr :props="props">
539
+ <q-th v-if="hasRowExpand" auto-width></q-th>
540
+ <q-th v-if="hasActions" auto-width></q-th>
541
+ <q-th v-for="col in props.cols" :key="col.name" :props="props">{{ col.label }}</q-th>
542
+ </q-tr>
543
+ </template>
544
+
545
+ <template #body="props">
546
+ <q-tr :props="props">
547
+ <q-td v-if="hasRowExpand" auto-width>
548
+ <q-btn :class="{ 'text-grey-8': !isDark }" flat round dense
549
+ :icon="props.expand ? 'sym_o_expand_more' : 'sym_o_expand_less'"
550
+ @click="props.expand = !props.expand"></q-btn>
551
+ </q-td>
552
+
553
+ <q-td v-if="hasActions" auto-width>
554
+ <div :class="{ 'text-grey-8': !isDark }">
555
+
556
+ <l-view-btn v-if="actionView && props.row.canView"
557
+ :to="`/${modelName}/${props.row[primaryKey]}/view`" />
558
+
559
+ <l-edit-btn v-if="activeEdit && props.row.canUpdate"
560
+ :to="`/${modelName}/${props.row[primaryKey]}/edit`" />
561
+
562
+ <l-delete-btn v-if="actionDelete && props.row.canDelete"
563
+ @submit="onDelete(props.row[primaryKey])"></l-delete-btn>
564
+
565
+ <slot name="actions" v-bind="props"></slot>
566
+ </div>
567
+
568
+ </q-td>
569
+
570
+ <template v-for="col in props.cols">
571
+ <template v-if="ss.indexOf('body-cell-' + col.name) >= 0">
572
+ <slot :name="'body-cell-' + col.name" v-bind="props"></slot>
573
+ </template>
574
+ <template v-else>
575
+ <q-td :key="col.name" :props="props" :auto-width="col.autoWidth ?? false"
576
+ :style="getCellStyle(col, props.row)" :class="getCellClass(col, props.row)"><template
577
+ v-if="col.to" class="bg-primary">
578
+ <l-link :to="col.to(props.row)">{{ col.value }}</l-link>
579
+ </template><template v-else>{{ col.value }}</template></q-td>
580
+ </template>
581
+ </template>
582
+ </q-tr>
583
+ <q-tr v-show="props.expand" :props="props">
584
+ <q-td colspan="100%">
585
+ <slot name="row-expand" v-bind="props"></slot>
586
+ </q-td>
587
+ </q-tr>
588
+ </template>
589
+
513
590
 
514
591
  <template #top-right="props" v-if="fullscreen || searchable">
515
592
  <q-input v-if="searchable" outlined dense debounce="300" v-model="filter" placeholder="Search">
@@ -522,44 +599,21 @@ const isDark = computed(() => {
522
599
  @click="props.toggleFullscreen" class="q-ml-md" />
523
600
  </template>
524
601
 
525
- <template v-for="s in ss" v-slot:[s]="props">
526
- <slot :name="s" v-bind="props"></slot>
527
- </template>
528
602
 
529
- <template v-for="col in toColumns" v-slot:[col.slot_name]="props">
603
+ <!-- template v-for="col in toColumns" v-slot:[col.slot_name]="props">
530
604
  <q-td :props="props">
531
605
  <l-link :to="col.to(props.row)">
532
606
  {{ col.field(props.row) }}
533
607
  </l-link>
534
608
  </q-td>
535
- </template>
536
-
537
- <template #body-cell-_actions="props">
538
- <q-td :props="props" auto-width>
539
- <div :class="{ 'text-grey-8': !isDark }">
540
-
541
- <l-view-btn v-if="actionView && props.row.canView"
542
- :to="`/${modelName}/${props.row[primaryKey]}/view`" />
543
-
544
- <l-edit-btn v-if="activeEdit && props.row.canUpdate"
545
- :to="`/${modelName}/${props.row[primaryKey]}/edit`" />
546
-
547
- <l-delete-btn v-if="actionDelete && props.row.canDelete"
548
- @submit="onDelete(props.row[primaryKey])"></l-delete-btn>
549
-
550
- <slot name="actions" v-bind="props"></slot>
551
- </div>
552
- </q-td>
553
- </template>
554
-
555
-
609
+ </template -->
556
610
 
557
611
 
558
612
  <template #top-row="props" v-if="hasSearch && isServerSide">
559
613
  <q-tr>
560
- <q-td v-if="selection != 'none'" auto-width>
561
-
562
- </q-td>
614
+ <q-td v-if="selection != 'none'" auto-width />
615
+ <q-td v-if="hasRowExpand" auto-width />
616
+ <q-td v-if="hasActions" auto-width />
563
617
  <q-td v-for="col in props.cols">
564
618
  <template v-if="col.searchable">
565
619
 
@@ -570,7 +624,8 @@ const isDark = computed(() => {
570
624
 
571
625
  <template v-if="col.searchType == 'select'">
572
626
  <q-select dense v-model="filters[col.name]" @update:model-value="onFilters" clearable
573
- :options="col.searchOptions" emit-value map-options :multiple="col.searchMultiple" />
627
+ options-dense :options="col.searchOptions" emit-value map-options
628
+ :multiple="col.searchMultiple" />
574
629
 
575
630
  </template>
576
631
 
@@ -0,0 +1,50 @@
1
+ <script setup>
2
+ import { useSlots } from "vue";
3
+
4
+ const slots = useSlots();
5
+
6
+ const ss = Object.entries(slots).map(([key, value]) => {
7
+ return key;
8
+ });
9
+
10
+
11
+
12
+ </script>
13
+ <template>
14
+ <q-table row-key="name">
15
+
16
+ <template #header="props">
17
+
18
+
19
+ <q-tr :props="props">
20
+
21
+ <q-th auto-width key="_expand" :props="{
22
+ colsMap: {
23
+ _expand: {
24
+ align: 'right'
25
+ }
26
+ }
27
+ }">1</q-th>
28
+
29
+ <q-th auto-width key="_actions">act</q-th>
30
+ <q-th v-for="col in props.cols" :key="col.name" :props="props">{{ col.label }}</q-th>
31
+ </q-tr>
32
+ </template>
33
+
34
+ <template #body="props">
35
+
36
+ <q-tr :props="props">
37
+ <template v-for="col in props.cols">
38
+ <slot v-if="slots['body-cell-' + col.name]" :name="'body-cell-' + col.name" v-bind="props"
39
+ :key="col.name"></slot>
40
+ <template v-else>
41
+ <q-td :props="props" :key="col.name">
42
+ {{ col.name }}
43
+ {{ col.value }}</q-td>
44
+ </template>
45
+ </template>
46
+ </q-tr>
47
+
48
+ </template>
49
+ </q-table>
50
+ </template>
@@ -1,10 +1,7 @@
1
- declare const _default: (name: string) => {
2
- name: string;
3
- update(id: number, data: Object): Promise<any>;
4
- delete(id: number): Promise<any>;
5
- add(data: Object): Promise<any>;
6
- fields(fields: string[]): import("@hostlink/light").ModelField[];
7
- get(filters: any, fields: import("@hostlink/light").Fields): Promise<any>;
8
- list(filters: any, fields: import("@hostlink/light").Fields): Promise<any>;
9
- };
1
+ import { model } from "@hostlink/light";
2
+ import type { LTableColumn } from "../components/l-table.vue";
3
+ interface LModel extends ReturnType<typeof model> {
4
+ columns(fields: string[]): Array<LTableColumn>;
5
+ }
6
+ declare const _default: (name: string) => LModel;
10
7
  export default _default;
@@ -15,5 +15,4 @@ export default (name) => {
15
15
  return columns;
16
16
  }
17
17
  });
18
- return m;
19
18
  };
@@ -4,7 +4,7 @@ const columns = model('EventLog').columns(['eventlog_id', 'class', 'id', 'action
4
4
  </script>
5
5
  <template>
6
6
  <l-page>
7
- <l-table @request="$event.loadObjects('EventLog')" :columns="columns" sort-by="eventlog_id:desc"
7
+ <l-table fullscreen @request="$event.loadObjects('EventLog')" :columns="columns" sort-by="eventlog_id:desc"
8
8
  :actions="['view']">
9
9
 
10
10
  </l-table>
@@ -2,13 +2,6 @@
2
2
  import { model } from "#imports"
3
3
  import { ref } from 'vue'
4
4
  const columns = model("MailLog").columns(["maillog_id", "from", "to", "subject", "created_time"])
5
-
6
-
7
- columns.push({
8
- label: "Content",
9
- name: "_act",
10
- gqlField: ["body"]
11
- })
12
5
  const show = ref(false)
13
6
  const content = ref("")
14
7
  </script>
@@ -22,18 +15,11 @@ const content = ref("")
22
15
  </q-card-section>
23
16
  </l-card>
24
17
  </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>
18
+ <l-table row-key="maillog_id" @request="$event.loadObjects('MailLog', {}, ['body'])" :columns="columns"
19
+ sort-by="maillog_id:desc" >
36
20
 
21
+ <template #row-expand="props">
22
+ <iframe width="100%" height="300px" :srcdoc="props.row.body" frameborder="0"></iframe>
37
23
  </template>
38
24
 
39
25
  </l-table>
@@ -1,9 +1,22 @@
1
1
  <script setup>
2
- import { q } from '../../'
2
+ import { q } from '#imports'
3
3
  const system = await q("system", ["server"])
4
+
5
+ const columns = [
6
+ {
7
+ name: "name",
8
+ label: "Name"
9
+ },
10
+ {
11
+ name: "value",
12
+ label: "Value",
13
+ whiteSpace: "pre-wrap"
14
+ },
15
+ ]
16
+
4
17
  </script>
5
18
  <template>
6
19
  <l-page>
7
- <q-table :rows="system.server" :rows-per-page-options="[0]" hide-pagination flat bordered></q-table>
20
+ <l-table :rows="system.server" :columns="columns" :rows-per-page-options="[0]" hide-pagination></l-table>
8
21
  </l-page>
9
22
  </template>
@@ -14,8 +14,8 @@ const status = ref("0");
14
14
 
15
15
  <l-tabs v-model="status">
16
16
  <l-tab label="Active" name="0">
17
- <l-table row-key="user_id" @request="onRequest" :columns="columns" :actions="['view', 'edit', 'delete']">
18
- </l-table>
17
+ <l-table row-key="user_id" @request="onRequest" :columns="columns"
18
+ :actions="['view', 'edit', 'delete']"></l-table>
19
19
  </l-tab>
20
20
  <l-tab label="Inactive" name="1">
21
21
  <l-table row-key="user_id" @request="onRequest" :columns="columns" :actions="['view', 'edit', 'delete']">
@@ -3,6 +3,7 @@ declare const _default: {
3
3
  label: string;
4
4
  sortable: boolean;
5
5
  searchable: boolean;
6
+ autoWidth: boolean;
6
7
  };
7
8
  class: {
8
9
  label: string;
@@ -2,7 +2,8 @@ export default {
2
2
  eventlog_id: {
3
3
  label: "EventLog ID",
4
4
  sortable: true,
5
- searchable: true
5
+ searchable: true,
6
+ autoWidth: true
6
7
  },
7
8
  class: {
8
9
  label: "Class",
@@ -4,6 +4,7 @@ declare const _default: {
4
4
  sortable: boolean;
5
5
  searchable: boolean;
6
6
  searchType: string;
7
+ autoWidth: boolean;
7
8
  };
8
9
  from: {
9
10
  label: string;
@@ -3,7 +3,8 @@ export default {
3
3
  label: "ID",
4
4
  sortable: true,
5
5
  searchable: true,
6
- searchType: "number"
6
+ searchType: "number",
7
+ autoWidth: true
7
8
  },
8
9
  from: {
9
10
  label: "From",
@@ -44,5 +44,13 @@ declare const _default: {
44
44
  }[];
45
45
  format: (value: any) => string;
46
46
  };
47
+ test: {
48
+ label: string;
49
+ name: string;
50
+ to: (row: any) => string;
51
+ gqlField: string[];
52
+ field: (row: any) => any;
53
+ backgroundColor: (row: any) => "primary" | undefined;
54
+ };
47
55
  };
48
56
  export default _default;
@@ -3,6 +3,16 @@ export default {
3
3
  label: "Username",
4
4
  sortable: true,
5
5
  searchable: true
6
+ //cellClass: (row: any) => (row.username == "admin" ? "text-danger" : ""),
7
+ /* backgroundColor: (row: any) => {
8
+
9
+
10
+ if (row.username == "admin") {
11
+ return "red";
12
+ } else {
13
+ return "white";
14
+ }
15
+ } */
6
16
  },
7
17
  first_name: {
8
18
  label: "First name",
@@ -45,13 +55,17 @@ export default {
45
55
  format: (value) => {
46
56
  return ["Active", "Inactive"][value];
47
57
  }
48
- }
49
- /* ,
58
+ },
50
59
  test: {
51
- label: "Test",
52
- name: "_test",
53
- to: (row: any) => `/User/${row.user_id}/view`,
54
- gqlField: ["user_id", "first_name"],
55
- field: (row: any) => row.first_name,
56
- } */
60
+ label: "Test",
61
+ name: "_test",
62
+ to: (row) => `/User/${row.user_id}/view`,
63
+ gqlField: ["user_id", "first_name"],
64
+ field: (row) => row.first_name,
65
+ backgroundColor: (row) => {
66
+ if (row.username == "admin") {
67
+ return "primary";
68
+ }
69
+ }
70
+ }
57
71
  };
@@ -3,6 +3,7 @@ declare const _default: {
3
3
  label: string;
4
4
  sortable: boolean;
5
5
  searchable: boolean;
6
+ autoWidth: boolean;
6
7
  };
7
8
  username: {
8
9
  label: string;
@@ -29,11 +30,13 @@ declare const _default: {
29
30
  label: string;
30
31
  value: string;
31
32
  }[];
33
+ autoWidth: boolean;
32
34
  };
33
35
  user_agent: {
34
36
  label: string;
35
37
  sortable: boolean;
36
38
  searchable: boolean;
39
+ whiteSpace: string;
37
40
  };
38
41
  };
39
42
  export default _default;
@@ -2,7 +2,8 @@ export default {
2
2
  userlog_id: {
3
3
  label: "ID",
4
4
  sortable: true,
5
- searchable: true
5
+ searchable: true,
6
+ autoWidth: true
6
7
  },
7
8
  username: {
8
9
  label: "User",
@@ -34,11 +35,13 @@ export default {
34
35
  label: "FAIL",
35
36
  value: "FAIL"
36
37
  }
37
- ]
38
+ ],
39
+ autoWidth: true
38
40
  },
39
41
  user_agent: {
40
42
  label: "User agent",
41
43
  sortable: true,
42
- searchable: true
44
+ searchable: true,
45
+ whiteSpace: "pre-line"
43
46
  }
44
47
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hostlink/nuxt-light",
3
- "version": "0.0.106",
3
+ "version": "0.0.108",
4
4
  "description": "HostLink Nuxt Light Framework",
5
5
  "repository": "@hostlink/nuxt-light",
6
6
  "license": "MIT",