quasar-ui-danx 0.4.13 → 0.4.15

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quasar-ui-danx",
3
- "version": "0.4.13",
3
+ "version": "0.4.15",
4
4
  "author": "Dan <dan@flytedesk.com>",
5
5
  "description": "DanX Vue / Quasar component library",
6
6
  "license": "MIT",
@@ -1,66 +1,66 @@
1
1
  <template>
2
- <div
3
- class="dx-action-table overflow-hidden"
4
- :class="{'dx-no-data': !hasData, 'dx-is-loading': loadingList || loadingSummary, 'dx-is-loading-list': loadingList}"
5
- >
6
- <ActionVnode />
7
- <QTable
8
- ref="actionTable"
9
- :selected="selectedRows"
10
- :pagination="pagination"
11
- :columns="tableColumns"
12
- :loading="loadingList || loadingSummary"
13
- :rows="pagedItems?.data || []"
14
- :binary-state-sort="false"
15
- selection="multiple"
16
- :rows-per-page-options="rowsPerPageOptions"
17
- class="sticky-column sticky-header w-full h-full !border-0"
18
- :color="color"
19
- @update:selected="$emit('update:selected-rows', $event)"
20
- @update:pagination="() => {}"
21
- @request="(e) => $emit('update:pagination', {...e.pagination, __sort: mapSortBy(e.pagination, tableColumns)})"
22
- >
23
- <template #no-data>
24
- <slot name="empty">
25
- <EmptyTableState :text="`There are no ${label.toLowerCase()} matching the applied filter`" />
26
- </slot>
27
- </template>
28
- <template #top-row>
29
- <TableSummaryRow
30
- v-if="hasData"
31
- :label="label"
32
- :item-count="summary?.count || 0"
33
- :selected-count="selectedRows.length"
34
- :sticky-colspan="summaryColSpan"
35
- :loading="loadingSummary"
36
- :summary="summary"
37
- :columns="tableColumns"
38
- @clear="$emit('update:selected-rows', [])"
39
- />
40
- </template>
41
- <template #header-cell="rowProps">
42
- <ActionTableHeaderColumn
43
- v-model="columnSettings"
44
- :row-props="rowProps"
45
- :name="name"
46
- @update:model-value="onUpdateColumnSettings"
47
- />
48
- </template>
49
- <template #body-cell="rowProps">
50
- <ActionTableColumn
51
- :key="rowProps.key"
52
- :row-props="rowProps"
53
- :settings="columnSettings[rowProps.col.name]"
54
- >
55
- <slot
56
- :column-name="rowProps.col.name"
57
- :row="rowProps.row"
58
- :value="rowProps.value"
59
- />
60
- </ActionTableColumn>
61
- </template>
62
- </QTable>
63
- </div>
2
+ <div
3
+ class="dx-action-table overflow-hidden"
4
+ :class="{'dx-no-data': !hasData, 'dx-is-loading': loadingList || loadingSummary, 'dx-is-loading-list': loadingList}"
5
+ >
6
+ <ActionVnode />
7
+ <QTable
8
+ ref="actionTable"
9
+ :selected="selectedRows"
10
+ :pagination="pagination"
11
+ :columns="tableColumns"
12
+ :loading="loadingList || loadingSummary"
13
+ :rows="pagedItems?.data || []"
14
+ :binary-state-sort="false"
15
+ :selection="selection"
16
+ :rows-per-page-options="rowsPerPageOptions"
17
+ class="sticky-column sticky-header w-full h-full !border-0"
18
+ :color="color"
19
+ @update:selected="$emit('update:selected-rows', $event)"
20
+ @update:pagination="() => {}"
21
+ @request="(e) => $emit('update:pagination', {...e.pagination, __sort: mapSortBy(e.pagination, tableColumns)})"
22
+ >
23
+ <template #no-data>
24
+ <slot name="empty">
25
+ <EmptyTableState :text="`There are no ${label.toLowerCase()} matching the applied filter`" />
26
+ </slot>
27
+ </template>
28
+ <template #top-row>
29
+ <TableSummaryRow
30
+ v-if="hasData"
31
+ :label="label"
32
+ :item-count="summary?.count || 0"
33
+ :selected-count="selectedRows.length"
34
+ :sticky-colspan="summaryColSpan"
35
+ :loading="loadingSummary"
36
+ :summary="summary"
37
+ :columns="tableColumns"
38
+ @clear="$emit('update:selected-rows', [])"
39
+ />
40
+ </template>
41
+ <template #header-cell="rowProps">
42
+ <ActionTableHeaderColumn
43
+ v-model="columnSettings"
44
+ :row-props="rowProps"
45
+ :name="name"
46
+ @update:model-value="onUpdateColumnSettings"
47
+ />
48
+ </template>
49
+ <template #body-cell="rowProps">
50
+ <ActionTableColumn
51
+ :key="rowProps.key"
52
+ :row-props="rowProps"
53
+ :settings="columnSettings[rowProps.col.name]"
54
+ >
55
+ <slot
56
+ :column-name="rowProps.col.name"
57
+ :row="rowProps.row"
58
+ :value="rowProps.value"
59
+ />
60
+ </ActionTableColumn>
61
+ </template>
62
+ </QTable>
63
+ </div>
64
64
  </template>
65
65
 
66
66
  <script setup lang="ts">
@@ -89,6 +89,7 @@ export interface Props {
89
89
  columns: TableColumn[];
90
90
  rowsPerPageOptions?: number[];
91
91
  summaryColSpan?: number;
92
+ selection: "multiple" | "single";
92
93
  }
93
94
 
94
95
  const props = withDefaults(defineProps<Props>(), {
@@ -97,7 +98,8 @@ const props = withDefaults(defineProps<Props>(), {
97
98
  summary: null,
98
99
  loadingSummary: false,
99
100
  rowsPerPageOptions: () => [10, 25, 50, 100],
100
- summaryColSpan: null
101
+ summaryColSpan: null,
102
+ selection: "multiple"
101
103
  });
102
104
 
103
105
  const actionTable = ref(null);
@@ -1,16 +1,19 @@
1
1
  <template>
2
- <div>
3
- <RenderedForm
4
- v-bind="renderedFormProps"
5
- v-model:values="input"
6
- empty-value=""
7
- :saving="action.isApplying"
8
- @update:values="action.trigger(target, input)"
9
- />
10
- </div>
2
+ <div>
3
+ <RenderedForm
4
+ v-bind="renderedFormProps"
5
+ v-model:values="input"
6
+ empty-value=""
7
+ :saved-at="target.updated_at"
8
+ :saving="action.isApplying"
9
+ @update:values="action.trigger(target, input)"
10
+ >
11
+ <slot />
12
+ </RenderedForm>
13
+ </div>
11
14
  </template>
12
15
  <script setup lang="ts">
13
- import { ref, watch } from "vue";
16
+ import { Ref, ref, watch } from "vue";
14
17
  import { ActionTargetItem, AnyObject, Form, ResourceAction } from "../../../types";
15
18
  import RenderedForm from "./RenderedForm.vue";
16
19
 
@@ -27,7 +30,10 @@ interface ActionFormProps {
27
30
  savingClass?: string;
28
31
  }
29
32
 
30
- const props = defineProps<ActionFormProps>();
33
+ const props = withDefaults(defineProps<ActionFormProps>(), {
34
+ fieldClass: "",
35
+ savingClass: undefined
36
+ });
31
37
  const renderedFormProps = {
32
38
  form: props.form,
33
39
  noLabel: props.noLabel,
@@ -39,7 +45,7 @@ const renderedFormProps = {
39
45
  savingClass: props.savingClass
40
46
  };
41
47
 
42
- const input: AnyObject = ref({ ...props.target });
48
+ const input: Ref<AnyObject> = ref({ ...props.target });
43
49
  const fieldStatus: AnyObject = {};
44
50
 
45
51
  // Only update field values from target changes when the field is not already being saved
@@ -92,6 +92,7 @@
92
92
  />
93
93
  </div>
94
94
  </template>
95
+ <slot />
95
96
  <div
96
97
  v-if="savedAt"
97
98
  :class="savingClass"
@@ -137,7 +138,7 @@
137
138
  </template>
138
139
  <script setup lang="ts">
139
140
  import { ExclamationCircleIcon as MissingIcon, PencilIcon as EditIcon } from "@heroicons/vue/solid";
140
- import { computed, ref } from "vue";
141
+ import { computed, onBeforeUnmount, onMounted, ref } from "vue";
141
142
  import { fDateTime, FlashMessages, incrementName, replace } from "../../../helpers";
142
143
  import { TrashIcon as RemoveIcon } from "../../../svg";
143
144
  import { AnyObject, FormFieldValue, RenderedFormProps } from "../../../types";
@@ -178,15 +179,20 @@ const FORM_FIELD_MAP = {
178
179
 
179
180
  const mappedFields = props.form.fields.map((field) => ({
180
181
  placeholder: `Enter ${field.label}`,
181
- default: field.type === "BOOLEAN" ? false : "",
182
182
  ...field,
183
183
  component: field.component || FORM_FIELD_MAP[field.type]
184
184
  }));
185
185
 
186
186
  const fieldResponses = computed(() => {
187
- if (!props.values) return [];
188
- if (Array.isArray(props.values)) return props.values;
189
- return Object.entries(props.values).map(([name, value]) => ({ name, value, variation: "" }));
187
+ const values = props.values;
188
+ if (!values) return [];
189
+ if (Array.isArray(values)) return values;
190
+
191
+ return Object.entries(values).filter((entry) => mappedFields.find(mf => mf.name === entry[0])).map(([name, value]) => ({
192
+ name,
193
+ value,
194
+ variation: ""
195
+ }));
190
196
  });
191
197
 
192
198
  const fieldInputs = computed(() => {
@@ -252,11 +258,38 @@ function onInput(name: string, value: any) {
252
258
  updateValues(newValues);
253
259
  }
254
260
 
261
+ function updateValues(values: FormFieldValue[]) {
262
+ let updatedValues: FormFieldValue[] | object = values;
263
+
264
+ if (!Array.isArray(props.values)) {
265
+ updatedValues = values.reduce((acc: AnyObject, v) => {
266
+ acc[v.name] = v.value;
267
+ return acc;
268
+ }, {});
269
+ }
270
+
271
+ emit("update:values", updatedValues);
272
+ }
273
+
274
+ onMounted(() => {
275
+ window.addEventListener("beforeunload", handleBeforeUnload);
276
+ });
277
+ onBeforeUnmount(() => {
278
+ window.removeEventListener("beforeunload", handleBeforeUnload);
279
+ });
280
+
281
+
282
+ function handleBeforeUnload(event: BeforeUnloadEvent) {
283
+ if (props.saving) {
284
+ return event.returnValue = "Changes are currently being saved. If you leave now, you might lose unsaved changes.";
285
+ }
286
+ }
287
+
255
288
  function createVariation(variation) {
256
289
  return props.form.fields.map((field) => ({
257
290
  variation,
258
291
  name: field.name,
259
- value: field.type === "BOOLEAN" ? false : null
292
+ value: field.default_value === undefined ? null : field.default_value
260
293
  }));
261
294
  }
262
295
 
@@ -293,19 +326,6 @@ function onChangeVariationName() {
293
326
  newVariationName.value = "";
294
327
  }
295
328
 
296
- function updateValues(values: FormFieldValue[]) {
297
- let updatedValues: FormFieldValue[] | object = values;
298
-
299
- if (!Array.isArray(props.values)) {
300
- updatedValues = values.reduce((acc: AnyObject, v) => {
301
- acc[v.name] = v.value;
302
- return acc;
303
- }, {});
304
- }
305
-
306
- emit("update:values", updatedValues);
307
- }
308
-
309
329
  function onRemoveVariation(name: string) {
310
330
  if (!name) return;
311
331
 
@@ -1,70 +1,72 @@
1
1
  <template>
2
- <div class="flex flex-grow flex-col flex-nowrap overflow-hidden h-full">
3
- <slot name="top" />
4
- <slot name="toolbar">
5
- <ActionToolbar
6
- :title="title"
7
- :refresh-button="refreshButton"
8
- :actions="actions?.filter(a => a.batch)"
9
- :action-target="controller.selectedRows.value"
10
- :exporter="controller.exportList"
11
- :loading="controller.isLoadingList.value || controller.isLoadingSummary.value"
12
- @refresh="controller.refreshAll"
13
- >
14
- <template #default>
15
- <slot name="action-toolbar" />
16
- </template>
17
- </ActionToolbar>
18
- </slot>
19
- <div class="flex flex-nowrap flex-grow overflow-hidden w-full">
20
- <slot name="filters">
21
- <CollapsableFiltersSidebar
22
- v-if="activeFilter"
23
- :name="controller.name"
24
- :show-filters="showFilters"
25
- :filters="filters"
26
- :active-filter="activeFilter"
27
- class="dx-action-table-filters"
28
- @update:active-filter="controller.setActiveFilter"
29
- />
30
- </slot>
31
- <slot>
32
- <ActionTable
33
- class="flex-grow"
34
- :pagination="controller.pagination.value"
35
- :selected-rows="controller.selectedRows.value"
36
- :label="controller.label"
37
- :name="controller.name"
38
- :class="tableClass"
39
- :summary="controller.summary.value"
40
- :loading-list="controller.isLoadingList.value"
41
- :loading-summary="controller.isLoadingSummary.value"
42
- :paged-items="controller.pagedItems.value"
43
- :columns="columns"
44
- @update:selected-rows="controller.setSelectedRows"
45
- @update:pagination="controller.setPagination"
46
- />
47
- </slot>
48
- <slot name="panels">
49
- <PanelsDrawer
50
- v-if="activeItem && panels"
51
- :title="panelTitle"
52
- :model-value="activePanel"
53
- :active-item="activeItem"
54
- :panels="panels"
55
- @update:model-value="panel => controller.activatePanel(activeItem, panel)"
56
- @close="controller.setActiveItem(null)"
57
- >
58
- <template #controls>
59
- <PreviousNextControls
60
- :is-loading="controller.isLoadingList.value"
61
- @next="controller.getNextItem"
62
- />
63
- </template>
64
- </PanelsDrawer>
65
- </slot>
66
- </div>
67
- </div>
2
+ <div class="flex flex-grow flex-col flex-nowrap overflow-hidden h-full">
3
+ <slot name="top" />
4
+ <slot name="toolbar">
5
+ <ActionToolbar
6
+ v-if="!hideToolbar"
7
+ :title="title"
8
+ :refresh-button="refreshButton"
9
+ :actions="actions?.filter(a => a.batch)"
10
+ :action-target="controller.selectedRows.value"
11
+ :exporter="controller.exportList"
12
+ :loading="controller.isLoadingList.value || controller.isLoadingSummary.value"
13
+ @refresh="controller.refreshAll"
14
+ >
15
+ <template #default>
16
+ <slot name="action-toolbar" />
17
+ </template>
18
+ </ActionToolbar>
19
+ </slot>
20
+ <div class="flex flex-nowrap flex-grow overflow-hidden w-full">
21
+ <slot name="filters">
22
+ <CollapsableFiltersSidebar
23
+ v-if="activeFilter"
24
+ :name="controller.name"
25
+ :show-filters="showFilters"
26
+ :filters="filters"
27
+ :active-filter="activeFilter"
28
+ class="dx-action-table-filters"
29
+ @update:active-filter="controller.setActiveFilter"
30
+ />
31
+ </slot>
32
+ <slot>
33
+ <ActionTable
34
+ class="flex-grow"
35
+ :pagination="controller.pagination.value"
36
+ :selected-rows="controller.selectedRows.value"
37
+ :label="controller.label"
38
+ :name="controller.name"
39
+ :class="tableClass"
40
+ :summary="controller.summary.value"
41
+ :loading-list="controller.isLoadingList.value"
42
+ :loading-summary="controller.isLoadingSummary.value"
43
+ :paged-items="controller.pagedItems.value"
44
+ :columns="columns"
45
+ :selection="selection"
46
+ @update:selected-rows="controller.setSelectedRows"
47
+ @update:pagination="controller.setPagination"
48
+ />
49
+ </slot>
50
+ <slot name="panels">
51
+ <PanelsDrawer
52
+ v-if="activeItem && panels"
53
+ :title="panelTitle"
54
+ :model-value="activePanel"
55
+ :active-item="activeItem"
56
+ :panels="panels"
57
+ @update:model-value="panel => controller.activatePanel(activeItem, panel)"
58
+ @close="controller.setActiveItem(null)"
59
+ >
60
+ <template #controls>
61
+ <PreviousNextControls
62
+ :is-loading="controller.isLoadingList.value"
63
+ @next="controller.getNextItem"
64
+ />
65
+ </template>
66
+ </PanelsDrawer>
67
+ </slot>
68
+ </div>
69
+ </div>
68
70
  </template>
69
71
  <script setup lang="ts">
70
72
  import { computed } from "vue";
@@ -75,10 +77,8 @@ import ActionTable from "../ActionTable.vue";
75
77
  import { CollapsableFiltersSidebar } from "../Filters";
76
78
  import { ActionToolbar } from "../Toolbars";
77
79
 
78
- const props = defineProps<{
80
+ export interface ActionTableLayoutProps {
79
81
  title?: string;
80
- refreshButton: boolean;
81
- showFilters: boolean;
82
82
  controller: ActionController;
83
83
  columns: TableColumn[];
84
84
  filters?: FilterGroup[];
@@ -87,7 +87,17 @@ const props = defineProps<{
87
87
  exporter?: () => Promise<void>;
88
88
  panelTitleField?: string;
89
89
  tableClass?: string;
90
- }>();
90
+ refreshButton?: boolean;
91
+ showFilters?: boolean;
92
+ hideToolbar?: boolean;
93
+ selection?: "multiple" | "single";
94
+ }
95
+
96
+ const props = withDefaults(defineProps<ActionTableLayoutProps>(), {
97
+ title: "",
98
+ tableClass: "",
99
+ selection: "multiple"
100
+ });
91
101
 
92
102
  const activeFilter = computed(() => props.controller.activeFilter.value);
93
103
  const activeItem = computed(() => props.controller.activeItem.value);
@@ -1,33 +1,33 @@
1
1
  <template>
2
- <div class="dx-action-toolbar flex items-center">
3
- <div class="flex-grow px-6">
4
- <slot name="title">
5
- <h4 v-if="title">
6
- {{ title }}
7
- </h4>
8
- </slot>
9
- </div>
10
- <div class="py-3 px-6 flex items-center flex-nowrap">
11
- <slot />
12
- <RefreshButton
13
- v-if="refreshButton"
14
- :loading="loading"
15
- @click="$emit('refresh')"
16
- />
17
- <ExportButton
18
- v-if="exporter"
19
- :exporter="exporter"
20
- class="ml-4"
21
- />
22
- <ActionMenu
23
- v-if="actions && actions.length > 0"
24
- class="ml-4 dx-batch-actions"
25
- :target="actionTarget"
26
- :actions="actions"
27
- />
28
- <slot name="after" />
29
- </div>
30
- </div>
2
+ <div class="dx-action-toolbar flex items-center">
3
+ <div class="flex-grow px-6">
4
+ <slot name="title">
5
+ <h4 v-if="title">
6
+ {{ title }}
7
+ </h4>
8
+ </slot>
9
+ </div>
10
+ <div class="py-3 flex items-center flex-nowrap">
11
+ <slot />
12
+ <RefreshButton
13
+ v-if="refreshButton"
14
+ :loading="loading"
15
+ @click="$emit('refresh')"
16
+ />
17
+ <ExportButton
18
+ v-if="exporter"
19
+ :exporter="exporter"
20
+ class="ml-4"
21
+ />
22
+ <ActionMenu
23
+ v-if="actions && actions.length > 0"
24
+ class="ml-4 dx-batch-actions"
25
+ :target="actionTarget"
26
+ :actions="actions"
27
+ />
28
+ <slot name="after" />
29
+ </div>
30
+ </div>
31
31
  </template>
32
32
  <script setup lang="ts">
33
33
  import { ActionTargetItem, AnyObject, ResourceAction } from "../../../types";