refactor: plugin list item component

Signed-off-by: Ryan Wang <i@ryanc.cc>
pull/591/head
Ryan Wang 2022-07-27 16:36:04 +08:00
parent bb25524c0a
commit 7bdbf2500f
3 changed files with 146 additions and 143 deletions

View File

@ -3,30 +3,21 @@ import {
IconAddCircle, IconAddCircle,
IconArrowDown, IconArrowDown,
IconPlug, IconPlug,
IconSettings,
VButton, VButton,
VCard, VCard,
VPageHeader, VPageHeader,
VPagination, VPagination,
VSpace, VSpace,
VSwitch,
VTag, VTag,
} from "@halo-dev/components"; } from "@halo-dev/components";
import PluginListItem from "./components/PluginListItem.vue";
import PluginInstallModal from "./components/PluginInstallModal.vue"; import PluginInstallModal from "./components/PluginInstallModal.vue";
import { onMounted, ref } from "vue"; import { onMounted, ref } from "vue";
import { apiClient } from "@halo-dev/admin-shared"; import { apiClient } from "@halo-dev/admin-shared";
import type { Plugin } from "@halo-dev/api-client"; import type { Plugin } from "@halo-dev/api-client";
import { usePluginLifeCycle } from "./composables/use-plugin";
const plugins = ref<Plugin[]>([] as Plugin[]); const plugins = ref<Plugin[]>([] as Plugin[]);
const pluginInstall = ref(false); const pluginInstall = ref(false);
const selectedPlugin = ref<Plugin | null>(null);
const { changeStatus, uninstall } = usePluginLifeCycle(selectedPlugin);
const isStarted = (plugin: Plugin) => {
return plugin.status?.phase === "STARTED" && plugin.spec.enabled;
};
const handleFetchPlugins = async () => { const handleFetchPlugins = async () => {
try { try {
@ -38,16 +29,6 @@ const handleFetchPlugins = async () => {
} }
}; };
function handleChangeStatus(plugin: Plugin) {
selectedPlugin.value = plugin;
changeStatus();
}
function handleUninstall(plugin: Plugin) {
selectedPlugin.value = plugin;
uninstall();
}
onMounted(handleFetchPlugins); onMounted(handleFetchPlugins);
</script> </script>
<template> <template>
@ -209,129 +190,7 @@ onMounted(handleFetchPlugins);
</template> </template>
<ul class="box-border h-full w-full divide-y divide-gray-100" role="list"> <ul class="box-border h-full w-full divide-y divide-gray-100" role="list">
<li v-for="(plugin, index) in plugins" :key="index"> <li v-for="(plugin, index) in plugins" :key="index">
<div <PluginListItem :plugin="plugin" />
class="relative block cursor-pointer px-4 py-3 transition-all hover:bg-gray-50"
>
<div class="relative flex flex-row items-center">
<div v-if="plugin.spec.logo" class="mr-4">
<RouterLink
:to="{
name: 'PluginDetail',
params: { name: plugin.metadata.name },
}"
>
<div
class="h-12 w-12 rounded border bg-white p-1 hover:shadow-sm"
>
<img
:alt="plugin.metadata.name"
:src="plugin.spec.logo"
class="h-full w-full"
/>
</div>
</RouterLink>
</div>
<div class="flex-1">
<div class="flex flex-row items-center">
<RouterLink
:to="{
name: 'PluginDetail',
params: { name: plugin.metadata.name },
}"
>
<span
class="mr-2 truncate text-sm font-medium text-gray-900"
>
{{ plugin.spec.displayName }}
</span>
</RouterLink>
<VSpace>
<VTag>
{{ isStarted(plugin) ? "已启用" : "未启用" }}
</VTag>
</VSpace>
</div>
<div class="mt-2 flex">
<VSpace align="start" direction="column" spacing="xs">
<span class="text-xs text-gray-500">
{{ plugin.spec.description }}
</span>
<span class="text-xs text-gray-500 sm:hidden">
@{{ plugin.spec.author }} {{ plugin.spec.version }}
</span>
</VSpace>
</div>
</div>
<div class="flex">
<div
class="inline-flex flex-col flex-col-reverse items-end gap-4 sm:flex-row sm:items-center sm:gap-6"
>
<FloatingTooltip
v-if="plugin.status?.phase === 'FAILED'"
class="hidden items-center sm:flex"
>
<div
class="inline-flex h-1.5 w-1.5 rounded-full bg-red-600"
>
<span
class="inline-block h-1.5 w-1.5 animate-ping rounded-full bg-red-600"
></span>
</div>
<template #popper>
{{ plugin.status?.reason }}:
{{ plugin.status?.message }}
</template>
</FloatingTooltip>
<a
:href="plugin.spec.homepage"
class="hidden text-sm text-gray-500 hover:text-gray-900 sm:block"
target="_blank"
>
@{{ plugin.spec.author }}
</a>
<span class="hidden text-sm text-gray-500 sm:block">
{{ plugin.spec.version }}
</span>
<time
class="hidden text-sm text-gray-500 sm:block"
datetime="2020-01-07"
>
{{ plugin.metadata.creationTimestamp }}
</time>
<div
v-permission="['system:plugins:manage']"
class="flex items-center"
>
<VSwitch
:model-value="plugin.spec.enabled"
@click="handleChangeStatus(plugin)"
/>
</div>
<span
v-permission="['system:plugins:manage']"
class="cursor-pointer"
>
<FloatingDropdown>
<IconSettings />
<template #popper>
<div class="links-w-48 links-p-2">
<VSpace class="links-w-full" direction="column">
<VButton
block
type="danger"
@click="handleUninstall(plugin)"
>
卸载
</VButton>
</VSpace>
</div>
</template>
</FloatingDropdown>
</span>
</div>
</div>
</div>
</div>
</li> </li>
</ul> </ul>

View File

@ -0,0 +1,136 @@
<script lang="ts" setup>
import {
IconSettings,
VButton,
VSpace,
VSwitch,
VTag,
} from "@halo-dev/components";
import type { PropType } from "vue";
import { toRefs } from "vue";
import { usePluginLifeCycle } from "../composables/use-plugin";
import type { Plugin } from "@halo-dev/api-client";
const props = defineProps({
plugin: {
type: Object as PropType<Plugin | null>,
default: null,
},
});
const { plugin } = toRefs(props);
const { isStarted, changeStatus, uninstall } = usePluginLifeCycle(plugin);
</script>
<template>
<div
class="relative block cursor-pointer px-4 py-3 transition-all hover:bg-gray-50"
>
<div class="relative flex flex-row items-center">
<div v-if="plugin?.spec.logo" class="mr-4">
<RouterLink
:to="{
name: 'PluginDetail',
params: { name: plugin?.metadata.name },
}"
>
<div class="h-12 w-12 rounded border bg-white p-1 hover:shadow-sm">
<img
:alt="plugin?.metadata.name"
:src="plugin?.spec.logo"
class="h-full w-full"
/>
</div>
</RouterLink>
</div>
<div class="flex-1">
<div class="flex flex-row items-center">
<RouterLink
:to="{
name: 'PluginDetail',
params: { name: plugin?.metadata.name },
}"
>
<span class="mr-2 truncate text-sm font-medium text-gray-900">
{{ plugin?.spec.displayName }}
</span>
</RouterLink>
<VSpace>
<VTag>
{{ isStarted ? "已启用" : "未启用" }}
</VTag>
</VSpace>
</div>
<div class="mt-2 flex">
<VSpace align="start" direction="column" spacing="xs">
<span class="text-xs text-gray-500">
{{ plugin?.spec.description }}
</span>
<span class="text-xs text-gray-500 sm:hidden">
@{{ plugin?.spec.author }} {{ plugin?.spec.version }}
</span>
</VSpace>
</div>
</div>
<div class="flex">
<div
class="inline-flex flex-col flex-col-reverse items-end gap-4 sm:flex-row sm:items-center sm:gap-6"
>
<FloatingTooltip
v-if="plugin?.status?.phase === 'FAILED'"
class="hidden items-center sm:flex"
>
<div class="inline-flex h-1.5 w-1.5 rounded-full bg-red-600">
<span
class="inline-block h-1.5 w-1.5 animate-ping rounded-full bg-red-600"
></span>
</div>
<template #popper>
{{ plugin?.status?.reason }}:
{{ plugin?.status?.message }}
</template>
</FloatingTooltip>
<a
:href="plugin?.spec.homepage"
class="hidden text-sm text-gray-500 hover:text-gray-900 sm:block"
target="_blank"
>
@{{ plugin?.spec.author }}
</a>
<span class="hidden text-sm text-gray-500 sm:block">
{{ plugin?.spec.version }}
</span>
<time
class="hidden text-sm text-gray-500 sm:block"
datetime="2020-01-07"
>
{{ plugin?.metadata.creationTimestamp }}
</time>
<div
v-permission="['system:plugins:manage']"
class="flex items-center"
>
<VSwitch
:model-value="plugin?.spec.enabled"
@click="changeStatus"
/>
</div>
<span v-permission="['system:plugins:manage']" class="cursor-pointer">
<FloatingDropdown>
<IconSettings />
<template #popper>
<div class="links-w-48 links-p-2">
<VSpace class="links-w-full" direction="column">
<VButton block type="danger" @click="uninstall">
卸载
</VButton>
</VSpace>
</div>
</template>
</FloatingDropdown>
</span>
</div>
</div>
</div>
</div>
</template>

View File

@ -1,4 +1,5 @@
import type { Ref } from "vue"; import type { Ref } from "vue";
import { computed } from "vue";
import type { Plugin } from "@halo-dev/api-client"; import type { Plugin } from "@halo-dev/api-client";
import cloneDeep from "lodash.clonedeep"; import cloneDeep from "lodash.clonedeep";
import { apiClient } from "@halo-dev/admin-shared"; import { apiClient } from "@halo-dev/admin-shared";
@ -7,6 +8,12 @@ import { useDialog } from "@halo-dev/components";
export function usePluginLifeCycle(plugin: Ref<Plugin | null>) { export function usePluginLifeCycle(plugin: Ref<Plugin | null>) {
const dialog = useDialog(); const dialog = useDialog();
const isStarted = computed(() => {
return (
plugin.value?.status?.phase === "STARTED" && plugin.value?.spec.enabled
);
});
const changeStatus = () => { const changeStatus = () => {
if (!plugin.value) return; if (!plugin.value) return;
@ -68,6 +75,7 @@ export function usePluginLifeCycle(plugin: Ref<Plugin | null>) {
}; };
return { return {
isStarted,
changeStatus, changeStatus,
uninstall, uninstall,
}; };