Skip to content

Commit daee702

Browse files
gcwioroGünther CwioroK-Dud
authored
Disable Buttons to Prevent Multiple Requests (#167)
* Disable buttons on actions and add loading. * lint --------- Co-authored-by: Günther Cwioro <guenther.cwioro@trustbit.tech> Co-authored-by: K-Dud <krystian.dudzik@veroo.io>
1 parent f3c98cb commit daee702

22 files changed

+1914
-549
lines changed

frontend-vue/package-lock.json

Lines changed: 1723 additions & 443 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend-vue/package.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@
2020
"@vueuse/core": "^10.7.2",
2121
"@vueuse/router": "^10.7.2",
2222
"d3": "^7.8.5",
23-
"oidc-client-ts": "^2.4.0",
2423
"fuse.js": "^7.0.0",
24+
"oidc-client-ts": "^2.4.0",
2525
"pinia": "^2.1.7",
2626
"vee-validate": "^4.12.4",
27-
"vue": "^3.4.13",
27+
"vite-plugin-pages": "^0.32.2",
28+
"vue": "^3.4.29",
2829
"vue-i18n": "^9.9.0",
2930
"vue-router": "^4.2.5",
3031
"zod": "^3.22.4"
@@ -57,7 +58,7 @@
5758
"unplugin-vue-components": "^0.24.0",
5859
"vite": "^4.5.1",
5960
"vitest": "^0.29.1",
60-
"vue-loader": "^16.8.3",
61-
"vue-tsc": "^1.1.7"
61+
"vue-loader": "^17.4.2",
62+
"vue-tsc": "^1.8.27"
6263
}
63-
}
64+
}

frontend-vue/src/components/bounded-context/ContextureMoveBoundedContextModal.vue

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@
3636
</template>
3737

3838
<script lang="ts" setup>
39-
import { Ref } from "vue";
40-
import { ref } from "vue";
39+
import { Ref, ref } from "vue";
4140
import { useI18n } from "vue-i18n";
4241
import ContextureAutocomplete from "~/components/primitives/autocomplete/ContextureAutocomplete.vue";
4342
import ContexturePrimaryButton from "~/components/primitives/button/ContexturePrimaryButton.vue";
@@ -70,7 +69,7 @@ const suggestions: Ref<Domain[]> = ref<Domain[]>(allDomains);
7069
let submitError = ref<HelpfulErrorProps>();
7170
7271
async function onSubmit() {
73-
submitError.value = null;
72+
submitError.value = undefined;
7473
const res = await moveBoundedContext(props.boundedContext.id, selectedDomain.value!.id);
7574
7675
if (res.error.value) {

frontend-vue/src/components/bounded-context/canvas/BCCBusinessDecisions.vue

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
label: t('bounded_context_canvas.business_decisions.actions.open.add'),
4343
size: 'sm',
4444
}"
45-
@submit="onBusinessDecisionAdd"
45+
:action="onBusinessDecisionAdd"
4646
/>
4747
</ContextureCollapsable>
4848
</div>
@@ -60,8 +60,9 @@ import ContextureBoundedContextCanvasElement from "~/components/bounded-context/
6060
import ContextureCollapsable from "~/components/primitives/collapsable/ContextureCollapsable.vue";
6161
import ContextureDynamicForm from "~/components/primitives/dynamic-form/ContextureDynamicForm.vue";
6262
import { DynamicFormSchema } from "~/components/primitives/dynamic-form/dynamicForm";
63-
import { HelpfulErrorProps } from "~/components/primitives/alert/ContextureHelpfulErrorAlert.vue";
64-
import ContextureHelpfulErrorAlert from "~/components/primitives/alert/ContextureHelpfulErrorAlert.vue";
63+
import ContextureHelpfulErrorAlert, {
64+
HelpfulErrorProps,
65+
} from "~/components/primitives/alert/ContextureHelpfulErrorAlert.vue";
6566
import ContextureInputText from "~/components/primitives/input/ContextureInputText.vue";
6667
import { isUniqueIn } from "~/core/validation";
6768
import { useBoundedContextsStore } from "~/stores/boundedContexts";
@@ -115,7 +116,7 @@ const businessDecisionSchema: DynamicFormSchema<BusinessDecision> = {
115116
};
116117
117118
async function onBusinessDecisionAdd(businessDecision: BusinessDecision) {
118-
submitError.value = null;
119+
submitError.value = undefined;
119120
const res = await store.addBusinessDecision(activeBoundedContext.value.id, businessDecision);
120121
121122
if (res.error.value) {
@@ -141,7 +142,7 @@ async function onBusinessDecisionDelete(businessDecision: BusinessDecision) {
141142
}
142143
143144
async function deleteBusinessDecision(businessDecision: BusinessDecision) {
144-
submitError.value = null;
145+
submitError.value = undefined;
145146
const res = await store.deleteBusinessDecision(activeBoundedContext.value.id, businessDecision);
146147
147148
if (res.error.value) {

frontend-vue/src/components/bounded-context/canvas/BCCConnection.vue

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
{{ t("bounded_context_canvas.collaborators.unknown_relationship") }}
5050
</p>
5151
<p
52-
v-if="
52+
v-else-if="
5353
collaboration.relationshipType?.upstreamDownstream?.downstreamType ||
5454
collaboration.relationshipType?.upstreamDownstream?.upstreamType
5555
"
@@ -59,16 +59,16 @@
5959
collaboration.relationshipType?.upstreamDownstream.upstreamType
6060
}}
6161
</p>
62-
<p v-if="collaboration.relationshipType?.upstreamDownstream?.role" class="text-xs">
62+
<p v-else-if="collaboration.relationshipType?.upstreamDownstream?.role" class="text-xs">
6363
{{ collaboration.relationshipType?.upstreamDownstream?.role }}
6464
</p>
6565
<span
66-
v-if="collaboration.relationshipType?.upstreamDownstream"
66+
v-else-if="collaboration.relationshipType?.upstreamDownstream"
6767
class="border-l-2 border-black pl-1 text-xs font-bold"
6868
>Upstream/Downstream</span
6969
>
7070
<span
71-
v-if="collaboration.relationshipType?.symmetric"
71+
v-else-if="collaboration.relationshipType?.symmetric"
7272
class="border-l-2 border-black pl-1 text-xs font-bold"
7373
>{{ t("bounded_context_canvas.collaborators.symmetric") }}</span
7474
>
@@ -141,15 +141,17 @@
141141
/>
142142

143143
<div>
144-
<ContexturePrimaryButton
145-
type="submit"
146-
:label="t('bounded_context_canvas.collaborators.add_connection')"
147-
size="sm"
148-
>
149-
<template #left>
150-
<Icon:material-symbols:add class="mr-2" />
151-
</template>
152-
</ContexturePrimaryButton>
144+
<LoadingWrapper :is-loading="isSubmitting">
145+
<ContexturePrimaryButton
146+
type="submit"
147+
:label="t('bounded_context_canvas.collaborators.add_connection')"
148+
size="sm"
149+
>
150+
<template #left>
151+
<Icon:material-symbols:add class="mr-2" />
152+
</template>
153+
</ContexturePrimaryButton>
154+
</LoadingWrapper>
153155
</div>
154156
</form>
155157
</div>
@@ -199,6 +201,7 @@ import { useDomainsStore } from "~/stores/domains";
199201
import { BoundedContext } from "~/types/boundedContext";
200202
import { Collaboration, CollaborationId, CollaboratorKeys } from "~/types/collaboration";
201203
import { Domain } from "~/types/domain";
204+
import LoadingWrapper from "~/components/primitives/button/util/LoadingWrapper.vue";
202205
203206
interface Props {
204207
collaborations: Collaboration[];
@@ -243,14 +246,14 @@ const initialValues: CollaboratorFormValue = {
243246
description: "",
244247
};
245248
246-
const { values, handleSubmit, resetForm, setFieldValue } = useForm({
249+
const { values, isSubmitting, handleSubmit, resetForm, setFieldValue } = useForm<CollaboratorFormValue>({
247250
validationSchema: validationSchema,
248251
initialValues: initialValues,
249252
});
250253
251254
const onSubmit = handleSubmit(async (formValue: CollaboratorFormValue) => {
252255
await createCollaborator(formValue);
253-
resetForm(initialValues);
256+
resetForm();
254257
});
255258
256259
function searchSuggestions(query: string): void {

frontend-vue/src/components/bounded-context/canvas/BCCDescription.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ const editMode = ref(false);
5959
const requiredString = toFieldValidator(zod.string().min(1, t("validation.required")));
6060
6161
async function onUpdate() {
62-
submitError.value = null;
62+
submitError.value = undefined;
6363
const res = await store.updateDescription(activeBoundedContext.value.id, description.value);
6464
6565
if (res.error.value) {
@@ -74,7 +74,7 @@ async function onUpdate() {
7474
}
7575
7676
function onClose() {
77-
submitError.value = null;
77+
submitError.value = undefined;
7878
editMode.value = false;
7979
description.value = activeBoundedContext.value?.description;
8080
}

frontend-vue/src/components/bounded-context/canvas/BCCDomainRoles.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
label: t('bounded_context_canvas.domain_roles.actions.open.add'),
4444
size: 'sm',
4545
}"
46-
@submit="onDomainRoleAdd"
46+
:action="onDomainRoleAdd"
4747
/>
4848
</ContextureCollapsable>
4949
<ContextureCollapsable

frontend-vue/src/components/bounded-context/canvas/BCCKey.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ const boundedContextShortNameValidator = computed(() =>
6363
);
6464
6565
async function onUpdate() {
66-
submitError.value = null;
66+
submitError.value = undefined;
6767
const res = await store.updateKey(activeBoundedContext.value.id, key.value);
6868
6969
if (res.error.value) {

frontend-vue/src/components/bounded-context/canvas/BCCUbiquitousLanguage.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
label: t('bounded_context_canvas.ubiquitous_language.actions.open.add'),
4343
size: 'sm',
4444
}"
45-
@submit="onUbiquitousLanguageAdd"
45+
:action="onUbiquitousLanguageAdd"
4646
/>
4747
</ContextureCollapsable>
4848
</div>
@@ -115,7 +115,7 @@ const ubiquitousLanguageSchema: DynamicFormSchema<UbiquitousLanguageItem> = {
115115
};
116116
117117
async function onUbiquitousLanguageAdd(ubiquitousLanguageItem: UbiquitousLanguageItem) {
118-
submitError.value = null;
118+
submitError.value = undefined;
119119
const res = await store.addUbiquitousLanguageItem(activeBoundedContext.value.id, ubiquitousLanguageItem);
120120
121121
if (res.error.value) {
@@ -141,7 +141,7 @@ async function onDeleteUbiquitousLanguage(ubiquitousLanguageKey: string) {
141141
}
142142
143143
async function deleteUbiquitousLanguage(ubiquitousLanguageKey: string) {
144-
submitError.value = null;
144+
submitError.value = undefined;
145145
const res = await store.deleteUbiquitousLanguage(activeBoundedContext.value.id, ubiquitousLanguageKey);
146146
147147
if (res.error.value) {

frontend-vue/src/components/bounded-context/canvas/ContextureEditBoundedContextForm.vue

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@
1818
/>
1919

2020
<div>
21-
<ContexturePrimaryButton :label="t('common.save')" type="submit">
22-
<template #left>
23-
<Icon:material-symbols:check class="mr-1 h-6 w-6" />
24-
</template>
25-
</ContexturePrimaryButton>
21+
<LoadingWrapper :is-loading="isLoading">
22+
<ContexturePrimaryButton :label="t('common.save')" type="submit">
23+
<template #left>
24+
<Icon:material-symbols:check class="mr-1 h-6 w-6" />
25+
</template>
26+
</ContexturePrimaryButton>
27+
</LoadingWrapper>
2628
</div>
2729
</Form>
2830
</template>
@@ -39,15 +41,18 @@ import ContextureInputText from "~/components/primitives/input/ContextureInputTe
3941
import { BoundedContext } from "~/types/boundedContext";
4042
import { useBoundedContextsStore } from "~/stores/boundedContexts";
4143
import { storeToRefs } from "pinia";
44+
import { ActionProps, useActionWithLoading } from "~/components/primitives/button/util/useActionWithLoading";
45+
import LoadingWrapper from "~/components/primitives/button/util/LoadingWrapper.vue";
4246
43-
interface Props {
47+
interface Props extends ActionProps {
4448
initialValue: BoundedContext;
4549
}
4650
4751
const props = defineProps<Props>();
4852
const emit = defineEmits(["submit"]);
4953
const { t } = useI18n();
5054
const editModel: Ref<BoundedContext> = toRef(props, "initialValue");
55+
const { isLoading, handleAction } = useActionWithLoading(props);
5156
const requiredString = toFieldValidator(zod.string().min(1, t("validation.required")));
5257
5358
const store = useBoundedContextsStore();
@@ -60,8 +65,9 @@ const boundedContextShortNameValidator = computed(() =>
6065
)
6166
);
6267
63-
function submit(values: any) {
68+
async function submit(values: any) {
6469
emit("submit", values);
70+
await handleAction(values);
6571
}
6672
</script>
6773

0 commit comments

Comments
 (0)