mirror of https://github.com/halo-dev/halo
feat: add description component (#3792)
#### What type of PR is this? /kind feature /area console /milestone 2.5.0 #### What this PR does / why we need it: 为 Console 端添加 Description 组件。 #### Which issue(s) this PR fixes: Fixes #3790 #### Special notes for your reviewer: 测试方式: 1. 检查主题管理、插件详情、认证方式详情页面的样式是否异常即可。 #### Does this PR introduce a user-facing change? ```release-note 为 Console 端添加 Description 组件。 ```pull/3822/head
parent
676df239ea
commit
eec1d0758e
|
@ -19,3 +19,4 @@ export * from "./components/toast";
|
|||
export * from "./components/loading";
|
||||
export * from "./components/dropdown";
|
||||
export * from "./components/tooltip";
|
||||
export * from "./components/description";
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<script lang="ts" setup></script>
|
||||
|
||||
<template>
|
||||
<dl class="description-wrapper">
|
||||
<slot />
|
||||
</dl>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.description-wrapper {
|
||||
@apply divide-y divide-gray-100;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,42 @@
|
|||
<script lang="ts" setup>
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
label: string;
|
||||
content?: string;
|
||||
verticalCenter?: boolean;
|
||||
}>(),
|
||||
{
|
||||
content: undefined,
|
||||
verticalCenter: false,
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="description-item-wrapper"
|
||||
:class="{ 'items-center': verticalCenter }"
|
||||
>
|
||||
<dt class="description-item__label">{{ label }}</dt>
|
||||
<dd class="description-item__content">
|
||||
<slot v-if="$slots.default" />
|
||||
<template v-else>
|
||||
{{ content }}
|
||||
</template>
|
||||
</dd>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.description-item-wrapper {
|
||||
@apply bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6;
|
||||
|
||||
.description-item__label {
|
||||
@apply text-sm font-medium text-gray-900;
|
||||
}
|
||||
|
||||
.description-item__content {
|
||||
@apply mt-1 text-sm text-gray-900 sm:col-span-6 md:col-span-5 lg:col-span-3 sm:mt-0;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,2 @@
|
|||
export { default as VDescription } from "./Description.vue";
|
||||
export { default as VDescriptionItem } from "./DescriptionItem.vue";
|
|
@ -1,5 +1,11 @@
|
|||
<script lang="ts" setup>
|
||||
import { VButton, VModal, VSpace } from "@halo-dev/components";
|
||||
import {
|
||||
VButton,
|
||||
VDescription,
|
||||
VDescriptionItem,
|
||||
VModal,
|
||||
VSpace,
|
||||
} from "@halo-dev/components";
|
||||
import LazyImage from "@/components/image/LazyImage.vue";
|
||||
import type { Attachment } from "@halo-dev/api-client";
|
||||
import prettyBytes from "pretty-bytes";
|
||||
|
@ -79,6 +85,7 @@ const onVisibleChange = (visible: boolean) => {
|
|||
:mount-to-body="mountToBody"
|
||||
:layer-closable="true"
|
||||
height="calc(100vh - 20px)"
|
||||
:body-class="['!p-0']"
|
||||
@update:visible="onVisibleChange"
|
||||
>
|
||||
<template #actions>
|
||||
|
@ -87,7 +94,7 @@ const onVisibleChange = (visible: boolean) => {
|
|||
<div class="overflow-hidden bg-white">
|
||||
<div
|
||||
v-if="onlyPreview && isImage(attachment?.spec.mediaType)"
|
||||
class="flex justify-center"
|
||||
class="flex justify-center p-4"
|
||||
>
|
||||
<img
|
||||
v-tooltip.bottom="
|
||||
|
@ -99,14 +106,11 @@ const onVisibleChange = (visible: boolean) => {
|
|||
@click="onlyPreview = !onlyPreview"
|
||||
/>
|
||||
</div>
|
||||
<dl v-else>
|
||||
<div
|
||||
class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.attachment.detail_modal.fields.preview") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
<div v-else>
|
||||
<VDescription>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.attachment.detail_modal.fields.preview')"
|
||||
>
|
||||
<div
|
||||
v-if="isImage(attachment?.spec.mediaType)"
|
||||
@click="onlyPreview = !onlyPreview"
|
||||
|
@ -149,80 +153,47 @@ const onVisibleChange = (visible: boolean) => {
|
|||
<span v-else>
|
||||
{{ $t("core.attachment.detail_modal.preview.not_support") }}
|
||||
</span>
|
||||
</dd>
|
||||
</div>
|
||||
<div class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.attachment.detail_modal.fields.storage_policy") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
{{ policy?.spec.displayName }}
|
||||
</dd>
|
||||
</div>
|
||||
<div class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.attachment.detail_modal.fields.group") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
{{
|
||||
</VDescriptionItem>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.attachment.detail_modal.fields.storage_policy')"
|
||||
:content="policy?.spec.displayName"
|
||||
></VDescriptionItem>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.attachment.detail_modal.fields.group')"
|
||||
:content="
|
||||
getGroupName(attachment?.spec.groupName) ||
|
||||
$t("core.attachment.common.text.ungrouped")
|
||||
}}
|
||||
</dd>
|
||||
</div>
|
||||
<div class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.attachment.detail_modal.fields.display_name") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
{{ attachment?.spec.displayName }}
|
||||
</dd>
|
||||
</div>
|
||||
<div class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.attachment.detail_modal.fields.media_type") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
{{ attachment?.spec.mediaType }}
|
||||
</dd>
|
||||
</div>
|
||||
<div class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.attachment.detail_modal.fields.size") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
{{ prettyBytes(attachment?.spec.size || 0) }}
|
||||
</dd>
|
||||
</div>
|
||||
<div class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.attachment.detail_modal.fields.owner") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
{{ attachment?.spec.ownerName }}
|
||||
</dd>
|
||||
</div>
|
||||
<div class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.attachment.detail_modal.fields.creation_time") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
{{ formatDatetime(attachment?.metadata.creationTimestamp) }}
|
||||
</dd>
|
||||
</div>
|
||||
<div class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.attachment.detail_modal.fields.permalink") }}
|
||||
</dt>
|
||||
<dd
|
||||
class="mt-1 text-sm text-gray-900 hover:text-blue-600 sm:col-span-2 sm:mt-0"
|
||||
$t('core.attachment.common.text.ungrouped')
|
||||
"
|
||||
/>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.attachment.detail_modal.fields.display_name')"
|
||||
:content="attachment?.spec.displayName"
|
||||
/>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.attachment.detail_modal.fields.media_type')"
|
||||
:content="attachment?.spec.mediaType"
|
||||
/>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.attachment.detail_modal.fields.size')"
|
||||
:content="prettyBytes(attachment?.spec.size || 0)"
|
||||
/>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.attachment.detail_modal.fields.owner')"
|
||||
:content="attachment?.spec.ownerName"
|
||||
/>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.attachment.detail_modal.fields.creation_time')"
|
||||
:content="formatDatetime(attachment?.metadata.creationTimestamp)"
|
||||
/>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.attachment.detail_modal.fields.permalink')"
|
||||
>
|
||||
<a target="_blank" :href="attachment?.status?.permalink">
|
||||
{{ attachment?.status?.permalink }}
|
||||
</a>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</VDescriptionItem>
|
||||
</VDescription>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<VSpace>
|
||||
|
|
|
@ -17,6 +17,8 @@ import {
|
|||
VDropdown,
|
||||
VDropdownItem,
|
||||
VDropdownDivider,
|
||||
VDescription,
|
||||
VDescriptionItem,
|
||||
} from "@halo-dev/components";
|
||||
import ThemeUploadModal from "./components/ThemeUploadModal.vue";
|
||||
|
||||
|
@ -126,141 +128,46 @@ const onUpgradeModalClose = () => {
|
|||
</div>
|
||||
</div>
|
||||
<div class="border-t border-gray-200">
|
||||
<dl class="divide-y divide-gray-100">
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">ID</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-3 sm:mt-0">
|
||||
{{ selectedTheme?.metadata.name }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.theme.detail.fields.author") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-3 sm:mt-0">
|
||||
{{ selectedTheme?.spec.author.name }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.theme.detail.fields.website") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-3 sm:mt-0">
|
||||
<a
|
||||
:href="selectedTheme?.spec.website"
|
||||
class="hover:text-gray-600"
|
||||
target="_blank"
|
||||
>
|
||||
{{ selectedTheme?.spec.website }}
|
||||
</a>
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.theme.detail.fields.repo") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-3 sm:mt-0">
|
||||
<a
|
||||
:href="selectedTheme?.spec.repo"
|
||||
class="hover:text-gray-600"
|
||||
target="_blank"
|
||||
>
|
||||
{{ selectedTheme?.spec.repo }}
|
||||
</a>
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.theme.detail.fields.version") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-3 sm:mt-0">
|
||||
{{ selectedTheme?.spec.version }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.theme.detail.fields.requires") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-3 sm:mt-0">
|
||||
{{ selectedTheme?.spec.requires }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.theme.detail.fields.storage_location") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-3 sm:mt-0">
|
||||
{{ selectedTheme?.status?.location }}
|
||||
</dd>
|
||||
</div>
|
||||
<!-- TODO: add display required plugins support -->
|
||||
<div
|
||||
v-if="false"
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.theme.detail.fields.plugin_requires") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm sm:col-span-3 sm:mt-0">
|
||||
<VAlert
|
||||
description="当前有 1 个插件还未安装"
|
||||
title="提示"
|
||||
></VAlert>
|
||||
<ul class="mt-2 space-y-2">
|
||||
<li>
|
||||
<div
|
||||
class="inline-flex w-96 cursor-pointer flex-col gap-y-3 rounded border p-5 hover:border-primary"
|
||||
>
|
||||
<RouterLink
|
||||
:to="{
|
||||
name: 'PluginDetail',
|
||||
params: { name: 'PluginLinks' },
|
||||
}"
|
||||
class="font-medium text-gray-900 hover:text-blue-400"
|
||||
>
|
||||
run.halo.plugins.links
|
||||
</RouterLink>
|
||||
<div class="text-xs">
|
||||
<VSpace>
|
||||
<VTag>{{ $t("core.common.status.installed") }}</VTag>
|
||||
</VSpace>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div
|
||||
class="inline-flex w-96 cursor-pointer flex-col gap-y-3 rounded border p-5 hover:border-primary"
|
||||
>
|
||||
<span class="font-medium hover:text-blue-400">
|
||||
run.halo.plugins.photos
|
||||
</span>
|
||||
<div class="text-xs">
|
||||
<VSpace>
|
||||
<VTag>
|
||||
{{ $t("core.common.status.not_installed") }}
|
||||
</VTag>
|
||||
</VSpace>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<VDescription>
|
||||
<VDescriptionItem
|
||||
label="ID"
|
||||
:content="selectedTheme?.metadata.name"
|
||||
/>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.theme.detail.fields.author')"
|
||||
:content="selectedTheme?.spec.author.name"
|
||||
/>
|
||||
<VDescriptionItem :label="$t('core.theme.detail.fields.website')">
|
||||
<a
|
||||
:href="selectedTheme?.spec.website"
|
||||
class="hover:text-gray-600"
|
||||
target="_blank"
|
||||
>
|
||||
{{ selectedTheme?.spec.website }}
|
||||
</a>
|
||||
</VDescriptionItem>
|
||||
<VDescriptionItem :label="$t('core.theme.detail.fields.repo')">
|
||||
<a
|
||||
:href="selectedTheme?.spec.repo"
|
||||
class="hover:text-gray-600"
|
||||
target="_blank"
|
||||
>
|
||||
{{ selectedTheme?.spec.repo }}
|
||||
</a>
|
||||
</VDescriptionItem>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.theme.detail.fields.version')"
|
||||
:content="selectedTheme?.spec.version"
|
||||
/>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.theme.detail.fields.requires')"
|
||||
:content="selectedTheme?.spec.requires"
|
||||
/>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.theme.detail.fields.storage_location')"
|
||||
:content="selectedTheme?.status?.location"
|
||||
/>
|
||||
</VDescription>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
|
|
|
@ -7,6 +7,8 @@ import {
|
|||
VCard,
|
||||
VButton,
|
||||
Toast,
|
||||
VDescription,
|
||||
VDescriptionItem,
|
||||
} from "@halo-dev/components";
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
import type { Info, GlobalInfo, Startup } from "./types";
|
||||
|
@ -159,64 +161,39 @@ const handleDownloadLogfile = () => {
|
|||
</div>
|
||||
</div>
|
||||
<div class="border-t border-gray-200">
|
||||
<dl class="divide-y divide-gray-100">
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.actuator.fields.external_url") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
<span v-if="globalInfo?.externalUrl">
|
||||
{{ globalInfo?.externalUrl }}
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ $t("core.actuator.fields_values.external_url.not_setup") }}
|
||||
</span>
|
||||
<VAlert
|
||||
v-if="!isExternalUrlValid"
|
||||
class="mt-3"
|
||||
type="warning"
|
||||
:title="$t('core.common.text.warning')"
|
||||
:closable="false"
|
||||
>
|
||||
<template #description>
|
||||
{{ $t("core.actuator.alert.external_url_invalid") }}
|
||||
</template>
|
||||
</VAlert>
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.actuator.fields.start_time") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
{{ formatDatetime(startup?.timeline.startTime) }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.actuator.fields.timezone") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
{{ globalInfo?.timeZone }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.actuator.fields.locale") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
{{ globalInfo?.locale }}
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<VDescription>
|
||||
<VDescriptionItem :label="$t('core.actuator.fields.external_url')">
|
||||
<span v-if="globalInfo?.externalUrl">
|
||||
{{ globalInfo?.externalUrl }}
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ $t("core.actuator.fields_values.external_url.not_setup") }}
|
||||
</span>
|
||||
<VAlert
|
||||
v-if="!isExternalUrlValid"
|
||||
class="mt-3"
|
||||
type="warning"
|
||||
:title="$t('core.common.text.warning')"
|
||||
:closable="false"
|
||||
>
|
||||
<template #description>
|
||||
{{ $t("core.actuator.alert.external_url_invalid") }}
|
||||
</template>
|
||||
</VAlert>
|
||||
</VDescriptionItem>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.actuator.fields.start_time')"
|
||||
:content="formatDatetime(startup?.timeline.startTime)"
|
||||
/>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.actuator.fields.timezone')"
|
||||
:content="globalInfo?.timeZone"
|
||||
/>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.actuator.fields.locale')"
|
||||
:content="globalInfo?.locale"
|
||||
/>
|
||||
</VDescription>
|
||||
</div>
|
||||
</div>
|
||||
</VCard>
|
||||
|
@ -232,91 +209,55 @@ const handleDownloadLogfile = () => {
|
|||
</div>
|
||||
</div>
|
||||
<div class="border-t border-gray-200">
|
||||
<dl class="divide-y divide-gray-100">
|
||||
<div
|
||||
<VDescription>
|
||||
<VDescriptionItem
|
||||
v-if="info.build"
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
:label="$t('core.actuator.fields.version')"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.actuator.fields.version") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
<a
|
||||
:href="`https://github.com/halo-dev/halo/releases/tag/v${info.build.version}`"
|
||||
class="hover:text-gray-600"
|
||||
target="_blank"
|
||||
>
|
||||
{{ info.build.version }}
|
||||
</a>
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
<a
|
||||
:href="`https://github.com/halo-dev/halo/releases/tag/v${info.build.version}`"
|
||||
class="hover:text-gray-600"
|
||||
target="_blank"
|
||||
>
|
||||
{{ info.build.version }}
|
||||
</a>
|
||||
</VDescriptionItem>
|
||||
<VDescriptionItem
|
||||
v-if="info.build"
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
:label="$t('core.actuator.fields.build_time')"
|
||||
:content="formatDatetime(info.build.time)"
|
||||
/>
|
||||
<VDescriptionItem v-if="info.git" label="Git Commit">
|
||||
<a
|
||||
:href="`https://github.com/halo-dev/halo/commit/${info.git.commit.id}`"
|
||||
class="hover:text-gray-600"
|
||||
target="_blank"
|
||||
>
|
||||
{{ info.git.commit.id }}
|
||||
</a>
|
||||
</VDescriptionItem>
|
||||
<VDescriptionItem
|
||||
label="Java"
|
||||
:content="
|
||||
[info.java.runtime.name, info.java.runtime.version].join(' / ')
|
||||
"
|
||||
/>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.actuator.fields.database')"
|
||||
:content="[info.database.name, info.database.version].join(' / ')"
|
||||
/>
|
||||
<VDescriptionItem :label="$t('core.actuator.fields.os')">
|
||||
{{ info.os.name }} {{ info.os.version }} / {{ info.os.arch }}
|
||||
</VDescriptionItem>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.actuator.fields.log')"
|
||||
vertical-center
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.actuator.fields.build_time") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
{{ formatDatetime(info.build.time) }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
v-if="info.git"
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">Git Commit</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
<a
|
||||
:href="`https://github.com/halo-dev/halo/commit/${info.git.commit.id}`"
|
||||
class="hover:text-gray-600"
|
||||
target="_blank"
|
||||
>
|
||||
{{ info.git.commit.id }}
|
||||
</a>
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">Java</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
{{ info.java.runtime.name }} / {{ info.java.runtime.version }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.actuator.fields.database") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
{{ [info.database.name, info.database.version].join(" / ") }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.actuator.fields.os") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
{{ info.os.name }} {{ info.os.version }} / {{ info.os.arch }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="items-center bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.actuator.fields.log") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
<VButton size="sm" @click="handleDownloadLogfile()">
|
||||
{{ $t("core.common.buttons.download") }}
|
||||
</VButton>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<VButton size="sm" @click="handleDownloadLogfile()">
|
||||
{{ $t("core.common.buttons.download") }}
|
||||
</VButton>
|
||||
</VDescriptionItem>
|
||||
</VDescription>
|
||||
</div>
|
||||
</div>
|
||||
</VCard>
|
||||
|
|
|
@ -9,6 +9,8 @@ import {
|
|||
VAvatar,
|
||||
VButton,
|
||||
VCard,
|
||||
VDescription,
|
||||
VDescriptionItem,
|
||||
VPageHeader,
|
||||
VTabbar,
|
||||
} from "@halo-dev/components";
|
||||
|
@ -167,82 +169,56 @@ const handleSaveConfigMap = async () => {
|
|||
</template>
|
||||
<div class="bg-white">
|
||||
<div v-if="activeTab === 'detail'">
|
||||
<dl class="divide-y divide-gray-100">
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
<VDescription>
|
||||
<VDescriptionItem
|
||||
:label="
|
||||
$t('core.identity_authentication.detail.fields.display_name')
|
||||
"
|
||||
:content="authProvider?.spec.displayName"
|
||||
/>
|
||||
<VDescriptionItem
|
||||
:label="
|
||||
$t('core.identity_authentication.detail.fields.description')
|
||||
"
|
||||
:content="authProvider?.spec.description"
|
||||
/>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.identity_authentication.detail.fields.website')"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{
|
||||
$t("core.identity_authentication.detail.fields.display_name")
|
||||
}}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-3 sm:mt-0">
|
||||
{{ authProvider?.spec.displayName }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
<a
|
||||
v-if="authProvider?.spec.website"
|
||||
:href="authProvider?.spec.website"
|
||||
target="_blank"
|
||||
>
|
||||
{{ authProvider.spec.website }}
|
||||
</a>
|
||||
<span v-else>
|
||||
{{ $t("core.common.text.none") }}
|
||||
</span>
|
||||
</VDescriptionItem>
|
||||
<VDescriptionItem
|
||||
:label="
|
||||
$t('core.identity_authentication.detail.fields.help_page')
|
||||
"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{
|
||||
$t("core.identity_authentication.detail.fields.description")
|
||||
}}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-3 sm:mt-0">
|
||||
{{ authProvider?.spec.description }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.identity_authentication.detail.fields.website") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-3 sm:mt-0">
|
||||
<a
|
||||
v-if="authProvider?.spec.website"
|
||||
:href="authProvider?.spec.website"
|
||||
target="_blank"
|
||||
>
|
||||
{{ authProvider.spec.website }}
|
||||
</a>
|
||||
<span v-else>
|
||||
{{ $t("core.common.text.none") }}
|
||||
</span>
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.identity_authentication.detail.fields.help_page") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-3 sm:mt-0">
|
||||
<a
|
||||
v-if="authProvider?.spec.helpPage"
|
||||
:href="authProvider?.spec.helpPage"
|
||||
target="_blank"
|
||||
>
|
||||
{{ authProvider.spec.helpPage }}
|
||||
</a>
|
||||
<span v-else>{{ $t("core.common.text.none") }}</span>
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{
|
||||
$t(
|
||||
"core.identity_authentication.detail.fields.authentication_url"
|
||||
)
|
||||
}}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-3 sm:mt-0">
|
||||
{{ authProvider?.spec.authenticationUrl }}
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<a
|
||||
v-if="authProvider?.spec.helpPage"
|
||||
:href="authProvider?.spec.helpPage"
|
||||
target="_blank"
|
||||
>
|
||||
{{ authProvider.spec.helpPage }}
|
||||
</a>
|
||||
<span v-else>{{ $t("core.common.text.none") }}</span>
|
||||
</VDescriptionItem>
|
||||
<VDescriptionItem
|
||||
:label="
|
||||
$t(
|
||||
'core.identity_authentication.detail.fields.authentication_url'
|
||||
)
|
||||
"
|
||||
:content="authProvider?.spec.authenticationUrl"
|
||||
/>
|
||||
</VDescription>
|
||||
</div>
|
||||
<div v-if="activeTab === 'setting'" class="bg-white p-4">
|
||||
<div>
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<script lang="ts" setup>
|
||||
import { VSwitch, VTag } from "@halo-dev/components";
|
||||
import {
|
||||
VDescription,
|
||||
VDescriptionItem,
|
||||
VSwitch,
|
||||
VTag,
|
||||
} from "@halo-dev/components";
|
||||
import type { Ref } from "vue";
|
||||
import { computed, inject } from "vue";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
|
@ -83,183 +88,114 @@ const pluginRoleTemplateGroups = computed<RoleTemplateGroup[]>(() => {
|
|||
</div>
|
||||
</div>
|
||||
<div class="border-t border-gray-200">
|
||||
<dl class="divide-y divide-gray-100">
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.plugin.detail.fields.display_name") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
{{ plugin?.spec.displayName }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.plugin.detail.fields.description") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
{{ plugin?.spec.description }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.plugin.detail.fields.version") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
{{ plugin?.spec.version }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.plugin.detail.fields.requires") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
{{ plugin?.spec.requires }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.plugin.detail.fields.author") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
<a
|
||||
v-if="plugin?.spec.author"
|
||||
:href="plugin?.spec.author.website"
|
||||
target="_blank"
|
||||
>
|
||||
{{ plugin?.spec.author.name }}
|
||||
</a>
|
||||
<span v-else>
|
||||
{{ $t("core.common.text.none") }}
|
||||
</span>
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.plugin.detail.fields.license") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
<ul
|
||||
v-if="plugin?.spec.license && plugin?.spec.license.length"
|
||||
class="list-inside"
|
||||
:class="{ 'list-disc': plugin?.spec.license.length > 1 }"
|
||||
>
|
||||
<li
|
||||
v-for="(license, index) in plugin.spec.license"
|
||||
:key="index"
|
||||
>
|
||||
<a v-if="license.url" :href="license.url" target="_blank">
|
||||
{{ license.name }}
|
||||
</a>
|
||||
<span>
|
||||
{{ license.name }}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</div>
|
||||
<!-- TODO add display extensions support -->
|
||||
<div
|
||||
v-if="false"
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">模型定义</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
<span>
|
||||
{{ $t("core.common.text.none") }}
|
||||
</span>
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
:class="`${
|
||||
pluginRoleTemplateGroups.length ? 'bg-gray-50' : 'bg-white'
|
||||
}`"
|
||||
class="px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.plugin.detail.fields.role_templates") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-5 sm:mt-0">
|
||||
<dl
|
||||
v-if="pluginRoleTemplateGroups.length"
|
||||
class="divide-y divide-gray-100"
|
||||
>
|
||||
<div
|
||||
v-for="(group, groupIndex) in pluginRoleTemplateGroups"
|
||||
:key="groupIndex"
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ group.module }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
<ul class="space-y-2">
|
||||
<li v-for="(role, index) in group.roles" :key="index">
|
||||
<div
|
||||
class="inline-flex w-72 cursor-pointer flex-row items-center gap-4 rounded border p-5 hover:border-primary"
|
||||
>
|
||||
<div class="inline-flex flex-col gap-y-3">
|
||||
<span class="font-medium text-gray-900">
|
||||
{{
|
||||
role.metadata.annotations?.[
|
||||
rbacAnnotations.DISPLAY_NAME
|
||||
]
|
||||
}}
|
||||
</span>
|
||||
<span
|
||||
v-if="
|
||||
role.metadata.annotations?.[
|
||||
rbacAnnotations.DEPENDENCIES
|
||||
]
|
||||
"
|
||||
class="text-xs text-gray-400"
|
||||
>
|
||||
{{
|
||||
$t("core.role.common.text.dependent_on", {
|
||||
roles: JSON.parse(
|
||||
role.metadata.annotations?.[
|
||||
rbacAnnotations.DEPENDENCIES
|
||||
]
|
||||
).join(", "),
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<span v-else>
|
||||
{{ $t("core.common.text.none") }}
|
||||
</span>
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.plugin.detail.fields.last_starttime") }}
|
||||
</dt>
|
||||
<dd
|
||||
class="mt-1 text-sm tabular-nums text-gray-900 sm:col-span-2 sm:mt-0"
|
||||
<VDescription>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.plugin.detail.fields.display_name')"
|
||||
:content="plugin?.spec.displayName"
|
||||
/>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.plugin.detail.fields.description')"
|
||||
:content="plugin?.spec.description"
|
||||
/>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.plugin.detail.fields.version')"
|
||||
:content="plugin?.spec.version"
|
||||
/>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.plugin.detail.fields.requires')"
|
||||
:content="plugin?.spec.requires"
|
||||
/>
|
||||
<VDescriptionItem :label="$t('core.plugin.detail.fields.author')">
|
||||
<a
|
||||
v-if="plugin?.spec.author"
|
||||
:href="plugin?.spec.author.website"
|
||||
target="_blank"
|
||||
>
|
||||
{{ formatDatetime(plugin?.status?.lastStartTime) }}
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
{{ plugin?.spec.author.name }}
|
||||
</a>
|
||||
<span v-else>
|
||||
{{ $t("core.common.text.none") }}
|
||||
</span>
|
||||
</VDescriptionItem>
|
||||
<VDescriptionItem :label="$t('core.plugin.detail.fields.license')">
|
||||
<ul
|
||||
v-if="plugin?.spec.license && plugin?.spec.license.length"
|
||||
class="list-inside"
|
||||
:class="{ 'list-disc': plugin?.spec.license.length > 1 }"
|
||||
>
|
||||
<li v-for="(license, index) in plugin.spec.license" :key="index">
|
||||
<a v-if="license.url" :href="license.url" target="_blank">
|
||||
{{ license.name }}
|
||||
</a>
|
||||
<span>
|
||||
{{ license.name }}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</VDescriptionItem>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.plugin.detail.fields.role_templates')"
|
||||
>
|
||||
<dl
|
||||
v-if="pluginRoleTemplateGroups.length"
|
||||
class="divide-y divide-gray-100"
|
||||
>
|
||||
<div
|
||||
v-for="(group, groupIndex) in pluginRoleTemplateGroups"
|
||||
:key="groupIndex"
|
||||
class="rounded bg-gray-50 px-4 py-5 hover:bg-gray-100 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ group.module }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
<ul class="space-y-2">
|
||||
<li v-for="(role, index) in group.roles" :key="index">
|
||||
<div
|
||||
class="inline-flex w-72 cursor-pointer flex-row items-center gap-4 rounded border p-5 hover:border-primary"
|
||||
>
|
||||
<div class="inline-flex flex-col gap-y-3">
|
||||
<span class="font-medium text-gray-900">
|
||||
{{
|
||||
role.metadata.annotations?.[
|
||||
rbacAnnotations.DISPLAY_NAME
|
||||
]
|
||||
}}
|
||||
</span>
|
||||
<span
|
||||
v-if="
|
||||
role.metadata.annotations?.[
|
||||
rbacAnnotations.DEPENDENCIES
|
||||
]
|
||||
"
|
||||
class="text-xs text-gray-400"
|
||||
>
|
||||
{{
|
||||
$t("core.role.common.text.dependent_on", {
|
||||
roles: JSON.parse(
|
||||
role.metadata.annotations?.[
|
||||
rbacAnnotations.DEPENDENCIES
|
||||
]
|
||||
).join(", "),
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<span v-else>
|
||||
{{ $t("core.common.text.none") }}
|
||||
</span>
|
||||
</VDescriptionItem>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.plugin.detail.fields.last_starttime')"
|
||||
:content="formatDatetime(plugin?.status?.lastStartTime)"
|
||||
/>
|
||||
</VDescription>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
|
|
|
@ -9,6 +9,8 @@ import {
|
|||
VTag,
|
||||
VAvatar,
|
||||
VAlert,
|
||||
VDescription,
|
||||
VDescriptionItem,
|
||||
} from "@halo-dev/components";
|
||||
import { useRoute } from "vue-router";
|
||||
import { computed, onMounted, ref, watch } from "vue";
|
||||
|
@ -19,7 +21,6 @@ import {
|
|||
useRoleForm,
|
||||
useRoleTemplateSelection,
|
||||
} from "@/modules/system/roles/composables/use-role";
|
||||
import { useUserFetch } from "@/modules/system/users/composables/use-user";
|
||||
import { SUPER_ROLE_NAME } from "@/constants/constants";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { formatDatetime } from "@/utils/date";
|
||||
|
@ -34,8 +35,6 @@ const { roleTemplateGroups, handleRoleTemplateSelect, selectedRoleTemplates } =
|
|||
|
||||
const { formState, saving, handleCreateOrUpdate } = useRoleForm();
|
||||
|
||||
const { users } = useUserFetch({ fetchOnMounted: false });
|
||||
|
||||
const isSystemReserved = computed(() => {
|
||||
return (
|
||||
formState.value.metadata.labels?.[roleLabels.SYSTEM_RESERVED] === "true"
|
||||
|
@ -130,114 +129,34 @@ onMounted(() => {
|
|||
</p>
|
||||
</div>
|
||||
<div class="border-t border-gray-200">
|
||||
<dl class="divide-y divide-gray-100">
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
||||
<VDescription>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.role.detail.fields.display_name')"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.role.detail.fields.display_name") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
{{
|
||||
formState.metadata?.annotations?.[
|
||||
rbacAnnotations.DISPLAY_NAME
|
||||
] || formState.metadata?.name
|
||||
}}
|
||||
</VDescriptionItem>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.role.detail.fields.name')"
|
||||
:content="formState.metadata?.name"
|
||||
/>
|
||||
<VDescriptionItem :label="$t('core.role.detail.fields.type')">
|
||||
<VTag>
|
||||
{{
|
||||
formState.metadata?.annotations?.[
|
||||
rbacAnnotations.DISPLAY_NAME
|
||||
] || formState.metadata?.name
|
||||
isSystemReserved
|
||||
? t("core.role.common.text.system_reserved")
|
||||
: t("core.role.common.text.custom")
|
||||
}}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.role.detail.fields.name") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
{{ formState.metadata?.name }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.role.detail.fields.type") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
<VTag>
|
||||
{{
|
||||
isSystemReserved
|
||||
? t("core.role.common.text.system_reserved")
|
||||
: t("core.role.common.text.custom")
|
||||
}}
|
||||
</VTag>
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.role.detail.fields.creation_time") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
{{ formatDatetime(formState.metadata.creationTimestamp) }}
|
||||
</dd>
|
||||
</div>
|
||||
<!-- TODO: 支持通过当前角色查询用户 -->
|
||||
<div
|
||||
v-if="false"
|
||||
class="bg-gray-50 px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">用户</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
<div
|
||||
class="h-96 overflow-y-auto overflow-x-hidden rounded-sm bg-white shadow-sm transition-all hover:shadow"
|
||||
>
|
||||
<ul class="divide-y divide-gray-100" role="list">
|
||||
<RouterLink
|
||||
v-for="(user, index) in users"
|
||||
:key="index"
|
||||
:to="{
|
||||
name: 'UserDetail',
|
||||
params: { name: user.metadata.name },
|
||||
}"
|
||||
>
|
||||
<li class="block cursor-pointer hover:bg-gray-50">
|
||||
<div class="flex items-center px-4 py-4">
|
||||
<div class="flex min-w-0 flex-1 items-center">
|
||||
<div class="flex flex-shrink-0 items-center">
|
||||
<VAvatar
|
||||
:alt="user.spec.displayName"
|
||||
:src="user.spec.avatar"
|
||||
size="md"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="min-w-0 flex-1 px-4 md:grid md:grid-cols-2 md:gap-4"
|
||||
>
|
||||
<div>
|
||||
<p
|
||||
class="truncate text-sm font-medium text-gray-900"
|
||||
>
|
||||
{{ user.spec.displayName }}
|
||||
</p>
|
||||
<p class="mt-2 flex items-center">
|
||||
<span class="text-xs text-gray-500">
|
||||
{{ user.metadata.name }}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<IconArrowRight />
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</RouterLink>
|
||||
</ul>
|
||||
</div>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</VTag>
|
||||
</VDescriptionItem>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.role.detail.fields.creation_time')"
|
||||
:content="formatDatetime(formState.metadata.creationTimestamp)"
|
||||
/>
|
||||
</VDescription>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
<script lang="ts" setup>
|
||||
import { Dialog, IconUserSettings, VButton, VTag } from "@halo-dev/components";
|
||||
import {
|
||||
Dialog,
|
||||
IconUserSettings,
|
||||
VButton,
|
||||
VDescription,
|
||||
VDescriptionItem,
|
||||
VTag,
|
||||
} from "@halo-dev/components";
|
||||
import type { ComputedRef, Ref } from "vue";
|
||||
import { inject, computed } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
|
@ -64,144 +71,99 @@ const handleBindAuth = (authProvider: ListedAuthProvider) => {
|
|||
</script>
|
||||
<template>
|
||||
<div class="border-t border-gray-100">
|
||||
<dl class="divide-y divide-gray-50">
|
||||
<div
|
||||
class="bg-white px-2 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4"
|
||||
<VDescription>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.user.detail.fields.display_name')"
|
||||
:content="user?.user.spec.displayName"
|
||||
class="!px-2"
|
||||
/>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.user.detail.fields.username')"
|
||||
:content="user?.user.metadata.name"
|
||||
class="!px-2"
|
||||
/>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.user.detail.fields.email')"
|
||||
:content="user?.user.spec.email || $t('core.common.text.none')"
|
||||
class="!px-2"
|
||||
/>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.user.detail.fields.roles')"
|
||||
class="!px-2"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.user.detail.fields.display_name") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-3 sm:mt-0">
|
||||
{{ user?.user.spec?.displayName }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-2 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.user.detail.fields.username") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-3 sm:mt-0">
|
||||
{{ user?.user.metadata?.name }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-2 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.user.detail.fields.email") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-3 sm:mt-0">
|
||||
{{ user?.user.spec?.email || $t("core.common.text.none") }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-2 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.user.detail.fields.roles") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-3 sm:mt-0">
|
||||
<VTag
|
||||
v-for="(role, index) in user?.roles"
|
||||
:key="index"
|
||||
@click="
|
||||
router.push({
|
||||
name: 'RoleDetail',
|
||||
params: { name: role.metadata.name },
|
||||
})
|
||||
"
|
||||
>
|
||||
<template #leftIcon>
|
||||
<IconUserSettings />
|
||||
</template>
|
||||
{{
|
||||
role.metadata.annotations?.[rbacAnnotations.DISPLAY_NAME] ||
|
||||
role.metadata.name
|
||||
}}
|
||||
</VTag>
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-2 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.user.detail.fields.bio") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-3 sm:mt-0">
|
||||
{{ user?.user.spec?.bio || $t("core.common.text.none") }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-2 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.user.detail.fields.creation_time") }}
|
||||
</dt>
|
||||
<dd
|
||||
class="mt-1 text-sm tabular-nums text-gray-900 sm:col-span-3 sm:mt-0"
|
||||
<VTag
|
||||
v-for="(role, index) in user?.roles"
|
||||
:key="index"
|
||||
@click="
|
||||
router.push({
|
||||
name: 'RoleDetail',
|
||||
params: { name: role.metadata.name },
|
||||
})
|
||||
"
|
||||
>
|
||||
{{ formatDatetime(user?.user.metadata?.creationTimestamp) }}
|
||||
</dd>
|
||||
</div>
|
||||
<!-- TODO: add display last login time support -->
|
||||
<div
|
||||
v-if="false"
|
||||
class="bg-white px-2 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">最近登录时间</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-3 sm:mt-0">
|
||||
{{ user?.user.metadata?.creationTimestamp }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
<template #leftIcon>
|
||||
<IconUserSettings />
|
||||
</template>
|
||||
{{
|
||||
role.metadata.annotations?.[rbacAnnotations.DISPLAY_NAME] ||
|
||||
role.metadata.name
|
||||
}}
|
||||
</VTag>
|
||||
</VDescriptionItem>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.user.detail.fields.bio')"
|
||||
:content="user?.user.spec?.bio || $t('core.common.text.none')"
|
||||
class="!px-2"
|
||||
/>
|
||||
<VDescriptionItem
|
||||
:label="$t('core.user.detail.fields.creation_time')"
|
||||
:content="formatDatetime(user?.user.metadata?.creationTimestamp)"
|
||||
class="!px-2"
|
||||
/>
|
||||
<VDescriptionItem
|
||||
v-if="!isFetching && isCurrentUser && availableAuthProviders?.length"
|
||||
class="bg-white px-2 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4"
|
||||
:label="$t('core.user.detail.fields.identity_authentication')"
|
||||
class="!px-2"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
{{ $t("core.user.detail.fields.identity_authentication") }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm sm:col-span-3 sm:mt-0">
|
||||
<ul class="space-y-2">
|
||||
<template v-for="(authProvider, index) in authProviders">
|
||||
<li
|
||||
v-if="authProvider.supportsBinding && authProvider.enabled"
|
||||
:key="index"
|
||||
<ul class="space-y-2">
|
||||
<template v-for="(authProvider, index) in authProviders">
|
||||
<li
|
||||
v-if="authProvider.supportsBinding && authProvider.enabled"
|
||||
:key="index"
|
||||
>
|
||||
<div
|
||||
class="flex w-full cursor-pointer flex-wrap justify-between gap-y-3 rounded border p-5 hover:border-primary sm:w-1/2"
|
||||
>
|
||||
<div
|
||||
class="flex w-full cursor-pointer flex-wrap justify-between gap-y-3 rounded border p-5 hover:border-primary sm:w-1/2"
|
||||
>
|
||||
<div class="inline-flex items-center gap-3">
|
||||
<div>
|
||||
<img class="h-7 w-7 rounded" :src="authProvider.logo" />
|
||||
</div>
|
||||
<div class="text-sm font-medium text-gray-900">
|
||||
{{ authProvider.displayName }}
|
||||
</div>
|
||||
<div class="inline-flex items-center gap-3">
|
||||
<div>
|
||||
<img class="h-7 w-7 rounded" :src="authProvider.logo" />
|
||||
</div>
|
||||
<div class="inline-flex items-center">
|
||||
<VButton
|
||||
v-if="authProvider.isBound"
|
||||
size="sm"
|
||||
@click="handleUnbindAuth(authProvider)"
|
||||
>
|
||||
{{ $t("core.user.detail.operations.unbind.button") }}
|
||||
</VButton>
|
||||
<VButton
|
||||
v-else
|
||||
size="sm"
|
||||
type="secondary"
|
||||
@click="handleBindAuth(authProvider)"
|
||||
>
|
||||
{{ $t("core.user.detail.operations.bind.button") }}
|
||||
</VButton>
|
||||
<div class="text-sm font-medium text-gray-900">
|
||||
{{ authProvider.displayName }}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<div class="inline-flex items-center">
|
||||
<VButton
|
||||
v-if="authProvider.isBound"
|
||||
size="sm"
|
||||
@click="handleUnbindAuth(authProvider)"
|
||||
>
|
||||
{{ $t("core.user.detail.operations.unbind.button") }}
|
||||
</VButton>
|
||||
<VButton
|
||||
v-else
|
||||
size="sm"
|
||||
type="secondary"
|
||||
@click="handleBindAuth(authProvider)"
|
||||
>
|
||||
{{ $t("core.user.detail.operations.bind.button") }}
|
||||
</VButton>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</VDescriptionItem>
|
||||
</VDescription>
|
||||
</div>
|
||||
</template>
|
||||
|
|
Loading…
Reference in New Issue