add a new PageDisplayToolbar only used in preview mode so far

This commit is contained in:
Ahmed Awan
2026-06-16 12:09:11 -05:00
parent 17d71c8e3c
commit 56293a7e87
5 changed files with 188 additions and 32 deletions
+7
View File
@@ -8,6 +8,9 @@
*
* Change strings here to rename across the entire UI.
*/
import type { IconDefinition } from "@fortawesome/fontawesome-svg-core";
import { faBook, faFileContract } from "@fortawesome/free-solid-svg-icons";
import type { PageEditorMode } from "@/stores/pageEditorStore";
/** Per-mode labels used by the page editor, history page list, chat panel, etc. */
@@ -16,6 +19,7 @@ export const PAGE_LABELS: Record<
{
entityName: string;
entityNamePlural: string;
titleIcon: IconDefinition;
defaultTitle: string;
editorBackLabel: string;
newButton: string;
@@ -30,6 +34,7 @@ export const PAGE_LABELS: Record<
history: {
entityName: "Galaxy Notebook",
entityNamePlural: "Galaxy Notebooks",
titleIcon: faBook,
defaultTitle: "Untitled Notebook",
editorBackLabel: "This History's Notebooks",
newButton: "New Notebook",
@@ -44,6 +49,7 @@ export const PAGE_LABELS: Record<
standalone: {
entityName: "Report",
entityNamePlural: "Reports",
titleIcon: faFileContract,
defaultTitle: "Untitled Report",
editorBackLabel: "Back to Reports",
newButton: "Create Report",
@@ -56,6 +62,7 @@ export const PAGE_LABELS: Record<
invocation: {
entityName: "Invocation Report",
entityNamePlural: "Invocation Reports",
titleIcon: faFileContract,
defaultTitle: "Untitled Invocation Report",
editorBackLabel: "This Invocation's Reports",
newButton: "New Invocation Report",
@@ -159,7 +159,6 @@ function handleBack() {
<PageDisplayOnly
v-else-if="store.hasCurrentPage && displayOnly"
:labels="labels"
:current-title="store.currentTitle"
:markdown-config="markdownConfig || undefined"
@back="handleBack"
@edit="handleEdit(props.pageId)" />
@@ -1,17 +1,13 @@
<script setup lang="ts">
import { faArrowLeft, faEdit } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import type { PAGE_LABELS } from "@/components/Page/constants";
import type { MarkdownConfig } from "../Markdown/types.js";
import GButton from "../BaseComponents/GButton.vue";
import Markdown from "../Markdown/Markdown.vue";
import PageDisplayToolbar from "./PageDisplayToolbar.vue";
const props = defineProps<{
labels: (typeof PAGE_LABELS)[keyof typeof PAGE_LABELS];
currentTitle?: string;
markdownConfig?: MarkdownConfig;
}>();
@@ -23,21 +19,7 @@ const emit = defineEmits<{
<template>
<div class="d-flex flex-column">
<div
class="page-display-toolbar d-flex align-items-center p-2 border-bottom"
data-description="page display toolbar">
<GButton color="blue" transparent size="small" data-description="page back button" @click="emit('back')">
<FontAwesomeIcon :icon="faArrowLeft" />
{{ props.labels.editorBackLabel }}
</GButton>
<span class="flex-grow-1 text-center font-weight-bold">
{{ props.currentTitle || props.labels.defaultTitle }}
</span>
<GButton color="blue" outline size="small" data-description="page edit button" @click="emit('edit')">
<FontAwesomeIcon :icon="faEdit" />
Edit
</GButton>
</div>
<PageDisplayToolbar :labels="props.labels" mode="display" @edit="emit('edit')" @back="emit('back')" />
<div class="page-display-content" data-description="page rendered view">
<Markdown
v-if="markdownConfig"
@@ -51,10 +33,6 @@ const emit = defineEmits<{
</template>
<style scoped>
.page-display-toolbar {
background: var(--color-grey-100);
}
.page-display-content {
overflow: auto;
flex: 1 1 0;
@@ -0,0 +1,178 @@
<script setup lang="ts">
import {
faArrowLeft,
faEdit,
faEye,
faHistory,
faInfo,
faPen,
faSave,
faSpinner,
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { BBadge } from "bootstrap-vue";
import { storeToRefs } from "pinia";
import { computed, ref } from "vue";
import type { PAGE_LABELS } from "@/components/Page/constants";
import { usePageEditorStore } from "@/stores/pageEditorStore.js";
import GButton from "../BaseComponents/GButton.vue";
import GButtonGroup from "../BaseComponents/GButtonGroup.vue";
import RenameModal from "../Common/RenameModal.vue";
const props = defineProps<{
labels: (typeof PAGE_LABELS)[keyof typeof PAGE_LABELS];
mode: "editor" | "display";
}>();
const pageEditorStore = usePageEditorStore();
const { canSave, currentTitle, revisionCount, showRevisions, isDirty, isSaving } = storeToRefs(pageEditorStore);
const emit = defineEmits<{
(e: "back"): void;
(e: "edit"): void;
(e: "preview"): void;
}>();
const showRename = ref(false);
const saveDisabledTitle = computed(() => {
const entity = props.labels.entityName.toLowerCase();
if (props.mode === "display") {
return `Currently previewing this ${entity}. Click 'Edit' to make changes and enable saving.`;
}
if (isSaving.value) {
return `This ${entity} is being saved`;
}
if (!canSave.value) {
return `There are no changes to save to this ${entity}`;
}
return "";
});
async function handleSave() {
await pageEditorStore.savePage();
}
function handleTitleChange(newTitle: string): Promise<void> {
return new Promise((resolve) => {
pageEditorStore.updateTitle(newTitle);
resolve();
});
}
</script>
<template>
<div
class="page-display-toolbar d-flex align-items-center py-2 px-3 border-bottom flex-gapx-1 justify-content-between"
:data-description="`page ${props.mode} toolbar`">
<div class="d-flex align-items-center flex-gapx-1 title-section">
<FontAwesomeIcon :icon="props.labels.titleIcon" fixed-width />
<b class="page-title" :data-description="`page ${props.mode} title`">
{{ currentTitle || props.labels.defaultTitle }}
</b>
<GButton
v-if="props.mode === 'editor'"
inline
transparent
data-description="page rename button"
:title="`Rename this ${props.labels.entityName.toLowerCase()}`"
@click="showRename = true">
<FontAwesomeIcon :icon="faPen" />
</GButton>
</div>
<div class="d-flex align-items-center flex-gapx-1 flex-shrink-0">
<span
v-if="isDirty"
class="d-flex align-items-center flex-gapx-1 text-warning small"
data-description="page unsaved indicator">
<BBadge variant="warning" class="text-light">
<FontAwesomeIcon :icon="faInfo" />
</BBadge>
Unsaved
</span>
<GButton color="blue" transparent size="small" data-description="page back button" @click="emit('back')">
<FontAwesomeIcon :icon="faArrowLeft" />
{{ props.labels.editorBackLabel }}
</GButton>
<slot name="extra-actions" />
<GButton
v-if="props.mode === 'editor'"
color="blue"
outline
:pressed="showRevisions"
data-description="page revisions button"
size="small"
@click="pageEditorStore.toggleRevisions">
<FontAwesomeIcon :icon="faHistory" />
Revisions
<BBadge v-if="revisionCount > 0" variant="light" class="ml-1">
{{ revisionCount }}
</BBadge>
</GButton>
<GButtonGroup data-description="revision view mode toggle">
<GButton
color="blue"
outline
:pressed="props.mode === 'editor'"
data-description="page edit button"
size="small"
@click="emit('edit')">
<FontAwesomeIcon :icon="faEdit" />
Edit
</GButton>
<GButton
color="blue"
outline
:pressed="props.mode === 'display'"
data-description="page preview button"
size="small"
@click="emit('preview')">
<FontAwesomeIcon :icon="faEye" />
Preview
</GButton>
</GButtonGroup>
<GButton
color="blue"
data-description="page save button"
:title="`Save ${props.labels.entityName}`"
tooltip
:disabled="props.mode === 'display' || !canSave"
:disabled-title="saveDisabledTitle"
size="small"
@click="handleSave">
<FontAwesomeIcon :icon="isSaving ? faSpinner : faSave" :spin="isSaving" />
Save
</GButton>
</div>
<RenameModal
v-if="showRename"
:item-type="props.labels.entityName"
:name="currentTitle || props.labels.defaultTitle"
:rename-action="handleTitleChange"
@close="showRename = false" />
</div>
</template>
<style scoped>
.page-display-toolbar {
background: var(--color-grey-100);
}
.title-section {
min-width: 0;
overflow: hidden;
}
.page-title {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>
@@ -187,7 +187,6 @@ function handleRevisionRestore(revisionId: string) {
<PageDisplayOnly
v-else-if="store.hasCurrentPage && displayOnly"
:labels="labels"
:current-title="store.currentTitle"
:markdown-config="markdownConfig || undefined"
@back="handleBack"
@edit="handleEdit" />
@@ -209,9 +208,7 @@ function handleRevisionRestore(revisionId: string) {
<!-- Edit mode: toolbar + editor + optional chat/revision panels -->
<template v-else-if="store.hasCurrentPage">
<div
class="page-toolbar d-flex align-items-center p-2 border-bottom"
data-description="page editor toolbar">
<div class="d-flex align-items-center p-2 border-bottom" data-description="page editor toolbar">
<BButton variant="link" size="sm" data-description="page back button" @click="handleBack">
<FontAwesomeIcon :icon="faArrowLeft" />
{{ labels.editorBackLabel }}
@@ -310,9 +307,6 @@ function handleRevisionRestore(revisionId: string) {
.page-editor-view {
background: var(--body-bg);
}
.page-toolbar {
background: var(--panel-header-bg);
}
.page-revision-panel {
width: 300px;
min-width: 300px;