@mouseless/baked 1.5.3 → 1.6.1

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.
Files changed (59) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +2 -1
  3. package/dist/runtime/components/AwaitLoading.d.ts +7 -4
  4. package/dist/runtime/components/AwaitLoading.js +39 -11
  5. package/dist/runtime/components/Bake.d.vue.ts +1 -3
  6. package/dist/runtime/components/Bake.vue +101 -60
  7. package/dist/runtime/components/Bake.vue.d.ts +1 -3
  8. package/dist/runtime/components/DataContainer.vue +4 -7
  9. package/dist/runtime/components/DataPanel.vue +5 -7
  10. package/dist/runtime/components/DataTable.vue +12 -3
  11. package/dist/runtime/components/ErrorPage.vue +6 -5
  12. package/dist/runtime/components/ErrorPopover.d.vue.ts +15 -0
  13. package/dist/runtime/components/ErrorPopover.vue +22 -0
  14. package/dist/runtime/components/ErrorPopover.vue.d.ts +15 -0
  15. package/dist/runtime/components/FormPage.vue +36 -8
  16. package/dist/runtime/components/InlineError.d.vue.ts +15 -0
  17. package/dist/runtime/components/InlineError.vue +27 -0
  18. package/dist/runtime/components/InlineError.vue.d.ts +15 -0
  19. package/dist/runtime/components/Input.d.vue.ts +9 -1
  20. package/dist/runtime/components/Input.vue +31 -5
  21. package/dist/runtime/components/Input.vue.d.ts +9 -1
  22. package/dist/runtime/components/InputNumber.vue +23 -23
  23. package/dist/runtime/components/InputText.vue +22 -22
  24. package/dist/runtime/components/Inputs.d.vue.ts +7 -0
  25. package/dist/runtime/components/Inputs.vue +4 -2
  26. package/dist/runtime/components/Inputs.vue.d.ts +7 -0
  27. package/dist/runtime/components/Labeler.d.vue.ts +9 -25
  28. package/dist/runtime/components/Labeler.vue +32 -25
  29. package/dist/runtime/components/Labeler.vue.d.ts +9 -25
  30. package/dist/runtime/components/Layout.vue +5 -1
  31. package/dist/runtime/components/LoadingError.d.vue.ts +13 -0
  32. package/dist/runtime/components/LoadingError.vue +27 -0
  33. package/dist/runtime/components/LoadingError.vue.d.ts +13 -0
  34. package/dist/runtime/components/Message.d.vue.ts +8 -1
  35. package/dist/runtime/components/Message.vue +48 -17
  36. package/dist/runtime/components/Message.vue.d.ts +8 -1
  37. package/dist/runtime/components/NavLink.vue +6 -3
  38. package/dist/runtime/components/Paginator.vue +1 -3
  39. package/dist/runtime/components/Select.vue +39 -39
  40. package/dist/runtime/components/SelectButton.vue +46 -40
  41. package/dist/runtime/components/SimpleForm.vue +46 -11
  42. package/dist/runtime/components/TabbedPage.vue +5 -7
  43. package/dist/runtime/components/Validation.d.vue.ts +17 -0
  44. package/dist/runtime/components/Validation.vue +48 -0
  45. package/dist/runtime/components/Validation.vue.d.ts +17 -0
  46. package/dist/runtime/composables/useBakeError.d.ts +13 -0
  47. package/dist/runtime/composables/useBakeError.js +51 -0
  48. package/dist/runtime/composables/useContext.d.ts +14 -0
  49. package/dist/runtime/composables/useContext.js +77 -2
  50. package/dist/runtime/composables/useDataMounter.d.ts +4 -2
  51. package/dist/runtime/composables/useDataMounter.js +15 -6
  52. package/dist/runtime/composables/useDefaultValidation.d.ts +4 -0
  53. package/dist/runtime/composables/useDefaultValidation.js +37 -0
  54. package/dist/runtime/composables/useRedirect.d.ts +1 -1
  55. package/dist/runtime/composables/useRedirect.js +7 -1
  56. package/dist/runtime/composables/useValidation.d.ts +15 -0
  57. package/dist/runtime/composables/useValidation.js +79 -0
  58. package/dist/runtime/plugins/errorHandling.js +2 -2
  59. package/package.json +14 -14
@@ -1,29 +1,60 @@
1
1
  <template>
2
- <Message
3
- :severity="severity"
4
- :pt="{ text: { class: 'min-w-[10rem] min-h-[1.5rem]' } }"
2
+ <div
3
+ class="b-message grid"
4
+ :class="[`message-${severity}`, `message-${variant}`]"
5
5
  >
6
- <template
7
- v-if="icon"
8
- #icon
9
- >
10
- <i :class="`pi ${icon}`" />
11
- </template>
12
- <AwaitLoading :skeleton="{ height: '1.5rem', width: '100%' }">
13
- <span v-if="data">{{ localizeMessage ? l(data) : data }}</span>
14
- <span v-else>-</span>
15
- </AwaitLoading>
16
- </Message>
6
+ <div class="min-h-0">
7
+ <div
8
+ :class="sizeClass"
9
+ class="
10
+ b-message-body
11
+ flex flex-col gap-3
12
+ "
13
+ >
14
+ <div class="flex flex-row items-center gap-2">
15
+ <i
16
+ v-if="icon"
17
+ class="b-message-icon"
18
+ :class="icon"
19
+ />
20
+ <AwaitLoading :skeleton="{ height: '1.5rem', width: '100%' }">
21
+ <span v-if="data">{{ localizeMessage ? l(data) : data }}</span>
22
+ <span v-else>-</span>
23
+ </AwaitLoading>
24
+ </div>
25
+ <slot name="content" />
26
+ </div>
27
+ </div>
28
+ </div>
17
29
  </template>
18
30
 
19
31
  <script setup>
20
- import { Message } from "primevue";
21
- import { useLocalization } from "#imports";
32
+ import { computed, useLocalization } from "#imports";
22
33
  import { AwaitLoading } from "#components";
23
34
  const { localize: l } = useLocalization();
24
35
  const { schema, data } = defineProps({
25
36
  schema: { type: null, required: true },
26
37
  data: { type: null, required: true }
27
38
  });
28
- const { icon, severity = "info", localizeMessage } = schema;
39
+ const { icon, localizeMessage, severity = "info", size, variant = "outlined" } = schema;
40
+ const sizeClass = computed(() => {
41
+ switch (size) {
42
+ case "small":
43
+ return "text-sm font-normal";
44
+ case "large":
45
+ return "text-lg font-semibold";
46
+ default:
47
+ return "text-base font-medium";
48
+ }
49
+ });
29
50
  </script>
51
+
52
+ <style scoped>
53
+ .message-outlined{@apply border rounded-md}.message-outlined .b-message-body{@apply py-[0.50rem] px-[0.75rem] min-w-[10rem] min-h-[1.5rem]}.message-simple{@apply !bg-transparent}.message-simple .b-message-body{@apply px-0}.message-info{@apply bg-blue-50/95 text-blue-600 border-blue-200
54
+ dark:bg-blue-950/95 dark:text-blue-500 dark:border-blue-700/65}.message-error{@apply bg-red-50/95 text-red-600 border-red-200
55
+ dark:bg-red-950/95 dark:text-red-500 dark:border-red-700/65}.message-warn{@apply bg-yellow-50/95 text-yellow-600 border-yellow-200
56
+ dark:bg-yellow-950/95 dark:text-yellow-500 dark:border-yellow-700/65}.message-success{@apply bg-green-50/95 text-green-600 border-green-200
57
+ dark:bg-green-950/95 dark:text-green-500 dark:border-green-700/65}.message-secondary{@apply bg-transparent text-slate-500 border-slate-500
58
+ dark:text-slate-400 dark:border-slate-400}.message-contrast{@apply bg-transparent text-slate-950 border-slate-950
59
+ dark:text-white dark:border-white}
60
+ </style>
@@ -1,6 +1,10 @@
1
1
  declare const _default: typeof __VLS_export;
2
2
  export default _default;
3
- declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
3
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
4
+ type __VLS_WithSlots<T, S> = T & (new () => {
5
+ $slots: S;
6
+ });
7
+ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
4
8
  schema: {
5
9
  type: null;
6
10
  required: true;
@@ -19,3 +23,6 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
19
23
  required: true;
20
24
  };
21
25
  }>> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
26
+ type __VLS_Slots = {
27
+ content?: ((props: {}) => any) | undefined;
28
+ };
@@ -1,13 +1,15 @@
1
1
  <template>
2
2
  <AwaitLoading :skeleton="{ height: '1.5rem' }">
3
3
  <Button
4
+ v-if="data"
4
5
  :icon
5
- :label="data"
6
+ :label
6
7
  :to
7
8
  as="router-link"
8
9
  link
9
10
  class="m-0 p-0"
10
11
  />
12
+ <span v-else>-</span>
11
13
  </AwaitLoading>
12
14
  </template>
13
15
 
@@ -16,15 +18,16 @@ import { computed } from "vue";
16
18
  import { Button } from "primevue";
17
19
  import { useDataMounter, usePathBuilder } from "#imports";
18
20
  import { AwaitLoading } from "#components";
19
- const { mount: mountData } = useDataMounter();
21
+ const { mount: mountData } = useDataMounter({ defaultInlineError: true });
20
22
  const pathBuilder = usePathBuilder();
21
23
  const { schema, data } = defineProps({
22
24
  schema: { type: null, required: true },
23
25
  data: { type: null, required: true }
24
26
  });
25
- const { icon, path, query: queryData, params: paramsData } = schema;
27
+ const { icon, labelProp, path, query: queryData, params: paramsData } = schema;
26
28
  const query = mountData(queryData);
27
29
  const params = mountData(paramsData);
30
+ const label = computed(() => labelProp ? data?.[labelProp] : data);
28
31
  const to = computed(() => ({
29
32
  path: params.value ? pathBuilder.build(path, params.value, { forRoute: true }) : path,
30
33
  query: query.value
@@ -40,9 +40,7 @@ const allowPrevious = computed(() => !Number.isNaN(page.value) && page.value > 1
40
40
  const allowNext = computed(() => !Number.isNaN(page.value) && data.length >= data.take);
41
41
  const page = computed({
42
42
  get: () => Number(model.value) / Number(data.take) + 1,
43
- set: (value) => {
44
- model.value = (value - 1) * Number(data.take);
45
- }
43
+ set: (value) => model.value = (value - 1) * Number(data.take)
46
44
  });
47
45
  const path = context.injectPath();
48
46
  const previousTake = paginatorStates[`${path}.previousTake`];
@@ -1,45 +1,44 @@
1
1
  <template>
2
- <AwaitLoading>
3
- <template #loading>
4
- <div class="min-w-40">
5
- <Skeleton class="min-h-10" />
6
- </div>
7
- </template>
8
- <Labeler
9
- :label
10
- :path
11
- :mode="labelMode"
12
- :variant="labelVariant"
13
- >
14
- <Select
15
- v-bind="$attrs"
16
- v-model="selected"
17
- :input-id="path"
18
- :options="data"
19
- :placeholder="l(label)"
20
- :show-clear
21
- :filter
22
- :auto-filter-focus="filter"
23
- :filter-fields="[optionLabel]"
24
- reset-filter-on-hide
25
- class="w-full"
2
+ <AwaitLoading
3
+ :skeleton="{
4
+ height: label?.mode === 'ifta' ? '3.6rem' : '2.6rem',
5
+ class: 'min-w-40'
6
+ }"
7
+ >
8
+ <Validation>
9
+ <Labeler
10
+ :label
11
+ :path
26
12
  >
27
- <template #value="slotProps">
28
- <span>{{ getValueLabel(slotProps) }}</span>
29
- </template>
30
- <template #option="slotProps">
31
- <span>{{ getOptionLabel(slotProps) }}</span>
32
- </template>
33
- </Select>
34
- </Labeler>
13
+ <Select
14
+ v-bind="$attrs"
15
+ v-model="selected"
16
+ :input-id="path"
17
+ :options="data"
18
+ :placeholder
19
+ :show-clear
20
+ :filter
21
+ :auto-filter-focus="filter"
22
+ :filter-fields="[optionLabel]"
23
+ reset-filter-on-hide
24
+ >
25
+ <template #value="slotProps">
26
+ <span>{{ getValueLabel(slotProps) }}</span>
27
+ </template>
28
+ <template #option="slotProps">
29
+ <span>{{ getOptionLabel(slotProps) }}</span>
30
+ </template>
31
+ </Select>
32
+ </Labeler>
33
+ </Validation>
35
34
  </AwaitLoading>
36
35
  </template>
37
36
 
38
37
  <script setup>
39
38
  import { ref, watch } from "vue";
40
- import { Select, Skeleton } from "primevue";
39
+ import { Select } from "primevue";
41
40
  import { useContext, useUiStates, useLocalization } from "#imports";
42
- import { AwaitLoading, Labeler } from "#components";
41
+ import { AwaitLoading, Labeler, Validation } from "#components";
43
42
  const context = useContext();
44
43
  const { localize: l } = useLocalization();
45
44
  const { value: { selectStates } } = useUiStates();
@@ -48,9 +47,10 @@ const { schema, data } = defineProps({
48
47
  data: { type: null, required: true }
49
48
  });
50
49
  const model = defineModel({ type: null, required: true });
51
- const { filter, label, labelMode, labelVariant, localizeLabel, optionLabel, optionValue, showClear, stateful, targetProp } = schema;
50
+ const { filter, label, localizeOptionLabels, optionLabel, optionValue, showClear, stateful, targetProp } = schema;
52
51
  const path = context.injectPath();
53
52
  const selected = ref();
53
+ const placeholder = label?.text ? l(label.text) : null;
54
54
  watch(
55
55
  [() => data, getModel],
56
56
  ([_data, _model]) => {
@@ -65,11 +65,11 @@ watch(
65
65
  watch(selected, (newSelected) => setModel(newSelected));
66
66
  function getOptionLabel(slotProps) {
67
67
  const result = slotProps.option[optionLabel] ?? slotProps.option;
68
- return localizeLabel ? l(result) : result;
68
+ return localizeOptionLabels ? l(result) : result;
69
69
  }
70
70
  function getValueLabel(slotProps) {
71
- const result = slotProps.value?.[optionLabel] ?? slotProps.value ?? label;
72
- return (localizeLabel ? l(result) : result) ?? "\xA0";
71
+ const result = slotProps.value?.[optionLabel] ?? slotProps.value ?? placeholder;
72
+ return (localizeOptionLabels ? l(result) : result) ?? "\xA0";
73
73
  }
74
74
  function getModel() {
75
75
  return targetProp ? model.value?.[targetProp] : model.value;
@@ -96,5 +96,5 @@ function setSelected(value) {
96
96
  </script>
97
97
 
98
98
  <style>
99
- .b-component--Select .p-placeholder{opacity:0}.b-component--Select .p-select-label{font-size:inherit}
99
+ .b-component--Select .p-placeholder{opacity:0}.b-component--Select .p-select-label{font-size:inherit}.p-popover-content .b-component--Select{@apply max-md:w-full}
100
100
  </style>
@@ -1,47 +1,54 @@
1
1
  <template>
2
- <AwaitLoading>
3
- <template #loading>
4
- <div class="min-w-60">
5
- <Skeleton class="min-h-10" />
6
- </div>
7
- </template>
8
- <Labeler
9
- :label
10
- :path
11
- :mode="labelMode == 'ifta' ? labelMode : null"
12
- :dt="{
13
- colorScheme: {
14
- light: {
15
- top: '-1rem',
16
- },
17
- dark: {
18
- top: '-1rem'
2
+ <AwaitLoading
3
+ :skeleton="{
4
+ height: label?.mode === 'ifta' ? '3.6rem' : '2.6rem',
5
+ class: 'min-w-60'
6
+ }"
7
+ >
8
+ <Validation>
9
+ <Labeler
10
+ :label="{
11
+ ...label,
12
+ mode: label?.mode === 'ifta' ? label.mode : null,
13
+ text: label?.mode === 'ifta' ? label.text : null
14
+ }"
15
+ :path
16
+ :dt="{
17
+ colorScheme: {
18
+ light: {
19
+ top: '-1rem',
20
+ },
21
+ dark: {
22
+ top: '-1rem'
23
+ }
19
24
  }
20
- }
21
- }"
22
- >
23
- <SelectButton
24
- v-if="data"
25
- v-model="selected"
26
- :options="data"
27
- :allow-empty
28
- :data-key="optionValue"
29
- :option-label
30
- :pt="{ pcToggleButton: { root: { class: 'text-[length:inherit]' } } }"
25
+ }"
31
26
  >
32
- <template #option="slotProps">
33
- <span>{{ getOptionLabel(slotProps) }}</span>
34
- </template>
35
- </SelectButton>
36
- </Labeler>
27
+ <SelectButton
28
+ v-if="data"
29
+ v-bind="$attrs"
30
+ v-model="selected"
31
+ :options="data"
32
+ :allow-empty
33
+ :data-key="optionValue"
34
+ :option-label
35
+ class="!w-auto"
36
+ pt:pc-toggle-button:root="text-[length:inherit]"
37
+ >
38
+ <template #option="slotProps">
39
+ <span>{{ getOptionLabel(slotProps) }}</span>
40
+ </template>
41
+ </SelectButton>
42
+ </Labeler>
43
+ </Validation>
37
44
  </AwaitLoading>
38
45
  </template>
39
46
 
40
47
  <script setup>
41
48
  import { ref, watch } from "vue";
42
- import { SelectButton, Skeleton } from "primevue";
49
+ import { SelectButton } from "primevue";
43
50
  import { useContext, useLocalization, useUiStates } from "#imports";
44
- import { AwaitLoading, Labeler } from "#components";
51
+ import { AwaitLoading, Labeler, Validation } from "#components";
45
52
  const context = useContext();
46
53
  const { localize: l } = useLocalization();
47
54
  const { value: { selectButtonStates } } = useUiStates();
@@ -53,8 +60,7 @@ const model = defineModel({ type: null, required: true });
53
60
  const {
54
61
  allowEmpty = false,
55
62
  label,
56
- labelMode,
57
- localizeLabel,
63
+ localizeOptionLabels,
58
64
  optionLabel,
59
65
  optionValue,
60
66
  stateful,
@@ -76,7 +82,7 @@ watch(
76
82
  watch(selected, (newSelected) => setModel(newSelected));
77
83
  function getOptionLabel(slotProps) {
78
84
  const result = slotProps.option[optionLabel] ?? slotProps.option;
79
- return localizeLabel ? l(result) : result;
85
+ return localizeOptionLabels ? l(result) : result;
80
86
  }
81
87
  function getModel() {
82
88
  return targetProp ? model.value?.[targetProp] : model.value;
@@ -103,9 +109,9 @@ function setSelected(value) {
103
109
  </script>
104
110
 
105
111
  <style>
106
- .p-togglebutton-content{@apply whitespace-nowrap}.p-popover-content .b-component--SelectButton .p-selectbutton{@apply max-sm:flex max-sm:flex-col}.p-popover-content .b-component--SelectButton .p-selectbutton .p-togglebutton:first-child{@apply max-sm:rounded-t-lg max-sm:rounded-es-none}.p-popover-content .b-component--SelectButton .p-selectbutton .p-togglebutton:last-child{@apply max-sm:rounded-b-lg max-sm:rounded-se-none}
112
+ .p-togglebutton-content{@apply whitespace-nowrap}.p-popover-content .b-component--SelectButton .p-selectbutton,.p-popover-content .b-component--SelectButton.p-selectbutton{@apply max-sm:flex max-sm:flex-col}.p-popover-content .b-component--SelectButton .p-selectbutton .p-togglebutton:first-child,.p-popover-content .b-component--SelectButton.p-selectbutton .p-togglebutton:first-child{@apply max-sm:rounded-t-lg max-sm:rounded-es-none}.p-popover-content .b-component--SelectButton .p-selectbutton .p-togglebutton:last-child,.p-popover-content .b-component--SelectButton.p-selectbutton .p-togglebutton:last-child{@apply max-sm:rounded-b-lg max-sm:rounded-se-none}
107
113
  </style>
108
114
 
109
115
  <style scoped>
110
- &:has(.p-iftalabel) .p-iftalabel{@apply mt-4}
116
+ .p-iftalabel:has(.p-selectbutton){@apply mt-4}
111
117
  </style>
@@ -1,6 +1,7 @@
1
1
  <template>
2
2
  <template v-if="dialogOptions">
3
3
  <Button
4
+ ref="submitRef"
4
5
  :schema="dialogOptions.open"
5
6
  v-bind="$attrs"
6
7
  @click="visible = true"
@@ -47,6 +48,9 @@
47
48
  />
48
49
  </template>
49
50
  </Dialog>
51
+ <ErrorPopover ref="errorPopoverRef">
52
+ <InlineError :error />
53
+ </ErrorPopover>
50
54
  </template>
51
55
  <template v-else>
52
56
  <div
@@ -60,49 +64,80 @@
60
64
  <Inputs
61
65
  v-if="inputs"
62
66
  :inputs
67
+ form-mode
63
68
  input-class="w-full"
64
69
  @ready="onReady"
65
70
  @changed="onChanged"
66
71
  />
67
72
  </div>
68
73
  <Button
74
+ ref="submitRef"
75
+ v-tooltip.top="{
76
+ disabled: !showValidationSummary,
77
+ value: messages,
78
+ pt: { text: 'text-sm' }
79
+ }"
69
80
  :schema="submit"
70
81
  :ready
71
- @submit="$emit('submit', formData)"
82
+ @submit="$emit('submit', model)"
72
83
  />
84
+ <ErrorPopover ref="errorPopoverRef">
85
+ <InlineError :error />
86
+ </ErrorPopover>
73
87
  </div>
74
88
  </template>
75
89
  </template>
76
90
 
77
91
  <script setup>
78
- import { ref } from "vue";
92
+ import { computed, ref, watch } from "vue";
79
93
  import { Dialog } from "primevue";
80
- import { useLocalization } from "#imports";
81
- import { Button, Inputs } from "#components";
94
+ import { useBakeError, useLocalization, useValidation } from "#imports";
95
+ import { Button, ErrorPopover, InlineError, Inputs } from "#components";
96
+ const { handle: handleError } = useBakeError();
82
97
  const { localize: l } = useLocalization();
98
+ const { validate } = useValidation();
83
99
  const { schema } = defineProps({
84
100
  schema: { type: null, required: true }
85
101
  });
86
102
  const emit = defineEmits(["submit"]);
87
- const { dialogOptions, inputs, submit, title } = schema;
88
- const formData = ref({});
89
- const ready = ref(inputs.length === 0);
103
+ const { dialogOptions, inputs, submit, title, validations = [], showValidationSummary = false } = schema;
104
+ const model = ref({});
105
+ const readyData = ref({});
90
106
  const submitted = ref(false);
91
107
  const visible = ref(false);
108
+ const submitRef = ref();
109
+ const errorPopoverRef = ref();
110
+ const { error } = handleError();
111
+ const ready = computed(() => Object.values(readyData.value).every((v) => v) && isValid.value);
112
+ const { isValid, messages } = validate({
113
+ inputs,
114
+ model,
115
+ composables: validations
116
+ });
117
+ watch(error, (newError) => {
118
+ if (newError) {
119
+ errorPopoverRef.value.show(submitRef);
120
+ } else {
121
+ errorPopoverRef.value.hide();
122
+ }
123
+ });
92
124
  function onReady(value) {
93
- ready.value = value;
125
+ readyData.value = value;
94
126
  }
95
127
  function onChanged({ values }) {
96
- formData.value = values;
128
+ model.value = values;
97
129
  }
98
130
  function execute() {
131
+ if (!ready.value) {
132
+ return;
133
+ }
99
134
  submitted.value = true;
100
135
  visible.value = false;
101
136
  }
102
137
  function emitSubmit() {
103
- if (submitted.value) {
138
+ if (submitted.value && ready.value) {
104
139
  submitted.value = false;
105
- emit("submit", formData.value);
140
+ emit("submit", model.value);
106
141
  }
107
142
  }
108
143
  </script>
@@ -40,11 +40,9 @@
40
40
  </Bake>
41
41
  <Message
42
42
  v-if="showRequiredMessage"
43
- severity="info"
44
- >
45
- <i class="pi pi-info-circle" />
46
- <span class="ml-3">{{ lc("Select required values to view this page") }}</span>
47
- </Message>
43
+ :schema="{ severity: 'info', icon: 'pi pi-info-circle' }"
44
+ :data="lc('Select required values to view this page')"
45
+ />
48
46
  <div
49
47
  v-if="ready"
50
48
  class="pt-4 flex flex-col gap-4 items-center"
@@ -70,9 +68,9 @@
70
68
 
71
69
  <script setup>
72
70
  import { computed, onBeforeUnmount, onMounted, reactive, ref } from "vue";
73
- import { Message, Tab, TabList, Tabs } from "primevue";
71
+ import { Tab, TabList, Tabs } from "primevue";
74
72
  import { useContext, useLocalization, useReactionHandler } from "#imports";
75
- import { Bake, Contents, DeferredTabContent, Inputs } from "#components";
73
+ import { Bake, Contents, DeferredTabContent, Inputs, Message } from "#components";
76
74
  const context = useContext();
77
75
  const { localize: l } = useLocalization();
78
76
  const { localize: lc } = useLocalization({ group: "TabbedPage" });
@@ -0,0 +1,17 @@
1
+ declare const _default: typeof __VLS_export;
2
+ export default _default;
3
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
4
+ type __VLS_WithSlots<T, S> = T & (new () => {
5
+ $slots: S;
6
+ });
7
+ declare const __VLS_base: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
8
+ type __VLS_Slots = {
9
+ default?: ((props: {}) => any) | undefined;
10
+ } & {
11
+ default?: ((props: {}) => any) | undefined;
12
+ } & {
13
+ message?: ((props: {
14
+ validation: any;
15
+ mutableValidation: any;
16
+ }) => any) | undefined;
17
+ };
@@ -0,0 +1,48 @@
1
+ <template>
2
+ <template v-if="validationHandled || !validation">
3
+ <slot />
4
+ </template>
5
+ <div
6
+ v-else
7
+ class="b-Validation flex flex-col gap-2"
8
+ >
9
+ <slot />
10
+ <slot
11
+ name="message"
12
+ :validation
13
+ :mutable-validation
14
+ >
15
+ <Message
16
+ v-if="message"
17
+ :schema="{
18
+ severity: severity,
19
+ variant: 'simple',
20
+ size: 'small'
21
+ }"
22
+ :data="message || ''"
23
+ class="ml-3"
24
+ />
25
+ </slot>
26
+ </div>
27
+ </template>
28
+
29
+ <script setup>
30
+ import { computed } from "vue";
31
+ import { useContext } from "#imports";
32
+ import { Message } from "#components";
33
+ const context = useContext();
34
+ const validationHandled = context.injectValidationHandled();
35
+ const validation = context.injectValidation();
36
+ const mutableValidation = context.injectMutableValidation();
37
+ context.provideValidationHandled(true);
38
+ const message = computed(() => {
39
+ if (mutableValidation?.value.message) {
40
+ return mutableValidation.value.message;
41
+ }
42
+ if (validation.value?.message && validation.value?.persist) {
43
+ return validation.value.message;
44
+ }
45
+ return null;
46
+ });
47
+ const severity = computed(() => mutableValidation?.value.severity || validation?.value.severity);
48
+ </script>
@@ -0,0 +1,17 @@
1
+ declare const _default: typeof __VLS_export;
2
+ export default _default;
3
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
4
+ type __VLS_WithSlots<T, S> = T & (new () => {
5
+ $slots: S;
6
+ });
7
+ declare const __VLS_base: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
8
+ type __VLS_Slots = {
9
+ default?: ((props: {}) => any) | undefined;
10
+ } & {
11
+ default?: ((props: {}) => any) | undefined;
12
+ } & {
13
+ message?: ((props: {
14
+ validation: any;
15
+ mutableValidation: any;
16
+ }) => any) | undefined;
17
+ };
@@ -0,0 +1,13 @@
1
+ export default function _default(): {
2
+ handle: () => {
3
+ error: import("vue").ComputedRef<{
4
+ title: any;
5
+ detail: any;
6
+ } | null>;
7
+ rawError: any;
8
+ };
9
+ normalize: (error: any) => import("vue").ComputedRef<{
10
+ title: any;
11
+ detail: any;
12
+ } | null>;
13
+ };
@@ -0,0 +1,51 @@
1
+ import { computed, unref } from "vue";
2
+ import { useContext } from "#imports";
3
+
4
+ export default function() {
5
+ const context = useContext();
6
+
7
+ function handle() {
8
+ const data = context.injectError({ handle: true });
9
+
10
+ return NormalizedError(data);
11
+ }
12
+
13
+ function normalize(error) {
14
+ return NormalizedError(error).error;
15
+ }
16
+
17
+ return {
18
+ handle,
19
+ normalize
20
+ };
21
+ }
22
+
23
+ function NormalizedError(rawError) {
24
+ const error = computed(() => {
25
+ const e = unref(rawError);
26
+ if(!e) {
27
+ return null;
28
+ }
29
+
30
+ if(e.name === "FetchError") {
31
+ const messages = e.data?.errors
32
+ ? Object.values(e.data.errors).flat().join(" ")
33
+ : null;
34
+
35
+ return {
36
+ title: e.data?.title ?? e.statusCode ?? "ERROR",
37
+ detail: messages ?? e.data?.detail ?? e.message ?? e.cause ?? "An error occured."
38
+ };
39
+ }
40
+
41
+ return {
42
+ title: e.statusCode ?? e.status ?? "ERROR",
43
+ detail: e.message ?? e.cause ?? "An error occured."
44
+ };
45
+ });
46
+
47
+ return {
48
+ error,
49
+ rawError
50
+ };
51
+ }