Skip to content

Commit

Permalink
Add view post snapshots feature
Browse files Browse the repository at this point in the history
Signed-off-by: Ryan Wang <i@ryanc.cc>
  • Loading branch information
ruibaby committed Apr 26, 2024
1 parent 3ec6bdb commit c447ffe
Show file tree
Hide file tree
Showing 32 changed files with 1,996 additions and 53 deletions.
17 changes: 17 additions & 0 deletions ui/console-src/modules/contents/pages/SinglePageEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import {
Dialog,
IconEye,
IconHistoryLine,
IconPages,
IconSave,
IconSendPlaneFill,
Expand Down Expand Up @@ -452,6 +453,22 @@ async function handleUploadImage(file: File, options?: AxiosRequestConfig) {
:allow-forced-select="!isUpdateMode"
@select="handleChangeEditorProvider"
/>
<VButton
v-if="isUpdateMode"
size="sm"
type="default"
@click="
$router.push({
name: 'SinglePageSnapshots',
query: { name: routeQueryName },
})
"
>
<template #icon>
<IconHistoryLine class="h-full w-full" />
</template>
{{ $t("core.page_editor.actions.snapshots") }}
</VButton>
<VButton
size="sm"
type="default"
Expand Down
125 changes: 125 additions & 0 deletions ui/console-src/modules/contents/pages/SinglePageSnapshots.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<script setup lang="ts">
import {
IconHistoryLine,
VButton,
VCard,
VLoading,
VPageHeader,
} from "@halo-dev/components";
import { useQuery } from "@tanstack/vue-query";
import { useRoute } from "vue-router";
import { apiClient } from "@/utils/api-client";
import { computed, watch } from "vue";
import { OverlayScrollbarsComponent } from "overlayscrollbars-vue";
import { useRouteQuery } from "@vueuse/router";
import SnapshotContent from "./components/SnapshotContent.vue";
import SnapshotListItem from "./components/SnapshotListItem.vue";
const route = useRoute();
const singlePageName = computed(() => route.query.name as string);
const { data: singlePage } = useQuery({
queryKey: ["singlePage-by-name", singlePageName],
queryFn: async () => {
const { data } =
await apiClient.extension.singlePage.getcontentHaloRunV1alpha1SinglePage({
name: singlePageName.value,
});
return data;
},
enabled: computed(() => !!singlePageName.value),
});
const { data: snapshots, isLoading } = useQuery({
queryKey: ["singlePage-snapshots-by-singlePage-name", singlePageName],
queryFn: async () => {
const { data } = await apiClient.singlePage.listSinglePageSnapshots({
name: singlePageName.value,
});
return data;
},
refetchInterval(data) {
const hasDeletingData = data?.some(
(item) => !!item.metadata.deletionTimestamp
);
return hasDeletingData ? 1000 : false;
},
enabled: computed(() => !!singlePageName.value),
});
const selectedSnapshotName = useRouteQuery<string | undefined>("snapshot-name");
watch(
() => snapshots.value,
(value) => {
if (value && !selectedSnapshotName.value) {
selectedSnapshotName.value = value[0].metadata.name;
}
},
{
immediate: true,
}
);
</script>

<template>
<VPageHeader :title="singlePage?.spec.title">
<template #icon>
<IconHistoryLine class="mr-2 self-center" />
</template>
<template #actions>
<VButton size="sm" @click="$router.back()">
{{ $t("core.common.buttons.back") }}
</VButton>
</template>
</VPageHeader>

<div class="m-0 md:m-4">
<VCard
style="height: calc(100vh - 5.5rem)"
:body-class="['h-full', '!p-0']"
>
<div class="grid h-full grid-cols-12 divide-y sm:divide-x sm:divide-y-0">
<div
class="relative col-span-12 h-full overflow-auto sm:col-span-6 lg:col-span-3 xl:col-span-2"
>
<OverlayScrollbarsComponent
element="div"
:options="{ scrollbars: { autoHide: 'scroll' } }"
class="h-full w-full"
defer
>
<VLoading v-if="isLoading" />
<Transition v-else appear name="fade">
<ul
class="box-border h-full w-full divide-y divide-gray-100"
role="list"
>
<li
v-for="snapshot in snapshots"
:key="snapshot.metadata.name"
@click="selectedSnapshotName = snapshot.metadata.name"
>
<SnapshotListItem
:snapshot="snapshot"
:single-page="singlePage"
:selected-snapshot-name="selectedSnapshotName"
/>
</li>
</ul>
</Transition>
</OverlayScrollbarsComponent>
</div>
<div
class="col-span-12 h-full overflow-auto sm:col-span-6 lg:col-span-9 xl:col-span-10"
>
<SnapshotContent
:single-page-name="singlePageName"
:snapshot-name="selectedSnapshotName"
/>
</div>
</div>
</VCard>
</div>
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ const handlePublishClick = () => {
};
// Fix me:
// Force update post settings,
// Force update singlePage settings,
// because currently there may be errors caused by changes in version due to asynchronous processing.
const { mutateAsync: singlePageUpdateMutate } = usePageUpdateMutate();
Expand Down
113 changes: 113 additions & 0 deletions ui/console-src/modules/contents/pages/components/SnapshotContent.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<script setup lang="ts">
import { useQuery } from "@tanstack/vue-query";
import { apiClient } from "@/utils/api-client";
import { computed, toRefs } from "vue";
import { Toast, VLoading } from "@halo-dev/components";
import { OverlayScrollbarsComponent } from "overlayscrollbars-vue";
const props = withDefaults(
defineProps<{
singlePageName?: string;
snapshotName?: string;
}>(),
{
singlePageName: undefined,
snapshotName: undefined,
}
);
const { singlePageName, snapshotName } = toRefs(props);
const { data: snapshot, isLoading } = useQuery({
queryKey: ["singlePage-snapshot-by-name", singlePageName, snapshotName],
queryFn: async () => {
if (!singlePageName.value || !snapshotName.value) {
throw new Error("singlePageName and snapshotName are required");
}
const { data } = await apiClient.singlePage.fetchSinglePageContent({
name: singlePageName.value,
snapshotName: snapshotName.value,
});
return data;
},
onError(err) {
if (err instanceof Error) {
Toast.error(err.message);
}
},
enabled: computed(() => !!singlePageName.value && !!snapshotName.value),
});
</script>
<template>
<OverlayScrollbarsComponent
element="div"
:options="{ scrollbars: { autoHide: 'scroll' } }"
class="h-full w-full"
defer
>
<VLoading v-if="isLoading" />
<div
v-else
class="snapshot-content markdown-body h-full w-full p-4"
v-html="snapshot?.content"
></div>
</OverlayScrollbarsComponent>
</template>

<style scoped lang="scss">
::v-deep(.snapshot-content) {
p {
margin-top: 0.75em;
margin-bottom: 0;
}
pre {
background: #0d0d0d;
padding: 0.75rem 1rem;
margin: 0;
code {
background: none;
font-size: 0.8rem;
padding: 0 !important;
border-radius: 0;
}
}
ul[data-type="taskList"] {
list-style: none;
padding: 0;
p {
margin: 0;
}
li {
display: flex;
> label {
flex: 0 0 auto;
margin-right: 0.5rem;
user-select: none;
}
> div {
flex: 1 1 auto;
}
}
}
ul {
list-style: disc !important;
}
ol {
list-style: decimal !important;
}
code br {
display: initial;
}
}
</style>
Loading

0 comments on commit c447ffe

Please sign in to comment.