Skip to content

Commit 79fe3e3

Browse files
committed
Datacore views correctly update paths on renames
Also adds the datacore 'rename' event.
1 parent aeac686 commit 79fe3e3

4 files changed

Lines changed: 68 additions & 37 deletions

File tree

src/api/local-api.tsx

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -231,13 +231,12 @@ export class DatacoreLocalApi {
231231

232232
/** Use the current path. Automatically updates the view if the path changes (though that would be weird). */
233233
public useCurrentPath(settings?: { debounce?: number }): string {
234-
const meta = this.useCurrentFile(settings);
235-
return meta.$path;
234+
return this.path;
236235
}
237236

238237
/** Use the file metadata for a specific file. Automatically updates the view when the file changes. */
239238
public useFile(path: string, settings?: { debounce?: number }): Indexable | undefined {
240-
return useFileMetadata(this.core, path, settings)!;
239+
return useFileMetadata(this.core, path, settings);
241240
}
242241

243242
/** Automatically refresh the view whenever the index updates; returns the latest index revision ID. */
@@ -403,17 +402,4 @@ export class DatacoreLocalApi {
403402
public Slider = Slider;
404403
public Switch = Switch;
405404
public VanillaSelect = VanillaSelect;
406-
407-
////////////////////////////////////
408-
// Stateful / internal components //
409-
////////////////////////////////////
410-
411-
/**
412-
* Updates the path for the local API; usually only called by the top-level script renderer on
413-
* path changes (such as renaming a file).
414-
* @internal
415-
*/
416-
updatePath(path: string): void {
417-
this.path = path;
418-
}
419405
}

src/index/datacore.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,11 @@ export class Datacore extends Component {
150150
// This is less optimal than what can probably be done, but paths are used in a bunch of places
151151
// (for sections, tasks, etc to refer to their parent file) and it requires some finesse to fix.
152152
this.datastore.delete(oldPath);
153-
this.reload(file);
153+
this.reload(file).then(() => this.trigger("rename", file.path, oldPath));
154154

155155
// TODO: For correctness, probably have to either fix links in all linked files OR
156-
// just stop normalizing links in the store.
156+
// just stop normalizing links in the store. We can traverse the links index to do so
157+
// but it is fairly painful.
157158
}
158159

159160
/**
@@ -182,7 +183,7 @@ export class Datacore extends Component {
182183
const result = await this.importer.import<ImportResult>(file);
183184

184185
if (result.type === "error") {
185-
throw new Error(`Failed to import file '${file.name}: ${result.$error}`);
186+
throw new Error(`Failed to import file '${file.name}': ${result.$error}`);
186187
} else if (result.type === "markdown") {
187188
// Parse the file and normalize metadata from it.
188189
const parsed = MarkdownPage.from(result.result, (link) => {
@@ -206,8 +207,14 @@ export class Datacore extends Component {
206207
if (rpath) return link.withPath(rpath.path);
207208
else return link;
208209
});
210+
211+
// Store it recursively into the datastore for querying.
209212
this.storeCanvas(parsed);
213+
214+
// Write it to the file cache for faster loads in the future.
210215
this.persister.storeFile(parsed.$path, parsed.json());
216+
217+
// And finally trigger an update.
211218
this.trigger("update", this.revision);
212219
return parsed;
213220
}
@@ -252,10 +259,15 @@ export class Datacore extends Component {
252259
});
253260
}
254261

255-
// Event propogation.
262+
///////////////////////
263+
// Event propogation //
264+
///////////////////////
256265

257266
/** Called whenever the index updates to a new revision. This is the broadest possible datacore event. */
258267
public on(evt: "update", callback: (revision: number) => any, context?: any): EventRef;
268+
/** Called whenever datacore records a file rename and has finished reindexing the rename. */
269+
public on(evt: "rename", callback: (newPath: string, oldPath: string) => any, context?: any): EventRef;
270+
/** Called when datacore has initialized and is querable. */
259271
public on(evt: "initialized", callback: () => any, context?: any): EventRef;
260272

261273
on(evt: string, callback: (...data: any) => any, context?: any): EventRef {
@@ -274,6 +286,8 @@ export class Datacore extends Component {
274286

275287
/** Trigger an update event. */
276288
private trigger(evt: "update", revision: number): void;
289+
/** Trigger a rename event. */
290+
private trigger(evt: "rename", newPath: string, oldPath: string): void;
277291
/** Trigger an initialization event. */
278292
private trigger(evt: "initialized"): void;
279293

src/ui/javascript.tsx

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { unmountComponentAtNode } from "preact/compat";
66
import { ScriptLanguage, asyncEvalInContext, transpile } from "utils/javascript";
77
import { LoadingBoundary, ScriptContainer } from "./loading-boundary";
88
import { Datacore } from "index/datacore";
9+
import { Literal } from "expression/literal";
910

1011
/**
1112
* Renders a script by executing it and handing it the appropriate React context to execute
@@ -38,22 +39,16 @@ export class DatacoreJSRenderer extends MarkdownRenderChild {
3839
});
3940
};
4041

41-
render(
42-
<DatacoreContextProvider
43-
app={this.api.app}
44-
component={this}
45-
datacore={this.api.core}
46-
settings={this.api.core.settings}
47-
>
48-
<CURRENT_FILE_CONTEXT.Provider value={this.path}>
49-
<SimpleErrorBoundary message="The datacore script failed to execute.">
50-
<LoadingBoundary datacore={this.api.core}>
51-
<ScriptContainer executor={renderer} sourcePath={this.path} />
52-
</LoadingBoundary>
53-
</SimpleErrorBoundary>
54-
</CURRENT_FILE_CONTEXT.Provider>
55-
</DatacoreContextProvider>,
56-
this.container
42+
this.renderScript(renderer);
43+
44+
// If the path ever changes, update the context provider and re-render.
45+
this.registerEvent(
46+
this.api.core.on("rename", (newPath, oldPath) => {
47+
if (oldPath === this.path) {
48+
this.path = this.api.path = newPath;
49+
this.renderScript(renderer);
50+
}
51+
})
5752
);
5853
} catch (ex) {
5954
render(
@@ -63,6 +58,27 @@ export class DatacoreJSRenderer extends MarkdownRenderChild {
6358
}
6459
}
6560

61+
/** Lazily renders a script, catching errors automatically. */
62+
private renderScript(renderer: () => Promise<Literal | VNode | Function>) {
63+
render(
64+
<DatacoreContextProvider
65+
app={this.api.app}
66+
component={this}
67+
datacore={this.api.core}
68+
settings={this.api.core.settings}
69+
>
70+
<CURRENT_FILE_CONTEXT.Provider value={this.path}>
71+
<SimpleErrorBoundary message="The datacore script failed to execute.">
72+
<LoadingBoundary datacore={this.api.core}>
73+
<ScriptContainer executor={renderer} sourcePath={this.path} />
74+
</LoadingBoundary>
75+
</SimpleErrorBoundary>
76+
</CURRENT_FILE_CONTEXT.Provider>
77+
</DatacoreContextProvider>,
78+
this.container
79+
);
80+
}
81+
6682
public onunload(): void {
6783
if (this.loaded) unmountComponentAtNode(this.container);
6884
this.loaded = false;
@@ -82,6 +98,21 @@ export class ReactRenderer extends MarkdownRenderChild {
8298
}
8399

84100
public onload(): void {
101+
this.renderElement();
102+
103+
// If the path ever changes, update the context provider and re-render.
104+
this.registerEvent(
105+
this.datacore.on("rename", (newPath, oldPath) => {
106+
if (oldPath === this.sourcePath) {
107+
this.sourcePath = newPath;
108+
this.renderElement();
109+
}
110+
})
111+
);
112+
}
113+
114+
/** Render the given element. */
115+
private renderElement(): void {
85116
render(
86117
<DatacoreContextProvider
87118
app={this.app}

src/ui/loading-boundary.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export function ScriptContainer({
6767
executor()
6868
.then((result) => setElement(makeRenderableElement(result, sourcePath)))
6969
.catch((error) => setError(error));
70-
}, [executor]);
70+
}, [executor, sourcePath]);
7171

7272
// Propogate error upwards.
7373
if (error) {

0 commit comments

Comments
 (0)