🔨 Send settings
This commit is contained in:
parent
f8d174224c
commit
f6baab77ed
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -8,7 +8,6 @@
|
|||||||
"typescript.inlayHints.propertyDeclarationTypes.enabled": true,
|
"typescript.inlayHints.propertyDeclarationTypes.enabled": true,
|
||||||
"typescript.inlayHints.parameterNames.suppressWhenArgumentMatchesName": true,
|
"typescript.inlayHints.parameterNames.suppressWhenArgumentMatchesName": true,
|
||||||
"typescript.inlayHints.parameterNames.enabled": "literals",
|
"typescript.inlayHints.parameterNames.enabled": "literals",
|
||||||
"typescript.inlayHints.parameterTypes.enabled": true,
|
|
||||||
"javascript.inlayHints.enumMemberValues.enabled": true,
|
"javascript.inlayHints.enumMemberValues.enabled": true,
|
||||||
"javascript.inlayHints.propertyDeclarationTypes.enabled": true,
|
"javascript.inlayHints.propertyDeclarationTypes.enabled": true,
|
||||||
"javascript.inlayHints.parameterNames.suppressWhenArgumentMatchesName": true,
|
"javascript.inlayHints.parameterNames.suppressWhenArgumentMatchesName": true,
|
||||||
|
@ -3,12 +3,14 @@
|
|||||||
v-for="(data, index) of snacks"
|
v-for="(data, index) of snacks"
|
||||||
:key="data.uuid"
|
:key="data.uuid"
|
||||||
v-model="data.snack"
|
v-model="data.snack"
|
||||||
top="true"
|
location="top start"
|
||||||
left="true"
|
|
||||||
:style="{ 'margin-top': calcMargin(index) }"
|
:style="{ 'margin-top': calcMargin(index) }"
|
||||||
:color="data.color"
|
:color="data.color"
|
||||||
>
|
>
|
||||||
<div>{{ data.text }}</div>
|
<div>
|
||||||
|
<v-icon class="mr-2">{{ data.icon }}</v-icon>
|
||||||
|
{{ data.text }}
|
||||||
|
</div>
|
||||||
<template v-slot:actions>
|
<template v-slot:actions>
|
||||||
<v-btn
|
<v-btn
|
||||||
variant="text"
|
variant="text"
|
||||||
@ -30,7 +32,7 @@ function calcMargin(i: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let snacks = ref<
|
let snacks = ref<
|
||||||
{ text: string; color: string; snack: boolean; uuid: string }[]
|
{ text: string; color: string; snack: boolean; uuid: string; icon: string }[]
|
||||||
>([]);
|
>([]);
|
||||||
|
|
||||||
eventQueuStore.$subscribe((mutation, state) => {
|
eventQueuStore.$subscribe((mutation, state) => {
|
||||||
@ -42,6 +44,7 @@ eventQueuStore.$subscribe((mutation, state) => {
|
|||||||
text: event.text,
|
text: event.text,
|
||||||
color: event.type,
|
color: event.type,
|
||||||
uuid: event.uuid,
|
uuid: event.uuid,
|
||||||
|
icon: getIcon(event.type),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,9 +69,23 @@ if (eventQueuStore.size != 0) {
|
|||||||
text: event.text,
|
text: event.text,
|
||||||
color: event.type,
|
color: event.type,
|
||||||
uuid: event.uuid,
|
uuid: event.uuid,
|
||||||
|
icon: getIcon(event.type),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getIcon(type: string) {
|
||||||
|
switch (type) {
|
||||||
|
case "success":
|
||||||
|
return "mdi-check";
|
||||||
|
case "warning":
|
||||||
|
return "mdi-alert";
|
||||||
|
case "error":
|
||||||
|
return "mdi-alert-decagram";
|
||||||
|
default:
|
||||||
|
return "mdi-alert-circle";
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
@ -12,13 +12,7 @@
|
|||||||
></bool-field-component>
|
></bool-field-component>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
<template
|
<template v-if="isOn">
|
||||||
v-if="
|
|
||||||
!!props.descriptor.mainField
|
|
||||||
? settingStoreRef.values.value[props.descriptor.mainField.id]
|
|
||||||
: true
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<v-row v-for="item of props.descriptor.fields" :key="item.id">
|
<v-row v-for="item of props.descriptor.fields" :key="item.id">
|
||||||
<v-col>
|
<v-col>
|
||||||
<bool-field-component
|
<bool-field-component
|
||||||
@ -26,10 +20,12 @@
|
|||||||
:fieldDescription="item"
|
:fieldDescription="item"
|
||||||
></bool-field-component>
|
></bool-field-component>
|
||||||
<select-field-component
|
<select-field-component
|
||||||
|
:required="isOn"
|
||||||
:fieldDescription="item"
|
:fieldDescription="item"
|
||||||
v-if="isSelect(item.type)"
|
v-if="isSelect(item.type)"
|
||||||
></select-field-component>
|
></select-field-component>
|
||||||
<text-field-component
|
<text-field-component
|
||||||
|
:required="isOn"
|
||||||
:fieldDescription="item"
|
:fieldDescription="item"
|
||||||
v-if="item.type == 'STRING'"
|
v-if="item.type == 'STRING'"
|
||||||
></text-field-component>
|
></text-field-component>
|
||||||
@ -45,6 +41,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { SettingDescrition } from "@/data/Setting/SettingDescription";
|
import type { SettingDescrition } from "@/data/Setting/SettingDescription";
|
||||||
import { useSettingStore } from "@/stores/setting";
|
import { useSettingStore } from "@/stores/setting";
|
||||||
|
import { computed } from "@vue/reactivity";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
import boolFieldComponent from "./fields/BoolFieldComponent.vue";
|
import boolFieldComponent from "./fields/BoolFieldComponent.vue";
|
||||||
import SelectFieldComponent from "./fields/SelectFieldComponent.vue";
|
import SelectFieldComponent from "./fields/SelectFieldComponent.vue";
|
||||||
@ -65,6 +62,12 @@ function isSelect(type: string) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isOn = computed(() => {
|
||||||
|
return props.descriptor.mainField
|
||||||
|
? !!settingStoreRef.values.value[props.descriptor.mainField.id]
|
||||||
|
: true;
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
@ -14,14 +14,30 @@
|
|||||||
width="15"
|
width="15"
|
||||||
></v-progress-circular>
|
></v-progress-circular>
|
||||||
</v-overlay>
|
</v-overlay>
|
||||||
<v-row>
|
<v-form ref="form">
|
||||||
<v-col
|
<v-row>
|
||||||
v-for="item of settingsDescription"
|
<v-col
|
||||||
:key="item.name"
|
v-for="item of settingsDescription"
|
||||||
md="6"
|
:key="item.name"
|
||||||
cols="12"
|
md="6"
|
||||||
>
|
cols="12"
|
||||||
<setting-group-component :descriptor="item"></setting-group-component>
|
>
|
||||||
|
<setting-group-component :descriptor="item"></setting-group-component>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-form>
|
||||||
|
<v-row justify="center">
|
||||||
|
<v-col cols="1">
|
||||||
|
<v-btn
|
||||||
|
v-on:click="send"
|
||||||
|
color="success"
|
||||||
|
prepend-icon="mdi-content-save"
|
||||||
|
block
|
||||||
|
:disabled="preventSave"
|
||||||
|
v-if="settingsDescription.length > 0"
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</v-btn>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</div>
|
</div>
|
||||||
@ -39,10 +55,12 @@ import {
|
|||||||
import {
|
import {
|
||||||
getSettingDescrition,
|
getSettingDescrition,
|
||||||
getSettingValues,
|
getSettingValues,
|
||||||
|
sendSetting,
|
||||||
} from "@/services/settingsService";
|
} from "@/services/settingsService";
|
||||||
|
import { useEventQueuStore } from "@/stores/eventQueu";
|
||||||
import { useSettingStore } from "@/stores/setting";
|
import { useSettingStore } from "@/stores/setting";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
import { ref } from "vue";
|
import { ref, watch } from "vue";
|
||||||
import SettingGroupComponent from "./SettingGroupComponent.vue";
|
import SettingGroupComponent from "./SettingGroupComponent.vue";
|
||||||
|
|
||||||
const props = defineProps<{ guild: Guild }>();
|
const props = defineProps<{ guild: Guild }>();
|
||||||
@ -50,8 +68,10 @@ const props = defineProps<{ guild: Guild }>();
|
|||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
const { values, loading, text_channels, voice_channels, roles } =
|
const { values, loading, text_channels, voice_channels, roles } =
|
||||||
storeToRefs(settingStore);
|
storeToRefs(settingStore);
|
||||||
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
values.value = {};
|
values.value = {};
|
||||||
|
|
||||||
const settingsDescription = ref([] as SettingDescrition[]);
|
const settingsDescription = ref([] as SettingDescrition[]);
|
||||||
|
|
||||||
getSettingDescrition().then((value) => {
|
getSettingDescrition().then((value) => {
|
||||||
@ -86,11 +106,59 @@ function loadSettings() {
|
|||||||
for (let item of value) {
|
for (let item of value) {
|
||||||
temp[item.id] = item.value;
|
temp[item.id] = item.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
values.value = temp;
|
values.value = temp;
|
||||||
|
settingStore.savedValues = JSON.parse(JSON.stringify(temp));
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const form = ref(null);
|
||||||
|
const preventSave = ref(false);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
values,
|
||||||
|
() => {
|
||||||
|
const theForm = form.value as any;
|
||||||
|
theForm?.validate().then((value: any) => {
|
||||||
|
preventSave.value =
|
||||||
|
!value.valid ||
|
||||||
|
JSON.stringify(values.value) ==
|
||||||
|
JSON.stringify(settingStore.savedValues);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
|
function send() {
|
||||||
|
const theForm = form.value as any;
|
||||||
|
theForm?.validate().then((value: any) => {
|
||||||
|
if (value.valid) {
|
||||||
|
loading.value = true;
|
||||||
|
sendSetting(
|
||||||
|
props.guild.id,
|
||||||
|
settingStore.values,
|
||||||
|
settingsDescription.value
|
||||||
|
)
|
||||||
|
.then((saved) => {
|
||||||
|
let temp = {} as SettingValue;
|
||||||
|
for (let item of saved) {
|
||||||
|
temp[item.id] = item.value;
|
||||||
|
}
|
||||||
|
values.value = temp;
|
||||||
|
settingStore.savedValues = JSON.parse(JSON.stringify(temp));
|
||||||
|
loading.value = false;
|
||||||
|
const eventQueuStore = useEventQueuStore();
|
||||||
|
eventQueuStore.push({
|
||||||
|
uuid: undefined,
|
||||||
|
type: "success",
|
||||||
|
text: "Settings saved",
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
:items="items?.value"
|
:items="items?.value"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
v-model="values[fieldDescription.id]"
|
v-model="values[fieldDescription.id]"
|
||||||
|
:rules="[required]"
|
||||||
></v-autocomplete>
|
></v-autocomplete>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
@ -24,10 +25,19 @@ import type { FieldDescriptor } from "@/data/Setting/SettingDescription";
|
|||||||
import { useSettingStore } from "@/stores/setting";
|
import { useSettingStore } from "@/stores/setting";
|
||||||
import { computed } from "@vue/reactivity";
|
import { computed } from "@vue/reactivity";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
const props = defineProps<{ fieldDescription: FieldDescriptor }>();
|
const props = defineProps<{
|
||||||
|
fieldDescription: FieldDescriptor;
|
||||||
|
required: boolean;
|
||||||
|
}>();
|
||||||
|
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
|
|
||||||
|
function required(value: string) {
|
||||||
|
return props.required
|
||||||
|
? !!values.value[props.fieldDescription.id] || "Required"
|
||||||
|
: true;
|
||||||
|
}
|
||||||
|
|
||||||
const { loading, roles, text_channels, voice_channels, values } =
|
const { loading, roles, text_channels, voice_channels, values } =
|
||||||
storeToRefs(settingStore);
|
storeToRefs(settingStore);
|
||||||
const loadingComp = computed(() => {
|
const loadingComp = computed(() => {
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
:loading="loading"
|
:loading="loading"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
v-model="settingStore.values[fieldDescription.id]"
|
v-model="settingStore.values[fieldDescription.id]"
|
||||||
|
:rules="[required]"
|
||||||
></v-text-field>
|
></v-text-field>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
@ -20,11 +21,18 @@
|
|||||||
import type { FieldDescriptor } from "@/data/Setting/SettingDescription";
|
import type { FieldDescriptor } from "@/data/Setting/SettingDescription";
|
||||||
import { useSettingStore } from "@/stores/setting";
|
import { useSettingStore } from "@/stores/setting";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
defineProps<{ fieldDescription: FieldDescriptor }>();
|
const props = defineProps<{
|
||||||
|
fieldDescription: FieldDescriptor;
|
||||||
|
required: boolean;
|
||||||
|
}>();
|
||||||
|
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
|
|
||||||
const { loading } = storeToRefs(settingStore);
|
const { loading } = storeToRefs(settingStore);
|
||||||
|
|
||||||
|
function required(value: string) {
|
||||||
|
return props.required ? !!value || "Required" : true;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
@ -35,13 +35,6 @@ async function login(code: string): Promise<boolean> {
|
|||||||
console.log("Loggin fail !");
|
console.log("Loggin fail !");
|
||||||
console.log(reason);
|
console.log(reason);
|
||||||
logout(false, true);
|
logout(false, true);
|
||||||
|
|
||||||
const eventQueuStore = useEventQueuStore();
|
|
||||||
eventQueuStore.push({
|
|
||||||
uuid: undefined,
|
|
||||||
type: "error",
|
|
||||||
text: "Login fail, Please try aguain.",
|
|
||||||
});
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import type { RawSettingValue } from "@/data/Setting/RawSettingValue";
|
import type { RawSettingValue } from "@/data/Setting/RawSettingValue";
|
||||||
import type { SettingDescrition } from "@/data/Setting/SettingDescription";
|
import type { SettingDescrition } from "@/data/Setting/SettingDescription";
|
||||||
|
import type { SettingValue } from "@/data/Setting/SettingValue";
|
||||||
import { useEventQueuStore } from "@/stores/eventQueu";
|
import { useEventQueuStore } from "@/stores/eventQueu";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
@ -46,4 +47,52 @@ function getSettingValues(guildId: string): Promise<RawSettingValue[]> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export { getSettingDescrition, getSettingValues };
|
function sendSetting(
|
||||||
|
guildId: string,
|
||||||
|
data: SettingValue,
|
||||||
|
description: SettingDescrition[]
|
||||||
|
): Promise<RawSettingValue[]> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const userStore = useUserStore();
|
||||||
|
|
||||||
|
const converted = buildValuePayload(data, description);
|
||||||
|
axios
|
||||||
|
.post<RawSettingValue[]>(`/setting/${guildId}/values`, converted, {
|
||||||
|
headers: {
|
||||||
|
authorization: `Bearer ${userStore.token}`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((value) => {
|
||||||
|
resolve(value.data);
|
||||||
|
})
|
||||||
|
.catch((reason) => {
|
||||||
|
console.error(`Fail to save settings !`);
|
||||||
|
console.log(reason);
|
||||||
|
const eventQueuStore = useEventQueuStore();
|
||||||
|
eventQueuStore.push({
|
||||||
|
uuid: undefined,
|
||||||
|
type: "error",
|
||||||
|
text: "Fail to save settings !",
|
||||||
|
});
|
||||||
|
reject(reason);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildValuePayload(
|
||||||
|
data: SettingValue,
|
||||||
|
description: SettingDescrition[]
|
||||||
|
): RawSettingValue[] {
|
||||||
|
const temp = [] as RawSettingValue[];
|
||||||
|
for (const item of description) {
|
||||||
|
if (item.mainField) {
|
||||||
|
temp.push({ id: item.mainField.id, value: data[item.mainField.id] });
|
||||||
|
}
|
||||||
|
for (const field of item.fields) {
|
||||||
|
temp.push({ id: field.id, value: data[field.id] });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { getSettingDescrition, getSettingValues, sendSetting };
|
||||||
|
@ -4,6 +4,7 @@ import { defineStore } from "pinia";
|
|||||||
export const useSettingStore = defineStore({
|
export const useSettingStore = defineStore({
|
||||||
id: "setting",
|
id: "setting",
|
||||||
state: () => ({
|
state: () => ({
|
||||||
|
savedValues: {} as SettingValue,
|
||||||
values: {} as SettingValue,
|
values: {} as SettingValue,
|
||||||
text_channels: [] as SettingValue[],
|
text_channels: [] as SettingValue[],
|
||||||
voice_channels: [] as SettingValue[],
|
voice_channels: [] as SettingValue[],
|
||||||
|
@ -13,12 +13,10 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { login } from "@/services/authService";
|
import { login } from "@/services/authService";
|
||||||
import { useUserStore } from "@/stores/user";
|
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const userStore = useUserStore();
|
|
||||||
if (route.query.code) {
|
if (route.query.code) {
|
||||||
login(route.query.code as string).then(() => {
|
login(route.query.code as string).then(() => {
|
||||||
router.push("/");
|
router.push("/");
|
||||||
|
Loading…
Reference in New Issue
Block a user