|
14 | 14 | > |
15 | 15 | <q-step |
16 | 16 | v-for="(step, stepIndex) in stepNames" |
17 | | - v-bind:active-icon="activeIcon(currentStepIndex > stepIndex && errorPerStep[step].value, step)" |
| 17 | + v-bind:active-icon="step === 'finish' ? 'done' : 'edit'" |
18 | 18 | v-bind:aria-label="toLabel(step)" |
19 | 19 | v-bind:caption="stepIndex < 2 ? 'required' : (step !== 'finish' ? 'optional' : '')" |
20 | 20 | v-bind:data-cy="`step-${step}`" |
21 | 21 | v-bind:done="screenVisited(step) && !errorPerStep[step].value" |
22 | 22 | v-bind:error="currentStepIndex != stepIndex && screenVisited(step) && errorPerStep[step].value" |
| 23 | + v-bind:header-nav="stepIndex !== currentStepIndex && screenVisited(step) && !anyErrorBetween('start', step)" |
23 | 24 | v-bind:key="step" |
24 | 25 | v-bind:name="step" |
25 | 26 | v-bind:order="stepIndex" |
26 | 27 | v-bind:title="toLabel(step)" |
27 | | - v-on:click="setStepName(step)" |
| 28 | + v-on:click="onStepClick(step)" |
28 | 29 | v-on:keyup.enter="setStepName(step)" |
29 | 30 | /> |
30 | 31 | </q-stepper> |
|
33 | 34 |
|
34 | 35 | <script lang="ts"> |
35 | 36 |
|
36 | | -import { ComputedRef, computed } from 'vue' |
37 | 37 | import { StepNameType, useApp } from 'src/store/app' |
38 | | -import { |
39 | | - byError, |
40 | | - instancePathStartsWithMatcher, |
41 | | - screenAuthorQueries, |
42 | | - screenIdentifiersQueries, |
43 | | - screenKeywordsQueries, |
44 | | - screenRelatedResourcesQueries, |
45 | | - screenStartQueries, |
46 | | - screenVersionSpecificQueries |
47 | | -} from 'src/error-filtering' |
48 | | -import { useValidation } from 'src/store/validation' |
| 38 | +import { errorPerStep } from 'src/store/stepper-errors' |
| 39 | +import { useQuasar } from 'quasar' |
49 | 40 |
|
50 | 41 | export default { |
51 | 42 | setup () { |
52 | 43 | const { currentStepIndex, screenVisited, stepName, setStepName, stepNames } = useApp() |
53 | | - const { errors } = useValidation() |
| 44 | + const $q = useQuasar() |
| 45 | + const anyErrorBetween = (stepA: StepNameType, stepB: StepNameType) => { |
| 46 | + const stepIndexA = stepNames.indexOf(stepA) |
| 47 | + const stepIndexB = stepNames.indexOf(stepB) |
| 48 | + return stepNames.slice(stepIndexA, stepIndexB) |
| 49 | + .map((step) => errorPerStep[step].value) |
| 50 | + .reduce((result, errorOnStep) => result || errorOnStep, false) |
| 51 | + } |
54 | 52 | const toLabel = (name: string) => { |
55 | 53 | if (name === 'start') { // Exception |
56 | | - return 'Basic information' |
| 54 | + return 'Basic Information' |
57 | 55 | } |
58 | 56 | return name.split('-').map((s) => s.slice(0, 1).toUpperCase() + s.slice(1)).join(' ') |
59 | 57 | } |
60 | | - const errorStateScreenAuthors = computed(() => { |
61 | | - return screenAuthorQueries |
62 | | - .filter(byError(errors.value, instancePathStartsWithMatcher)) |
63 | | - .length > 0 |
64 | | - }) |
65 | | - const errorStateScreenIdentifiers = computed(() => { |
66 | | - return screenIdentifiersQueries |
67 | | - .filter(byError(errors.value, instancePathStartsWithMatcher)) |
68 | | - .length > 0 |
69 | | - }) |
70 | | - const errorStateScreenKeywords = computed(() => { |
71 | | - return screenKeywordsQueries |
72 | | - .filter(byError(errors.value, instancePathStartsWithMatcher)) |
73 | | - .length > 0 |
74 | | - }) |
75 | | - const errorStateScreenRelatedResources = computed(() => { |
76 | | - return screenRelatedResourcesQueries |
77 | | - .filter(byError(errors.value, instancePathStartsWithMatcher)) |
78 | | - .length > 0 |
79 | | - }) |
80 | | - const errorStateScreenStart = computed(() => { |
81 | | - return screenStartQueries |
82 | | - .filter(byError(errors.value)) // One of the possible errors is instancePath == '', so we use a traditional approach here |
83 | | - .length > 0 |
84 | | - }) |
85 | | - const errorStateScreenVersionSpecific = computed(() => { |
86 | | - return screenVersionSpecificQueries |
87 | | - .filter(byError(errors.value, instancePathStartsWithMatcher)) |
88 | | - .length > 0 |
89 | | - }) |
90 | | - const errorPerStep: Record<StepNameType, ComputedRef<boolean>> = { |
91 | | - start: errorStateScreenStart, |
92 | | - authors: errorStateScreenAuthors, |
93 | | - identifiers: errorStateScreenIdentifiers, |
94 | | - 'related-resources': errorStateScreenRelatedResources, |
95 | | - abstract: computed(() => false), |
96 | | - keywords: errorStateScreenKeywords, |
97 | | - license: computed(() => false), |
98 | | - 'version-specific': errorStateScreenVersionSpecific, |
99 | | - finish: computed(() => false) |
100 | | - } |
101 | 58 | return { |
102 | | - activeIcon: (hasError: boolean, step: StepNameType) => { |
103 | | - if (hasError) { |
104 | | - return 'warning' |
105 | | - } else if (step === 'finish' && errors.value.length === 0) { |
106 | | - return 'done' |
107 | | - } else { |
108 | | - return 'edit' |
| 59 | + anyErrorBetween, |
| 60 | + currentStepIndex, |
| 61 | + onStepClick: (step: StepNameType) => { |
| 62 | + const curIndex = currentStepIndex.value |
| 63 | + const clickIndex = stepNames.indexOf(step) |
| 64 | + if ( // Only allow clicking on stepper if |
| 65 | + step !== stepName.value && // it is not the current step |
| 66 | + screenVisited(step) && // it is not a new screen |
| 67 | + ( // don't skip errors when moving forward |
| 68 | + curIndex > clickIndex || // it is going back (up); OR |
| 69 | + ( |
| 70 | + !errorPerStep[stepName.value].value && // it is not leaving an erroring screen |
| 71 | + !anyErrorBetween(stepName.value, step) // not skipping intermediary erroring screens if going forward |
| 72 | + ) |
| 73 | + ) |
| 74 | + ) { |
| 75 | + void setStepName(step) |
| 76 | + } else if ( // Can't skip erroring screens |
| 77 | + curIndex < clickIndex && |
| 78 | + anyErrorBetween(stepName.value, step) |
| 79 | + ) { |
| 80 | + const firstStepWithError = stepNames.filter((step) => errorPerStep[step].value)[0] |
| 81 | + $q.notify({ |
| 82 | + message: `Fix error in "${toLabel(firstStepWithError)}" before proceeding`, |
| 83 | + color: 'negative', |
| 84 | + progress: true, |
| 85 | + timeout: 1200 |
| 86 | + }) |
109 | 87 | } |
110 | 88 | }, |
111 | | - currentStepIndex, |
112 | 89 | errorPerStep, |
113 | 90 | screenVisited, |
114 | 91 | setStepName, |
|
0 commit comments