Skip to content

Commit 1688bf3

Browse files
committed
Release v1.4.2
1 parent 3815d19 commit 1688bf3

37 files changed

Lines changed: 38439 additions & 27069 deletions

main.js

Lines changed: 32324 additions & 22308 deletions
Large diffs are not rendered by default.

manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"id": "discourse-graphs",
33
"name": "Discourse Graph",
4-
"version": "1.3.0",
4+
"version": "1.4.2",
55
"minAppVersion": "1.7.0",
66
"description": "Add semantic structure to your notes with the Discourse Graph protocol.",
77
"author": "Discourse Graphs",

plugin.zip

4.86 MB
Binary file not shown.

scripts/compile.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/* eslint-disable @typescript-eslint/naming-convention */
21
import esbuild from "esbuild";
32
import fs from "fs";
43
import path from "path";

scripts/publish.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ const createGithubRelease = async ({
447447
const octokit = new Octokit({ auth: token });
448448
const owner = OWNER;
449449
const repo = REPO;
450-
const tagName = `${version}`;
450+
const tagName = `v${version}`;
451451
const releaseTitle = releaseName || `Discourse Graph v${version}`;
452452
const isPrerelease = !isExternalRelease(version);
453453

src/components/AdminPanelSettings.tsx

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { useState, useCallback } from "react";
22
import { usePlugin } from "./PluginContext";
3-
import { Notice } from "obsidian";
3+
import { Notice, setIcon } from "obsidian";
44
import { updateUsername } from "~/utils/supabaseContext";
55
import { initializeSupabaseSync } from "~/utils/syncDgNodesToSupabase";
6+
import { nextRoot } from "@repo/utils/execContext";
7+
import { getLoggedInClient } from "~/utils/supabaseContext";
68

79
export const AdminPanelSettings = () => {
810
const plugin = usePlugin();
@@ -41,6 +43,33 @@ export const AdminPanelSettings = () => {
4143
await updateUsername(plugin, newValue);
4244
};
4345

46+
const handleLoginHandoff = async () => {
47+
const client = await getLoggedInClient(plugin);
48+
if (!client) {
49+
new Notice("Failed to connect to the database", 3000);
50+
return;
51+
}
52+
const sessionData = await client.auth.getSession();
53+
if (!sessionData.data.session) {
54+
new Notice("Failed to connect to the database", 3000);
55+
return;
56+
}
57+
const { access_token, refresh_token } = sessionData.data.session;
58+
const { data, error } = await client.rpc("create_secret_token", {
59+
v_payload: JSON.stringify({ access_token, refresh_token }),
60+
expiry_interval: "45s",
61+
});
62+
if (error || typeof data !== "string") {
63+
new Notice("Failed to connect to the database", 3000);
64+
return;
65+
}
66+
if (data)
67+
window.open(
68+
`${nextRoot()}auth/token?t=${data}&url=/auth/group`,
69+
"_blank",
70+
);
71+
};
72+
4473
return (
4574
<div className="general-settings">
4675
<div className="setting-item">
@@ -80,6 +109,31 @@ export const AdminPanelSettings = () => {
80109
/>
81110
</div>
82111
</div>
112+
<div
113+
className={
114+
"setting-item " + (plugin.settings.syncModeEnabled ? "" : "hidden")
115+
}
116+
>
117+
<div className="setting-item-info">
118+
<div className="setting-item-name">Group management</div>
119+
<div className="setting-item-description">
120+
This will allow you to view and manage your sharing groups
121+
</div>
122+
</div>
123+
<div className="setting-item-control">
124+
<button
125+
onClick={() => {
126+
void handleLoginHandoff();
127+
}}
128+
>
129+
Manage groups
130+
<span
131+
className="icon"
132+
ref={(el) => (el && setIcon(el, "arrow-up-right")) || undefined}
133+
/>
134+
</button>
135+
</div>
136+
</div>
83137
</div>
84138
);
85139
};

src/components/DiscourseContextView.tsx

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ type InfoTooltipProps = {
3131
content: string;
3232
};
3333

34-
const InfoTooltip = ({ content }: InfoTooltipProps) => (
34+
export const InfoTooltip = ({ content }: InfoTooltipProps) => (
3535
<button
3636
ref={(el) => {
3737
if (el) setTooltip(el, content);
@@ -243,7 +243,14 @@ const DiscourseContext = ({ activeFile }: DiscourseContextProps) => {
243243
View only
244244
</span>
245245
<InfoTooltip
246-
content={`Imported from ${formattedVaultName}. Direct edits will be overwritten when refreshed.`}
246+
content={
247+
`Imported from ${formattedVaultName}. ` +
248+
(frontmatter.authorId &&
249+
typeof frontmatter.authorId === "number"
250+
? `By ${getUserNameById(plugin, frontmatter.authorId)}. `
251+
: "") +
252+
"Direct edits will be overwritten when refreshed."
253+
}
247254
/>
248255
</div>
249256
)}
@@ -255,15 +262,6 @@ const DiscourseContext = ({ activeFile }: DiscourseContextProps) => {
255262
</div>
256263
)}
257264

258-
{isImported &&
259-
frontmatter.authorId &&
260-
typeof frontmatter.authorId === "number" && (
261-
<div className="text-modifier-text mt-2 text-xs">
262-
<div>
263-
Author: {getUserNameById(plugin, frontmatter.authorId)}
264-
</div>
265-
</div>
266-
)}
267265
{isImported && sourceDates && (
268266
<div className="text-modifier-text mt-2 text-xs">
269267
<div>Created in source: {sourceDates.createdAt}</div>

src/components/GeneralSettings.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ const GeneralSettings = () => {
301301
handleNodeTagHotkeyChange("");
302302
}
303303
}}
304-
placeholder="\\"
304+
placeholder="\"
305305
maxLength={1}
306306
/>
307307
</div>

src/components/InlineNodeTypePicker.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { Editor } from "obsidian";
1+
import { Editor, MarkdownView } from "obsidian";
22
import { DiscourseNode } from "~/types";
3-
import { createDiscourseNode } from "~/utils/createNode";
43
import type DiscourseGraphPlugin from "~/index";
4+
import { createModifyNodeModalSubmitHandler } from "~/utils/registerCommands";
5+
import ModifyNodeModal from "./ModifyNodeModal";
56

67
/**
78
* A popover that shows all node types inline near the cursor/selection.
@@ -98,7 +99,7 @@ export class InlineNodeTypePicker {
9899
itemEl.addEventListener("mousedown", (e) => {
99100
e.preventDefault();
100101
e.stopPropagation();
101-
void this.selectItem(item);
102+
this.selectItem(item);
102103
});
103104

104105
itemEl.addEventListener("mouseenter", () => {
@@ -138,14 +139,22 @@ export class InlineNodeTypePicker {
138139
}
139140
}
140141

141-
private async selectItem(item: DiscourseNode) {
142+
private selectItem(item: DiscourseNode) {
142143
this.close();
143-
await createDiscourseNode({
144+
const currentFile =
145+
this.options.plugin.app.workspace.getActiveViewOfType(MarkdownView)
146+
?.file || undefined;
147+
new ModifyNodeModal(this.options.plugin.app, {
148+
nodeTypes: this.options.plugin.settings.nodeTypes,
144149
plugin: this.options.plugin,
145-
nodeType: item,
146-
text: this.options.selectedText,
147-
editor: this.options.editor,
148-
});
150+
initialTitle: this.options.selectedText,
151+
initialNodeType: item,
152+
currentFile,
153+
onSubmit: createModifyNodeModalSubmitHandler(
154+
this.options.plugin,
155+
this.options.editor,
156+
),
157+
}).open();
149158
}
150159

151160
private setupEventHandlers() {
@@ -173,7 +182,7 @@ export class InlineNodeTypePicker {
173182
e.stopPropagation();
174183
const selectedItem = this.items[this.selectedIndex];
175184
if (selectedItem) {
176-
void this.selectItem(selectedItem);
185+
this.selectItem(selectedItem);
177186
}
178187
} else if (e.key === "Escape") {
179188
e.preventDefault();

src/components/ModifyNodeModal.tsx

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,13 @@ type ModifyNodeFormProps = {
5353
onCancel: () => void;
5454
initialTitle?: string;
5555
initialNodeType?: DiscourseNode;
56-
initialFile?: TFile; // for edit mode
57-
currentFile?: TFile; // the file where the node is being created from
56+
/** Present in edit mode — the file being modified. Also drives `isEditMode`. */
57+
initialFile?: TFile;
58+
/** Context file for the "Relationship with …" block (editor "Turn into" flow). */
59+
currentFile?: TFile;
60+
/** Hides the search-existing-nodes dropdown. Used when intent is always to create
61+
* (e.g. file explorer "Convert into"), not to reuse an existing node. */
62+
disableExistingNodeSearch?: boolean;
5863
plugin: DiscourseGraphPlugin;
5964
};
6065

@@ -66,6 +71,7 @@ export const ModifyNodeForm = ({
6671
initialNodeType,
6772
initialFile,
6873
currentFile,
74+
disableExistingNodeSearch = false,
6975
plugin,
7076
}: ModifyNodeFormProps) => {
7177
const isEditMode = !!initialFile;
@@ -95,9 +101,9 @@ export const ModifyNodeForm = ({
95101
[selectedNodeType],
96102
);
97103

98-
// Search for nodes when query changes (only in create mode)
104+
// Search for nodes when query changes (only in create mode, and only when search is enabled)
99105
useEffect(() => {
100-
if (isEditMode) {
106+
if (isEditMode || disableExistingNodeSearch) {
101107
setSearchResults([]);
102108
return;
103109
}
@@ -137,16 +143,23 @@ export const ModifyNodeForm = ({
137143
clearTimeout(debounceTimeoutRef.current);
138144
}
139145
};
140-
}, [query, selectedNodeType, isEditMode]);
146+
}, [query, selectedNodeType, isEditMode, disableExistingNodeSearch]);
141147

142148
const isOpen = useMemo(() => {
143149
return (
150+
!disableExistingNodeSearch &&
144151
!selectedExistingNode &&
145152
isFocused &&
146153
searchResults.length > 0 &&
147154
query.trim().length >= 2
148155
);
149-
}, [selectedExistingNode, isFocused, searchResults.length, query]);
156+
}, [
157+
disableExistingNodeSearch,
158+
selectedExistingNode,
159+
isFocused,
160+
searchResults.length,
161+
query,
162+
]);
150163

151164
useEffect(() => {
152165
setActiveIndex(0);
@@ -177,9 +190,14 @@ export const ModifyNodeForm = ({
177190
}
178191
}, [activeIndex, isOpen]);
179192

180-
// Focus the content input on mount so users can start typing immediately
193+
// Focus the content input on mount so users can start typing immediately,
194+
// with cursor placed at the end of any pre-filled text
181195
useEffect(() => {
182-
titleInputRef.current?.focus();
196+
const el = titleInputRef.current;
197+
if (!el) return;
198+
el.focus();
199+
const len = el.value.length;
200+
el.setSelectionRange(len, len);
183201
}, []);
184202

185203
useEffect(() => {
@@ -449,15 +467,19 @@ export const ModifyNodeForm = ({
449467
placeholder={
450468
isEditMode
451469
? "Enter new content"
452-
: selectedNodeType
453-
? `Search for existing ${selectedNodeType.name.toLowerCase()} or enter new content`
454-
: "Search for existing nodes or enter new content"
470+
: disableExistingNodeSearch
471+
? selectedNodeType
472+
? `Enter ${selectedNodeType.name.toLowerCase()} content`
473+
: "Enter content"
474+
: selectedNodeType
475+
? `Search for existing ${selectedNodeType.name.toLowerCase()} or enter new content`
476+
: "Search for existing nodes or enter new content"
455477
}
456478
value={query}
457479
onChange={handleQueryChange}
458480
onKeyDown={handleKeyDown}
459481
onFocus={() => {
460-
if (!isEditMode) {
482+
if (!isEditMode && !disableExistingNodeSearch) {
461483
setIsFocused(true);
462484
}
463485
}}
@@ -604,8 +626,12 @@ type ModifyNodeModalProps = {
604626
}) => Promise<void>;
605627
initialTitle?: string;
606628
initialNodeType?: DiscourseNode;
629+
/** Present in edit mode — the file being modified. */
607630
initialFile?: TFile;
631+
/** Context file for the "Relationship with …" block (editor "Turn into" flow). */
608632
currentFile?: TFile;
633+
/** See `ModifyNodeFormProps.disableExistingNodeSearch`. */
634+
disableExistingNodeSearch?: boolean;
609635
};
610636

611637
class ModifyNodeModal extends Modal {
@@ -623,6 +649,7 @@ class ModifyNodeModal extends Modal {
623649
private initialNodeType?: DiscourseNode;
624650
private initialFile?: TFile;
625651
private currentFile?: TFile;
652+
private disableExistingNodeSearch: boolean;
626653
private plugin: DiscourseGraphPlugin;
627654

628655
constructor(app: App, props: ModifyNodeModalProps) {
@@ -633,6 +660,7 @@ class ModifyNodeModal extends Modal {
633660
this.initialNodeType = props.initialNodeType;
634661
this.initialFile = props.initialFile;
635662
this.currentFile = props.currentFile;
663+
this.disableExistingNodeSearch = props.disableExistingNodeSearch ?? false;
636664
this.plugin = props.plugin;
637665
}
638666

@@ -651,6 +679,7 @@ class ModifyNodeModal extends Modal {
651679
initialNodeType={this.initialNodeType}
652680
initialFile={this.initialFile}
653681
currentFile={this.currentFile}
682+
disableExistingNodeSearch={this.disableExistingNodeSearch}
654683
plugin={this.plugin}
655684
/>
656685
</StrictMode>,

0 commit comments

Comments
 (0)