mirror of https://github.com/halo-dev/halo-admin
refactor: use new apis to refactor themes management (#820)
#### What type of PR is this? /kind improvement #### What this PR does / why we need it: 使用新的 API 来管理主题,用于区分主题管理和配置相关的权限。适配:https://github.com/halo-dev/halo/pull/3135 #### Which issue(s) this PR fixes: Ref https://github.com/halo-dev/halo/issues/3069 #### Screenshots: #### Special notes for your reviewer: 重点测试: 1. Halo 需要切换到 https://github.com/halo-dev/halo/pull/3135 分支。 2. Console 需要 `pnpm install`。 1. 主题设置项,需要测试保存,安装新主题之后表单是否正常。 3. 创建一个角色,测试仅有管理/查看主题的角色,登录之后检查是否符合预期。 #### Does this PR introduce a user-facing change? ```release-note 重构 Console 端主题的设置表单逻辑。 ```pull/828/head^2
parent
a2935de6ef
commit
ab888119ef
|
@ -16,11 +16,14 @@ import { computed, markRaw, ref, watch, type Component } from "vue";
|
||||||
import Fuse from "fuse.js";
|
import Fuse from "fuse.js";
|
||||||
import { apiClient } from "@/utils/api-client";
|
import { apiClient } from "@/utils/api-client";
|
||||||
import { usePermission } from "@/utils/permission";
|
import { usePermission } from "@/utils/permission";
|
||||||
|
import { useThemeStore } from "@/stores/theme";
|
||||||
|
import { storeToRefs } from "pinia";
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
const { currentUserHasPermission } = usePermission();
|
const { currentUserHasPermission } = usePermission();
|
||||||
|
const { activatedTheme } = storeToRefs(useThemeStore());
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
@ -248,46 +251,29 @@ const handleBuildSearchIndex = () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// get theme settings
|
if (currentUserHasPermission(["system:themes:view"])) {
|
||||||
apiClient.extension.configMap
|
apiClient.theme
|
||||||
.getv1alpha1ConfigMap({
|
.fetchThemeSetting({ name: "-" })
|
||||||
name: "system",
|
.then(({ data: themeSettings }) => {
|
||||||
})
|
themeSettings.spec.forms.forEach((form) => {
|
||||||
.then(({ data: systemConfigMap }) => {
|
fuse.add({
|
||||||
if (systemConfigMap.data?.theme) {
|
title: [activatedTheme.value?.spec.displayName, form.label].join(
|
||||||
const themeConfig = JSON.parse(systemConfigMap.data.theme);
|
" / "
|
||||||
|
),
|
||||||
apiClient.extension.theme
|
icon: {
|
||||||
.getthemeHaloRunV1alpha1Theme({
|
component: markRaw(IconPalette),
|
||||||
name: themeConfig.active,
|
},
|
||||||
})
|
group: "主题设置",
|
||||||
.then(({ data: theme }) => {
|
route: {
|
||||||
if (theme && theme.spec.settingName) {
|
name: "ThemeSetting",
|
||||||
apiClient.extension.setting
|
params: {
|
||||||
.getv1alpha1Setting({
|
group: form.group,
|
||||||
name: theme.spec.settingName,
|
},
|
||||||
})
|
},
|
||||||
.then(({ data: themeSettings }) => {
|
});
|
||||||
themeSettings.spec.forms.forEach((form) => {
|
});
|
||||||
fuse.add({
|
|
||||||
title: `${theme.spec.displayName} / ${form.label}`,
|
|
||||||
icon: {
|
|
||||||
component: markRaw(IconPalette),
|
|
||||||
},
|
|
||||||
group: "主题设置",
|
|
||||||
route: {
|
|
||||||
name: "ThemeSetting",
|
|
||||||
params: {
|
|
||||||
group: form.group,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// core libs
|
// core libs
|
||||||
// types
|
// types
|
||||||
import type { Ref } from "vue";
|
import { computed, watch, type ComputedRef, type Ref } from "vue";
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { apiClient } from "../utils/api-client";
|
import { apiClient } from "../utils/api-client";
|
||||||
|
|
||||||
|
@ -179,3 +179,68 @@ export function useSettingForm(
|
||||||
handleReset,
|
handleReset,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface useSettingFormConvertReturn {
|
||||||
|
formSchema: ComputedRef<
|
||||||
|
(FormKitSchemaCondition | FormKitSchemaNode)[] | undefined
|
||||||
|
>;
|
||||||
|
configMapFormData: Ref<Record<string, Record<string, string>>>;
|
||||||
|
convertToSave: () => ConfigMap | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useSettingFormConvert(
|
||||||
|
setting: Ref<Setting | undefined>,
|
||||||
|
configMap: Ref<ConfigMap | undefined>,
|
||||||
|
group: Ref<string>
|
||||||
|
): useSettingFormConvertReturn {
|
||||||
|
const configMapFormData = ref<Record<string, Record<string, string>>>({});
|
||||||
|
|
||||||
|
const formSchema = computed(() => {
|
||||||
|
if (!setting.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { forms } = setting.value.spec;
|
||||||
|
return forms.find((item) => item.group === group?.value)?.formSchema as (
|
||||||
|
| FormKitSchemaCondition
|
||||||
|
| FormKitSchemaNode
|
||||||
|
)[];
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => configMap.value,
|
||||||
|
() => {
|
||||||
|
const { forms } = setting.value?.spec || {};
|
||||||
|
|
||||||
|
forms?.forEach((form) => {
|
||||||
|
configMapFormData.value[form.group] = JSON.parse(
|
||||||
|
configMap.value?.data?.[form.group] || "{}"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
function convertToSave() {
|
||||||
|
const configMapToUpdate = cloneDeep(configMap.value);
|
||||||
|
|
||||||
|
if (!configMapToUpdate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data: {
|
||||||
|
[key: string]: string;
|
||||||
|
} = {};
|
||||||
|
|
||||||
|
setting.value?.spec.forms.forEach((item: SettingForm) => {
|
||||||
|
data[item.group] = JSON.stringify(configMapFormData?.value?.[item.group]);
|
||||||
|
});
|
||||||
|
|
||||||
|
configMapToUpdate.data = data;
|
||||||
|
return configMapToUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
formSchema,
|
||||||
|
configMapFormData,
|
||||||
|
convertToSave,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -203,7 +203,11 @@ async function loadUserPermissions() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
enable ? (el.style.backgroundColor = "red") : el.remove();
|
if (enable) {
|
||||||
|
//TODO
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
el?.remove?.();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ const actions: Action[] = [
|
||||||
action: () => {
|
action: () => {
|
||||||
themePreviewVisible.value = true;
|
themePreviewVisible.value = true;
|
||||||
},
|
},
|
||||||
|
permissions: ["system:themes:view"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: markRaw(IconBookRead),
|
icon: markRaw(IconBookRead),
|
||||||
|
|
|
@ -1,45 +1,73 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
// core libs
|
// core libs
|
||||||
import { computed, inject, watch } from "vue";
|
import { inject, ref, watch } from "vue";
|
||||||
|
|
||||||
// components
|
// components
|
||||||
import { VButton } from "@halo-dev/components";
|
import { VButton } from "@halo-dev/components";
|
||||||
|
|
||||||
// types
|
// types
|
||||||
import type { Ref } from "vue";
|
import type { Ref } from "vue";
|
||||||
import type { Theme } from "@halo-dev/api-client";
|
import type { ConfigMap, Setting, Theme } from "@halo-dev/api-client";
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useSettingForm } from "@/composables/use-setting-form";
|
|
||||||
import { useRouteParams } from "@vueuse/router";
|
import { useRouteParams } from "@vueuse/router";
|
||||||
import type { FormKitSchemaCondition, FormKitSchemaNode } from "@formkit/core";
|
import { apiClient } from "@/utils/api-client";
|
||||||
|
import { useSettingFormConvert } from "@/composables/use-setting-form";
|
||||||
|
|
||||||
const group = useRouteParams<string>("group");
|
const group = useRouteParams<string>("group");
|
||||||
|
|
||||||
const selectedTheme = inject<Ref<Theme | undefined>>("selectedTheme");
|
const selectedTheme = inject<Ref<Theme | undefined>>("selectedTheme");
|
||||||
|
|
||||||
const settingName = computed(() => selectedTheme?.value?.spec.settingName);
|
const saving = ref(false);
|
||||||
const configMapName = computed(() => selectedTheme?.value?.spec.configMapName);
|
const setting = ref<Setting>();
|
||||||
|
const configMap = ref<ConfigMap>();
|
||||||
|
|
||||||
const {
|
const { configMapFormData, formSchema, convertToSave } = useSettingFormConvert(
|
||||||
setting,
|
setting,
|
||||||
configMapFormData,
|
configMap,
|
||||||
saving,
|
group
|
||||||
handleFetchConfigMap,
|
);
|
||||||
handleFetchSettings,
|
|
||||||
handleSaveConfigMap,
|
|
||||||
} = useSettingForm(settingName, configMapName);
|
|
||||||
|
|
||||||
const formSchema = computed(() => {
|
const handleFetchSettings = async () => {
|
||||||
if (!setting.value) {
|
if (!selectedTheme?.value) return;
|
||||||
|
|
||||||
|
const { data } = await apiClient.theme.fetchThemeSetting({
|
||||||
|
name: selectedTheme?.value?.metadata.name,
|
||||||
|
});
|
||||||
|
|
||||||
|
setting.value = data;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleFetchConfigMap = async () => {
|
||||||
|
if (!selectedTheme?.value) return;
|
||||||
|
|
||||||
|
const { data } = await apiClient.theme.fetchThemeConfig({
|
||||||
|
name: selectedTheme?.value?.metadata.name,
|
||||||
|
});
|
||||||
|
|
||||||
|
configMap.value = data;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSaveConfigMap = async () => {
|
||||||
|
saving.value = true;
|
||||||
|
|
||||||
|
const configMapToUpdate = convertToSave();
|
||||||
|
|
||||||
|
if (!configMapToUpdate || !selectedTheme?.value) {
|
||||||
|
saving.value = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { forms } = setting.value.spec;
|
|
||||||
return forms.find((item) => item.group === group?.value)?.formSchema as (
|
const { data: newConfigMap } = await apiClient.theme.updateThemeConfig({
|
||||||
| FormKitSchemaCondition
|
name: selectedTheme?.value?.metadata.name,
|
||||||
| FormKitSchemaNode
|
configMap: configMapToUpdate,
|
||||||
)[];
|
});
|
||||||
});
|
|
||||||
|
await handleFetchSettings();
|
||||||
|
configMap.value = newConfigMap;
|
||||||
|
|
||||||
|
saving.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
await handleFetchSettings();
|
await handleFetchSettings();
|
||||||
await handleFetchConfigMap();
|
await handleFetchConfigMap();
|
||||||
|
@ -57,7 +85,7 @@ watch(
|
||||||
<div class="bg-white p-4">
|
<div class="bg-white p-4">
|
||||||
<div>
|
<div>
|
||||||
<FormKit
|
<FormKit
|
||||||
v-if="group && formSchema && configMapFormData"
|
v-if="group && formSchema && configMapFormData?.[group]"
|
||||||
:id="group"
|
:id="group"
|
||||||
v-model="configMapFormData[group]"
|
v-model="configMapFormData[group]"
|
||||||
:name="group"
|
:name="group"
|
||||||
|
@ -72,7 +100,7 @@ watch(
|
||||||
/>
|
/>
|
||||||
</FormKit>
|
</FormKit>
|
||||||
</div>
|
</div>
|
||||||
<div v-permission="['system:configmaps:manage']" class="pt-5">
|
<div v-permission="['system:themes:manage']" class="pt-5">
|
||||||
<div class="flex justify-start">
|
<div class="flex justify-start">
|
||||||
<VButton
|
<VButton
|
||||||
:loading="saving"
|
:loading="saving"
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import ThemePreviewListItem from "./ThemePreviewListItem.vue";
|
import ThemePreviewListItem from "./ThemePreviewListItem.vue";
|
||||||
import { useSettingForm } from "@/composables/use-setting-form";
|
import { useSettingFormConvert } from "@/composables/use-setting-form";
|
||||||
import { useThemeStore } from "@/stores/theme";
|
import { useThemeStore } from "@/stores/theme";
|
||||||
import { apiClient } from "@/utils/api-client";
|
import { apiClient } from "@/utils/api-client";
|
||||||
import type { FormKitSchemaCondition, FormKitSchemaNode } from "@formkit/core";
|
import type {
|
||||||
import type { SettingForm, Theme } from "@halo-dev/api-client";
|
ConfigMap,
|
||||||
|
Setting,
|
||||||
|
SettingForm,
|
||||||
|
Theme,
|
||||||
|
} from "@halo-dev/api-client";
|
||||||
import {
|
import {
|
||||||
VModal,
|
VModal,
|
||||||
IconLink,
|
IconLink,
|
||||||
|
@ -111,21 +115,61 @@ const modalTitle = computed(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// theme settings
|
// theme settings
|
||||||
|
const setting = ref<Setting>();
|
||||||
|
const configMap = ref<ConfigMap>();
|
||||||
|
const saving = ref(false);
|
||||||
const settingTabs = ref<SettingTab[]>([] as SettingTab[]);
|
const settingTabs = ref<SettingTab[]>([] as SettingTab[]);
|
||||||
const activeSettingTab = ref("");
|
const activeSettingTab = ref("");
|
||||||
const settingsVisible = ref(false);
|
const settingsVisible = ref(false);
|
||||||
|
|
||||||
const settingName = computed(() => selectedTheme.value?.spec.settingName);
|
const { formSchema, configMapFormData, convertToSave } = useSettingFormConvert(
|
||||||
const configMapName = computed(() => selectedTheme.value?.spec.configMapName);
|
|
||||||
|
|
||||||
const {
|
|
||||||
setting,
|
setting,
|
||||||
configMapFormData,
|
configMap,
|
||||||
saving,
|
activeSettingTab
|
||||||
handleFetchConfigMap,
|
);
|
||||||
handleFetchSettings,
|
|
||||||
handleSaveConfigMap,
|
const handleFetchSettings = async () => {
|
||||||
} = useSettingForm(settingName, configMapName);
|
if (!selectedTheme?.value) return;
|
||||||
|
|
||||||
|
const { data } = await apiClient.theme.fetchThemeSetting({
|
||||||
|
name: selectedTheme?.value?.metadata.name,
|
||||||
|
});
|
||||||
|
|
||||||
|
setting.value = data;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleFetchConfigMap = async () => {
|
||||||
|
if (!selectedTheme?.value) return;
|
||||||
|
|
||||||
|
const { data } = await apiClient.theme.fetchThemeConfig({
|
||||||
|
name: selectedTheme?.value?.metadata.name,
|
||||||
|
});
|
||||||
|
|
||||||
|
configMap.value = data;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSaveConfigMap = async () => {
|
||||||
|
saving.value = true;
|
||||||
|
|
||||||
|
const configMapToUpdate = convertToSave();
|
||||||
|
|
||||||
|
if (!configMapToUpdate || !selectedTheme?.value) {
|
||||||
|
saving.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data: newConfigMap } = await apiClient.theme.updateThemeConfig({
|
||||||
|
name: selectedTheme?.value?.metadata.name,
|
||||||
|
configMap: configMapToUpdate,
|
||||||
|
});
|
||||||
|
|
||||||
|
await handleFetchSettings();
|
||||||
|
configMap.value = newConfigMap;
|
||||||
|
|
||||||
|
saving.value = false;
|
||||||
|
|
||||||
|
handleRefresh();
|
||||||
|
};
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => selectedTheme.value,
|
() => selectedTheme.value,
|
||||||
|
@ -157,20 +201,6 @@ const handleOpenSettings = (theme?: Theme) => {
|
||||||
settingsVisible.value = !settingsVisible.value;
|
settingsVisible.value = !settingsVisible.value;
|
||||||
};
|
};
|
||||||
|
|
||||||
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 handleSaveThemeConfigMap = async () => {
|
|
||||||
await handleSaveConfigMap();
|
|
||||||
handleRefresh();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRefresh = () => {
|
const handleRefresh = () => {
|
||||||
previewFrame.value?.contentWindow?.location.reload();
|
previewFrame.value?.contentWindow?.location.reload();
|
||||||
};
|
};
|
||||||
|
@ -288,14 +318,14 @@ const iframeClasses = computed(() => {
|
||||||
configMapFormData &&
|
configMapFormData &&
|
||||||
formSchema
|
formSchema
|
||||||
"
|
"
|
||||||
:id="tab.id"
|
:id="`preview-setting-${tab.id}`"
|
||||||
:key="tab.id"
|
:key="tab.id"
|
||||||
v-model="configMapFormData[tab.id]"
|
v-model="configMapFormData[tab.id]"
|
||||||
:name="tab.id"
|
:name="tab.id"
|
||||||
:actions="false"
|
:actions="false"
|
||||||
:preserve="true"
|
:preserve="true"
|
||||||
type="form"
|
type="form"
|
||||||
@submit="handleSaveThemeConfigMap"
|
@submit="handleSaveConfigMap"
|
||||||
>
|
>
|
||||||
<FormKitSchema
|
<FormKitSchema
|
||||||
:schema="formSchema"
|
:schema="formSchema"
|
||||||
|
@ -303,12 +333,16 @@ const iframeClasses = computed(() => {
|
||||||
/>
|
/>
|
||||||
</FormKit>
|
</FormKit>
|
||||||
</div>
|
</div>
|
||||||
<div v-permission="['system:configmaps:manage']" class="pt-5">
|
<div v-permission="['system:themes:manage']" class="pt-5">
|
||||||
<div class="flex justify-start">
|
<div class="flex justify-start">
|
||||||
<VButton
|
<VButton
|
||||||
:loading="saving"
|
:loading="saving"
|
||||||
type="secondary"
|
type="secondary"
|
||||||
@click="$formkit.submit(activeSettingTab || '')"
|
@click="
|
||||||
|
$formkit.submit(
|
||||||
|
`preview-setting-${activeSettingTab}` || ''
|
||||||
|
)
|
||||||
|
"
|
||||||
>
|
>
|
||||||
保存
|
保存
|
||||||
</VButton>
|
</VButton>
|
||||||
|
|
|
@ -45,23 +45,11 @@ export function useThemeLifeCycle(
|
||||||
description: theme.value?.spec.displayName,
|
description: theme.value?.spec.displayName,
|
||||||
onConfirm: async () => {
|
onConfirm: async () => {
|
||||||
try {
|
try {
|
||||||
const { data: systemConfigMap } =
|
if (!theme.value) return;
|
||||||
await apiClient.extension.configMap.getv1alpha1ConfigMap({
|
|
||||||
name: "system",
|
|
||||||
});
|
|
||||||
|
|
||||||
if (systemConfigMap.data) {
|
await apiClient.theme.activateTheme({
|
||||||
const themeConfigToUpdate = JSON.parse(
|
name: theme.value?.metadata.name,
|
||||||
systemConfigMap.data?.theme || "{}"
|
});
|
||||||
);
|
|
||||||
themeConfigToUpdate.active = theme.value?.metadata.name;
|
|
||||||
systemConfigMap.data["theme"] = JSON.stringify(themeConfigToUpdate);
|
|
||||||
|
|
||||||
await apiClient.extension.configMap.updatev1alpha1ConfigMap({
|
|
||||||
name: "system",
|
|
||||||
configMap: systemConfigMap,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Toast.success("启用成功");
|
Toast.success("启用成功");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
// core libs
|
// core libs
|
||||||
import { nextTick, onMounted, type Ref } from "vue";
|
import { nextTick, onMounted, type Ref } from "vue";
|
||||||
import { computed, provide, ref, watch } from "vue";
|
import { provide, ref, watch } from "vue";
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
|
|
||||||
// libs
|
// libs
|
||||||
|
@ -11,7 +11,6 @@ import cloneDeep from "lodash.clonedeep";
|
||||||
import { useThemeLifeCycle } from "../composables/use-theme";
|
import { useThemeLifeCycle } from "../composables/use-theme";
|
||||||
// types
|
// types
|
||||||
import BasicLayout from "@/layouts/BasicLayout.vue";
|
import BasicLayout from "@/layouts/BasicLayout.vue";
|
||||||
import { useSettingForm } from "@/composables/use-setting-form";
|
|
||||||
|
|
||||||
// components
|
// components
|
||||||
import {
|
import {
|
||||||
|
@ -28,10 +27,11 @@ import {
|
||||||
} from "@halo-dev/components";
|
} from "@halo-dev/components";
|
||||||
import ThemeListModal from "../components/ThemeListModal.vue";
|
import ThemeListModal from "../components/ThemeListModal.vue";
|
||||||
import ThemePreviewModal from "../components/preview/ThemePreviewModal.vue";
|
import ThemePreviewModal from "../components/preview/ThemePreviewModal.vue";
|
||||||
import type { SettingForm, Theme } from "@halo-dev/api-client";
|
import type { Setting, SettingForm, Theme } from "@halo-dev/api-client";
|
||||||
import { usePermission } from "@/utils/permission";
|
import { usePermission } from "@/utils/permission";
|
||||||
import { useThemeStore } from "@/stores/theme";
|
import { useThemeStore } from "@/stores/theme";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
|
import { apiClient } from "@/utils/api-client";
|
||||||
|
|
||||||
const { currentUserHasPermission } = usePermission();
|
const { currentUserHasPermission } = usePermission();
|
||||||
|
|
||||||
|
@ -63,19 +63,23 @@ const activeTab = ref("");
|
||||||
const { loading, isActivated, handleActiveTheme } =
|
const { loading, isActivated, handleActiveTheme } =
|
||||||
useThemeLifeCycle(selectedTheme);
|
useThemeLifeCycle(selectedTheme);
|
||||||
|
|
||||||
const settingName = computed(() => selectedTheme.value?.spec.settingName);
|
|
||||||
const configMapName = computed(() => selectedTheme.value?.spec.configMapName);
|
|
||||||
|
|
||||||
const { setting, handleFetchSettings } = useSettingForm(
|
|
||||||
settingName,
|
|
||||||
configMapName
|
|
||||||
);
|
|
||||||
|
|
||||||
provide<Ref<Theme | undefined>>("selectedTheme", selectedTheme);
|
provide<Ref<Theme | undefined>>("selectedTheme", selectedTheme);
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
const setting = ref<Setting>();
|
||||||
|
|
||||||
|
const handleFetchSettings = async () => {
|
||||||
|
if (!selectedTheme.value) return;
|
||||||
|
|
||||||
|
const { data } = await apiClient.theme.fetchThemeSetting({
|
||||||
|
name: selectedTheme.value?.metadata.name,
|
||||||
|
});
|
||||||
|
|
||||||
|
setting.value = data;
|
||||||
|
};
|
||||||
|
|
||||||
const handleTabChange = (id: string) => {
|
const handleTabChange = (id: string) => {
|
||||||
const tab = tabs.value.find((item) => item.id === id);
|
const tab = tabs.value.find((item) => item.id === id);
|
||||||
if (tab) {
|
if (tab) {
|
||||||
|
@ -91,7 +95,7 @@ watch(
|
||||||
// reset tabs
|
// reset tabs
|
||||||
tabs.value = cloneDeep(initialTabs);
|
tabs.value = cloneDeep(initialTabs);
|
||||||
|
|
||||||
if (!currentUserHasPermission(["system:settings:view"])) {
|
if (!currentUserHasPermission(["system:themes:view"])) {
|
||||||
handleTriggerTabChange();
|
handleTriggerTabChange();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ export default definePlugin({
|
||||||
component: ThemeSetting,
|
component: ThemeSetting,
|
||||||
meta: {
|
meta: {
|
||||||
title: "主题设置",
|
title: "主题设置",
|
||||||
permissions: ["system:settings:view"],
|
permissions: ["system:themes:view"],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -2,36 +2,24 @@ import { apiClient } from "@/utils/api-client";
|
||||||
import type { Theme } from "@halo-dev/api-client";
|
import type { Theme } from "@halo-dev/api-client";
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
|
import { usePermission } from "@/utils/permission";
|
||||||
|
|
||||||
export const useThemeStore = defineStore("theme", () => {
|
export const useThemeStore = defineStore("theme", () => {
|
||||||
const activatedTheme = ref<Theme>();
|
const activatedTheme = ref<Theme>();
|
||||||
|
|
||||||
|
const { currentUserHasPermission } = usePermission();
|
||||||
|
|
||||||
async function fetchActivatedTheme() {
|
async function fetchActivatedTheme() {
|
||||||
|
if (!currentUserHasPermission(["system:themes:view"])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { data } = await apiClient.extension.configMap.getv1alpha1ConfigMap(
|
const { data } = await apiClient.theme.fetchActivatedTheme({
|
||||||
{
|
mute: true,
|
||||||
name: "system",
|
});
|
||||||
},
|
|
||||||
{ mute: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!data.data?.theme) {
|
activatedTheme.value = data;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const themeConfig = JSON.parse(data.data.theme);
|
|
||||||
|
|
||||||
const { data: themeData } =
|
|
||||||
await apiClient.extension.theme.getthemeHaloRunV1alpha1Theme(
|
|
||||||
{
|
|
||||||
name: themeConfig.active,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
mute: true,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
activatedTheme.value = themeData;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Failed to fetch active theme", e);
|
console.error("Failed to fetch active theme", e);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue