quasar-ui-danx 0.0.10 → 0.0.11
Sign up to get free protection for your applications and to get access to all the features.
- package/package.json +3 -2
- package/src/components/ActionTable/ActionTable.vue +135 -0
- package/src/components/ActionTable/BatchActionMenu.vue +60 -0
- package/src/components/ActionTable/EmptyTableState.vue +33 -0
- package/src/components/ActionTable/Filters/CollapsableFiltersSidebar.vue +36 -0
- package/src/components/ActionTable/Filters/FilterGroupItem.vue +28 -0
- package/src/components/ActionTable/Filters/FilterGroupList.vue +76 -0
- package/src/components/ActionTable/Filters/FilterListToggle.vue +50 -0
- package/src/components/ActionTable/Filters/FilterableField.vue +141 -0
- package/src/components/ActionTable/Form/Fields/BooleanField.vue +37 -0
- package/src/components/ActionTable/Form/Fields/ConfirmPasswordField.vue +46 -0
- package/src/components/ActionTable/Form/Fields/DateField.vue +59 -0
- package/src/components/ActionTable/Form/Fields/DateRangeField.vue +110 -0
- package/src/components/ActionTable/Form/Fields/DateTimeField.vue +50 -0
- package/src/components/ActionTable/Form/Fields/DateTimePicker.vue +59 -0
- package/src/components/ActionTable/Form/Fields/EditableDiv.vue +39 -0
- package/src/components/ActionTable/Form/Fields/FieldLabel.vue +32 -0
- package/src/components/ActionTable/Form/Fields/FileUploadButton.vue +78 -0
- package/src/components/ActionTable/Form/Fields/InlineDateTimeField.vue +44 -0
- package/src/components/ActionTable/Form/Fields/IntegerField.vue +26 -0
- package/src/components/ActionTable/Form/Fields/LabeledInput.vue +63 -0
- package/src/components/ActionTable/Form/Fields/MultiFileField.vue +91 -0
- package/src/components/ActionTable/Form/Fields/MultiKeywordField.vue +57 -0
- package/src/components/ActionTable/Form/Fields/NewPasswordField.vue +39 -0
- package/src/components/ActionTable/Form/Fields/NumberField.vue +94 -0
- package/src/components/ActionTable/Form/Fields/NumberRangeField.vue +140 -0
- package/src/components/ActionTable/Form/Fields/SelectDrawer.vue +136 -0
- package/src/components/ActionTable/Form/Fields/SelectField.vue +318 -0
- package/src/components/ActionTable/Form/Fields/SelectWithChildrenField.vue +81 -0
- package/src/components/ActionTable/Form/Fields/SingleFileField.vue +78 -0
- package/src/components/ActionTable/Form/Fields/TextField.vue +82 -0
- package/src/components/ActionTable/Form/Fields/WysiwygField.vue +46 -0
- package/src/components/ActionTable/Form/Fields/index.ts +23 -0
- package/src/components/ActionTable/Form/RenderedForm.vue +74 -0
- package/src/components/ActionTable/RenderComponentColumn.vue +22 -0
- package/src/components/ActionTable/TableSummaryRow.vue +95 -0
- package/src/components/ActionTable/index.ts +15 -0
- package/src/components/ActionTable/listActions.ts +361 -0
- package/src/components/ActionTable/tableColumns.ts +72 -0
- package/src/components/ActionTable/tableHelpers.ts +83 -0
- package/src/components/Utility/CollapsableSidebar.vue +119 -0
- package/src/components/Utility/ContentDrawer.vue +70 -0
- package/src/components/Utility/Dialogs/ConfirmDialog.vue +132 -0
- package/src/components/Utility/Dialogs/FullScreenDialog.vue +46 -0
- package/src/components/Utility/Dialogs/InfoDialog.vue +92 -0
- package/src/components/Utility/Dialogs/InputDialog.vue +35 -0
- package/src/components/Utility/Transitions/ListTransition.vue +50 -0
- package/src/components/Utility/Transitions/SlideTransition.vue +63 -0
- package/src/components/Utility/Transitions/StaggeredListTransition.vue +97 -0
- package/src/components/Utility/index.ts +9 -0
- package/src/components/index.ts +3 -0
- package/src/helpers/FileUpload.ts +294 -0
- package/src/helpers/FlashMessages.ts +79 -0
- package/src/helpers/array.ts +37 -0
- package/src/helpers/compatibility.ts +64 -0
- package/src/helpers/date.ts +5 -0
- package/src/helpers/download.ts +192 -0
- package/src/helpers/downloadPdf.ts +92 -0
- package/src/helpers/files.ts +52 -0
- package/src/helpers/formats.ts +183 -0
- package/src/helpers/http.ts +62 -0
- package/src/helpers/index.ts +10 -1
- package/src/helpers/multiFileUpload.ts +68 -0
- package/src/helpers/singleFileUpload.ts +54 -0
- package/src/helpers/storage.ts +8 -0
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "quasar-ui-danx",
|
3
|
-
"version": "0.0.
|
3
|
+
"version": "0.0.11",
|
4
4
|
"author": "Dan <dan@flytedesk.com>",
|
5
5
|
"description": "DanX Vue / Quasar component library",
|
6
6
|
"license": "MIT",
|
@@ -62,6 +62,7 @@
|
|
62
62
|
"last 4 iOS versions"
|
63
63
|
],
|
64
64
|
"dependencies": {
|
65
|
-
"@vueuse/core": "^10.7.2"
|
65
|
+
"@vueuse/core": "^10.7.2",
|
66
|
+
"tailwindcss": "^3.4.1"
|
66
67
|
}
|
67
68
|
}
|
@@ -0,0 +1,135 @@
|
|
1
|
+
<!--suppress VueUnrecognizedSlot -->
|
2
|
+
<template>
|
3
|
+
<QTable
|
4
|
+
ref="actionTable"
|
5
|
+
:selected="selectedRows"
|
6
|
+
:pagination="quasarPagination"
|
7
|
+
:columns="columns"
|
8
|
+
:loading="isLoadingList"
|
9
|
+
:rows="pagedItems?.data || []"
|
10
|
+
selection="multiple"
|
11
|
+
:rows-per-page-options="[25,50,100]"
|
12
|
+
class="sticky-column sticky-header w-full !border-0"
|
13
|
+
color="blue-base"
|
14
|
+
@update:selected="$emit('update:selected-rows', $event)"
|
15
|
+
@update:pagination="() => {}"
|
16
|
+
@request="$emit('update:quasar-pagination', $event.pagination)"
|
17
|
+
>
|
18
|
+
<template #no-data>
|
19
|
+
<slot name="empty">
|
20
|
+
<EmptyTableState :text="`There are no ${label.toLowerCase()} matching the applied filter`" />
|
21
|
+
</slot>
|
22
|
+
</template>
|
23
|
+
<template #top-row>
|
24
|
+
<TableSummaryRow
|
25
|
+
:label="label"
|
26
|
+
:item-count="summary?.count || 0"
|
27
|
+
:selected-count="selectedRows.length"
|
28
|
+
:loading="isLoadingSummary"
|
29
|
+
:summary="summary"
|
30
|
+
:columns="columns"
|
31
|
+
@clear="$emit('update:selected-rows', [])"
|
32
|
+
/>
|
33
|
+
</template>
|
34
|
+
<template #header-cell="rowProps">
|
35
|
+
<QTh
|
36
|
+
:key="rowProps.key"
|
37
|
+
:props="rowProps"
|
38
|
+
:data-drop-zone="`resize-column-` + rowProps.col.name"
|
39
|
+
>
|
40
|
+
{{ rowProps.col.label }}
|
41
|
+
<HandleDraggable
|
42
|
+
v-if="rowProps.col.resizeable"
|
43
|
+
:drop-zone="`resize-column-` + rowProps.col.name"
|
44
|
+
class="resize-handle"
|
45
|
+
@resize="rowProps.col.onResize"
|
46
|
+
>
|
47
|
+
<RowResizeIcon class="w-4 text-neutral-base" />
|
48
|
+
</HandleDraggable>
|
49
|
+
</QTh>
|
50
|
+
</template>
|
51
|
+
<template #body-cell="rowProps">
|
52
|
+
<QTd :key="rowProps.key" :props="rowProps">
|
53
|
+
<template v-if="rowProps.col.component">
|
54
|
+
<RenderComponentColumn
|
55
|
+
:row-props="rowProps"
|
56
|
+
@action="$emit('action', $event)"
|
57
|
+
/>
|
58
|
+
</template>
|
59
|
+
<template v-else-if="rowProps.col.fieldList">
|
60
|
+
<div v-for="field in rowProps.col.fieldList" :key="field">
|
61
|
+
{{ rowProps.row[field] }}
|
62
|
+
</div>
|
63
|
+
</template>
|
64
|
+
<template v-else-if="rowProps.col.filterOnClick">
|
65
|
+
<a @click="$emit('filter', rowProps.col.filterOnClick(rowProps.row))">
|
66
|
+
{{ rowProps.value }}
|
67
|
+
</a>
|
68
|
+
</template>
|
69
|
+
<template v-else>
|
70
|
+
<slot v-bind="{name: rowProps.col.name, row: rowProps.row, value: rowProps.value}">
|
71
|
+
{{ rowProps.value }}
|
72
|
+
</slot>
|
73
|
+
</template>
|
74
|
+
</QTd>
|
75
|
+
</template>
|
76
|
+
</QTable>
|
77
|
+
</template>
|
78
|
+
|
79
|
+
<script setup>
|
80
|
+
import { DragHandleIcon as RowResizeIcon } from "@/svg";
|
81
|
+
import { EmptyTableState, registerStickyScrolling, RenderComponentColumn, TableSummaryRow } from "danx/src/components";
|
82
|
+
import { HandleDraggable } from "quasar-ui-danx/src";
|
83
|
+
import { ref } from "vue";
|
84
|
+
|
85
|
+
defineEmits(["action", "filter", "update:quasar-pagination", "update:selected-rows"]);
|
86
|
+
defineProps({
|
87
|
+
label: {
|
88
|
+
type: String,
|
89
|
+
required: true
|
90
|
+
},
|
91
|
+
selectedRows: {
|
92
|
+
type: Array,
|
93
|
+
required: true
|
94
|
+
},
|
95
|
+
quasarPagination: {
|
96
|
+
type: Object,
|
97
|
+
required: true
|
98
|
+
},
|
99
|
+
isLoadingList: Boolean,
|
100
|
+
pagedItems: {
|
101
|
+
type: Object,
|
102
|
+
default: null
|
103
|
+
},
|
104
|
+
isLoadingSummary: Boolean,
|
105
|
+
summary: {
|
106
|
+
type: Object,
|
107
|
+
default: null
|
108
|
+
},
|
109
|
+
columns: {
|
110
|
+
type: Array,
|
111
|
+
required: true
|
112
|
+
}
|
113
|
+
});
|
114
|
+
const actionTable = ref(null);
|
115
|
+
registerStickyScrolling(actionTable);
|
116
|
+
</script>
|
117
|
+
|
118
|
+
<style lang="scss" scoped>
|
119
|
+
[data-drop-zone] {
|
120
|
+
.resize-handle {
|
121
|
+
position: absolute;
|
122
|
+
top: 0;
|
123
|
+
right: -.45em;
|
124
|
+
width: .9em;
|
125
|
+
opacity: 0;
|
126
|
+
transition: all .3s;
|
127
|
+
}
|
128
|
+
|
129
|
+
&:hover {
|
130
|
+
.resize-handle {
|
131
|
+
opacity: 1;
|
132
|
+
}
|
133
|
+
}
|
134
|
+
}
|
135
|
+
</style>
|
@@ -0,0 +1,60 @@
|
|
1
|
+
<template>
|
2
|
+
<div>
|
3
|
+
<PopoverMenu
|
4
|
+
class="bg-neutral-plus-6 px-4 h-full flex"
|
5
|
+
:items="items"
|
6
|
+
:disabled="selectedRows.length === 0"
|
7
|
+
@action="onAction"
|
8
|
+
/>
|
9
|
+
<QTooltip v-if="selectedRows.length === 0">
|
10
|
+
Batch actions require a selection
|
11
|
+
</QTooltip>
|
12
|
+
<slot>
|
13
|
+
<Component
|
14
|
+
:is="activeComponent.is"
|
15
|
+
v-if="activeComponent"
|
16
|
+
v-bind="activeComponent.props"
|
17
|
+
:is-saving="isSaving"
|
18
|
+
@close="activeAction = false"
|
19
|
+
@confirm="onConfirmAction"
|
20
|
+
/>
|
21
|
+
</slot>
|
22
|
+
</div>
|
23
|
+
</template>
|
24
|
+
<script setup>
|
25
|
+
import PopoverMenu from "components/Common/Menu/PopoverMenu";
|
26
|
+
import { computed, ref } from "vue";
|
27
|
+
|
28
|
+
const emit = defineEmits(["action"]);
|
29
|
+
const props = defineProps({
|
30
|
+
items: {
|
31
|
+
type: Array,
|
32
|
+
required: true
|
33
|
+
},
|
34
|
+
selectedRows: {
|
35
|
+
type: Array,
|
36
|
+
required: true
|
37
|
+
},
|
38
|
+
applyBatchAction: {
|
39
|
+
type: Function,
|
40
|
+
required: true
|
41
|
+
},
|
42
|
+
isSaving: Boolean
|
43
|
+
});
|
44
|
+
|
45
|
+
|
46
|
+
const activeAction = ref(null);
|
47
|
+
const activeComponent = computed(() => (props.items.find(i => i.action === activeAction.value)?.component || (() => null))(props.selectedRows));
|
48
|
+
|
49
|
+
function onAction(action) {
|
50
|
+
activeAction.value = action;
|
51
|
+
emit("action", action);
|
52
|
+
}
|
53
|
+
async function onConfirmAction(input) {
|
54
|
+
const result = await props.applyBatchAction(input || activeComponent.value.input());
|
55
|
+
|
56
|
+
if (result?.success) {
|
57
|
+
activeAction.value = null;
|
58
|
+
}
|
59
|
+
}
|
60
|
+
</script>
|
@@ -0,0 +1,33 @@
|
|
1
|
+
<template>
|
2
|
+
<div class="flex items-center justify-center text-sm py-14 w-full">
|
3
|
+
<div v-if="loading">
|
4
|
+
<slot name="loading">{{ loadingText }}
|
5
|
+
<QSpinnerBall class="w-4 ml-2" />
|
6
|
+
</slot>
|
7
|
+
</div>
|
8
|
+
<div v-if="saving">
|
9
|
+
<slot name="saving">{{ savingText }}
|
10
|
+
<QSpinnerBall class="w-4 ml-2" />
|
11
|
+
</slot>
|
12
|
+
</div>
|
13
|
+
<slot>{{ text }}</slot>
|
14
|
+
</div>
|
15
|
+
</template>
|
16
|
+
<script setup>
|
17
|
+
defineProps({
|
18
|
+
loading: Boolean,
|
19
|
+
saving: Boolean,
|
20
|
+
text: {
|
21
|
+
type: String,
|
22
|
+
default: "No records found"
|
23
|
+
},
|
24
|
+
loadingText: {
|
25
|
+
type: String,
|
26
|
+
default: "Loading..."
|
27
|
+
},
|
28
|
+
savingText: {
|
29
|
+
type: String,
|
30
|
+
default: "Saving..."
|
31
|
+
}
|
32
|
+
});
|
33
|
+
</script>
|
@@ -0,0 +1,36 @@
|
|
1
|
+
<template>
|
2
|
+
<CollapsableSidebar
|
3
|
+
:collapse="!showFilters"
|
4
|
+
disabled
|
5
|
+
min-width="0"
|
6
|
+
max-width="18rem"
|
7
|
+
name="admin-ads"
|
8
|
+
@update:collapse="$emit('update:show-filters', !$event)"
|
9
|
+
>
|
10
|
+
<FilterGroupList
|
11
|
+
:filter="filter"
|
12
|
+
:filter-groups="filterGroups"
|
13
|
+
@update:filter="$emit('update:filter', $event)"
|
14
|
+
/>
|
15
|
+
</CollapsableSidebar>
|
16
|
+
</template>
|
17
|
+
<script setup>
|
18
|
+
import { CollapsableSidebar, FilterGroupList } from "danx/src/components";
|
19
|
+
|
20
|
+
defineEmits(["update:filter", "update:show-filters"]);
|
21
|
+
defineProps({
|
22
|
+
name: {
|
23
|
+
type: String,
|
24
|
+
required: true
|
25
|
+
},
|
26
|
+
showFilters: Boolean,
|
27
|
+
filter: {
|
28
|
+
type: Object,
|
29
|
+
default: null
|
30
|
+
},
|
31
|
+
filterGroups: {
|
32
|
+
type: Array,
|
33
|
+
default: () => []
|
34
|
+
}
|
35
|
+
});
|
36
|
+
</script>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<template>
|
2
|
+
<QExpansionItem>
|
3
|
+
<template #header>
|
4
|
+
<div class="flex items-center flex-nowrap flex-grow">
|
5
|
+
<div class="whitespace-nowrap flex-grow text-left text-sm font-bold">{{ name }}</div>
|
6
|
+
<QBadge
|
7
|
+
:label="count"
|
8
|
+
rounded
|
9
|
+
class="ml-2 transition-all"
|
10
|
+
:class="{'bg-gray-base': !count, 'bg-blue-base': count}"
|
11
|
+
/>
|
12
|
+
</div>
|
13
|
+
</template>
|
14
|
+
<slot />
|
15
|
+
</QExpansionItem>
|
16
|
+
</template>
|
17
|
+
<script setup>
|
18
|
+
defineProps({
|
19
|
+
name: {
|
20
|
+
type: String,
|
21
|
+
required: true
|
22
|
+
},
|
23
|
+
count: {
|
24
|
+
type: Number,
|
25
|
+
required: true
|
26
|
+
}
|
27
|
+
});
|
28
|
+
</script>
|
@@ -0,0 +1,76 @@
|
|
1
|
+
<template>
|
2
|
+
<QList>
|
3
|
+
<div class="px-4 py-2 max-w-full">
|
4
|
+
<template
|
5
|
+
v-for="(group, index) in filterGroups"
|
6
|
+
:key="'group-' + group.name"
|
7
|
+
>
|
8
|
+
<template v-if="group.flat">
|
9
|
+
<FilterableField
|
10
|
+
v-for="field in group.fields"
|
11
|
+
:key="'field-' + field.name"
|
12
|
+
:model-value="field.calcValue ? field.calcValue(filter) : filter[field.name]"
|
13
|
+
:field="field"
|
14
|
+
:loading="loading"
|
15
|
+
class="mb-4"
|
16
|
+
@update:model-value="updateFilter(field, $event)"
|
17
|
+
/>
|
18
|
+
</template>
|
19
|
+
|
20
|
+
<FilterGroupItem
|
21
|
+
v-else
|
22
|
+
:name="group.name"
|
23
|
+
:count="activeCountByGroup[group.name]"
|
24
|
+
>
|
25
|
+
<FilterableField
|
26
|
+
v-for="field in group.fields"
|
27
|
+
:key="'field-' + field.name"
|
28
|
+
:model-value="field.calcValue ? field.calcValue(filter) : filter[field.name]"
|
29
|
+
:field="field"
|
30
|
+
:loading="loading"
|
31
|
+
class="mb-4"
|
32
|
+
@update:model-value="updateFilter(field, $event)"
|
33
|
+
/>
|
34
|
+
</FilterGroupItem>
|
35
|
+
|
36
|
+
<QSeparator
|
37
|
+
v-if="index < (filterGroups.length - 1)"
|
38
|
+
class="my-2"
|
39
|
+
/>
|
40
|
+
</template>
|
41
|
+
</div>
|
42
|
+
</QList>
|
43
|
+
</template>
|
44
|
+
<script setup>
|
45
|
+
import FilterableField from "danx/src/components/ActionTable/Filters/FilterableField";
|
46
|
+
import FilterGroupItem from "danx/src/components/ActionTable/Filters/FilterGroupItem";
|
47
|
+
import { computed } from "vue";
|
48
|
+
|
49
|
+
const emit = defineEmits(["update:filter"]);
|
50
|
+
const props = defineProps({
|
51
|
+
filterGroups: {
|
52
|
+
type: Array,
|
53
|
+
required: true
|
54
|
+
},
|
55
|
+
filter: {
|
56
|
+
type: Object,
|
57
|
+
required: true
|
58
|
+
},
|
59
|
+
loading: Boolean
|
60
|
+
});
|
61
|
+
|
62
|
+
const activeCountByGroup = computed(() => {
|
63
|
+
const activeCountByGroup = {};
|
64
|
+
for (const group of props.filterGroups) {
|
65
|
+
activeCountByGroup[group.name] = group.fields.filter(field => props.filter[field.name] !== undefined).length;
|
66
|
+
}
|
67
|
+
return activeCountByGroup;
|
68
|
+
});
|
69
|
+
function updateFilter(field, value) {
|
70
|
+
let fieldFilter = { [field.name]: value };
|
71
|
+
if (field.filterBy) {
|
72
|
+
fieldFilter = field.filterBy(value);
|
73
|
+
}
|
74
|
+
emit("update:filter", { ...props.filter, ...fieldFilter });
|
75
|
+
}
|
76
|
+
</script>
|
@@ -0,0 +1,50 @@
|
|
1
|
+
<template>
|
2
|
+
<div class="flex items-center" :class="{'w-72': showFilters}">
|
3
|
+
<div class="flex-grow">
|
4
|
+
<QBtn
|
5
|
+
class="btn-blue-highlight"
|
6
|
+
:class="{'highlighted': showFilters}"
|
7
|
+
@click="$emit('update:show-filters', !showFilters)"
|
8
|
+
>
|
9
|
+
<FilterIcon class="w-5 mr-2" />
|
10
|
+
<QBadge
|
11
|
+
:label="'' + activeCount"
|
12
|
+
rounded
|
13
|
+
:color="activeCount > 0 ? 'blue-base' : 'gray-base'"
|
14
|
+
/>
|
15
|
+
</QBtn>
|
16
|
+
</div>
|
17
|
+
<a
|
18
|
+
v-if="activeCount > 0"
|
19
|
+
class="text-blue-base hover:text-blue-plus-1 text-sm ml-4"
|
20
|
+
@click="$emit('update:filter', {})"
|
21
|
+
>Clear All</a>
|
22
|
+
</div>
|
23
|
+
</template>
|
24
|
+
<script setup>
|
25
|
+
import { FilterIcon } from "@/svg";
|
26
|
+
import { computed } from "vue";
|
27
|
+
|
28
|
+
defineEmits(["update:show-filters", "update:filter"]);
|
29
|
+
const props = defineProps({
|
30
|
+
filter: {
|
31
|
+
type: Object,
|
32
|
+
required: true
|
33
|
+
},
|
34
|
+
filterGroups: {
|
35
|
+
type: Array,
|
36
|
+
required: true
|
37
|
+
},
|
38
|
+
showFilters: Boolean
|
39
|
+
});
|
40
|
+
|
41
|
+
const filterNameDictionary = computed(() => {
|
42
|
+
return props.filterGroups.reduce((acc, fg) => {
|
43
|
+
fg.fields.forEach(f => {
|
44
|
+
acc[f.name] = true;
|
45
|
+
});
|
46
|
+
return acc;
|
47
|
+
}, {});
|
48
|
+
});
|
49
|
+
const activeCount = computed(() => Object.keys(props.filter).filter(key => props.filter[key] !== undefined && filterNameDictionary.value[key]).length);
|
50
|
+
</script>
|
@@ -0,0 +1,141 @@
|
|
1
|
+
<template>
|
2
|
+
<div>
|
3
|
+
<template v-if="field.type === 'multi-select'">
|
4
|
+
<SelectField
|
5
|
+
v-if="field.options?.length > 0 || loading"
|
6
|
+
:model-value="modelValue"
|
7
|
+
:options="field.options"
|
8
|
+
multiple
|
9
|
+
:loading="loading"
|
10
|
+
:chip-limit="1"
|
11
|
+
filterable
|
12
|
+
:placeholder="field.placeholder"
|
13
|
+
:label="field.label"
|
14
|
+
@update:model-value="onUpdate"
|
15
|
+
/>
|
16
|
+
<div
|
17
|
+
v-else
|
18
|
+
class="mt-2"
|
19
|
+
>
|
20
|
+
<div class="text-xs font-bold">{{ field.label }}</div>
|
21
|
+
<div class="text-sm ml-3 py-2">No Available Options</div>
|
22
|
+
</div>
|
23
|
+
</template>
|
24
|
+
|
25
|
+
<SelectField
|
26
|
+
v-else-if="field.type === 'single-select'"
|
27
|
+
:model-value="modelValue"
|
28
|
+
:options="field.options"
|
29
|
+
:placeholder="field.placeholder"
|
30
|
+
:loading="loading"
|
31
|
+
:label="field.label"
|
32
|
+
@update:model-value="onUpdate"
|
33
|
+
/>
|
34
|
+
<DateField
|
35
|
+
v-else-if="field.type === 'date'"
|
36
|
+
:model-value="modelValue"
|
37
|
+
:label="field.label"
|
38
|
+
class="mt-2"
|
39
|
+
@update:model-value="onUpdate"
|
40
|
+
/>
|
41
|
+
<DateRangeField
|
42
|
+
v-else-if="field.type === 'date-range'"
|
43
|
+
:model-value="modelValue"
|
44
|
+
:label="field.label"
|
45
|
+
:inline="field.inline"
|
46
|
+
with-time
|
47
|
+
class="mt-2 reactive"
|
48
|
+
@update:model-value="onUpdate"
|
49
|
+
/>
|
50
|
+
<NumberRangeField
|
51
|
+
v-else-if="field.type === 'number-range'"
|
52
|
+
:model-value="modelValue"
|
53
|
+
:label="field.label"
|
54
|
+
class="mt-2"
|
55
|
+
:debounce="1000"
|
56
|
+
@update:model-value="onUpdate"
|
57
|
+
/>
|
58
|
+
<NumberRangeField
|
59
|
+
v-else-if="field.type === 'currency-range'"
|
60
|
+
:model-value="modelValue"
|
61
|
+
:label="field.label"
|
62
|
+
class="mt-2"
|
63
|
+
:debounce="1000"
|
64
|
+
currency
|
65
|
+
@update:model-value="onUpdate"
|
66
|
+
/>
|
67
|
+
<NumberRangeField
|
68
|
+
v-else-if="field.type === 'percent-range'"
|
69
|
+
:model-value="modelValue"
|
70
|
+
:label="field.label"
|
71
|
+
class="mt-2"
|
72
|
+
:debounce="1000"
|
73
|
+
percent
|
74
|
+
@update:model-value="onUpdate"
|
75
|
+
/>
|
76
|
+
<BooleanField
|
77
|
+
v-else-if="field.type === 'boolean'"
|
78
|
+
:field="field"
|
79
|
+
:model-value="modelValue"
|
80
|
+
class="mt-2"
|
81
|
+
label-class="text-xs font-bold"
|
82
|
+
@update:model-value="onUpdate"
|
83
|
+
/>
|
84
|
+
<MultiKeywordField
|
85
|
+
v-else-if="field.type === 'multi-keywords'"
|
86
|
+
:model-value="modelValue"
|
87
|
+
:field="field"
|
88
|
+
@update:model-value="onUpdate"
|
89
|
+
/>
|
90
|
+
<SelectWithChildrenField
|
91
|
+
v-else-if="field.type === 'select-with-children'"
|
92
|
+
:model-value="modelValue"
|
93
|
+
:options="field.options"
|
94
|
+
:loading="loading"
|
95
|
+
:label="field.label"
|
96
|
+
:placeholder="field.placeholder"
|
97
|
+
@update:model-value="onUpdate"
|
98
|
+
/>
|
99
|
+
<template v-else>
|
100
|
+
Field "{{ field.name }}": Unknown filter type {{ field.type }}
|
101
|
+
</template>
|
102
|
+
</div>
|
103
|
+
</template>
|
104
|
+
<script setup>
|
105
|
+
import BooleanField from "danx/src/components/ActionTable/Form/Fields/BooleanField";
|
106
|
+
import DateField from "danx/src/components/ActionTable/Form/Fields/DateField";
|
107
|
+
import DateRangeField from "danx/src/components/ActionTable/Form/Fields/DateRangeField";
|
108
|
+
import MultiKeywordField from "danx/src/components/ActionTable/Form/Fields/MultiKeywordField";
|
109
|
+
import NumberRangeField from "danx/src/components/ActionTable/Form/Fields/NumberRangeField";
|
110
|
+
import SelectField from "danx/src/components/ActionTable/Form/Fields/SelectField";
|
111
|
+
import SelectWithChildrenField from "danx/src/components/ActionTable/Form/Fields/SelectWithChildrenField";
|
112
|
+
|
113
|
+
const emit = defineEmits(["update:model-value"]);
|
114
|
+
const props = defineProps({
|
115
|
+
field: {
|
116
|
+
type: Object,
|
117
|
+
required: true
|
118
|
+
},
|
119
|
+
modelValue: {
|
120
|
+
type: [String, Array, Number, Object, Boolean],
|
121
|
+
default: undefined
|
122
|
+
},
|
123
|
+
loading: Boolean
|
124
|
+
});
|
125
|
+
|
126
|
+
function onUpdate(val) {
|
127
|
+
let newVal = val || undefined;
|
128
|
+
|
129
|
+
switch (props.field.type) {
|
130
|
+
case "multi-select":
|
131
|
+
newVal = val.length > 0 ? val : undefined;
|
132
|
+
break;
|
133
|
+
case "single-select":
|
134
|
+
case "boolean":
|
135
|
+
newVal = val === null ? undefined : val;
|
136
|
+
break;
|
137
|
+
}
|
138
|
+
|
139
|
+
emit("update:model-value", newVal);
|
140
|
+
}
|
141
|
+
</script>
|
@@ -0,0 +1,37 @@
|
|
1
|
+
<template>
|
2
|
+
<QToggle
|
3
|
+
:data-testid="'boolean-field-' + field.id"
|
4
|
+
:model-value="modelValue"
|
5
|
+
:toggle-indeterminate="toggleIndeterminate"
|
6
|
+
:indeterminate-value="undefined"
|
7
|
+
@update:model-value="$emit('update:model-value', $event)"
|
8
|
+
>
|
9
|
+
<FieldLabel
|
10
|
+
:field="field"
|
11
|
+
:show-name="showName"
|
12
|
+
:class="labelClass"
|
13
|
+
/>
|
14
|
+
</QToggle>
|
15
|
+
</template>
|
16
|
+
|
17
|
+
<script setup>
|
18
|
+
import FieldLabel from "./FieldLabel";
|
19
|
+
|
20
|
+
defineEmits(["update:model-value"]);
|
21
|
+
defineProps({
|
22
|
+
modelValue: {
|
23
|
+
type: [Boolean],
|
24
|
+
default: undefined
|
25
|
+
},
|
26
|
+
field: {
|
27
|
+
type: Object,
|
28
|
+
required: true
|
29
|
+
},
|
30
|
+
labelClass: {
|
31
|
+
type: String,
|
32
|
+
default: "text-sm"
|
33
|
+
},
|
34
|
+
showName: Boolean,
|
35
|
+
toggleIndeterminate: Boolean
|
36
|
+
});
|
37
|
+
</script>
|
@@ -0,0 +1,46 @@
|
|
1
|
+
<template>
|
2
|
+
<LabeledInput
|
3
|
+
type="password"
|
4
|
+
v-bind="props"
|
5
|
+
:rules="rules"
|
6
|
+
@update:model-value="$emit('update:model-value', $event)"
|
7
|
+
/>
|
8
|
+
</template>
|
9
|
+
|
10
|
+
<script setup>
|
11
|
+
import LabeledInput from "danx/src/components/ActionTable/Form/Fields/LabeledInput";
|
12
|
+
|
13
|
+
defineEmits(["update:model-value"]);
|
14
|
+
const props = defineProps({
|
15
|
+
name: {
|
16
|
+
type: String,
|
17
|
+
default: "password_confirmation"
|
18
|
+
},
|
19
|
+
label: {
|
20
|
+
type: String,
|
21
|
+
default: "Confirm Password"
|
22
|
+
},
|
23
|
+
placeholder: {
|
24
|
+
type: String,
|
25
|
+
default: "Confirm Password"
|
26
|
+
},
|
27
|
+
modelValue: {
|
28
|
+
type: [String, Number],
|
29
|
+
required: true
|
30
|
+
},
|
31
|
+
error: {
|
32
|
+
type: String,
|
33
|
+
default: null
|
34
|
+
},
|
35
|
+
password: {
|
36
|
+
type: String,
|
37
|
+
default: ""
|
38
|
+
},
|
39
|
+
disabled: Boolean
|
40
|
+
});
|
41
|
+
|
42
|
+
const rules = [
|
43
|
+
(val) =>
|
44
|
+
val === props.password || "The password and confirmation do not match"
|
45
|
+
];
|
46
|
+
</script>
|