mirror of https://github.com/halo-dev/halo
parent
c27cbb5204
commit
f36531119a
|
@ -142,7 +142,7 @@ const actions: Action[] = [
|
||||||
confirmText: t("core.common.buttons.confirm"),
|
confirmText: t("core.common.buttons.confirm"),
|
||||||
cancelText: t("core.common.buttons.cancel"),
|
cancelText: t("core.common.buttons.cancel"),
|
||||||
onConfirm: async () => {
|
onConfirm: async () => {
|
||||||
await consoleApiClient.content.indices.buildPostIndices();
|
await consoleApiClient.content.indices.rebuildAllIndices();
|
||||||
Toast.success(
|
Toast.success(
|
||||||
t(
|
t(
|
||||||
"core.dashboard.widgets.presets.quicklink.actions.refresh_search_engine.success_message"
|
"core.dashboard.widgets.presets.quicklink.actions.refresh_search_engine.success_message"
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import StickyBlock from "@/components/sticky-block/StickyBlock.vue";
|
import StickyBlock from "@/components/sticky-block/StickyBlock.vue";
|
||||||
import { useSettingFormConvert } from "@console/composables/use-setting-form";
|
|
||||||
import { useThemeStore } from "@console/stores/theme";
|
import { useThemeStore } from "@console/stores/theme";
|
||||||
import type {
|
import type { FormKitSchemaCondition, FormKitSchemaNode } from "@formkit/core";
|
||||||
ConfigMap,
|
import type { Setting, SettingForm, Theme } from "@halo-dev/api-client";
|
||||||
Setting,
|
|
||||||
SettingForm,
|
|
||||||
Theme,
|
|
||||||
} from "@halo-dev/api-client";
|
|
||||||
import { consoleApiClient } from "@halo-dev/api-client";
|
import { consoleApiClient } from "@halo-dev/api-client";
|
||||||
import {
|
import {
|
||||||
IconComputer,
|
IconComputer,
|
||||||
|
@ -24,7 +19,8 @@ import {
|
||||||
VModal,
|
VModal,
|
||||||
VTabbar,
|
VTabbar,
|
||||||
} from "@halo-dev/components";
|
} from "@halo-dev/components";
|
||||||
import { useQuery } from "@tanstack/vue-query";
|
import { useQuery, useQueryClient } from "@tanstack/vue-query";
|
||||||
|
import { cloneDeep, set } from "lodash-es";
|
||||||
import { OverlayScrollbarsComponent } from "overlayscrollbars-vue";
|
import { OverlayScrollbarsComponent } from "overlayscrollbars-vue";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
import { computed, markRaw, onMounted, ref, toRaw } from "vue";
|
import { computed, markRaw, onMounted, ref, toRaw } from "vue";
|
||||||
|
@ -46,6 +42,7 @@ const emit = defineEmits<{
|
||||||
(event: "close"): void;
|
(event: "close"): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const queryClient = useQueryClient();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
interface SettingTab {
|
interface SettingTab {
|
||||||
|
@ -132,10 +129,10 @@ const { data: setting } = useQuery<Setting>({
|
||||||
enabled: computed(() => !!selectedTheme.value?.spec.settingName),
|
enabled: computed(() => !!selectedTheme.value?.spec.settingName),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: configMap, refetch: handleFetchConfigMap } = useQuery<ConfigMap>({
|
const { data: configMapData } = useQuery({
|
||||||
queryKey: ["theme-configMap", selectedTheme],
|
queryKey: ["core:theme:configMap:data", selectedTheme],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const { data } = await consoleApiClient.theme.theme.fetchThemeConfig({
|
const { data } = await consoleApiClient.theme.theme.fetchThemeJsonConfig({
|
||||||
name: selectedTheme?.value?.metadata.name as string,
|
name: selectedTheme?.value?.metadata.name as string,
|
||||||
});
|
});
|
||||||
return data;
|
return data;
|
||||||
|
@ -145,34 +142,43 @@ const { data: configMap, refetch: handleFetchConfigMap } = useQuery<ConfigMap>({
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { formSchema, configMapFormData, convertToSave } = useSettingFormConvert(
|
const currentConfigMapGroupData = computed(() => {
|
||||||
setting,
|
return configMapData.value?.[activeSettingTab.value];
|
||||||
configMap,
|
});
|
||||||
activeSettingTab
|
|
||||||
);
|
const formSchema = computed(() => {
|
||||||
|
if (!setting.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { forms } = setting.value.spec;
|
||||||
|
return forms.find((item) => item.group === activeSettingTab.value)
|
||||||
|
?.formSchema as (FormKitSchemaCondition | FormKitSchemaNode)[];
|
||||||
|
});
|
||||||
|
|
||||||
const handleRefresh = () => {
|
const handleRefresh = () => {
|
||||||
previewFrame.value?.contentWindow?.location.reload();
|
previewFrame.value?.contentWindow?.location.reload();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSaveConfigMap = async () => {
|
const handleSaveConfigMap = async (data: object) => {
|
||||||
saving.value = true;
|
saving.value = true;
|
||||||
|
|
||||||
const configMapToUpdate = convertToSave();
|
if (!selectedTheme?.value) {
|
||||||
|
|
||||||
if (!configMapToUpdate || !selectedTheme?.value) {
|
|
||||||
saving.value = false;
|
saving.value = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await consoleApiClient.theme.theme.updateThemeConfig({
|
await consoleApiClient.theme.theme.updateThemeJsonConfig({
|
||||||
name: selectedTheme?.value?.metadata.name,
|
name: selectedTheme?.value?.metadata.name,
|
||||||
configMap: configMapToUpdate,
|
body: set(
|
||||||
|
cloneDeep(configMapData.value) || {},
|
||||||
|
activeSettingTab.value,
|
||||||
|
data
|
||||||
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
Toast.success(t("core.common.toast.save_success"));
|
Toast.success(t("core.common.toast.save_success"));
|
||||||
|
|
||||||
await handleFetchConfigMap();
|
queryClient.invalidateQueries({ queryKey: ["core:theme:configMap:data"] });
|
||||||
|
|
||||||
saving.value = false;
|
saving.value = false;
|
||||||
|
|
||||||
|
@ -313,28 +319,23 @@ const iframeClasses = computed(() => {
|
||||||
type="outline"
|
type="outline"
|
||||||
></VTabbar>
|
></VTabbar>
|
||||||
<div class="bg-white p-3">
|
<div class="bg-white p-3">
|
||||||
<div v-for="(tab, index) in settingTabs" :key="index">
|
|
||||||
<FormKit
|
<FormKit
|
||||||
v-if="
|
v-if="
|
||||||
tab.id === activeSettingTab &&
|
activeSettingTab && formSchema && currentConfigMapGroupData
|
||||||
configMapFormData[tab.id] &&
|
|
||||||
formSchema
|
|
||||||
"
|
"
|
||||||
:id="`preview-setting-${tab.id}`"
|
:id="activeSettingTab"
|
||||||
:key="tab.id"
|
:key="activeSettingTab"
|
||||||
v-model="configMapFormData[tab.id]"
|
:value="currentConfigMapGroupData || {}"
|
||||||
:name="tab.id"
|
:name="activeSettingTab"
|
||||||
:actions="false"
|
|
||||||
:preserve="true"
|
:preserve="true"
|
||||||
type="form"
|
type="form"
|
||||||
@submit="handleSaveConfigMap"
|
@submit="handleSaveConfigMap"
|
||||||
>
|
>
|
||||||
<FormKitSchema
|
<FormKitSchema
|
||||||
:schema="toRaw(formSchema)"
|
:schema="toRaw(formSchema)"
|
||||||
:data="configMapFormData[tab.id]"
|
:data="toRaw(currentConfigMapGroupData)"
|
||||||
/>
|
/>
|
||||||
</FormKit>
|
</FormKit>
|
||||||
</div>
|
|
||||||
<StickyBlock
|
<StickyBlock
|
||||||
v-permission="['system:themes:manage']"
|
v-permission="['system:themes:manage']"
|
||||||
class="-mx-4 -mb-4 -mr-3 rounded-b-base rounded-t-lg bg-white p-4 pt-5"
|
class="-mx-4 -mb-4 -mr-3 rounded-b-base rounded-t-lg bg-white p-4 pt-5"
|
||||||
|
@ -343,11 +344,7 @@ const iframeClasses = computed(() => {
|
||||||
<VButton
|
<VButton
|
||||||
:loading="saving"
|
:loading="saving"
|
||||||
type="secondary"
|
type="secondary"
|
||||||
@click="
|
@click="$formkit.submit(activeSettingTab)"
|
||||||
$formkit.submit(
|
|
||||||
`preview-setting-${activeSettingTab}` || ''
|
|
||||||
)
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
{{ $t("core.common.buttons.save") }}
|
{{ $t("core.common.buttons.save") }}
|
||||||
</VButton>
|
</VButton>
|
||||||
|
|
|
@ -3,6 +3,7 @@ import type { Theme } from "@halo-dev/api-client";
|
||||||
import { consoleApiClient } from "@halo-dev/api-client";
|
import { consoleApiClient } from "@halo-dev/api-client";
|
||||||
import { Dialog, Toast } from "@halo-dev/components";
|
import { Dialog, Toast } from "@halo-dev/components";
|
||||||
import { useFileDialog } from "@vueuse/core";
|
import { useFileDialog } from "@vueuse/core";
|
||||||
|
import { merge } from "lodash-es";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
import type { ComputedRef, Ref } from "vue";
|
import type { ComputedRef, Ref } from "vue";
|
||||||
import { computed, ref } from "vue";
|
import { computed, ref } from "vue";
|
||||||
|
@ -145,7 +146,7 @@ interface ExportData {
|
||||||
version: string;
|
version: string;
|
||||||
settingName: string;
|
settingName: string;
|
||||||
configMapName: string;
|
configMapName: string;
|
||||||
configs: { [key: string]: string };
|
configs: Record<string, unknown>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useThemeConfigFile(theme: Ref<Theme | undefined>) {
|
export function useThemeConfigFile(theme: Ref<Theme | undefined>) {
|
||||||
|
@ -157,22 +158,25 @@ export function useThemeConfigFile(theme: Ref<Theme | undefined>) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { data } = await consoleApiClient.theme.theme.fetchThemeConfig({
|
const { data } = await consoleApiClient.theme.theme.fetchThemeJsonConfig({
|
||||||
name: theme?.value?.metadata.name as string,
|
name: theme?.value?.metadata.name as string,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
console.error("Failed to fetch theme config");
|
console.error("Failed to fetch theme config");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const themeName = theme.value.metadata.name;
|
const themeName = theme.value.metadata.name;
|
||||||
const exportData = {
|
|
||||||
|
const exportData: ExportData = {
|
||||||
themeName: themeName,
|
themeName: themeName,
|
||||||
version: theme.value.spec.version,
|
version: theme.value.spec.version || "",
|
||||||
settingName: theme.value.spec.settingName,
|
settingName: theme.value.spec.settingName || "",
|
||||||
configMapName: theme.value.spec.configMapName,
|
configMapName: theme.value.spec.configMapName || "",
|
||||||
configs: data.data,
|
configs: data as Record<string, unknown>,
|
||||||
} as ExportData;
|
};
|
||||||
|
|
||||||
const exportStr = JSON.stringify(exportData, null, 2);
|
const exportStr = JSON.stringify(exportData, null, 2);
|
||||||
const blob = new Blob([exportStr], { type: "application/json" });
|
const blob = new Blob([exportStr], { type: "application/json" });
|
||||||
const temporaryExportUrl = URL.createObjectURL(blob);
|
const temporaryExportUrl = URL.createObjectURL(blob);
|
||||||
|
@ -203,7 +207,7 @@ export function useThemeConfigFile(theme: Ref<Theme | undefined>) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const configText = await files[0].text();
|
const configText = await files[0].text();
|
||||||
const configJson = JSON.parse(configText || "{}");
|
const configJson = JSON.parse(configText || "{}") as ExportData;
|
||||||
if (!configJson.configs) {
|
if (!configJson.configs) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -246,57 +250,27 @@ export function useThemeConfigFile(theme: Ref<Theme | undefined>) {
|
||||||
handleSaveConfigMap(configJson.configs);
|
handleSaveConfigMap(configJson.configs);
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleSaveConfigMap = async (importData: Record<string, string>) => {
|
const handleSaveConfigMap = async (importData: Record<string, unknown>) => {
|
||||||
if (!theme.value) {
|
if (!theme.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { data } = await consoleApiClient.theme.theme.fetchThemeConfig({
|
const { data: originalData } =
|
||||||
|
await consoleApiClient.theme.theme.fetchThemeJsonConfig({
|
||||||
name: theme.value.metadata.name as string,
|
name: theme.value.metadata.name as string,
|
||||||
});
|
});
|
||||||
if (!data || !data.data) {
|
|
||||||
|
if (!originalData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const combinedConfigData = combinedConfigMap(data.data, importData);
|
|
||||||
await consoleApiClient.theme.theme.updateThemeConfig({
|
await consoleApiClient.theme.theme.updateThemeJsonConfig({
|
||||||
name: theme.value.metadata.name,
|
name: theme.value.metadata.name,
|
||||||
configMap: {
|
body: merge(originalData, importData),
|
||||||
...data,
|
|
||||||
data: combinedConfigData,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Toast.success(t("core.common.toast.save_success"));
|
Toast.success(t("core.common.toast.save_success"));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* combined benchmark configuration and import configuration
|
|
||||||
*
|
|
||||||
* benchmark: { a: "{\"a\": 1}", b: "{\"b\": 2}" }
|
|
||||||
* expand: { a: "{\"c\": 3}", b: "{\"d\": 4}" }
|
|
||||||
* => { a: "{\"a\": 1, \"c\": 3}", b: "{\"b\": 2, \"d\": 4}" }
|
|
||||||
*
|
|
||||||
* benchmark: { a: "{\"a\": 1}", b: "{\"b\": 2}", d: "{\"d\": 4}"
|
|
||||||
* expand: { a: "{\"a\": 2}", b: "{\"b\": 3, \"d\": 4}", c: "{\"c\": 5}" }
|
|
||||||
* => { a: "{\"a\": 2}", b: "{\"b\": 3, \"d\": 4}", d: "{\"d\": 4}" }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
const combinedConfigMap = (
|
|
||||||
benchmarkConfigMap: { [key: string]: string },
|
|
||||||
importConfigMap: { [key: string]: string }
|
|
||||||
): { [key: string]: string } => {
|
|
||||||
const result = benchmarkConfigMap;
|
|
||||||
|
|
||||||
for (const key in result) {
|
|
||||||
const benchmarkValueJson = JSON.parse(benchmarkConfigMap[key] || "{}");
|
|
||||||
const expandValueJson = JSON.parse(importConfigMap[key] || "{}");
|
|
||||||
const combinedValue = {
|
|
||||||
...benchmarkValueJson,
|
|
||||||
...expandValueJson,
|
|
||||||
};
|
|
||||||
result[key] = JSON.stringify(combinedValue);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
handleExportThemeConfiguration,
|
handleExportThemeConfiguration,
|
||||||
openSelectImportFileDialog,
|
openSelectImportFileDialog,
|
||||||
|
|
|
@ -47,7 +47,6 @@ import {
|
||||||
ReverseProxyV1alpha1Api,
|
ReverseProxyV1alpha1Api,
|
||||||
RoleBindingV1alpha1Api,
|
RoleBindingV1alpha1Api,
|
||||||
RoleV1alpha1Api,
|
RoleV1alpha1Api,
|
||||||
SearchEngineV1alpha1Api,
|
|
||||||
SecretV1alpha1Api,
|
SecretV1alpha1Api,
|
||||||
SettingV1alpha1Api,
|
SettingV1alpha1Api,
|
||||||
SinglePageV1alpha1Api,
|
SinglePageV1alpha1Api,
|
||||||
|
@ -182,11 +181,6 @@ function createCoreApiClient(axiosInstance: AxiosInstance) {
|
||||||
baseURL,
|
baseURL,
|
||||||
axiosInstance
|
axiosInstance
|
||||||
),
|
),
|
||||||
searchEngine: new SearchEngineV1alpha1Api(
|
|
||||||
undefined,
|
|
||||||
baseURL,
|
|
||||||
axiosInstance
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// metrics.halo.run
|
// metrics.halo.run
|
||||||
|
|
Loading…
Reference in New Issue