feat: allow edit

This commit is contained in:
Shivam Mishra
2025-10-03 19:48:50 +05:30
parent 5b8554d216
commit e4631e4294
5 changed files with 123 additions and 25 deletions
@@ -1,5 +1,5 @@
<script setup>
import { ref } from 'vue';
import { ref, computed } from 'vue';
import { useStore } from 'dashboard/composables/store';
import { useAlert } from 'dashboard/composables';
import { useI18n } from 'vue-i18n';
@@ -8,22 +8,49 @@ import { parseAPIErrorResponse } from 'dashboard/store/utils/api';
import Dialog from 'dashboard/components-next/dialog/Dialog.vue';
import CustomToolForm from './CustomToolForm.vue';
const props = defineProps({
selectedTool: {
type: Object,
default: () => ({}),
},
type: {
type: String,
default: 'create',
validator: value => ['create', 'edit'].includes(value),
},
});
const emit = defineEmits(['close']);
const { t } = useI18n();
const store = useStore();
const dialogRef = ref(null);
const i18nKey = 'CAPTAIN.CUSTOM_TOOLS.CREATE';
const updateTool = toolDetails =>
store.dispatch('captainCustomTools/update', {
id: props.selectedTool.id,
...toolDetails,
});
const handleSubmit = async newTool => {
const i18nKey = computed(
() => `CAPTAIN.CUSTOM_TOOLS.${props.type.toUpperCase()}`
);
const createTool = toolDetails =>
store.dispatch('captainCustomTools/create', toolDetails);
const handleSubmit = async updatedTool => {
try {
await store.dispatch('captainCustomTools/create', newTool);
useAlert(t(`${i18nKey}.SUCCESS_MESSAGE`));
if (props.type === 'edit') {
await updateTool(updatedTool);
} else {
await createTool(updatedTool);
}
useAlert(t(`${i18nKey.value}.SUCCESS_MESSAGE`));
dialogRef.value.close();
} catch (error) {
const errorMessage =
parseAPIErrorResponse(error) || t(`${i18nKey}.ERROR_MESSAGE`);
parseAPIErrorResponse(error) || t(`${i18nKey.value}.ERROR_MESSAGE`);
useAlert(errorMessage);
}
};
@@ -49,7 +76,12 @@ defineExpose({ dialogRef });
:show-confirm-button="false"
@close="handleClose"
>
<CustomToolForm @submit="handleSubmit" @cancel="handleCancel" />
<CustomToolForm
:mode="type"
:tool="selectedTool"
@submit="handleSubmit"
@cancel="handleCancel"
/>
<template #footer />
</Dialog>
</template>
@@ -1,5 +1,5 @@
<script setup>
import { reactive, computed, useTemplateRef } from 'vue';
import { reactive, computed, useTemplateRef, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { useVuelidate } from '@vuelidate/core';
import { required, url } from '@vuelidate/validators';
@@ -12,6 +12,18 @@ import ComboBox from 'dashboard/components-next/combobox/ComboBox.vue';
import ParamRow from './ParamRow.vue';
import AuthConfig from './AuthConfig.vue';
const props = defineProps({
mode: {
type: String,
default: 'create',
validator: value => ['create', 'edit'].includes(value),
},
tool: {
type: Object,
default: () => ({}),
},
});
const emit = defineEmits(['submit', 'cancel']);
const { t } = useI18n();
@@ -34,6 +46,25 @@ const initialState = {
const state = reactive({ ...initialState });
// Populate form when in edit mode
watch(
() => props.tool,
newTool => {
if (props.mode === 'edit' && newTool && newTool.id) {
state.title = newTool.title || '';
state.description = newTool.description || '';
state.endpoint_url = newTool.endpoint_url || '';
state.http_method = newTool.http_method || 'GET';
state.request_template = newTool.request_template || '';
state.response_template = newTool.response_template || '';
state.auth_type = newTool.auth_type || 'none';
state.auth_config = newTool.auth_config || {};
state.param_schema = newTool.param_schema || [];
}
},
{ immediate: true }
);
const DEFAULT_PARAM = {
name: '',
type: 'string',
@@ -65,7 +96,11 @@ const authTypeOptions = computed(() => [
const v$ = useVuelidate(validationRules, state);
const isLoading = computed(() => formState.uiFlags.value.creatingItem);
const isLoading = computed(() =>
props.mode === 'edit'
? formState.uiFlags.value.updatingItem
: formState.uiFlags.value.creatingItem
);
const getErrorMessage = (field, errorKey) => {
return v$.value[field].$error
@@ -221,7 +256,9 @@ const handleSubmit = async () => {
/>
<Button
type="submit"
:label="t('CAPTAIN.FORM.CREATE')"
:label="
t(mode === 'edit' ? 'CAPTAIN.FORM.EDIT' : 'CAPTAIN.FORM.CREATE')
"
class="w-full"
:is-loading="isLoading"
:disabled="isLoading"
@@ -69,17 +69,17 @@ defineExpose({ validate });
}"
>
<div class="flex flex-col flex-1 gap-3">
<div class="flex gap-2">
<div class="grid grid-cols-3 gap-2">
<Input
v-model="name"
:placeholder="t('CAPTAIN.CUSTOM_TOOLS.FORM.PARAM_NAME.PLACEHOLDER')"
class="flex-1 [&>input]:h-8 [&>input]:py-1.5 [&>input]:outline-offset-0"
class="col-span-2"
/>
<ComboBox
v-model="type"
:options="paramTypeOptions"
:placeholder="t('CAPTAIN.CUSTOM_TOOLS.FORM.PARAM_TYPE.PLACEHOLDER')"
class="w-36 [&>div>button]:h-8 [&>div>button]:py-1.5"
class="[&>div>button]:bg-n-alpha-black2"
/>
</div>
<Input
@@ -87,7 +87,6 @@ defineExpose({ validate });
:placeholder="
t('CAPTAIN.CUSTOM_TOOLS.FORM.PARAM_DESCRIPTION.PLACEHOLDER')
"
class="[&>input]:h-8 [&>input]:py-1.5 [&>input]:outline-offset-0"
/>
<label class="flex items-center gap-2 cursor-pointer">
<Checkbox v-model="required" />
@@ -97,11 +96,10 @@ defineExpose({ validate });
</label>
</div>
<Button
sm
solid
slate
icon="i-lucide-trash"
class="flex-shrink-0 mt-0.5"
class="flex-shrink-0"
@click.stop="emit('remove')"
/>
</div>