quasar-ui-danx 0.4.1 → 0.4.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/danx.es.js +7234 -6741
- package/dist/danx.es.js.map +1 -1
- package/dist/danx.umd.js +11 -5
- package/dist/danx.umd.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +3 -1
- package/src/components/ActionTable/ActionTable.vue +31 -43
- package/src/components/ActionTable/Columns/ActionTableColumn.vue +19 -18
- package/src/components/ActionTable/Filters/CollapsableFiltersSidebar.vue +15 -14
- package/src/components/ActionTable/Filters/{FilterFieldList.vue → FilterList.vue} +26 -26
- package/src/components/ActionTable/Filters/FilterableField.vue +28 -31
- package/src/components/ActionTable/Filters/index.ts +2 -2
- package/src/components/ActionTable/Form/Fields/EditOnClickTextField.vue +71 -0
- package/src/components/ActionTable/Form/Fields/FieldLabel.vue +8 -13
- package/src/components/ActionTable/Form/Fields/FileUploadButton.vue +34 -33
- package/src/components/ActionTable/Form/Fields/MultiFileField.vue +48 -44
- package/src/components/ActionTable/Form/Fields/NumberField.vue +60 -59
- package/src/components/ActionTable/Form/Fields/SelectField.vue +124 -138
- package/src/components/ActionTable/Form/Fields/SelectWithChildrenField.vue +28 -33
- package/src/components/ActionTable/Form/Fields/SingleFileField.vue +15 -15
- package/src/components/ActionTable/Form/Fields/SliderNumberField.vue +45 -0
- package/src/components/ActionTable/Form/Fields/TextField.vue +47 -66
- package/src/components/ActionTable/Form/Fields/index.ts +2 -0
- package/src/components/ActionTable/Form/RenderedForm.vue +50 -13
- package/src/components/ActionTable/Form/Utilities/MaxLengthCounter.vue +17 -0
- package/src/components/ActionTable/Form/Utilities/index.ts +1 -0
- package/src/components/ActionTable/Form/index.ts +1 -0
- package/src/components/ActionTable/Layouts/ActionTableLayout.vue +22 -16
- package/src/components/ActionTable/Toolbars/ActionToolbar.vue +11 -11
- package/src/components/ActionTable/listControls.ts +104 -166
- package/src/components/ActionTable/listHelpers.ts +2 -3
- package/src/components/ActionTable/tableColumns.ts +53 -77
- package/src/components/AuditHistory/AuditHistoryItemValue.vue +26 -26
- package/src/components/PanelsDrawer/PanelsDrawer.vue +17 -4
- package/src/components/PanelsDrawer/PanelsDrawerPanels.vue +6 -11
- package/src/components/PanelsDrawer/PanelsDrawerTabs.vue +20 -20
- package/src/components/Utility/Dialogs/ConfirmActionDialog.vue +39 -0
- package/src/components/Utility/Dialogs/ConfirmDialog.vue +57 -117
- package/src/components/Utility/Dialogs/DialogLayout.vue +77 -0
- package/src/components/Utility/Dialogs/FullscreenCarouselDialog.vue +42 -36
- package/src/components/Utility/Dialogs/InfoDialog.vue +40 -80
- package/src/components/Utility/Dialogs/index.ts +1 -0
- package/src/components/Utility/Files/FilePreview.vue +76 -73
- package/src/components/Utility/Layouts/ContentDrawer.vue +24 -31
- package/src/components/Utility/Tools/ActionVnode.vue +3 -3
- package/src/components/Utility/Tools/RenderVnode.vue +20 -11
- package/src/components/Utility/Transitions/MaxHeightTransition.vue +26 -0
- package/src/components/Utility/Transitions/index.ts +1 -0
- package/src/config/index.ts +36 -31
- package/src/helpers/FileUpload.ts +295 -297
- package/src/helpers/FlashMessages.ts +80 -71
- package/src/helpers/actions.ts +102 -82
- package/src/helpers/download.ts +189 -189
- package/src/helpers/downloadPdf.ts +55 -52
- package/src/helpers/formats.ts +151 -109
- package/src/helpers/index.ts +2 -0
- package/src/helpers/multiFileUpload.ts +72 -58
- package/src/helpers/objectStore.ts +52 -0
- package/src/helpers/request.ts +70 -51
- package/src/helpers/routes.ts +29 -0
- package/src/helpers/storage.ts +7 -3
- package/src/helpers/utils.ts +47 -29
- package/src/styles/quasar-reset.scss +94 -68
- package/src/styles/themes/danx/dialogs.scss +47 -0
- package/src/styles/themes/danx/forms.scss +18 -0
- package/src/styles/themes/danx/index.scss +4 -0
- package/src/types/actions.d.ts +43 -0
- package/src/types/config.d.ts +15 -0
- package/src/types/controls.d.ts +99 -0
- package/src/types/dialogs.d.ts +32 -0
- package/src/types/fields.d.ts +20 -0
- package/src/types/files.d.ts +54 -0
- package/src/types/formats.d.ts +4 -0
- package/src/{components/ActionTable/Form/form.d.ts → types/forms.d.ts} +6 -0
- package/src/types/index.d.ts +12 -0
- package/src/types/requests.d.ts +13 -0
- package/src/types/shared.d.ts +15 -0
- package/src/types/tables.d.ts +27 -0
- package/types/index.d.ts +1 -1
- /package/src/components/ActionTable/Filters/{FilterFieldItem.vue → FilterItem.vue} +0 -0
@@ -31,55 +31,50 @@
|
|
31
31
|
</div>
|
32
32
|
</div>
|
33
33
|
</template>
|
34
|
-
<script setup>
|
34
|
+
<script setup lang="ts">
|
35
35
|
import { ref, watch } from "vue";
|
36
36
|
import { remove } from "../../../../helpers";
|
37
37
|
import SelectField from "./SelectField";
|
38
38
|
|
39
|
+
export interface SelectWithChildrenFieldProps {
|
40
|
+
modelValue?: string[];
|
41
|
+
label?: string;
|
42
|
+
placeholder?: string;
|
43
|
+
options?: any[];
|
44
|
+
loading?: boolean;
|
45
|
+
}
|
46
|
+
|
39
47
|
const emit = defineEmits(["update:model-value"]);
|
40
|
-
const props = defineProps({
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
label: {
|
46
|
-
type: String,
|
47
|
-
default: "Selection"
|
48
|
-
},
|
49
|
-
placeholder: {
|
50
|
-
type: String,
|
51
|
-
default: "Select an option"
|
52
|
-
},
|
53
|
-
options: {
|
54
|
-
type: Array,
|
55
|
-
default: () => []
|
56
|
-
},
|
57
|
-
loading: Boolean
|
48
|
+
const props = withDefaults(defineProps<SelectWithChildrenFieldProps>(), {
|
49
|
+
modelValue: () => [],
|
50
|
+
label: "Selection",
|
51
|
+
placeholder: "Select an option",
|
52
|
+
options: () => []
|
58
53
|
});
|
59
54
|
|
60
55
|
function resolveSelectedOption() {
|
61
|
-
|
62
|
-
|
63
|
-
|
56
|
+
if (props.modelValue?.length > 0) {
|
57
|
+
return props.options.find((option) => option.children.find(child => props.modelValue.includes(child.id)));
|
58
|
+
}
|
64
59
|
|
65
|
-
|
60
|
+
return null;
|
66
61
|
}
|
67
62
|
const selectedOption = ref(resolveSelectedOption());
|
68
63
|
const selectedChildren = ref(props.modelValue || []);
|
69
64
|
function onSelectChild(child) {
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
65
|
+
if (selectedChildren.value.includes(child.id)) {
|
66
|
+
selectedChildren.value = remove(selectedChildren.value, child.id);
|
67
|
+
} else {
|
68
|
+
selectedChildren.value.push(child.id);
|
69
|
+
}
|
70
|
+
emit("update:model-value", selectedChildren.value.length > 0 ? selectedChildren.value : undefined);
|
76
71
|
}
|
77
72
|
function onSelectOption() {
|
78
|
-
|
79
|
-
|
73
|
+
selectedChildren.value = [];
|
74
|
+
emit("update:model-value", undefined);
|
80
75
|
}
|
81
76
|
watch(() => props.modelValue, (value) => {
|
82
|
-
|
83
|
-
|
77
|
+
selectedOption.value = resolveSelectedOption();
|
78
|
+
selectedChildren.value = value || [];
|
84
79
|
});
|
85
80
|
</script>
|
@@ -35,7 +35,7 @@
|
|
35
35
|
v-if="!readonly || uploadedFile"
|
36
36
|
class="w-32 cursor-pointer mt-2"
|
37
37
|
:class="{'border border-dashed border-blue-600': !uploadedFile, 'mx-auto': !readonly}"
|
38
|
-
:
|
38
|
+
:file="uploadedFile"
|
39
39
|
downloadable
|
40
40
|
@click="!disable && $refs.file.click()"
|
41
41
|
/>
|
@@ -56,24 +56,24 @@ import FieldLabel from "./FieldLabel";
|
|
56
56
|
|
57
57
|
const emit = defineEmits(["update:model-value"]);
|
58
58
|
const props = defineProps({
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
59
|
+
modelValue: {
|
60
|
+
type: [Object, String],
|
61
|
+
default: null
|
62
|
+
},
|
63
|
+
field: {
|
64
|
+
type: Object,
|
65
|
+
required: true
|
66
|
+
},
|
67
|
+
showName: Boolean,
|
68
|
+
disable: Boolean,
|
69
|
+
readonly: Boolean
|
70
70
|
});
|
71
71
|
const { onComplete, onDrop, onFileSelected, uploadedFile, clearUploadedFile } = useSingleFileUpload();
|
72
72
|
onComplete(() => emit("update:model-value", uploadedFile.value));
|
73
73
|
|
74
74
|
onMounted(() => {
|
75
|
-
|
76
|
-
|
77
|
-
|
75
|
+
if (props.modelValue) {
|
76
|
+
uploadedFile.value = props.modelValue;
|
77
|
+
}
|
78
78
|
});
|
79
79
|
</script>
|
@@ -0,0 +1,45 @@
|
|
1
|
+
<template>
|
2
|
+
<div class="dx-slider-number-field">
|
3
|
+
<FieldLabel
|
4
|
+
:label="label"
|
5
|
+
:field="field"
|
6
|
+
/>
|
7
|
+
<QSlider
|
8
|
+
v-bind="sliderProps"
|
9
|
+
:min="min"
|
10
|
+
:max="max"
|
11
|
+
label
|
12
|
+
label-always
|
13
|
+
switch-label-side
|
14
|
+
:price-label="priceLabel"
|
15
|
+
/>
|
16
|
+
</div>
|
17
|
+
</template>
|
18
|
+
|
19
|
+
<script setup lang="ts">
|
20
|
+
import { QSliderProps } from "quasar";
|
21
|
+
import { computed } from "vue";
|
22
|
+
import { FormField } from "../../../../types";
|
23
|
+
import FieldLabel from "./FieldLabel";
|
24
|
+
|
25
|
+
export interface SliderFieldProps extends QSliderProps {
|
26
|
+
modelValue?: number | null;
|
27
|
+
field?: FormField;
|
28
|
+
label?: string;
|
29
|
+
currency?: boolean;
|
30
|
+
percent?: boolean;
|
31
|
+
}
|
32
|
+
|
33
|
+
defineEmits(["update:model-value"]);
|
34
|
+
const props = defineProps<SliderFieldProps>();
|
35
|
+
const sliderProps = computed(() => ({ ...props, field: undefined, label: !!props.label }));
|
36
|
+
const priceLabel = computed(() => {
|
37
|
+
if (props.currency) {
|
38
|
+
return "$" + props.modelValue;
|
39
|
+
} else if (props.percent) {
|
40
|
+
return props.modelValue + "%";
|
41
|
+
} else {
|
42
|
+
return props.modelValue;
|
43
|
+
}
|
44
|
+
});
|
45
|
+
</script>
|
@@ -1,82 +1,63 @@
|
|
1
1
|
<template>
|
2
2
|
<div>
|
3
|
-
<QInput
|
4
|
-
v-if="!readonly"
|
5
|
-
:data-dusk="'text-field-' + field?.id"
|
6
|
-
:data-testid="'text-field-' + field?.id"
|
7
|
-
:placeholder="field?.placeholder"
|
8
|
-
outlined
|
9
|
-
dense
|
10
|
-
:disable="disabled"
|
11
|
-
:label-slot="!noLabel"
|
12
|
-
:input-class="inputClass"
|
13
|
-
:class="parentClass"
|
14
|
-
stack-label
|
15
|
-
:type="type"
|
16
|
-
:model-value="modelValue"
|
17
|
-
:debounce="debounce"
|
18
|
-
@keydown.enter="$emit('submit')"
|
19
|
-
@update:model-value="$emit('update:model-value', $event)"
|
20
|
-
>
|
21
|
-
<template #label>
|
22
|
-
<FieldLabel
|
23
|
-
:field="field"
|
24
|
-
:label="label"
|
25
|
-
:show-name="showName"
|
26
|
-
:class="labelClass"
|
27
|
-
/>
|
28
|
-
</template>
|
29
|
-
</QInput>
|
30
3
|
<div v-if="readonly">
|
31
4
|
<LabelValueBlock
|
32
|
-
:label="label || field
|
5
|
+
:label="label || field?.label || 'Text'"
|
33
6
|
:value="modelValue"
|
34
7
|
/>
|
35
8
|
</div>
|
9
|
+
<template v-else>
|
10
|
+
<QInput
|
11
|
+
:placeholder="field?.placeholder"
|
12
|
+
outlined
|
13
|
+
dense
|
14
|
+
:readonly="readonly"
|
15
|
+
:autogrow="autogrow"
|
16
|
+
:disable="disabled"
|
17
|
+
:label-slot="!noLabel"
|
18
|
+
:input-class="inputClass"
|
19
|
+
:class="parentClass"
|
20
|
+
stack-label
|
21
|
+
:type="type"
|
22
|
+
:model-value="modelValue"
|
23
|
+
:maxlength="allowOverMax ? undefined : field?.maxLength"
|
24
|
+
:debounce="debounce"
|
25
|
+
@keydown.enter="$emit('submit')"
|
26
|
+
@update:model-value="$emit('update:model-value', $event)"
|
27
|
+
>
|
28
|
+
<template #label>
|
29
|
+
<FieldLabel
|
30
|
+
:field="field"
|
31
|
+
:label="label"
|
32
|
+
:show-name="showName"
|
33
|
+
:class="labelClass"
|
34
|
+
/>
|
35
|
+
</template>
|
36
|
+
</QInput>
|
37
|
+
<MaxLengthCounter
|
38
|
+
:length="modelValue?.length || 0"
|
39
|
+
:max-length="field?.maxLength"
|
40
|
+
/>
|
41
|
+
</template>
|
36
42
|
</div>
|
37
43
|
</template>
|
38
44
|
|
39
|
-
<script setup>
|
45
|
+
<script setup lang="ts">
|
46
|
+
import { TextFieldProps } from "../../../../types";
|
47
|
+
import MaxLengthCounter from "../Utilities/MaxLengthCounter";
|
40
48
|
import FieldLabel from "./FieldLabel";
|
41
49
|
import LabelValueBlock from "./LabelValueBlock";
|
42
50
|
|
43
51
|
defineEmits(["update:model-value", "submit"]);
|
44
|
-
defineProps({
|
45
|
-
modelValue:
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
type: String,
|
55
|
-
default: "text"
|
56
|
-
},
|
57
|
-
label: {
|
58
|
-
type: String,
|
59
|
-
default: null
|
60
|
-
},
|
61
|
-
labelClass: {
|
62
|
-
type: String,
|
63
|
-
default: ""
|
64
|
-
},
|
65
|
-
parentClass: {
|
66
|
-
type: String,
|
67
|
-
default: ""
|
68
|
-
},
|
69
|
-
inputClass: {
|
70
|
-
type: String,
|
71
|
-
default: ""
|
72
|
-
},
|
73
|
-
noLabel: Boolean,
|
74
|
-
showName: Boolean,
|
75
|
-
disabled: Boolean,
|
76
|
-
readonly: Boolean,
|
77
|
-
debounce: {
|
78
|
-
type: [String, Number],
|
79
|
-
default: 0
|
80
|
-
}
|
52
|
+
withDefaults(defineProps<TextFieldProps>(), {
|
53
|
+
modelValue: "",
|
54
|
+
field: null,
|
55
|
+
type: "text",
|
56
|
+
label: "",
|
57
|
+
labelClass: "",
|
58
|
+
parentClass: "",
|
59
|
+
inputClass: "",
|
60
|
+
maxLength: null,
|
61
|
+
debounce: 0
|
81
62
|
});
|
82
63
|
</script>
|
@@ -5,6 +5,7 @@ export { default as DateRangeField } from "./DateRangeField.vue";
|
|
5
5
|
export { default as DateTimeField } from "./DateTimeField.vue";
|
6
6
|
export { default as DateTimePicker } from "./DateTimePicker.vue";
|
7
7
|
export { default as EditableDiv } from "./EditableDiv.vue";
|
8
|
+
export { default as EditOnClickTextField } from "./EditOnClickTextField.vue";
|
8
9
|
export { default as FieldLabel } from "./FieldLabel.vue";
|
9
10
|
export { default as FileUploadButton } from "./FileUploadButton.vue";
|
10
11
|
export { default as InlineDateTimeField } from "./InlineDateTimeField.vue";
|
@@ -20,5 +21,6 @@ export { default as SelectDrawer } from "./SelectDrawer.vue";
|
|
20
21
|
export { default as SelectField } from "./SelectField.vue";
|
21
22
|
export { default as SelectWithChildrenField } from "./SelectWithChildrenField.vue";
|
22
23
|
export { default as SingleFileField } from "./SingleFileField.vue";
|
24
|
+
export { default as SliderNumberField } from "./SliderNumberField.vue";
|
23
25
|
export { default as TextField } from "./TextField.vue";
|
24
26
|
export { default as WysiwygField } from "./WysiwygField.vue";
|
@@ -1,5 +1,5 @@
|
|
1
1
|
<template>
|
2
|
-
<div class="rendered-form">
|
2
|
+
<div class="dx-rendered-form">
|
3
3
|
<div
|
4
4
|
v-if="form.variations > 1"
|
5
5
|
class="mb-4"
|
@@ -65,16 +65,13 @@
|
|
65
65
|
<div
|
66
66
|
v-for="(field, index) in mappedFields"
|
67
67
|
:key="field.id"
|
68
|
-
:class="{ 'mt-4': index > 0 }"
|
68
|
+
:class="{ 'mt-4': index > 0, [fieldClass]: true }"
|
69
69
|
>
|
70
70
|
<RenderVnode
|
71
71
|
v-if="field.vnode"
|
72
72
|
:vnode="field.vnode"
|
73
|
-
:
|
74
|
-
:
|
75
|
-
:show-name="showName"
|
76
|
-
:no-label="noLabel"
|
77
|
-
:model-value="getFieldValue(field.name)"
|
73
|
+
:field="field"
|
74
|
+
:props="getVnodeProps(field)"
|
78
75
|
@update:model-value="onInput(field.name, $event)"
|
79
76
|
/>
|
80
77
|
<Component
|
@@ -85,11 +82,31 @@
|
|
85
82
|
:label="field.label || undefined"
|
86
83
|
:no-label="noLabel"
|
87
84
|
:show-name="showName"
|
85
|
+
:clearable="field.clearable || clearable"
|
88
86
|
:disable="disable"
|
89
87
|
:readonly="readonly"
|
90
88
|
@update:model-value="onInput(field.name, $event)"
|
91
89
|
/>
|
92
90
|
</div>
|
91
|
+
<div
|
92
|
+
v-if="savedAt"
|
93
|
+
:class="savingClass"
|
94
|
+
class="dx-saving-indicator flex items-center flex-nowrap"
|
95
|
+
>
|
96
|
+
<slot
|
97
|
+
v-if="saving"
|
98
|
+
name="saving"
|
99
|
+
>
|
100
|
+
Saving...
|
101
|
+
<QSpinnerPie class="ml-2" />
|
102
|
+
</slot>
|
103
|
+
<slot
|
104
|
+
v-else
|
105
|
+
name="saved"
|
106
|
+
>
|
107
|
+
Saved at {{ fDateTime(savedAt, { format: "M/d/yy h:mm:ssa" }) }}
|
108
|
+
</slot>
|
109
|
+
</div>
|
93
110
|
<ConfirmDialog
|
94
111
|
v-if="variationToEdit !== false"
|
95
112
|
title="Change variation name"
|
@@ -117,8 +134,9 @@
|
|
117
134
|
<script setup lang="ts">
|
118
135
|
import { ExclamationCircleIcon as MissingIcon, PencilIcon as EditIcon } from "@heroicons/vue/solid";
|
119
136
|
import { computed, ref } from "vue";
|
120
|
-
import { FlashMessages, incrementName, replace } from "../../../helpers";
|
137
|
+
import { fDateTime, FlashMessages, incrementName, replace } from "../../../helpers";
|
121
138
|
import { TrashIcon as RemoveIcon } from "../../../svg";
|
139
|
+
import { Form, FormFieldValue } from "../../../types";
|
122
140
|
import { ConfirmDialog, RenderVnode } from "../../Utility";
|
123
141
|
import {
|
124
142
|
BooleanField,
|
@@ -131,9 +149,8 @@ import {
|
|
131
149
|
TextField,
|
132
150
|
WysiwygField
|
133
151
|
} from "./Fields";
|
134
|
-
import { Form, FormFieldValue } from "./form.d.ts";
|
135
152
|
|
136
|
-
export interface
|
153
|
+
export interface RenderedFormProps {
|
137
154
|
values?: FormFieldValue[] | object;
|
138
155
|
form: Form;
|
139
156
|
noLabel?: boolean;
|
@@ -141,13 +158,20 @@ export interface Props {
|
|
141
158
|
disable?: boolean;
|
142
159
|
readonly?: boolean;
|
143
160
|
saving?: boolean;
|
161
|
+
clearable?: boolean;
|
144
162
|
emptyValue?: string | number | boolean;
|
145
163
|
canModifyVariations?: boolean;
|
164
|
+
fieldClass?: string;
|
165
|
+
savingClass?: string;
|
166
|
+
savedAt?: string;
|
146
167
|
}
|
147
168
|
|
148
|
-
const props = withDefaults(defineProps<
|
169
|
+
const props = withDefaults(defineProps<RenderedFormProps>(), {
|
149
170
|
values: null,
|
150
|
-
emptyValue: undefined
|
171
|
+
emptyValue: undefined,
|
172
|
+
fieldClass: "",
|
173
|
+
savingClass: "text-sm text-slate-500 justify-end mt-4",
|
174
|
+
savedAt: null
|
151
175
|
});
|
152
176
|
|
153
177
|
const emit = defineEmits(["update:values"]);
|
@@ -176,6 +200,19 @@ const fieldResponses = computed(() => {
|
|
176
200
|
if (Array.isArray(props.values)) return props.values;
|
177
201
|
return Object.entries(props.values).map(([name, value]) => ({ name, value, variation: "" }));
|
178
202
|
});
|
203
|
+
|
204
|
+
function getVnodeProps(field) {
|
205
|
+
return {
|
206
|
+
modelValue: getFieldValue(field.name),
|
207
|
+
label: field.label,
|
208
|
+
clearable: field.clearable || props.clearable,
|
209
|
+
readonly: props.readonly,
|
210
|
+
disable: props.disable,
|
211
|
+
showName: props.showName,
|
212
|
+
noLabel: props.noLabel
|
213
|
+
};
|
214
|
+
}
|
215
|
+
|
179
216
|
const variationNames = computed(() => {
|
180
217
|
const names = [...new Set(fieldResponses.value.map(v => v.variation))].sort();
|
181
218
|
// Always guarantee that we show the default variation
|
@@ -187,7 +224,7 @@ const variationNames = computed(() => {
|
|
187
224
|
|
188
225
|
const currentVariation = ref(variationNames.value[0] || "");
|
189
226
|
const newVariationName = ref("");
|
190
|
-
const variationToEdit = ref(false);
|
227
|
+
const variationToEdit = ref<boolean | string>(false);
|
191
228
|
const variationToDelete = ref("");
|
192
229
|
const canAddVariation = computed(() => props.canModifyVariations && !props.readonly && !props.disable && variationNames.value.length < props.form.variations);
|
193
230
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<template>
|
2
|
+
<div
|
3
|
+
v-if="maxLength"
|
4
|
+
class="danx-input-chars mt-1"
|
5
|
+
:class="{'danx-input-chars--error': length > maxLength}"
|
6
|
+
>
|
7
|
+
{{ fNumber(length) }} / {{ fNumber(maxLength) }} characters
|
8
|
+
</div>
|
9
|
+
</template>
|
10
|
+
<script setup lang="ts">
|
11
|
+
import { fNumber } from "../../../../helpers";
|
12
|
+
|
13
|
+
defineProps<{
|
14
|
+
length: number;
|
15
|
+
maxLength?: number;
|
16
|
+
}>();
|
17
|
+
</script>
|
@@ -0,0 +1 @@
|
|
1
|
+
export { default as MaxLengthCounter } from "./MaxLengthCounter.vue";
|
@@ -3,21 +3,27 @@
|
|
3
3
|
<slot name="top" />
|
4
4
|
<slot name="toolbar">
|
5
5
|
<ActionToolbar
|
6
|
+
:title="title"
|
6
7
|
:refresh-button="refreshButton"
|
7
8
|
:actions="actions?.filter(a => a.batch)"
|
8
9
|
:action-target="controller.selectedRows.value"
|
9
10
|
:exporter="controller.exportList"
|
10
11
|
@refresh="controller.refreshAll"
|
11
|
-
|
12
|
+
>
|
13
|
+
<template #default>
|
14
|
+
<slot name="action-toolbar" />
|
15
|
+
</template>
|
16
|
+
</ActionToolbar>
|
12
17
|
</slot>
|
13
18
|
<div class="flex flex-nowrap flex-grow overflow-hidden w-full">
|
14
|
-
<slot name="
|
19
|
+
<slot name="filters">
|
15
20
|
<CollapsableFiltersSidebar
|
16
21
|
v-if="activeFilter"
|
17
22
|
:name="controller.name"
|
18
23
|
:show-filters="showFilters"
|
19
24
|
:filters="filters"
|
20
25
|
:active-filter="activeFilter"
|
26
|
+
class="dx-action-table-filters"
|
21
27
|
@update:active-filter="controller.setActiveFilter"
|
22
28
|
/>
|
23
29
|
</slot>
|
@@ -43,6 +49,7 @@
|
|
43
49
|
v-if="activeItem && panels"
|
44
50
|
:title="panelTitle"
|
45
51
|
:model-value="activePanel"
|
52
|
+
:active-item="activeItem"
|
46
53
|
:panels="panels"
|
47
54
|
@update:model-value="panel => controller.activatePanel(activeItem, panel)"
|
48
55
|
@close="controller.setActiveItem(null)"
|
@@ -60,26 +67,25 @@
|
|
60
67
|
</template>
|
61
68
|
<script setup lang="ts">
|
62
69
|
import { computed } from "vue";
|
63
|
-
import { ActionOptions } from "../../../
|
70
|
+
import { ActionController, ActionOptions, ActionPanel, FilterGroup, TableColumn } from "../../../types";
|
64
71
|
import { PanelsDrawer } from "../../PanelsDrawer";
|
65
72
|
import { PreviousNextControls } from "../../Utility";
|
66
73
|
import ActionTable from "../ActionTable";
|
67
74
|
import { CollapsableFiltersSidebar } from "../Filters";
|
68
|
-
import { ActionController, ActionPanel, FilterField } from "../listControls";
|
69
|
-
import { TableColumn } from "../tableColumns";
|
70
75
|
import { ActionToolbar } from "../Toolbars";
|
71
76
|
|
72
77
|
const props = defineProps<{
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
78
|
+
title?: string;
|
79
|
+
refreshButton: boolean;
|
80
|
+
showFilters: boolean;
|
81
|
+
controller: ActionController;
|
82
|
+
columns: TableColumn[];
|
83
|
+
filters?: FilterGroup[];
|
84
|
+
panels?: ActionPanel[];
|
85
|
+
actions?: ActionOptions[];
|
86
|
+
exporter?: () => Promise<void>;
|
87
|
+
panelTitleField?: string;
|
88
|
+
tableClass?: string;
|
83
89
|
}>();
|
84
90
|
|
85
91
|
const activeFilter = computed(() => props.controller.activeFilter.value);
|
@@ -87,7 +93,7 @@ const activeItem = computed(() => props.controller.activeItem.value);
|
|
87
93
|
const activePanel = computed(() => props.controller.activePanel.value || "");
|
88
94
|
const panelTitle = computed(() => {
|
89
95
|
if (activeItem.value) {
|
90
|
-
return activeItem.value[props.
|
96
|
+
return activeItem.value[props.panelTitleField || "title"] || activeItem.value.label || activeItem.value.name || (props.title + " " + activeItem.value.id);
|
91
97
|
}
|
92
98
|
return null;
|
93
99
|
});
|
@@ -1,10 +1,10 @@
|
|
1
1
|
<template>
|
2
|
-
<div class="flex items-center">
|
2
|
+
<div class="dx-action-toolbar flex items-center">
|
3
3
|
<div class="flex-grow px-6">
|
4
4
|
<slot name="title">
|
5
|
-
<
|
5
|
+
<h4 v-if="title">
|
6
6
|
{{ title }}
|
7
|
-
</
|
7
|
+
</h4>
|
8
8
|
</slot>
|
9
9
|
</div>
|
10
10
|
<div class="py-3 px-6 flex items-center flex-nowrap">
|
@@ -20,7 +20,7 @@
|
|
20
20
|
class="ml-4"
|
21
21
|
/>
|
22
22
|
<ActionMenu
|
23
|
-
v-if="actions.length > 0"
|
23
|
+
v-if="actions && actions.length > 0"
|
24
24
|
class="ml-4 dx-batch-actions"
|
25
25
|
:target="actionTarget"
|
26
26
|
:actions="actions"
|
@@ -30,17 +30,17 @@
|
|
30
30
|
</div>
|
31
31
|
</template>
|
32
32
|
<script setup lang="ts">
|
33
|
-
import { ActionOptions, ActionTargetItem } from "../../../
|
33
|
+
import { ActionOptions, ActionTargetItem, AnyObject } from "../../../types";
|
34
34
|
import { ExportButton, RefreshButton } from "../../Utility";
|
35
35
|
import ActionMenu from "../ActionMenu";
|
36
36
|
|
37
37
|
defineEmits(["refresh"]);
|
38
38
|
defineProps<{
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
39
|
+
title?: string,
|
40
|
+
actions?: ActionOptions[],
|
41
|
+
actionTarget?: ActionTargetItem[],
|
42
|
+
refreshButton?: boolean,
|
43
|
+
loading?: boolean,
|
44
|
+
exporter?: (filter?: AnyObject) => void | Promise<void>
|
45
45
|
}>();
|
46
46
|
</script>
|