Skip to content

Commit

Permalink
Merge pull request #983 from owi92/allow-series-path-removal
Browse files Browse the repository at this point in the history
Allow series path removal via Tobira tab in series details
  • Loading branch information
Arnei authored Dec 11, 2024
2 parents a063f4f + d419aeb commit 1df75da
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 81 deletions.
151 changes: 90 additions & 61 deletions src/components/events/partials/ModalTabsAndPages/DetailsTobiraTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import { Formik } from "formik";
import { useState } from "react";
import EventDetailsTabHierarchyNavigation from "./EventDetailsTabHierarchyNavigation";
import NewTobiraPage, { TobiraFormProps } from "./NewTobiraPage";
import { fetchSeriesDetailsTobira, setTobiraTabHierarchy, TobiraData, updateSeriesTobiraPath } from "../../../../slices/seriesDetailsSlice";
import { fetchSeriesDetailsTobira, removeSeriesTobiraPath, setTobiraTabHierarchy, TobiraData, updateSeriesTobiraPath } from "../../../../slices/seriesDetailsSlice";
import { fetchSeriesDetailsTobiraNew, TobiraPage } from "../../../../slices/seriesSlice";
import ConfirmModal from "../../../shared/ConfirmModal";
import { Tooltip } from "../../../shared/Tooltip";


export type TobiraTabHierarchy = "main" | "edit-path";
Expand Down Expand Up @@ -92,6 +94,13 @@ const DetailsTobiraTab = ({ kind, id }: DetailsTobiraTabProps) => {
dispatch(setTobiraTabHierarchy("main"));
};

const handleDelete = async (hostPage: TobiraPage) => {
await dispatch(removeSeriesTobiraPath({
seriesId: id,
currentPath: hostPage.path,
})).then(() => dispatch(fetchSeriesDetailsTobira(id)))
}

const openSubTab = async (tabType: TobiraTabHierarchy, currentPage?: TobiraPage) => {
if (!!currentPage) {
const breadcrumbs = getBreadcrumbs(currentPage);
Expand Down Expand Up @@ -139,16 +148,13 @@ const DetailsTobiraTab = ({ kind, id }: DetailsTobiraTabProps) => {
{kind === "series" && <p className="tab-description">
{t("EVENTS.SERIES.DETAILS.TOBIRA.DESCRIPTION")}
</p>}
<div className="obj-container">
<div className="obj tbl-list">
<header>
{t(`EVENTS.${i18nKey}.DETAILS.TOBIRA.PAGES`)}
</header>
<div className="obj-container">
<TobiraTable {...{ tobiraData, i18nKey, openSubTab }} />
</div>
</div>
</div>
<TobiraTable {...{
tobiraData,
i18nKey,
openSubTab,
dispatch,
handleDelete,
}} />
</>}
</div>}
</div>
Expand All @@ -159,7 +165,10 @@ const DetailsTobiraTab = ({ kind, id }: DetailsTobiraTabProps) => {
onSubmit={values => handleSubmit(values)}
>
{formik => <NewTobiraPage
editMode
mode={{
edit: true,
mount: tobiraData.hostPages.length === 0,
}}
formik={formik}
nextPage={() => {}}
previousPage={() => {}}
Expand All @@ -172,59 +181,79 @@ const DetailsTobiraTab = ({ kind, id }: DetailsTobiraTabProps) => {
type TobiraTableProps = {
tobiraData: TobiraData;
i18nKey: "SERIES" | "EVENTS";
openSubTab: (tabType: TobiraTabHierarchy, currentPage?: TobiraPage) => Promise<void>
openSubTab: (tabType: TobiraTabHierarchy, currentPage?: TobiraPage) => Promise<void>;
handleDelete: (hostPage: TobiraPage) => Promise<void>;
};

const TobiraTable: React.FC<TobiraTableProps> = ({ tobiraData, i18nKey, openSubTab }) => {
const TobiraTable = ({ tobiraData, i18nKey, openSubTab, handleDelete }: TobiraTableProps) => {
const { t } = useTranslation();
return <table className="main-tbl">
<tbody>
{tobiraData.hostPages.length === 0 && <tr>
<td className="tobira-not-mounted">
{t(`EVENTS.${i18nKey}.DETAILS.TOBIRA.NOT_MOUNTED`)}
{i18nKey === "SERIES" && (
<button
style={{ margin: 5 }}
className="button-like-anchor details-link pull-right"
onClick={() => openSubTab("edit-path")}
>
{t("EVENTS.SERIES.DETAILS.TOBIRA.MOUNT_SERIES")}
</button>
)}
</td>
</tr>}
{tobiraData.hostPages.map(hostPage => <tr key={hostPage.path}>
<td>
<a href={tobiraData.baseURL + hostPage.path}>
{hostPage.path !== '/' && <>
<span className="tobira-page-separator">/</span>
{hostPage.ancestors.map((ancestor, key) => (
<span key={key}>
{ancestor.title}
<span className="tobira-page-separator">/</span>
</span>
))}
const [showConfirmationModal, setShowConfirmationModal] = useState(false);

return <div className="obj">
<header>{t(`EVENTS.${i18nKey}.DETAILS.TOBIRA.PAGES`)}</header>
<table className="main-tbl">
<tbody>
{tobiraData.hostPages.length === 0 && <tr>
<td className="tobira-not-mounted">
{t(`EVENTS.${i18nKey}.DETAILS.TOBIRA.NOT_MOUNTED`)}
{i18nKey === "SERIES" && <Tooltip title={t("EVENTS.SERIES.DETAILS.TOBIRA.MOUNT_SERIES")}>
<button
style={{ margin: 5 }}
className="button-like-anchor edit fa fa-pencil-square pull-right"
onClick={() => openSubTab("edit-path")}
/>
</Tooltip>}
</td>
</tr>}
{tobiraData.hostPages.map(hostPage => <tr key={hostPage.path}>
<td>
<a href={tobiraData.baseURL + hostPage.path}>
{hostPage.path !== '/' && <>
<span className="tobira-page-separator">/</span>
{hostPage.ancestors.map((ancestor, key) => (
<span key={key}>
{ancestor.title}
<span className="tobira-page-separator">/</span>
</span>
))}
</>}
<span className="tobira-leaf-page">
{hostPage.path !== '/' && <span>
{hostPage.title}
</span>}
{hostPage.path === '/' && <span>
{t(`EVENTS.${i18nKey}.DETAILS.TOBIRA.HOMEPAGE`)}
</span>}
</span>
</a>
{i18nKey === "SERIES" && hostPage.blocks?.length === 1 && <>
<Tooltip title={t("EVENTS.SERIES.DETAILS.TOBIRA.REMOVE_PATH")}>
<button
style={{ margin: 5 }}
onClick={() => setShowConfirmationModal(true)}
className="button-like-anchor remove pull-right"
/>
</Tooltip>
<Tooltip title={t("EVENTS.SERIES.DETAILS.TOBIRA.EDIT_PATH")}>
<button
style={{ margin: 5 }}
className="button-like-anchor edit fa fa-pencil-square pull-right"
onClick={() => openSubTab("edit-path", hostPage)}
/>
</Tooltip>
{showConfirmationModal && <ConfirmModal
close={() => setShowConfirmationModal(false)}
resourceName={hostPage.path}
resourceId={null}
deleteMethod={() => handleDelete(hostPage)}
resourceType="TOBIRA_PATH"
/>}
</>}
<span className="tobira-leaf-page">
{hostPage.path !== '/' && <span>
{hostPage.title}
</span>}
{hostPage.path === '/' && <span>
{t(`EVENTS.${i18nKey}.DETAILS.TOBIRA.HOMEPAGE`)}
</span>}
</span>
</a>
{i18nKey === "SERIES" && hostPage.blocks?.length === 1 && <button
style={{ margin: 5 }}
className="button-like-anchor details-link pull-right"
onClick={() => openSubTab("edit-path", hostPage)}
>
{t("EVENTS.SERIES.DETAILS.TOBIRA.EDIT_PATH")}
</button>}
</td>
</tr>)}
</tbody>
</table>;
</td>
</tr>)}
</tbody>
</table>
</div>;
};

export default DetailsTobiraTab;
31 changes: 23 additions & 8 deletions src/components/events/partials/ModalTabsAndPages/NewTobiraPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,16 @@ const NewTobiraPage = <T extends TobiraFormProps>({
formik,
nextPage,
previousPage,
editMode,
mode,
}: {
formik: FormikProps<T>,
nextPage: (values: T) => void,
previousPage:(values: T) => void,
editMode?: boolean,
mode: {
edit?: boolean,
mount?: boolean,
},
}) => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
Expand Down Expand Up @@ -202,7 +206,7 @@ const NewTobiraPage = <T extends TobiraFormProps>({
<div className="modal-body">
{/* Notifications */}
<Notifications context="tobira" />
{!editMode && <p className="tab-description">{t("EVENTS.SERIES.NEW.TOBIRA.DESCRIPTION")}</p>}
<p className="tab-description">{t("EVENTS.SERIES.NEW.TOBIRA.DESCRIPTION")}</p>
{!error && <>
<div className="obj-container padded">
<div className="obj">
Expand All @@ -226,7 +230,7 @@ const NewTobiraPage = <T extends TobiraFormProps>({
<table className="main-tbl highlight-hover">
<thead>
<tr>
<th className="small"/>
{currentPage.children.length > 0 && <th className="small"/>}
<th>
{t("EVENTS.SERIES.NEW.TOBIRA.PAGE_TITLE") /* Title */}
</th>
Expand Down Expand Up @@ -300,7 +304,15 @@ const NewTobiraPage = <T extends TobiraFormProps>({
</td>
{editing && <td>
{page.new && <button
onClick={() => select(undefined)}
onClick={() => {
dispatch(setTobiraPage({
...currentPage,
children: currentPage.children.filter((_, idx) => (
idx !== currentPage.children.length - 1
))
}));
select(undefined);
}}
title={t('EVENTS.SERIES.NEW.TOBIRA.CANCEL')}
className="button-like-anchor remove"
/>}
Expand Down Expand Up @@ -329,14 +341,17 @@ const NewTobiraPage = <T extends TobiraFormProps>({
{formik.values.selectedPage.path}
</code>
</>
: t("EVENTS.SERIES.NEW.TOBIRA.NO_PAGE_SELECTED")
: (mode.edit && !mode.mount
? t("EVENTS.SERIES.NEW.TOBIRA.NO_PAGE_SELECTED_EDIT")
: t("EVENTS.SERIES.NEW.TOBIRA.NO_PAGE_SELECTED")
)
}
</p>
<p style={{ fontSize: 12 }}>{t("EVENTS.SERIES.NEW.TOBIRA.DIRECT_LINK")}</p>
{!mode.edit && <p style={{ fontSize: 12 }}>{t("EVENTS.SERIES.NEW.TOBIRA.DIRECT_LINK")}</p>}
</>}
</div>
{/* Render buttons for saving or resetting updated path */}
{editMode && <SaveEditFooter
{mode.edit && <SaveEditFooter
active={formik.values.selectedPage !== undefined}
reset={() => formik.setFieldValue("selectedPage", undefined)}
submit={() => formik.handleSubmit()}
Expand All @@ -345,7 +360,7 @@ const NewTobiraPage = <T extends TobiraFormProps>({
</div>

{/* Button for navigation to next page and previous page */}
{!editMode && <WizardNavigationButtons
{!mode.edit && <WizardNavigationButtons
formik={formik}
nextPage={nextPage}
previousPage={previousPage}
Expand Down
3 changes: 1 addition & 2 deletions src/components/events/partials/modals/EventDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -266,12 +266,11 @@ const EventDetails = ({
header={tabs[page].bodyHeaderTranslation ?? ""}
/>
)}
{page === EventDetailsPage.Tobira && (<>
{page === EventDetailsPage.Tobira && (
<DetailsTobiraTab
kind="event"
id={eventId}
/>
</>
)}
{page === EventDetailsPage.Statistics && !isLoadingStatistics && (
<EventDetailsStatisticsTab
Expand Down
4 changes: 4 additions & 0 deletions src/components/events/partials/modals/SeriesDetailsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { useTranslation } from "react-i18next";
import SeriesDetails from "./SeriesDetails";
import { useHotkeys } from "react-hotkeys-hook";
import { availableHotkeys } from "../../../../configs/hotkeysConfig";
import { removeNotificationWizardForm } from "../../../../slices/notificationSlice";
import { useAppDispatch } from "../../../../store";

/**
* This component renders the modal for displaying series details
Expand All @@ -17,6 +19,7 @@ const SeriesDetailsModal = ({
seriesId: string
}) => {
const { t } = useTranslation();
const dispatch = useAppDispatch();

// tracks, whether the policies are different to the initial value
const [policyChanged, setPolicyChanged] = useState(false);
Expand All @@ -28,6 +31,7 @@ const SeriesDetailsModal = ({
const close = () => {
if (!policyChanged || confirmUnsaved()) {
setPolicyChanged(false);
dispatch(removeNotificationWizardForm());
handleClose();
}
};
Expand Down
1 change: 1 addition & 0 deletions src/components/events/partials/wizards/NewSeriesWizard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ const NewSeriesWizard: React.FC<{
)}
{page === 4 && (
<NewTobiraPage
mode={{ mount: true }}
formik={formik}
nextPage={nextPage}
previousPage={previousPage}
Expand Down
4 changes: 2 additions & 2 deletions src/components/shared/ConfirmModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const ConfirmModal = <T,>({
deleteWithCautionMessage = "",
}: {
close: () => void,
resourceType: "EVENT" | "SERIES" | "LOCATION" | "USER" | "GROUP" | "ACL" | "THEME",
resourceType: "EVENT" | "SERIES" | "LOCATION" | "USER" | "GROUP" | "ACL" | "THEME" | "TOBIRA_PATH",
resourceName: string,
resourceId: T,
deleteMethod: (id: T) => void,
Expand Down Expand Up @@ -68,7 +68,7 @@ const ConfirmModal = <T,>({

<div>
<p>
<span>
<span style={{ padding: "0px 4px"}}>
{t("CONFIRMATIONS.METADATA.NOTICE." + resourceType)}
</span>
</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@
"GROUP": "The following group will be deleted",
"USER": "The following user will be deleted",
"THEME": "The following theme will be deleted",
"LOCATION": "The following location will be deleted"
"LOCATION": "The following location will be deleted",
"TOBIRA_PATH": "The series will be removed from the following path in Tobira:"
},
"NAME": "Name"
},
Expand Down Expand Up @@ -171,7 +172,9 @@
"SERIES_ADDED": "The series has been created",
"SERIES_NOT_SAVED": "The series could not be saved",
"SERIES_PATH_UPDATED": "The series path has been updated",
"SERIES_PATH_REMOVED": "The series path has been removed",
"SERIES_PATH_NOT_UPDATED": "The series path could not be updated",
"SERIES_PATH_NOT_REMOVED": "The series path could not be removed",
"EVENTS_CREATED": "The event has been created",
"EVENTS_UPLOAD_STARTED": "The event is being uploaded… {{ progress }}%",
"EVENTS_NOT_CREATED": "The event could not be created",
Expand Down Expand Up @@ -1146,6 +1149,7 @@
"HOMEPAGE": "Homepage",
"SELECTED_PAGE": "Series will be mounted under the following path",
"NO_PAGE_SELECTED": "No page selected. Series will not be mounted in Tobira.",
"NO_PAGE_SELECTED_EDIT": "No page selected. Series path will not be changed.",
"PATH": "Path",
"DIRECT_LINK": "A direct link will be available.",
"MOUNT_DISCLAIMER": "Series can only be mounted in empty pages"
Expand Down Expand Up @@ -1234,6 +1238,7 @@
"PAGES": "Pages in Tobira that contain this series",
"SHOW_PAGES": "Show all pages",
"EDIT_PATH" : "Edit path",
"REMOVE_PATH" : "Remove path",
"MOUNT_SERIES": "Mount series",
"DESCRIPTION": "You may edit the path of pages containing this series if the page has no other content."
},
Expand Down
Loading

0 comments on commit 1df75da

Please sign in to comment.