quasar-ui-danx 0.0.10 → 0.0.11
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 +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
 
| 
         @@ -0,0 +1,318 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <template>
         
     | 
| 
      
 2 
     | 
    
         
            +
              <div>
         
     | 
| 
      
 3 
     | 
    
         
            +
                <QSelect
         
     | 
| 
      
 4 
     | 
    
         
            +
                  ref="selectField"
         
     | 
| 
      
 5 
     | 
    
         
            +
                  v-bind="$props"
         
     | 
| 
      
 6 
     | 
    
         
            +
                  :model-value="selectedValue"
         
     | 
| 
      
 7 
     | 
    
         
            +
                  outlined
         
     | 
| 
      
 8 
     | 
    
         
            +
                  hide-dropdown-icon
         
     | 
| 
      
 9 
     | 
    
         
            +
                  dense
         
     | 
| 
      
 10 
     | 
    
         
            +
                  emit-value
         
     | 
| 
      
 11 
     | 
    
         
            +
                  :use-input="filterable"
         
     | 
| 
      
 12 
     | 
    
         
            +
                  :hide-selected="filterable && isShowing && !$props.multiple"
         
     | 
| 
      
 13 
     | 
    
         
            +
                  :input-debounce="100"
         
     | 
| 
      
 14 
     | 
    
         
            +
                  :options="filteredOptions"
         
     | 
| 
      
 15 
     | 
    
         
            +
                  option-label="label"
         
     | 
| 
      
 16 
     | 
    
         
            +
                  option-value="value"
         
     | 
| 
      
 17 
     | 
    
         
            +
                  placeholder=""
         
     | 
| 
      
 18 
     | 
    
         
            +
                  :input-class="{'is-hidden': !isShowing, [inputClass]: true}"
         
     | 
| 
      
 19 
     | 
    
         
            +
                  class="max-w-full"
         
     | 
| 
      
 20 
     | 
    
         
            +
                  @filter="onFilter"
         
     | 
| 
      
 21 
     | 
    
         
            +
                  @clear="onClear"
         
     | 
| 
      
 22 
     | 
    
         
            +
                  @popup-show="onShow"
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @popup-hide="onHide"
         
     | 
| 
      
 24 
     | 
    
         
            +
                  @update:model-value="onUpdate"
         
     | 
| 
      
 25 
     | 
    
         
            +
                >
         
     | 
| 
      
 26 
     | 
    
         
            +
                  <template #append>
         
     | 
| 
      
 27 
     | 
    
         
            +
                    <DropDownIcon
         
     | 
| 
      
 28 
     | 
    
         
            +
                      class="w-4 transition"
         
     | 
| 
      
 29 
     | 
    
         
            +
                      :class="isShowing ? 'rotate-180' : ''"
         
     | 
| 
      
 30 
     | 
    
         
            +
                    />
         
     | 
| 
      
 31 
     | 
    
         
            +
                  </template>
         
     | 
| 
      
 32 
     | 
    
         
            +
                  <template #selected>
         
     | 
| 
      
 33 
     | 
    
         
            +
                    <div
         
     | 
| 
      
 34 
     | 
    
         
            +
                      v-if="$props.multiple"
         
     | 
| 
      
 35 
     | 
    
         
            +
                      class="flex gap-y-1 overflow-hidden"
         
     | 
| 
      
 36 
     | 
    
         
            +
                      :class="{'flex-nowrap gap-y-0': chipLimit === 1, [selectionClass]: true}"
         
     | 
| 
      
 37 
     | 
    
         
            +
                    >
         
     | 
| 
      
 38 
     | 
    
         
            +
                      <template v-if="chipOptions.length > 0">
         
     | 
| 
      
 39 
     | 
    
         
            +
                        <QChip
         
     | 
| 
      
 40 
     | 
    
         
            +
                          v-for="chipOption in chipOptions"
         
     | 
| 
      
 41 
     | 
    
         
            +
                          :key="'selected-' + chipOption.label"
         
     | 
| 
      
 42 
     | 
    
         
            +
                          class="!mr-1"
         
     | 
| 
      
 43 
     | 
    
         
            +
                        >{{ chipOption.label }}
         
     | 
| 
      
 44 
     | 
    
         
            +
                        </QChip>
         
     | 
| 
      
 45 
     | 
    
         
            +
                        <QChip
         
     | 
| 
      
 46 
     | 
    
         
            +
                          v-if="selectedOptions.length > chipOptions.length"
         
     | 
| 
      
 47 
     | 
    
         
            +
                          class="!mr-1"
         
     | 
| 
      
 48 
     | 
    
         
            +
                        >
         
     | 
| 
      
 49 
     | 
    
         
            +
                          +{{ selectedOptions.length - chipOptions.length }}
         
     | 
| 
      
 50 
     | 
    
         
            +
                        </QChip>
         
     | 
| 
      
 51 
     | 
    
         
            +
                      </template>
         
     | 
| 
      
 52 
     | 
    
         
            +
                      <template v-else>
         
     | 
| 
      
 53 
     | 
    
         
            +
                        {{ placeholder }}
         
     | 
| 
      
 54 
     | 
    
         
            +
                      </template>
         
     | 
| 
      
 55 
     | 
    
         
            +
                    </div>
         
     | 
| 
      
 56 
     | 
    
         
            +
                    <div
         
     | 
| 
      
 57 
     | 
    
         
            +
                      v-else
         
     | 
| 
      
 58 
     | 
    
         
            +
                      :class="selectionClass"
         
     | 
| 
      
 59 
     | 
    
         
            +
                    >{{ selectedLabel }}
         
     | 
| 
      
 60 
     | 
    
         
            +
                    </div>
         
     | 
| 
      
 61 
     | 
    
         
            +
                  </template>
         
     | 
| 
      
 62 
     | 
    
         
            +
                </QSelect>
         
     | 
| 
      
 63 
     | 
    
         
            +
              </div>
         
     | 
| 
      
 64 
     | 
    
         
            +
            </template>
         
     | 
| 
      
 65 
     | 
    
         
            +
            <script setup>
         
     | 
| 
      
 66 
     | 
    
         
            +
            import { ChevronDownIcon as DropDownIcon } from "@heroicons/vue/outline";
         
     | 
| 
      
 67 
     | 
    
         
            +
            import { QSelect } from "quasar";
         
     | 
| 
      
 68 
     | 
    
         
            +
            import { computed, isRef, nextTick, ref } from "vue";
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
            const emit = defineEmits(["update:model-value", "search"]);
         
     | 
| 
      
 71 
     | 
    
         
            +
            const props = defineProps({
         
     | 
| 
      
 72 
     | 
    
         
            +
              ...QSelect.props,
         
     | 
| 
      
 73 
     | 
    
         
            +
              modelValue: {
         
     | 
| 
      
 74 
     | 
    
         
            +
                type: [Array, String, Number, Object],
         
     | 
| 
      
 75 
     | 
    
         
            +
                default: undefined
         
     | 
| 
      
 76 
     | 
    
         
            +
              },
         
     | 
| 
      
 77 
     | 
    
         
            +
              placeholder: {
         
     | 
| 
      
 78 
     | 
    
         
            +
                type: String,
         
     | 
| 
      
 79 
     | 
    
         
            +
                default: ""
         
     | 
| 
      
 80 
     | 
    
         
            +
              },
         
     | 
| 
      
 81 
     | 
    
         
            +
              selectionLabel: {
         
     | 
| 
      
 82 
     | 
    
         
            +
                type: String,
         
     | 
| 
      
 83 
     | 
    
         
            +
                default: null
         
     | 
| 
      
 84 
     | 
    
         
            +
              },
         
     | 
| 
      
 85 
     | 
    
         
            +
              chipLimit: {
         
     | 
| 
      
 86 
     | 
    
         
            +
                type: Number,
         
     | 
| 
      
 87 
     | 
    
         
            +
                default: 3
         
     | 
| 
      
 88 
     | 
    
         
            +
              },
         
     | 
| 
      
 89 
     | 
    
         
            +
              inputClass: {
         
     | 
| 
      
 90 
     | 
    
         
            +
                type: String,
         
     | 
| 
      
 91 
     | 
    
         
            +
                default: ""
         
     | 
| 
      
 92 
     | 
    
         
            +
              },
         
     | 
| 
      
 93 
     | 
    
         
            +
              selectionClass: {
         
     | 
| 
      
 94 
     | 
    
         
            +
                type: String,
         
     | 
| 
      
 95 
     | 
    
         
            +
                default: ""
         
     | 
| 
      
 96 
     | 
    
         
            +
              },
         
     | 
| 
      
 97 
     | 
    
         
            +
              options: {
         
     | 
| 
      
 98 
     | 
    
         
            +
                type: Array,
         
     | 
| 
      
 99 
     | 
    
         
            +
                default: () => []
         
     | 
| 
      
 100 
     | 
    
         
            +
              },
         
     | 
| 
      
 101 
     | 
    
         
            +
              filterable: Boolean,
         
     | 
| 
      
 102 
     | 
    
         
            +
              filterFn: {
         
     | 
| 
      
 103 
     | 
    
         
            +
                type: Function,
         
     | 
| 
      
 104 
     | 
    
         
            +
                default: null
         
     | 
| 
      
 105 
     | 
    
         
            +
              }
         
     | 
| 
      
 106 
     | 
    
         
            +
            });
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
            const selectField = ref(null);
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
            // The filter applied to the dropdown list of options
         
     | 
| 
      
 111 
     | 
    
         
            +
            const filter = ref(null);
         
     | 
| 
      
 112 
     | 
    
         
            +
            // Is showing the dropdown list
         
     | 
| 
      
 113 
     | 
    
         
            +
            const isShowing = ref(false);
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
            /**
         
     | 
| 
      
 116 
     | 
    
         
            +
             * The options formatted so each has a label, value and selectionLabel
         
     | 
| 
      
 117 
     | 
    
         
            +
             * @type {ComputedRef<{selectionLabel: string, label: string, value: string|*}[]>}
         
     | 
| 
      
 118 
     | 
    
         
            +
             */
         
     | 
| 
      
 119 
     | 
    
         
            +
            const computedOptions = computed(() => {
         
     | 
| 
      
 120 
     | 
    
         
            +
              let options = props.options;
         
     | 
| 
      
 121 
     | 
    
         
            +
              if (props.placeholder && !props.multiple && !props.filterable) {
         
     | 
| 
      
 122 
     | 
    
         
            +
                options = [{ label: props.placeholder, value: null }, ...props.options];
         
     | 
| 
      
 123 
     | 
    
         
            +
              }
         
     | 
| 
      
 124 
     | 
    
         
            +
              options = options.map((o) => {
         
     | 
| 
      
 125 
     | 
    
         
            +
                let opt = isRef(o) ? o.value : o;
         
     | 
| 
      
 126 
     | 
    
         
            +
                return {
         
     | 
| 
      
 127 
     | 
    
         
            +
                  label: resolveLabel(opt),
         
     | 
| 
      
 128 
     | 
    
         
            +
                  value: resolveValue(opt),
         
     | 
| 
      
 129 
     | 
    
         
            +
                  selectionLabel: resolveSelectionLabel(opt)
         
     | 
| 
      
 130 
     | 
    
         
            +
                };
         
     | 
| 
      
 131 
     | 
    
         
            +
              });
         
     | 
| 
      
 132 
     | 
    
         
            +
              return options;
         
     | 
| 
      
 133 
     | 
    
         
            +
            });
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
            const filteredOptions = computed(() => {
         
     | 
| 
      
 136 
     | 
    
         
            +
              if (filter.value && !props.filterFn) {
         
     | 
| 
      
 137 
     | 
    
         
            +
                return computedOptions.value.filter(o => o.label.toLocaleLowerCase().indexOf(filter.value.toLowerCase()) > -1);
         
     | 
| 
      
 138 
     | 
    
         
            +
              } else {
         
     | 
| 
      
 139 
     | 
    
         
            +
                return computedOptions.value;
         
     | 
| 
      
 140 
     | 
    
         
            +
              }
         
     | 
| 
      
 141 
     | 
    
         
            +
            });
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
            /**
         
     | 
| 
      
 144 
     | 
    
         
            +
             * The value selected. Basically a wrapper to better handle null values (see onUpdate function for more details)
         
     | 
| 
      
 145 
     | 
    
         
            +
             * @type {ComputedRef<unknown>}
         
     | 
| 
      
 146 
     | 
    
         
            +
             */
         
     | 
| 
      
 147 
     | 
    
         
            +
            const selectedValue = computed(() => {
         
     | 
| 
      
 148 
     | 
    
         
            +
              if (props.multiple) {
         
     | 
| 
      
 149 
     | 
    
         
            +
                const arrVal = Array.isArray(props.modelValue) ? props.modelValue : [];
         
     | 
| 
      
 150 
     | 
    
         
            +
                return arrVal.map((v) => {
         
     | 
| 
      
 151 
     | 
    
         
            +
                  return v === null ? "__null__" : v;
         
     | 
| 
      
 152 
     | 
    
         
            +
                }) || [];
         
     | 
| 
      
 153 
     | 
    
         
            +
              } else {
         
     | 
| 
      
 154 
     | 
    
         
            +
                return props.modelValue === null ? "__null__" : props.modelValue;
         
     | 
| 
      
 155 
     | 
    
         
            +
              }
         
     | 
| 
      
 156 
     | 
    
         
            +
            });
         
     | 
| 
      
 157 
     | 
    
         
            +
             
     | 
| 
      
 158 
     | 
    
         
            +
            /**
         
     | 
| 
      
 159 
     | 
    
         
            +
             * The selected options. The list of options from the computedOptions list that are selected as defined by the modelValue
         
     | 
| 
      
 160 
     | 
    
         
            +
             * @type {ComputedRef<*>}
         
     | 
| 
      
 161 
     | 
    
         
            +
             */
         
     | 
| 
      
 162 
     | 
    
         
            +
            const selectedOptions = computed(() => {
         
     | 
| 
      
 163 
     | 
    
         
            +
              let values = selectedValue.value;
         
     | 
| 
      
 164 
     | 
    
         
            +
              if (!props.multiple) {
         
     | 
| 
      
 165 
     | 
    
         
            +
                values = (values || values === 0) ? [values] : [];
         
     | 
| 
      
 166 
     | 
    
         
            +
              }
         
     | 
| 
      
 167 
     | 
    
         
            +
              return computedOptions.value.filter((o) => {
         
     | 
| 
      
 168 
     | 
    
         
            +
                return values.includes(o.value) || values.map(v => typeof v === "object" && v.id).includes(o.value?.id);
         
     | 
| 
      
 169 
     | 
    
         
            +
              });
         
     | 
| 
      
 170 
     | 
    
         
            +
            });
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
            /**
         
     | 
| 
      
 173 
     | 
    
         
            +
             * The label to display in the input field of the dropdown for a selected state, non-selected state or an active filtering state.
         
     | 
| 
      
 174 
     | 
    
         
            +
             * NOTE: Only applies to single select (not multiselect)
         
     | 
| 
      
 175 
     | 
    
         
            +
             * @type {ComputedRef<unknown>}
         
     | 
| 
      
 176 
     | 
    
         
            +
             */
         
     | 
| 
      
 177 
     | 
    
         
            +
            const selectedLabel = computed(() => {
         
     | 
| 
      
 178 
     | 
    
         
            +
              if (props.filterable && isShowing.value) return "";
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
              if (!selectedOptions.value || selectedOptions.value.length === 0) {
         
     | 
| 
      
 181 
     | 
    
         
            +
                return props.placeholder || "(Select Option)";
         
     | 
| 
      
 182 
     | 
    
         
            +
              }
         
     | 
| 
      
 183 
     | 
    
         
            +
              return selectedOptions.value[0].selectionLabel;
         
     | 
| 
      
 184 
     | 
    
         
            +
            });
         
     | 
| 
      
 185 
     | 
    
         
            +
             
     | 
| 
      
 186 
     | 
    
         
            +
            /**
         
     | 
| 
      
 187 
     | 
    
         
            +
             * The options to display as chips (limited by chipLimit prop)
         
     | 
| 
      
 188 
     | 
    
         
            +
             * @type {ComputedRef<*>}
         
     | 
| 
      
 189 
     | 
    
         
            +
             */
         
     | 
| 
      
 190 
     | 
    
         
            +
            const chipOptions = computed(() => {
         
     | 
| 
      
 191 
     | 
    
         
            +
              return selectedOptions.value.slice(0, props.chipLimit);
         
     | 
| 
      
 192 
     | 
    
         
            +
            });
         
     | 
| 
      
 193 
     | 
    
         
            +
             
     | 
| 
      
 194 
     | 
    
         
            +
            /**
         
     | 
| 
      
 195 
     | 
    
         
            +
             * Resolve the label of the option. This will display as the text in the dropdown list
         
     | 
| 
      
 196 
     | 
    
         
            +
             * @param option
         
     | 
| 
      
 197 
     | 
    
         
            +
             * @returns {*|string}
         
     | 
| 
      
 198 
     | 
    
         
            +
             */
         
     | 
| 
      
 199 
     | 
    
         
            +
            function resolveLabel(option) {
         
     | 
| 
      
 200 
     | 
    
         
            +
              if (typeof option === "string") {
         
     | 
| 
      
 201 
     | 
    
         
            +
                return option;
         
     | 
| 
      
 202 
     | 
    
         
            +
              }
         
     | 
| 
      
 203 
     | 
    
         
            +
              if (typeof props.optionLabel === "string") {
         
     | 
| 
      
 204 
     | 
    
         
            +
                return option[props.optionLabel];
         
     | 
| 
      
 205 
     | 
    
         
            +
              }
         
     | 
| 
      
 206 
     | 
    
         
            +
              if (typeof props.optionLabel === "function") {
         
     | 
| 
      
 207 
     | 
    
         
            +
                return props.optionLabel(option);
         
     | 
| 
      
 208 
     | 
    
         
            +
              }
         
     | 
| 
      
 209 
     | 
    
         
            +
              return option?.label;
         
     | 
| 
      
 210 
     | 
    
         
            +
            }
         
     | 
| 
      
 211 
     | 
    
         
            +
             
     | 
| 
      
 212 
     | 
    
         
            +
            /**
         
     | 
| 
      
 213 
     | 
    
         
            +
             * Resolve the label to display in the input field of the dropdown when an option is selected
         
     | 
| 
      
 214 
     | 
    
         
            +
             * NOTE: Does not apply to multiselect, single select only
         
     | 
| 
      
 215 
     | 
    
         
            +
             * @param option
         
     | 
| 
      
 216 
     | 
    
         
            +
             * @returns {*|{default: null, type: String | StringConstructor}|string}
         
     | 
| 
      
 217 
     | 
    
         
            +
             */
         
     | 
| 
      
 218 
     | 
    
         
            +
            function resolveSelectionLabel(option) {
         
     | 
| 
      
 219 
     | 
    
         
            +
              if (typeof option === "string") {
         
     | 
| 
      
 220 
     | 
    
         
            +
                return option;
         
     | 
| 
      
 221 
     | 
    
         
            +
              }
         
     | 
| 
      
 222 
     | 
    
         
            +
              if (typeof props.selectionLabel === "string") {
         
     | 
| 
      
 223 
     | 
    
         
            +
                return option[props.selectionLabel];
         
     | 
| 
      
 224 
     | 
    
         
            +
              }
         
     | 
| 
      
 225 
     | 
    
         
            +
              if (typeof props.selectionLabel === "function") {
         
     | 
| 
      
 226 
     | 
    
         
            +
                return props.selectionLabel(option);
         
     | 
| 
      
 227 
     | 
    
         
            +
              }
         
     | 
| 
      
 228 
     | 
    
         
            +
              return option?.selectionLabel || option?.label;
         
     | 
| 
      
 229 
     | 
    
         
            +
            }
         
     | 
| 
      
 230 
     | 
    
         
            +
             
     | 
| 
      
 231 
     | 
    
         
            +
            /**
         
     | 
| 
      
 232 
     | 
    
         
            +
             * Resolve the value of the option using either defaults or the provided optionValue prop
         
     | 
| 
      
 233 
     | 
    
         
            +
             * @param option
         
     | 
| 
      
 234 
     | 
    
         
            +
             * @returns {string|*|string}
         
     | 
| 
      
 235 
     | 
    
         
            +
             */
         
     | 
| 
      
 236 
     | 
    
         
            +
            function resolveValue(option) {
         
     | 
| 
      
 237 
     | 
    
         
            +
              if (typeof option === "string") {
         
     | 
| 
      
 238 
     | 
    
         
            +
                return option;
         
     | 
| 
      
 239 
     | 
    
         
            +
              }
         
     | 
| 
      
 240 
     | 
    
         
            +
              let value = option.value;
         
     | 
| 
      
 241 
     | 
    
         
            +
              if (typeof props.optionValue === "string") {
         
     | 
| 
      
 242 
     | 
    
         
            +
                value = option[props.optionValue];
         
     | 
| 
      
 243 
     | 
    
         
            +
              } else if (typeof props.optionValue === "function") {
         
     | 
| 
      
 244 
     | 
    
         
            +
                value = props.optionValue(option);
         
     | 
| 
      
 245 
     | 
    
         
            +
              }
         
     | 
| 
      
 246 
     | 
    
         
            +
              // Note the __null__ special case here. See the onUpdate function for more details
         
     | 
| 
      
 247 
     | 
    
         
            +
              return value === null ? "__null__" : value;
         
     | 
| 
      
 248 
     | 
    
         
            +
            }
         
     | 
| 
      
 249 
     | 
    
         
            +
             
     | 
| 
      
 250 
     | 
    
         
            +
            /**
         
     | 
| 
      
 251 
     | 
    
         
            +
             * Handle the update event from the QSelect
         
     | 
| 
      
 252 
     | 
    
         
            +
             * NOTE: casts all null values as a special __null__ string as the null character is handled the same as undefined by QSelect.
         
     | 
| 
      
 253 
     | 
    
         
            +
             * SelectField differentiates between these 2 to provide a null value selected state vs undefined is no value selected.
         
     | 
| 
      
 254 
     | 
    
         
            +
             * @param value
         
     | 
| 
      
 255 
     | 
    
         
            +
             */
         
     | 
| 
      
 256 
     | 
    
         
            +
            function onUpdate(value) {
         
     | 
| 
      
 257 
     | 
    
         
            +
              if (Array.isArray(value)) {
         
     | 
| 
      
 258 
     | 
    
         
            +
                value = value.map((v) => v === "__null__" ? null : v);
         
     | 
| 
      
 259 
     | 
    
         
            +
              }
         
     | 
| 
      
 260 
     | 
    
         
            +
              emit("update:model-value", value === "__null__" ? null : value);
         
     | 
| 
      
 261 
     | 
    
         
            +
            }
         
     | 
| 
      
 262 
     | 
    
         
            +
             
     | 
| 
      
 263 
     | 
    
         
            +
            /** XXX: This tells us when we should apply the filter. QSelect likes to trigger a new filter everytime you open the dropdown
         
     | 
| 
      
 264 
     | 
    
         
            +
             *       But most of the time when you open the dropdown it is already filtered and annoying to try and clear the previous filter
         
     | 
| 
      
 265 
     | 
    
         
            +
             **/
         
     | 
| 
      
 266 
     | 
    
         
            +
            const shouldFilter = ref(false);
         
     | 
| 
      
 267 
     | 
    
         
            +
             
     | 
| 
      
 268 
     | 
    
         
            +
            /**
         
     | 
| 
      
 269 
     | 
    
         
            +
             * Filter the options list. Do this asynchronously for the update so that the QSelect can update its internal state first, then update SelectField
         
     | 
| 
      
 270 
     | 
    
         
            +
             * @param val
         
     | 
| 
      
 271 
     | 
    
         
            +
             * @param update
         
     | 
| 
      
 272 
     | 
    
         
            +
             */
         
     | 
| 
      
 273 
     | 
    
         
            +
            async function onFilter(val, update) {
         
     | 
| 
      
 274 
     | 
    
         
            +
              if (!props.filterFn) {
         
     | 
| 
      
 275 
     | 
    
         
            +
                filter.value = val;
         
     | 
| 
      
 276 
     | 
    
         
            +
                await nextTick(update);
         
     | 
| 
      
 277 
     | 
    
         
            +
              } else {
         
     | 
| 
      
 278 
     | 
    
         
            +
                update();
         
     | 
| 
      
 279 
     | 
    
         
            +
                if (shouldFilter.value === false) return;
         
     | 
| 
      
 280 
     | 
    
         
            +
                if (val !== null && val !== filter.value) {
         
     | 
| 
      
 281 
     | 
    
         
            +
                  filter.value = val;
         
     | 
| 
      
 282 
     | 
    
         
            +
                  if (props.filterFn) {
         
     | 
| 
      
 283 
     | 
    
         
            +
                    await props.filterFn(val);
         
     | 
| 
      
 284 
     | 
    
         
            +
                  }
         
     | 
| 
      
 285 
     | 
    
         
            +
                }
         
     | 
| 
      
 286 
     | 
    
         
            +
              }
         
     | 
| 
      
 287 
     | 
    
         
            +
            }
         
     | 
| 
      
 288 
     | 
    
         
            +
             
     | 
| 
      
 289 
     | 
    
         
            +
            /**
         
     | 
| 
      
 290 
     | 
    
         
            +
             * Clear the selected value using undefined. SelectField differentiates between null and undefined.
         
     | 
| 
      
 291 
     | 
    
         
            +
             * See the onUpdate function for more details
         
     | 
| 
      
 292 
     | 
    
         
            +
             */
         
     | 
| 
      
 293 
     | 
    
         
            +
            function onClear() {
         
     | 
| 
      
 294 
     | 
    
         
            +
              emit("update:model-value", undefined);
         
     | 
| 
      
 295 
     | 
    
         
            +
            }
         
     | 
| 
      
 296 
     | 
    
         
            +
             
     | 
| 
      
 297 
     | 
    
         
            +
            /**
         
     | 
| 
      
 298 
     | 
    
         
            +
             * Handle behavior when showing the dropdown
         
     | 
| 
      
 299 
     | 
    
         
            +
             */
         
     | 
| 
      
 300 
     | 
    
         
            +
            function onShow() {
         
     | 
| 
      
 301 
     | 
    
         
            +
              isShowing.value = true;
         
     | 
| 
      
 302 
     | 
    
         
            +
             
     | 
| 
      
 303 
     | 
    
         
            +
              // XXX: See description on shouldFilter declaration. Only allow filtering after dropdown is ALREADY opened
         
     | 
| 
      
 304 
     | 
    
         
            +
              shouldFilter.value = false;
         
     | 
| 
      
 305 
     | 
    
         
            +
              nextTick(() => {
         
     | 
| 
      
 306 
     | 
    
         
            +
                shouldFilter.value = true;
         
     | 
| 
      
 307 
     | 
    
         
            +
                selectField.value.focus();
         
     | 
| 
      
 308 
     | 
    
         
            +
              });
         
     | 
| 
      
 309 
     | 
    
         
            +
            }
         
     | 
| 
      
 310 
     | 
    
         
            +
             
     | 
| 
      
 311 
     | 
    
         
            +
            /**
         
     | 
| 
      
 312 
     | 
    
         
            +
             * Handle behavior when hiding the dropdown
         
     | 
| 
      
 313 
     | 
    
         
            +
             */
         
     | 
| 
      
 314 
     | 
    
         
            +
            function onHide() {
         
     | 
| 
      
 315 
     | 
    
         
            +
              isShowing.value = false;
         
     | 
| 
      
 316 
     | 
    
         
            +
              shouldFilter.value = false;
         
     | 
| 
      
 317 
     | 
    
         
            +
            }
         
     | 
| 
      
 318 
     | 
    
         
            +
            </script>
         
     | 
| 
         @@ -0,0 +1,81 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <template>
         
     | 
| 
      
 2 
     | 
    
         
            +
              <div>
         
     | 
| 
      
 3 
     | 
    
         
            +
                <template v-if="!loading && !options.length">
         
     | 
| 
      
 4 
     | 
    
         
            +
                  <div class="text-gray-silver">No options available</div>
         
     | 
| 
      
 5 
     | 
    
         
            +
                </template>
         
     | 
| 
      
 6 
     | 
    
         
            +
                <SelectField
         
     | 
| 
      
 7 
     | 
    
         
            +
                  v-model="selectedOption"
         
     | 
| 
      
 8 
     | 
    
         
            +
                  :options="options"
         
     | 
| 
      
 9 
     | 
    
         
            +
                  :label="label"
         
     | 
| 
      
 10 
     | 
    
         
            +
                  :placeholder="placeholder"
         
     | 
| 
      
 11 
     | 
    
         
            +
                  :option-value="opt => opt"
         
     | 
| 
      
 12 
     | 
    
         
            +
                  :loading="loading"
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @update:model-value="onSelectOption"
         
     | 
| 
      
 14 
     | 
    
         
            +
                />
         
     | 
| 
      
 15 
     | 
    
         
            +
                <div v-if="selectedOption">
         
     | 
| 
      
 16 
     | 
    
         
            +
                  <QCheckbox
         
     | 
| 
      
 17 
     | 
    
         
            +
                    v-for="child in selectedOption.children"
         
     | 
| 
      
 18 
     | 
    
         
            +
                    :key="child.id"
         
     | 
| 
      
 19 
     | 
    
         
            +
                    :model-value="selectedChildren.includes(child.id)"
         
     | 
| 
      
 20 
     | 
    
         
            +
                    :field="child"
         
     | 
| 
      
 21 
     | 
    
         
            +
                    class="mt-3"
         
     | 
| 
      
 22 
     | 
    
         
            +
                    @update:model-value="onSelectChild(child)"
         
     | 
| 
      
 23 
     | 
    
         
            +
                  >
         
     | 
| 
      
 24 
     | 
    
         
            +
                    <div>{{ child.label }}</div>
         
     | 
| 
      
 25 
     | 
    
         
            +
                    <div class="text-xs text-gray-silver">{{ child.name }}</div>
         
     | 
| 
      
 26 
     | 
    
         
            +
                  </QCheckbox>
         
     | 
| 
      
 27 
     | 
    
         
            +
                </div>
         
     | 
| 
      
 28 
     | 
    
         
            +
              </div>
         
     | 
| 
      
 29 
     | 
    
         
            +
            </template>
         
     | 
| 
      
 30 
     | 
    
         
            +
            <script setup>
         
     | 
| 
      
 31 
     | 
    
         
            +
            import SelectField from "danx/src/components/ActionTable/Form/Fields/SelectField";
         
     | 
| 
      
 32 
     | 
    
         
            +
            import { remove } from "danx/src/helpers/array";
         
     | 
| 
      
 33 
     | 
    
         
            +
            import { ref, watch } from "vue";
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            const emit = defineEmits(["update:model-value"]);
         
     | 
| 
      
 36 
     | 
    
         
            +
            const props = defineProps({
         
     | 
| 
      
 37 
     | 
    
         
            +
              modelValue: {
         
     | 
| 
      
 38 
     | 
    
         
            +
                type: Array,
         
     | 
| 
      
 39 
     | 
    
         
            +
                default: () => ([])
         
     | 
| 
      
 40 
     | 
    
         
            +
              },
         
     | 
| 
      
 41 
     | 
    
         
            +
              label: {
         
     | 
| 
      
 42 
     | 
    
         
            +
                type: String,
         
     | 
| 
      
 43 
     | 
    
         
            +
                default: "Selection"
         
     | 
| 
      
 44 
     | 
    
         
            +
              },
         
     | 
| 
      
 45 
     | 
    
         
            +
              placeholder: {
         
     | 
| 
      
 46 
     | 
    
         
            +
                type: String,
         
     | 
| 
      
 47 
     | 
    
         
            +
                default: "Select an option"
         
     | 
| 
      
 48 
     | 
    
         
            +
              },
         
     | 
| 
      
 49 
     | 
    
         
            +
              options: {
         
     | 
| 
      
 50 
     | 
    
         
            +
                type: Array,
         
     | 
| 
      
 51 
     | 
    
         
            +
                default: () => []
         
     | 
| 
      
 52 
     | 
    
         
            +
              },
         
     | 
| 
      
 53 
     | 
    
         
            +
              loading: Boolean
         
     | 
| 
      
 54 
     | 
    
         
            +
            });
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
            function resolveSelectedOption() {
         
     | 
| 
      
 57 
     | 
    
         
            +
              if (props.modelValue?.length > 0) {
         
     | 
| 
      
 58 
     | 
    
         
            +
                return props.options.find((option) => option.children.find(child => props.modelValue.includes(child.id)));
         
     | 
| 
      
 59 
     | 
    
         
            +
              }
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
              return null;
         
     | 
| 
      
 62 
     | 
    
         
            +
            }
         
     | 
| 
      
 63 
     | 
    
         
            +
            const selectedOption = ref(resolveSelectedOption());
         
     | 
| 
      
 64 
     | 
    
         
            +
            const selectedChildren = ref(props.modelValue || []);
         
     | 
| 
      
 65 
     | 
    
         
            +
            function onSelectChild(child) {
         
     | 
| 
      
 66 
     | 
    
         
            +
              if (selectedChildren.value.includes(child.id)) {
         
     | 
| 
      
 67 
     | 
    
         
            +
                selectedChildren.value = remove(selectedChildren.value, child.id);
         
     | 
| 
      
 68 
     | 
    
         
            +
              } else {
         
     | 
| 
      
 69 
     | 
    
         
            +
                selectedChildren.value.push(child.id);
         
     | 
| 
      
 70 
     | 
    
         
            +
              }
         
     | 
| 
      
 71 
     | 
    
         
            +
              emit("update:model-value", selectedChildren.value.length > 0 ? selectedChildren.value : undefined);
         
     | 
| 
      
 72 
     | 
    
         
            +
            }
         
     | 
| 
      
 73 
     | 
    
         
            +
            function onSelectOption() {
         
     | 
| 
      
 74 
     | 
    
         
            +
              selectedChildren.value = [];
         
     | 
| 
      
 75 
     | 
    
         
            +
              emit("update:model-value", undefined);
         
     | 
| 
      
 76 
     | 
    
         
            +
            }
         
     | 
| 
      
 77 
     | 
    
         
            +
            watch(() => props.modelValue, (value) => {
         
     | 
| 
      
 78 
     | 
    
         
            +
              selectedOption.value = resolveSelectedOption();
         
     | 
| 
      
 79 
     | 
    
         
            +
              selectedChildren.value = value || [];
         
     | 
| 
      
 80 
     | 
    
         
            +
            });
         
     | 
| 
      
 81 
     | 
    
         
            +
            </script>
         
     | 
| 
         @@ -0,0 +1,78 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <template>
         
     | 
| 
      
 2 
     | 
    
         
            +
              <div
         
     | 
| 
      
 3 
     | 
    
         
            +
                class="max-w-full relative overflow-auto"
         
     | 
| 
      
 4 
     | 
    
         
            +
                :class="{'p-4 border rounded border-gray-medium text-center': !readonly}"
         
     | 
| 
      
 5 
     | 
    
         
            +
                @dragover.prevent
         
     | 
| 
      
 6 
     | 
    
         
            +
                @drop.prevent="onDrop"
         
     | 
| 
      
 7 
     | 
    
         
            +
              >
         
     | 
| 
      
 8 
     | 
    
         
            +
                <FieldLabel
         
     | 
| 
      
 9 
     | 
    
         
            +
                  :field="field"
         
     | 
| 
      
 10 
     | 
    
         
            +
                  :show-name="showName"
         
     | 
| 
      
 11 
     | 
    
         
            +
                  class="text-sm font-semibold"
         
     | 
| 
      
 12 
     | 
    
         
            +
                />
         
     | 
| 
      
 13 
     | 
    
         
            +
                <div
         
     | 
| 
      
 14 
     | 
    
         
            +
                  v-if="!disable && !readonly"
         
     | 
| 
      
 15 
     | 
    
         
            +
                  class="text-sm mt-2"
         
     | 
| 
      
 16 
     | 
    
         
            +
                >
         
     | 
| 
      
 17 
     | 
    
         
            +
                  <a
         
     | 
| 
      
 18 
     | 
    
         
            +
                    class="text-blue-base"
         
     | 
| 
      
 19 
     | 
    
         
            +
                    @click="$refs.file.click()"
         
     | 
| 
      
 20 
     | 
    
         
            +
                  >Upload</a>
         
     | 
| 
      
 21 
     | 
    
         
            +
                  <a
         
     | 
| 
      
 22 
     | 
    
         
            +
                    v-if="uploadedFile"
         
     | 
| 
      
 23 
     | 
    
         
            +
                    class="ml-3 text-red-dark"
         
     | 
| 
      
 24 
     | 
    
         
            +
                    @click="onClear"
         
     | 
| 
      
 25 
     | 
    
         
            +
                  >Clear</a>
         
     | 
| 
      
 26 
     | 
    
         
            +
                  <input
         
     | 
| 
      
 27 
     | 
    
         
            +
                    ref="file"
         
     | 
| 
      
 28 
     | 
    
         
            +
                    class="hidden"
         
     | 
| 
      
 29 
     | 
    
         
            +
                    type="file"
         
     | 
| 
      
 30 
     | 
    
         
            +
                    @change="onFileSelected"
         
     | 
| 
      
 31 
     | 
    
         
            +
                  />
         
     | 
| 
      
 32 
     | 
    
         
            +
                </div>
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                <ImagePreview
         
     | 
| 
      
 35 
     | 
    
         
            +
                  v-if="!readonly || uploadedFile"
         
     | 
| 
      
 36 
     | 
    
         
            +
                  class="w-32 cursor-pointer mt-2"
         
     | 
| 
      
 37 
     | 
    
         
            +
                  :class="{'border border-dashed border-blue-base': !uploadedFile, 'mx-auto': !readonly}"
         
     | 
| 
      
 38 
     | 
    
         
            +
                  :image="uploadedFile"
         
     | 
| 
      
 39 
     | 
    
         
            +
                  downloadable
         
     | 
| 
      
 40 
     | 
    
         
            +
                  @click="!disable && $refs.file.click()"
         
     | 
| 
      
 41 
     | 
    
         
            +
                />
         
     | 
| 
      
 42 
     | 
    
         
            +
                <div
         
     | 
| 
      
 43 
     | 
    
         
            +
                  v-else-if="readonly"
         
     | 
| 
      
 44 
     | 
    
         
            +
                  class="py-1"
         
     | 
| 
      
 45 
     | 
    
         
            +
                >--
         
     | 
| 
      
 46 
     | 
    
         
            +
                </div>
         
     | 
| 
      
 47 
     | 
    
         
            +
              </div>
         
     | 
| 
      
 48 
     | 
    
         
            +
            </template>
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            <script setup>
         
     | 
| 
      
 51 
     | 
    
         
            +
            import ImagePreview from "components/Common/ImagePreview";
         
     | 
| 
      
 52 
     | 
    
         
            +
            import FieldLabel from "danx/src/components/ActionTable/Form/Fields/FieldLabel";
         
     | 
| 
      
 53 
     | 
    
         
            +
            import { useSingleFileUpload } from "src/helpers/singleFileUpload";
         
     | 
| 
      
 54 
     | 
    
         
            +
            import { onMounted } from "vue";
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
            const emit = defineEmits(["update:model-value"]);
         
     | 
| 
      
 57 
     | 
    
         
            +
            const props = defineProps({
         
     | 
| 
      
 58 
     | 
    
         
            +
              modelValue: {
         
     | 
| 
      
 59 
     | 
    
         
            +
                type: [Object, String],
         
     | 
| 
      
 60 
     | 
    
         
            +
                default: null
         
     | 
| 
      
 61 
     | 
    
         
            +
              },
         
     | 
| 
      
 62 
     | 
    
         
            +
              field: {
         
     | 
| 
      
 63 
     | 
    
         
            +
                type: Object,
         
     | 
| 
      
 64 
     | 
    
         
            +
                required: true
         
     | 
| 
      
 65 
     | 
    
         
            +
              },
         
     | 
| 
      
 66 
     | 
    
         
            +
              showName: Boolean,
         
     | 
| 
      
 67 
     | 
    
         
            +
              disable: Boolean,
         
     | 
| 
      
 68 
     | 
    
         
            +
              readonly: Boolean
         
     | 
| 
      
 69 
     | 
    
         
            +
            });
         
     | 
| 
      
 70 
     | 
    
         
            +
            const { onComplete, onDrop, onFileSelected, uploadedFile, onClear } = useSingleFileUpload();
         
     | 
| 
      
 71 
     | 
    
         
            +
            onComplete(() => emit("update:model-value", uploadedFile.value));
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
            onMounted(() => {
         
     | 
| 
      
 74 
     | 
    
         
            +
              if (props.modelValue) {
         
     | 
| 
      
 75 
     | 
    
         
            +
                uploadedFile.value = props.modelValue;
         
     | 
| 
      
 76 
     | 
    
         
            +
              }
         
     | 
| 
      
 77 
     | 
    
         
            +
            });
         
     | 
| 
      
 78 
     | 
    
         
            +
            </script>
         
     | 
| 
         @@ -0,0 +1,82 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <template>
         
     | 
| 
      
 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 
     | 
    
         
            +
                <div v-if="readonly">
         
     | 
| 
      
 31 
     | 
    
         
            +
                  <LabelValueBlock
         
     | 
| 
      
 32 
     | 
    
         
            +
                    :label="label || field.label"
         
     | 
| 
      
 33 
     | 
    
         
            +
                    :value="modelValue"
         
     | 
| 
      
 34 
     | 
    
         
            +
                  />
         
     | 
| 
      
 35 
     | 
    
         
            +
                </div>
         
     | 
| 
      
 36 
     | 
    
         
            +
              </div>
         
     | 
| 
      
 37 
     | 
    
         
            +
            </template>
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
            <script setup>
         
     | 
| 
      
 40 
     | 
    
         
            +
            import LabelValueBlock from "components/Common/LabelValueBlock";
         
     | 
| 
      
 41 
     | 
    
         
            +
            import FieldLabel from "danx/src/components/ActionTable/Form/Fields/FieldLabel";
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
            defineEmits(["update:model-value", "submit"]);
         
     | 
| 
      
 44 
     | 
    
         
            +
            defineProps({
         
     | 
| 
      
 45 
     | 
    
         
            +
              modelValue: {
         
     | 
| 
      
 46 
     | 
    
         
            +
                type: [String, Number],
         
     | 
| 
      
 47 
     | 
    
         
            +
                default: ""
         
     | 
| 
      
 48 
     | 
    
         
            +
              },
         
     | 
| 
      
 49 
     | 
    
         
            +
              field: {
         
     | 
| 
      
 50 
     | 
    
         
            +
                type: Object,
         
     | 
| 
      
 51 
     | 
    
         
            +
                default: null
         
     | 
| 
      
 52 
     | 
    
         
            +
              },
         
     | 
| 
      
 53 
     | 
    
         
            +
              type: {
         
     | 
| 
      
 54 
     | 
    
         
            +
                type: String,
         
     | 
| 
      
 55 
     | 
    
         
            +
                default: "text"
         
     | 
| 
      
 56 
     | 
    
         
            +
              },
         
     | 
| 
      
 57 
     | 
    
         
            +
              label: {
         
     | 
| 
      
 58 
     | 
    
         
            +
                type: String,
         
     | 
| 
      
 59 
     | 
    
         
            +
                default: null
         
     | 
| 
      
 60 
     | 
    
         
            +
              },
         
     | 
| 
      
 61 
     | 
    
         
            +
              labelClass: {
         
     | 
| 
      
 62 
     | 
    
         
            +
                type: String,
         
     | 
| 
      
 63 
     | 
    
         
            +
                default: "text-sm text-gray-shadow"
         
     | 
| 
      
 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 
     | 
    
         
            +
              }
         
     | 
| 
      
 81 
     | 
    
         
            +
            });
         
     | 
| 
      
 82 
     | 
    
         
            +
            </script>
         
     | 
| 
         @@ -0,0 +1,46 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <template>
         
     | 
| 
      
 2 
     | 
    
         
            +
              <div>
         
     | 
| 
      
 3 
     | 
    
         
            +
                <FieldLabel
         
     | 
| 
      
 4 
     | 
    
         
            +
                  v-if="!noLabel"
         
     | 
| 
      
 5 
     | 
    
         
            +
                  :field="field"
         
     | 
| 
      
 6 
     | 
    
         
            +
                  :show-name="showName"
         
     | 
| 
      
 7 
     | 
    
         
            +
                  class="text-sm font-semibold text-gray-shadow block mb-2"
         
     | 
| 
      
 8 
     | 
    
         
            +
                />
         
     | 
| 
      
 9 
     | 
    
         
            +
                <template v-if="readonly">
         
     | 
| 
      
 10 
     | 
    
         
            +
                  <div
         
     | 
| 
      
 11 
     | 
    
         
            +
                    class="border border-gray-300 rounded-md p-2 bg-gray-100"
         
     | 
| 
      
 12 
     | 
    
         
            +
                    v-html="modelValue"
         
     | 
| 
      
 13 
     | 
    
         
            +
                  />
         
     | 
| 
      
 14 
     | 
    
         
            +
                </template>
         
     | 
| 
      
 15 
     | 
    
         
            +
                <TinyMceEditor
         
     | 
| 
      
 16 
     | 
    
         
            +
                  v-else
         
     | 
| 
      
 17 
     | 
    
         
            +
                  class="mt-2"
         
     | 
| 
      
 18 
     | 
    
         
            +
                  :api-key="apiKey"
         
     | 
| 
      
 19 
     | 
    
         
            +
                  :disabled="disable"
         
     | 
| 
      
 20 
     | 
    
         
            +
                  :model-value="modelValue"
         
     | 
| 
      
 21 
     | 
    
         
            +
                  @update:model-value="$emit('update:model-value', $event)"
         
     | 
| 
      
 22 
     | 
    
         
            +
                />
         
     | 
| 
      
 23 
     | 
    
         
            +
              </div>
         
     | 
| 
      
 24 
     | 
    
         
            +
            </template>
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            <script setup>
         
     | 
| 
      
 27 
     | 
    
         
            +
            import { default as TinyMceEditor } from "@tinymce/tinymce-vue";
         
     | 
| 
      
 28 
     | 
    
         
            +
            import { apiKey } from "components/Cms/SlideshowEditor/ContentEditor/tinymce-config";
         
     | 
| 
      
 29 
     | 
    
         
            +
            import FieldLabel from "danx/src/components/ActionTable/Form/Fields/FieldLabel";
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            defineEmits(["update:model-value"]);
         
     | 
| 
      
 32 
     | 
    
         
            +
            defineProps({
         
     | 
| 
      
 33 
     | 
    
         
            +
              modelValue: {
         
     | 
| 
      
 34 
     | 
    
         
            +
                type: [String, Number],
         
     | 
| 
      
 35 
     | 
    
         
            +
                default: null
         
     | 
| 
      
 36 
     | 
    
         
            +
              },
         
     | 
| 
      
 37 
     | 
    
         
            +
              field: {
         
     | 
| 
      
 38 
     | 
    
         
            +
                type: Object,
         
     | 
| 
      
 39 
     | 
    
         
            +
                required: true
         
     | 
| 
      
 40 
     | 
    
         
            +
              },
         
     | 
| 
      
 41 
     | 
    
         
            +
              noLabel: Boolean,
         
     | 
| 
      
 42 
     | 
    
         
            +
              showName: Boolean,
         
     | 
| 
      
 43 
     | 
    
         
            +
              disable: Boolean,
         
     | 
| 
      
 44 
     | 
    
         
            +
              readonly: Boolean
         
     | 
| 
      
 45 
     | 
    
         
            +
            });
         
     | 
| 
      
 46 
     | 
    
         
            +
            </script>
         
     | 
| 
         @@ -0,0 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            export { default as BooleanField } from "./BooleanField";
         
     | 
| 
      
 2 
     | 
    
         
            +
            export { default as ConfirmPasswordField } from "./ConfirmPasswordField";
         
     | 
| 
      
 3 
     | 
    
         
            +
            export { default as DateField } from "./DateField";
         
     | 
| 
      
 4 
     | 
    
         
            +
            export { default as DateRangeField } from "./DateRangeField";
         
     | 
| 
      
 5 
     | 
    
         
            +
            export { default as DateTimeField } from "./DateTimeField";
         
     | 
| 
      
 6 
     | 
    
         
            +
            export { default as DateTimePicker } from "./DateTimePicker";
         
     | 
| 
      
 7 
     | 
    
         
            +
            export { default as EditableDiv } from "./EditableDiv";
         
     | 
| 
      
 8 
     | 
    
         
            +
            export { default as FieldLabel } from "./FieldLabel";
         
     | 
| 
      
 9 
     | 
    
         
            +
            export { default as FileUploadButton } from "./FileUploadButton";
         
     | 
| 
      
 10 
     | 
    
         
            +
            export { default as InlineDateTimeField } from "./InlineDateTimeField";
         
     | 
| 
      
 11 
     | 
    
         
            +
            export { default as IntegerField } from "./IntegerField";
         
     | 
| 
      
 12 
     | 
    
         
            +
            export { default as LabeledInput } from "./LabeledInput";
         
     | 
| 
      
 13 
     | 
    
         
            +
            export { default as MultiFileField } from "./MultiFileField";
         
     | 
| 
      
 14 
     | 
    
         
            +
            export { default as MultiKeywordField } from "./MultiKeywordField";
         
     | 
| 
      
 15 
     | 
    
         
            +
            export { default as NewPasswordField } from "./NewPasswordField";
         
     | 
| 
      
 16 
     | 
    
         
            +
            export { default as NumberField } from "./NumberField";
         
     | 
| 
      
 17 
     | 
    
         
            +
            export { default as NumberRangeField } from "./NumberRangeField";
         
     | 
| 
      
 18 
     | 
    
         
            +
            export { default as SelectDrawer } from "./SelectDrawer";
         
     | 
| 
      
 19 
     | 
    
         
            +
            export { default as SelectField } from "./SelectField";
         
     | 
| 
      
 20 
     | 
    
         
            +
            export { default as SelectWithChildrenField } from "./SelectWithChildrenField";
         
     | 
| 
      
 21 
     | 
    
         
            +
            export { default as SingleFileField } from "./SingleFileField";
         
     | 
| 
      
 22 
     | 
    
         
            +
            export { default as TextField } from "./TextField";
         
     | 
| 
      
 23 
     | 
    
         
            +
            export { default as WysiwygField } from "./WysiwygField";
         
     | 
| 
         @@ -0,0 +1,74 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <template>
         
     | 
| 
      
 2 
     | 
    
         
            +
              <div class="rendered-form">
         
     | 
| 
      
 3 
     | 
    
         
            +
                <div
         
     | 
| 
      
 4 
     | 
    
         
            +
                  v-for="(field, index) in mappedFields"
         
     | 
| 
      
 5 
     | 
    
         
            +
                  :key="field.id"
         
     | 
| 
      
 6 
     | 
    
         
            +
                  :class="{ 'mt-4': index > 0 }"
         
     | 
| 
      
 7 
     | 
    
         
            +
                >
         
     | 
| 
      
 8 
     | 
    
         
            +
                  <Component
         
     | 
| 
      
 9 
     | 
    
         
            +
                    :is="field.component"
         
     | 
| 
      
 10 
     | 
    
         
            +
                    v-model="fieldValues[field.name]"
         
     | 
| 
      
 11 
     | 
    
         
            +
                    :field="field"
         
     | 
| 
      
 12 
     | 
    
         
            +
                    :label="field.label || undefined"
         
     | 
| 
      
 13 
     | 
    
         
            +
                    :no-label="noLabel"
         
     | 
| 
      
 14 
     | 
    
         
            +
                    :show-name="showName"
         
     | 
| 
      
 15 
     | 
    
         
            +
                    :disable="disable"
         
     | 
| 
      
 16 
     | 
    
         
            +
                    :readonly="readonly"
         
     | 
| 
      
 17 
     | 
    
         
            +
                    @update:model-value="onInput(field.name, $event)"
         
     | 
| 
      
 18 
     | 
    
         
            +
                  />
         
     | 
| 
      
 19 
     | 
    
         
            +
                </div>
         
     | 
| 
      
 20 
     | 
    
         
            +
              </div>
         
     | 
| 
      
 21 
     | 
    
         
            +
            </template>
         
     | 
| 
      
 22 
     | 
    
         
            +
            <script setup>
         
     | 
| 
      
 23 
     | 
    
         
            +
            import BooleanField from "danx/src/components/ActionTable/Form/Fields/BooleanField";
         
     | 
| 
      
 24 
     | 
    
         
            +
            import DateField from "danx/src/components/ActionTable/Form/Fields/DateField";
         
     | 
| 
      
 25 
     | 
    
         
            +
            import DateRangeField from "danx/src/components/ActionTable/Form/Fields/DateRangeField";
         
     | 
| 
      
 26 
     | 
    
         
            +
            import IntegerField from "danx/src/components/ActionTable/Form/Fields/IntegerField";
         
     | 
| 
      
 27 
     | 
    
         
            +
            import MultiFileField from "danx/src/components/ActionTable/Form/Fields/MultiFileField";
         
     | 
| 
      
 28 
     | 
    
         
            +
            import NumberField from "danx/src/components/ActionTable/Form/Fields/NumberField";
         
     | 
| 
      
 29 
     | 
    
         
            +
            import SingleFileField from "danx/src/components/ActionTable/Form/Fields/SingleFileField";
         
     | 
| 
      
 30 
     | 
    
         
            +
            import TextField from "danx/src/components/ActionTable/Form/Fields/TextField";
         
     | 
| 
      
 31 
     | 
    
         
            +
            import WysiwygField from "danx/src/components/ActionTable/Form/Fields/WysiwygField";
         
     | 
| 
      
 32 
     | 
    
         
            +
            import { reactive } from "vue";
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            const emit = defineEmits(["update:values"]);
         
     | 
| 
      
 35 
     | 
    
         
            +
            const props = defineProps({
         
     | 
| 
      
 36 
     | 
    
         
            +
              values: {
         
     | 
| 
      
 37 
     | 
    
         
            +
                type: Object,
         
     | 
| 
      
 38 
     | 
    
         
            +
                default: null
         
     | 
| 
      
 39 
     | 
    
         
            +
              },
         
     | 
| 
      
 40 
     | 
    
         
            +
              fields: {
         
     | 
| 
      
 41 
     | 
    
         
            +
                type: Array,
         
     | 
| 
      
 42 
     | 
    
         
            +
                required: true
         
     | 
| 
      
 43 
     | 
    
         
            +
              },
         
     | 
| 
      
 44 
     | 
    
         
            +
              noLabel: Boolean,
         
     | 
| 
      
 45 
     | 
    
         
            +
              showName: Boolean,
         
     | 
| 
      
 46 
     | 
    
         
            +
              disable: Boolean,
         
     | 
| 
      
 47 
     | 
    
         
            +
              readonly: Boolean
         
     | 
| 
      
 48 
     | 
    
         
            +
            });
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            const FORM_FIELD_MAP = {
         
     | 
| 
      
 51 
     | 
    
         
            +
              BOOLEAN: BooleanField,
         
     | 
| 
      
 52 
     | 
    
         
            +
              DATE: DateField,
         
     | 
| 
      
 53 
     | 
    
         
            +
              DATE_RANGE: DateRangeField,
         
     | 
| 
      
 54 
     | 
    
         
            +
              INTEGER: IntegerField,
         
     | 
| 
      
 55 
     | 
    
         
            +
              NUMBER: NumberField,
         
     | 
| 
      
 56 
     | 
    
         
            +
              TEXT: TextField,
         
     | 
| 
      
 57 
     | 
    
         
            +
              SINGLE_FILE: SingleFileField,
         
     | 
| 
      
 58 
     | 
    
         
            +
              MULTI_FILE: MultiFileField,
         
     | 
| 
      
 59 
     | 
    
         
            +
              WYSIWYG: WysiwygField
         
     | 
| 
      
 60 
     | 
    
         
            +
            };
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
            const mappedFields = props.fields.map((field) => ({
         
     | 
| 
      
 63 
     | 
    
         
            +
              placeholder: `Enter ${field.label}`,
         
     | 
| 
      
 64 
     | 
    
         
            +
              ...field,
         
     | 
| 
      
 65 
     | 
    
         
            +
              component: FORM_FIELD_MAP[field.type],
         
     | 
| 
      
 66 
     | 
    
         
            +
              default: field.type === "BOOLEAN" ? false : ""
         
     | 
| 
      
 67 
     | 
    
         
            +
            }));
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
            const fieldValues = reactive(props.values || {});
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
            function onInput(key, value) {
         
     | 
| 
      
 72 
     | 
    
         
            +
              emit("update:values", { ...fieldValues, [key]: value });
         
     | 
| 
      
 73 
     | 
    
         
            +
            }
         
     | 
| 
      
 74 
     | 
    
         
            +
            </script>
         
     |