Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 90 additions & 12 deletions apps/roam/src/components/settings/DiscourseNodeConfigPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
Alert,
Button,
ControlGroup,
InputGroup,
Expand All @@ -12,6 +13,8 @@ import refreshConfigTree from "~/utils/refreshConfigTree";
import createPage from "roamjs-components/writes/createPage";
import type { CustomField } from "roamjs-components/components/ConfigPanels/types";
import posthog from "posthog-js";
import getDiscourseRelations from "~/utils/getDiscourseRelations";
import { deleteBlock } from "roamjs-components/writes";

type DiscourseNodeConfigPanelProps = React.ComponentProps<
CustomField["options"]["component"]
Expand All @@ -32,6 +35,10 @@ const DiscourseNodeConfigPanel: React.FC<DiscourseNodeConfigPanelProps> = ({
null,
);

const [isAlertOpen, setIsAlertOpen] = useState(false);
const [alertMessage, setAlertMessage] = useState("");
const [affectedRelations, setAffectedRelations] = useState<any[]>([]);
const [nodeTypeIdToDelete, setNodeTypeIdToDelete] = useState<string>("");
const navigateToNode = (uid: string) => {
if (isPopup) {
setSelectedTabId(uid);
Expand All @@ -40,6 +47,15 @@ const DiscourseNodeConfigPanel: React.FC<DiscourseNodeConfigPanelProps> = ({
}
};

const deleteNodeType = async (uid: string) => {
await window.roamAlphaAPI.deletePage({
page: { uid },
});
setNodes((prevNodes) => prevNodes.filter((nn) => nn.type !== uid));
refreshConfigTree();
setDeleteConfirmation(null);
};

return (
<>
<ControlGroup className="mb-4 mt-1 flex space-x-2">
Expand Down Expand Up @@ -121,38 +137,100 @@ const DiscourseNodeConfigPanel: React.FC<DiscourseNodeConfigPanelProps> = ({
icon="trash"
minimal
onClick={() => {
if (deleteConfirmation) setDeleteConfirmation(null);
else setDeleteConfirmation(n.type);
if (deleteConfirmation === n.type) {
setDeleteConfirmation(null);
} else {
setDeleteConfirmation(n.type);
}
}}
/>
</Tooltip>
<Button
children="Confirm"
intent={Intent.DANGER}
onClick={() => {
window.roamAlphaAPI
.deletePage({ page: { uid: n.type } })
.then(() => {
setNodes(nodes.filter((nn) => nn.type !== n.type));
refreshConfigTree();
});
const affectedRelations = getDiscourseRelations().filter(
(r) => r.source === n.type || r.destination === n.type,
);

let dialogMessage = `Are you sure you want to delete the Node Type "${n.text}"?`;

if (affectedRelations.length > 0) {
dialogMessage = `The Node Type "${n.text}" is used by the following relations, which will also be deleted:\n\n${affectedRelations
.map((r) => {
const sourceNodeDetails = nodes.find(
(s) => s.type === r.source,
);
const destinationNodeDetails = nodes.find(
(d) => d.type === r.destination,
);
return `- ${sourceNodeDetails?.text || r.source} ${r.label} ${destinationNodeDetails?.text || r.destination}`;
})
.join("\n")}\n\nProceed with deletion?`;
setIsAlertOpen(true);
setAlertMessage(dialogMessage);
setAffectedRelations(affectedRelations);
setNodeTypeIdToDelete(n.type);
} else {
deleteNodeType(n.type);
}
}}
className={`mx-1 ${
deleteConfirmation !== n.type ? "opacity-0" : ""
}`}
/>
>
Confirm
</Button>
<Button
children="Cancel"
onClick={() => setDeleteConfirmation(null)}
className={`mx-1 ${
deleteConfirmation !== n.type ? "opacity-0" : ""
}`}
/>
>
Cancel
</Button>
</td>
</tr>
))}
</tbody>
</HTMLTable>

<Alert
isOpen={isAlertOpen}
onConfirm={async () => {
if (affectedRelations.length > 0) {
try {
for (const rel of affectedRelations) {
await deleteBlock(rel.id).catch((error) => {
console.error(
`Failed to delete relation: ${rel.id}, ${error.message}`,
);
throw error;
});
}
deleteNodeType(nodeTypeIdToDelete);
} catch (error) {
console.error(
`Failed to complete deletion for UID: ${nodeTypeIdToDelete}): ${error instanceof Error ? error.message : String(error)}`,
);
} finally {
setIsAlertOpen(false);
}
}
}}
onCancel={() => {
setIsAlertOpen(false);
setDeleteConfirmation(null);
}}
intent={Intent.DANGER}
confirmButtonText="Delete"
cancelButtonText="Cancel"
canEscapeKeyCancel={true}
canOutsideClickCancel={true}
>
<div style={{ whiteSpace: "pre-wrap", wordBreak: "break-word" }}>
{alertMessage}
</div>
</Alert>
</>
);
};
Expand Down