-
-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'custom-default-settings' of https://github.com/socfortr…
…ess/CoPilot into custom-default-settings
- Loading branch information
Showing
7 changed files
with
319 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
235 changes: 235 additions & 0 deletions
235
frontend/src/components/customers/CustomerDefaultSettingForm.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,235 @@ | ||
<template> | ||
<n-spin :show="loading" class="customer-provisioning-default-settings-form"> | ||
<n-form :label-width="80" :model="form" :rules="rules" ref="formRef"> | ||
<div class="flex flex-col gap-4"> | ||
<div class="flex flex-wrap gap-4"> | ||
<div v-for="(_, key) of form" :key="key" class="grow"> | ||
<n-form-item :label="fieldsMeta[key].label" :path="key" class="grow"> | ||
<n-input | ||
v-model:value.trim="form[key]" | ||
:placeholder="fieldsMeta[key].placeholder" | ||
clearable | ||
/> | ||
</n-form-item> | ||
</div> | ||
</div> | ||
<div class="flex justify-between gap-4"> | ||
<div class="flex gap-4"> | ||
<slot name="additionalActions"></slot> | ||
</div> | ||
<div class="flex gap-4"> | ||
<n-button @click="reset()" :disabled="loading">Reset</n-button> | ||
<n-button | ||
type="primary" | ||
:disabled="!isValid" | ||
@click="validate()" | ||
:loading="submittingDefaultSettings" | ||
> | ||
Submit | ||
</n-button> | ||
</div> | ||
</div> | ||
</div> | ||
</n-form> | ||
</n-spin> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import { computed, onBeforeMount, onMounted, ref, watch } from "vue" | ||
import Api from "@/api" | ||
import { | ||
useMessage, | ||
NForm, | ||
NFormItem, | ||
NInput, | ||
NButton, | ||
NSpin, | ||
type FormValidationError, | ||
type FormInst, | ||
type FormRules, | ||
type FormItemRule | ||
} from "naive-ui" | ||
import type { CustomerProvisioningDefaultSettings } from "@/types/customers.d" | ||
import _trim from "lodash/trim" | ||
import _get from "lodash/get" | ||
import isURL from "validator/es/lib/isURL" | ||
import isIP from "validator/es/lib/isIP" | ||
const emit = defineEmits<{ | ||
(e: "update:loading", value: boolean): void | ||
( | ||
e: "mounted", | ||
value: { | ||
load: () => void | ||
} | ||
): void | ||
}>() | ||
const loadingDefaultSettings = ref(false) | ||
const submittingDefaultSettings = ref(false) | ||
const loading = computed(() => loadingDefaultSettings.value || submittingDefaultSettings.value) | ||
const message = useMessage() | ||
const form = ref<Omit<CustomerProvisioningDefaultSettings, "id">>(getClearForm()) | ||
const formRef = ref<FormInst | null>(null) | ||
const isNew = ref(true) | ||
const rules: FormRules = { | ||
cluster_name: { | ||
message: "Please input the Cluster Name", | ||
trigger: ["input", "blur"] | ||
}, | ||
cluster_key: { | ||
message: "Please input the Cluster Key", | ||
trigger: ["input", "blur"] | ||
}, | ||
master_ip: { | ||
validator: validateIp, | ||
trigger: ["blur"] | ||
}, | ||
grafana_url: { | ||
validator: validateUrl, | ||
trigger: ["blur"] | ||
} | ||
} | ||
const fieldsMeta = { | ||
cluster_name: { | ||
label: "Cluster Name", | ||
placeholder: "Insert the Cluster Name" | ||
}, | ||
cluster_key: { | ||
label: "Cluster Key", | ||
placeholder: "Insert the Cluster Key" | ||
}, | ||
master_ip: { | ||
label: "Master IP", | ||
placeholder: "Insert the Master IP" | ||
}, | ||
grafana_url: { | ||
label: "Grafana URL", | ||
placeholder: "Insert the Grafana URL" | ||
} | ||
} | ||
const isValid = computed(() => { | ||
let valid = true | ||
for (const key in rules) { | ||
const rule = rules[key] as FormRules | ||
if (rule.required && !_trim(_get(form.value, key))) { | ||
valid = false | ||
} | ||
} | ||
return valid | ||
}) | ||
function validate() { | ||
if (!formRef.value) return | ||
formRef.value.validate((errors?: Array<FormValidationError>) => { | ||
if (!errors) { | ||
submit() | ||
} else { | ||
message.warning("You must fill in the required fields correctly.") | ||
return false | ||
} | ||
}) | ||
} | ||
function getClearForm(settings?: Omit<CustomerProvisioningDefaultSettings, "id">) { | ||
return { | ||
cluster_name: settings?.cluster_name || "", | ||
cluster_key: settings?.cluster_key || "", | ||
master_ip: settings?.master_ip || "", | ||
grafana_url: settings?.grafana_url || "" | ||
} | ||
} | ||
function reset() { | ||
if (!loading.value) { | ||
form.value = getClearForm() | ||
} | ||
} | ||
function submit() { | ||
submittingDefaultSettings.value = true | ||
const method = isNew.value ? "setProvisioningDefaultSettings" : "updateProvisioningDefaultSettings" | ||
const payload = { | ||
clusterName: form.value.cluster_name, | ||
clusterKey: form.value.cluster_key, | ||
masterIp: form.value.master_ip, | ||
grafanaUrl: form.value.grafana_url | ||
} | ||
Api.customers[method](payload) | ||
.then(res => { | ||
if (res.data.success) { | ||
isNew.value = false | ||
} else { | ||
message.warning(res.data?.message || "An error occurred. Please try again later.") | ||
} | ||
}) | ||
.catch(err => { | ||
message.error(err.response?.data?.message || "An error occurred. Please try again later.") | ||
}) | ||
.finally(() => { | ||
submittingDefaultSettings.value = false | ||
}) | ||
} | ||
function setForm(settings?: CustomerProvisioningDefaultSettings) { | ||
form.value = getClearForm(settings) | ||
} | ||
function validateIp(rule: FormItemRule, value: string) { | ||
if (value && !isIP(value)) { | ||
return new Error("Please input a valid IP Address") | ||
} | ||
return true | ||
} | ||
function validateUrl(rule: FormItemRule, value: string) { | ||
if (value && !isURL(value)) { | ||
return new Error("Please input a valid URL") | ||
} | ||
return true | ||
} | ||
function getProvisioningDefaultSettings() { | ||
if (!loadingDefaultSettings.value) { | ||
loadingDefaultSettings.value = true | ||
Api.customers | ||
.getProvisioningDefaultSettings() | ||
.then(res => { | ||
if (res.data.success) { | ||
isNew.value = false | ||
setForm(res.data?.customer_provisioning_default_settings) | ||
} | ||
}) | ||
.finally(() => { | ||
loadingDefaultSettings.value = false | ||
}) | ||
} | ||
} | ||
watch(loading, val => { | ||
emit("update:loading", val) | ||
}) | ||
onBeforeMount(() => { | ||
getProvisioningDefaultSettings() | ||
}) | ||
onMounted(() => { | ||
emit("mounted", { | ||
load: getProvisioningDefaultSettings | ||
}) | ||
}) | ||
</script> |
36 changes: 36 additions & 0 deletions
36
frontend/src/components/customers/CustomerDefaultSettingsButton.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
<template> | ||
<n-button size="small" secondary @click="showForm = true" :loading="loading"> | ||
<template #icon> | ||
<Icon :name="SettingsIcon" :size="14"></Icon> | ||
</template> | ||
Default Settings | ||
</n-button> | ||
|
||
<n-modal | ||
v-model:show="showForm" | ||
display-directive="show" | ||
preset="card" | ||
:style="{ maxWidth: 'min(600px, 90vw)', minHeight: 'min(300px, 90vh)', overflow: 'hidden' }" | ||
title="Customer Provisioning Default Settings" | ||
:bordered="false" | ||
segmented | ||
> | ||
<CustomerDefaultSettingForm @mounted="settingsFormCTX = $event" v-model:loading="loading" /> | ||
</n-modal> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import { ref, watch } from "vue" | ||
import { NButton, NModal } from "naive-ui" | ||
import Icon from "@/components/common/Icon.vue" | ||
import CustomerDefaultSettingForm from "./CustomerDefaultSettingForm.vue" | ||
const SettingsIcon = "carbon:settings-edit" | ||
const settingsFormCTX = ref<{ load: () => void } | null>(null) | ||
const showForm = ref(false) | ||
const loading = ref(false) | ||
watch(showForm, () => { | ||
settingsFormCTX.value?.load() | ||
}) | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters