alinea 0.5.4 → 0.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backend/Database.js +3 -2
- package/dist/backend/Store.js +1 -1
- package/dist/backend/resolver/EntryResolver.js +5 -2
- package/dist/chunks/{chunk-TY7XOXM3.js → chunk-CYNFUAZ7.js} +3 -1
- package/dist/chunks/{chunk-TBAB475U.js → chunk-HWXESJ6U.js} +1 -1
- package/dist/chunks/{chunk-VRXHB6DJ.js → chunk-LMUDRU2U.js} +2 -1
- package/dist/chunks/{sql.js-75HGQX6U.js → sql.js-RSY2XONK.js} +1 -1
- package/dist/cli/Generate.js +1 -1
- package/dist/cli/Serve.js +2 -2
- package/dist/cli/bin.js +1 -1
- package/dist/cli/generate/GenerateDashboard.js +1 -1
- package/dist/cloud/server/CloudAuthServer.js +1 -1
- package/dist/core/EntrySearch.d.ts +1 -0
- package/dist/core/EntrySearch.js +1 -0
- package/dist/core/Shape.d.ts +1 -1
- package/dist/core/Tracker.d.ts +2 -2
- package/dist/core/Tracker.js +2 -0
- package/dist/core/Type.d.ts +1 -0
- package/dist/core/Type.js +4 -0
- package/dist/core/Type.test.d.ts +1 -0
- package/dist/core/driver/TestDriver.js +1 -1
- package/dist/core/field/RichTextField.d.ts +3 -1
- package/dist/core/field/RichTextField.js +2 -1
- package/dist/core/field/ScalarField.d.ts +3 -1
- package/dist/core/field/ScalarField.js +5 -1
- package/dist/core/shape/ListShape.d.ts +1 -0
- package/dist/core/shape/ListShape.js +13 -0
- package/dist/core/shape/RecordShape.d.ts +1 -0
- package/dist/core/shape/RecordShape.js +8 -0
- package/dist/core/shape/RichTextShape.d.ts +5 -2
- package/dist/core/shape/RichTextShape.js +26 -1
- package/dist/core/shape/ScalarShape.d.ts +3 -1
- package/dist/core/shape/ScalarShape.js +8 -1
- package/dist/core/shape/UnionShape.d.ts +1 -0
- package/dist/core/shape/UnionShape.js +16 -0
- package/dist/core/util/EntryRows.js +4 -1
- package/dist/dashboard/atoms/FormAtoms.d.ts +5 -5
- package/dist/dashboard/atoms/FormAtoms.js +7 -7
- package/dist/dashboard/editor/UseField.js +3 -3
- package/dist/dashboard/hook/UseExplorer.d.ts +1 -0
- package/dist/dashboard/util/PersistentStore.js +1 -1
- package/dist/dashboard/view/entry/EntrySummary.js +2 -2
- package/dist/dashboard/view/entry/NewEntry.js +63 -26
- package/dist/dashboard/view/explorer/Explorer.d.ts +1 -0
- package/dist/dashboard/view/explorer/ExplorerItem.js +1 -1
- package/dist/index.css +3 -2
- package/dist/input/richtext/RichTextField.d.ts +2 -6
- package/dist/input/text/TextField.d.ts +2 -0
- package/dist/picker/entry/EntryPicker.browser.js +2 -1
- package/package.json +1 -1
package/dist/backend/Database.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
alias,
|
|
6
6
|
create,
|
|
7
7
|
exists
|
|
8
|
-
} from "../chunks/chunk-
|
|
8
|
+
} from "../chunks/chunk-CYNFUAZ7.js";
|
|
9
9
|
import {
|
|
10
10
|
Expr
|
|
11
11
|
} from "../chunks/chunk-4JLFL6LD.js";
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
PageSeed,
|
|
18
18
|
Root,
|
|
19
19
|
Schema,
|
|
20
|
+
Type,
|
|
20
21
|
Workspace,
|
|
21
22
|
createId,
|
|
22
23
|
unreachable
|
|
@@ -438,7 +439,7 @@ ${JSON.stringify(mutation)}`
|
|
|
438
439
|
...data,
|
|
439
440
|
path: pathData
|
|
440
441
|
};
|
|
441
|
-
const searchableText =
|
|
442
|
+
const searchableText = Type.searchableText(type, entryData);
|
|
442
443
|
return {
|
|
443
444
|
workspace: meta.workspace,
|
|
444
445
|
root: meta.root,
|
package/dist/backend/Store.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
|
+
bm25,
|
|
2
3
|
count,
|
|
3
4
|
iif,
|
|
4
5
|
match,
|
|
5
6
|
withRecursive
|
|
6
|
-
} from "../../chunks/chunk-
|
|
7
|
+
} from "../../chunks/chunk-CYNFUAZ7.js";
|
|
7
8
|
import {
|
|
8
9
|
BinOpType,
|
|
9
10
|
Expr,
|
|
@@ -365,7 +366,9 @@ var EntryResolver = class {
|
|
|
365
366
|
extra.singleResult = true;
|
|
366
367
|
if (groupBy)
|
|
367
368
|
extra.groupBy = groupBy.map((expr) => this.expr(ctx, expr));
|
|
368
|
-
if (
|
|
369
|
+
if (searchTerms)
|
|
370
|
+
extra.orderBy = [bm25(EntrySearch, 20, 1).asc()];
|
|
371
|
+
else if (orderBy)
|
|
369
372
|
extra.orderBy = this.orderBy(ctx, orderBy);
|
|
370
373
|
return query[Query.Data].with(extra);
|
|
371
374
|
}
|
|
@@ -335,8 +335,8 @@ var AsyncDriver = class extends DriverBase {
|
|
|
335
335
|
}
|
|
336
336
|
}
|
|
337
337
|
async transaction(run) {
|
|
338
|
-
const id = `t${this.transactionId++}`;
|
|
339
338
|
const [connection, release] = await this.isolate();
|
|
339
|
+
const id = `t${this.transactionId++}`;
|
|
340
340
|
await connection.executeQuery(
|
|
341
341
|
new QueryData.Transaction({ op: QueryData.TransactionOperation.Begin, id })
|
|
342
342
|
);
|
|
@@ -1353,6 +1353,7 @@ var SqliteFormatter = class extends Formatter {
|
|
|
1353
1353
|
stmt.raw(" MATCH ");
|
|
1354
1354
|
this.formatExprValue(ctx, query);
|
|
1355
1355
|
return stmt;
|
|
1356
|
+
case "bm25":
|
|
1356
1357
|
case "highlight":
|
|
1357
1358
|
case "snippet":
|
|
1358
1359
|
stmt.identifier(expr.method);
|
package/dist/cli/Generate.js
CHANGED
|
@@ -27,7 +27,7 @@ function generatePackage(context, config) {
|
|
|
27
27
|
async function createDb() {
|
|
28
28
|
const { default: sqlite } = await import("@alinea/sqlite-wasm");
|
|
29
29
|
const { Database } = await sqlite();
|
|
30
|
-
const { connect } = await import("../chunks/sql.js-
|
|
30
|
+
const { connect } = await import("../chunks/sql.js-RSY2XONK.js");
|
|
31
31
|
const db = new Database();
|
|
32
32
|
const store = connect(db).toAsync();
|
|
33
33
|
return [store, () => db.export()];
|
package/dist/cli/Serve.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
package_default
|
|
3
|
-
} from "../chunks/chunk-
|
|
3
|
+
} from "../chunks/chunk-HWXESJ6U.js";
|
|
4
4
|
import "../chunks/chunk-U5RRZUYZ.js";
|
|
5
5
|
|
|
6
6
|
// src/cli/Serve.ts
|
|
@@ -49,7 +49,7 @@ async function serve(options) {
|
|
|
49
49
|
liveReload: new LiveReload()
|
|
50
50
|
};
|
|
51
51
|
server.then(async () => {
|
|
52
|
-
console.log(` \x1B[
|
|
52
|
+
console.log(` \x1B[36m\u03B1 Alinea ${package_default.version}\x1B[39m`);
|
|
53
53
|
console.log(` - Local CMS: ${await dashboardUrl}
|
|
54
54
|
`);
|
|
55
55
|
});
|
package/dist/cli/bin.js
CHANGED
|
@@ -2,5 +2,6 @@ import { table } from 'rado';
|
|
|
2
2
|
export declare const EntrySearch: import("rado").Table<{
|
|
3
3
|
title: import("rado").ValueColumn<string>;
|
|
4
4
|
searchableText: import("rado").ValueColumn<string>;
|
|
5
|
+
rank: import("rado").ValueColumn<number>;
|
|
5
6
|
}>;
|
|
6
7
|
export type EntrySearch = table<typeof EntrySearch>;
|
package/dist/core/EntrySearch.js
CHANGED
package/dist/core/Shape.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export interface Shape<Value = any, Mutator = any> {
|
|
|
12
12
|
init(parent: YType, key: string): void;
|
|
13
13
|
watch(parent: YType, key: string): (fun: () => void) => () => void;
|
|
14
14
|
mutator(parent: YType, key: string, readOnly: boolean): Mutator;
|
|
15
|
-
toString(): string;
|
|
16
15
|
applyLinks(value: Value, loader: LinkResolver): Promise<void>;
|
|
16
|
+
searchableText(value: Value): string;
|
|
17
17
|
}
|
|
18
18
|
export {};
|
package/dist/core/Tracker.d.ts
CHANGED
|
@@ -15,6 +15,6 @@ export interface MutationTracker {
|
|
|
15
15
|
export declare function optionTrackerOf(field: Field): OptionsTracker<any> | undefined;
|
|
16
16
|
export declare function valueTrackerOf(field: Field): ValueTracker<any> | undefined;
|
|
17
17
|
export declare namespace track {
|
|
18
|
-
function options<Value, OnChange, Options extends FieldOptions<Value>>(field: Field<Value, OnChange, Options>, tracker: OptionsTracker<Options>):
|
|
19
|
-
function value<Value>(field: Field<Value>, tracker: ValueTracker<Value>):
|
|
18
|
+
function options<Value, OnChange, Options extends FieldOptions<Value>>(field: Field<Value, OnChange, Options>, tracker: OptionsTracker<Options>): Field<Value, OnChange, Options>;
|
|
19
|
+
function value<Value>(field: Field<Value>, tracker: ValueTracker<Value>): Field<Value>;
|
|
20
20
|
}
|
package/dist/core/Tracker.js
CHANGED
|
@@ -14,10 +14,12 @@ var track;
|
|
|
14
14
|
((track2) => {
|
|
15
15
|
function options(field, tracker) {
|
|
16
16
|
optionTrackers.set(Field.ref(field), tracker);
|
|
17
|
+
return field;
|
|
17
18
|
}
|
|
18
19
|
track2.options = options;
|
|
19
20
|
function value(field, tracker) {
|
|
20
21
|
valueTrackers.set(Field.ref(field), tracker);
|
|
22
|
+
return field;
|
|
21
23
|
}
|
|
22
24
|
track2.value = value;
|
|
23
25
|
})(track || (track = {}));
|
package/dist/core/Type.d.ts
CHANGED
|
@@ -64,6 +64,7 @@ export declare namespace Type {
|
|
|
64
64
|
function label(type: Type): Label;
|
|
65
65
|
function meta(type: Type): TypeMeta;
|
|
66
66
|
function shape(type: Type): RecordShape;
|
|
67
|
+
function searchableText(type: Type, value: any): string;
|
|
67
68
|
function fields(type: Type): Record<string, Field>;
|
|
68
69
|
function hint(type: Type): Hint;
|
|
69
70
|
function sections(type: Type): Section[];
|
package/dist/core/Type.js
CHANGED
|
@@ -34,6 +34,10 @@ var Type;
|
|
|
34
34
|
return type2[Type2.Data].shape;
|
|
35
35
|
}
|
|
36
36
|
Type2.shape = shape;
|
|
37
|
+
function searchableText(type2, value) {
|
|
38
|
+
return shape(type2).searchableText(value).trim();
|
|
39
|
+
}
|
|
40
|
+
Type2.searchableText = searchableText;
|
|
37
41
|
function fields(type2) {
|
|
38
42
|
return type2;
|
|
39
43
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -2,7 +2,9 @@ import { RichTextMutator } from 'alinea/core';
|
|
|
2
2
|
import { Field, FieldMeta, FieldOptions } from '../Field.js';
|
|
3
3
|
import { TextDoc } from '../TextDoc.js';
|
|
4
4
|
import { RecordShape } from '../shape/RecordShape.js';
|
|
5
|
-
export declare class RichTextField<Blocks, Options extends FieldOptions<TextDoc<Blocks
|
|
5
|
+
export declare class RichTextField<Blocks, Options extends FieldOptions<TextDoc<Blocks>> & {
|
|
6
|
+
searchable?: boolean;
|
|
7
|
+
}> extends Field<TextDoc<Blocks>, RichTextMutator<Blocks>, Options> {
|
|
6
8
|
constructor(shape: {
|
|
7
9
|
[key: string]: RecordShape<any>;
|
|
8
10
|
} | undefined, meta: FieldMeta<TextDoc<Blocks>, RichTextMutator<Blocks>, Options>);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Field, FieldMeta, FieldOptions } from '../Field.js';
|
|
2
|
-
export declare class ScalarField<Value, Options extends FieldOptions<Value
|
|
2
|
+
export declare class ScalarField<Value, Options extends FieldOptions<Value> & {
|
|
3
|
+
searchable?: boolean;
|
|
4
|
+
}> extends Field<Value, (value: Value) => void, Options> {
|
|
3
5
|
constructor(meta: FieldMeta<Value, (value: Value) => void, Options>);
|
|
4
6
|
}
|
|
@@ -6,7 +6,11 @@ import { ScalarShape } from "../shape/ScalarShape.js";
|
|
|
6
6
|
var ScalarField = class extends Field {
|
|
7
7
|
constructor(meta) {
|
|
8
8
|
super({
|
|
9
|
-
shape: new ScalarShape(
|
|
9
|
+
shape: new ScalarShape(
|
|
10
|
+
meta.options.label,
|
|
11
|
+
meta.options.initialValue,
|
|
12
|
+
meta.options.searchable
|
|
13
|
+
),
|
|
10
14
|
...meta
|
|
11
15
|
});
|
|
12
16
|
}
|
|
@@ -206,6 +206,19 @@ var ListShape = class {
|
|
|
206
206
|
if (this.postProcess)
|
|
207
207
|
await this.postProcess(value, loader);
|
|
208
208
|
}
|
|
209
|
+
searchableText(value) {
|
|
210
|
+
let res = "";
|
|
211
|
+
const rows = Array.isArray(value) ? value : [];
|
|
212
|
+
for (const row of rows) {
|
|
213
|
+
const id = row.id;
|
|
214
|
+
const type = row.type;
|
|
215
|
+
const shape = this.values[type];
|
|
216
|
+
if (!id || !type || !shape)
|
|
217
|
+
continue;
|
|
218
|
+
res += shape.searchableText(row);
|
|
219
|
+
}
|
|
220
|
+
return res;
|
|
221
|
+
}
|
|
209
222
|
};
|
|
210
223
|
export {
|
|
211
224
|
ListShape
|
|
@@ -81,6 +81,14 @@ var RecordShape = class _RecordShape {
|
|
|
81
81
|
}
|
|
82
82
|
await Promise.all(tasks);
|
|
83
83
|
}
|
|
84
|
+
searchableText(value) {
|
|
85
|
+
let res = "";
|
|
86
|
+
const self = value || {};
|
|
87
|
+
for (const key of keys(this.properties)) {
|
|
88
|
+
res += this.properties[key].searchableText(self[key]);
|
|
89
|
+
}
|
|
90
|
+
return res;
|
|
91
|
+
}
|
|
84
92
|
};
|
|
85
93
|
export {
|
|
86
94
|
RecordShape
|
|
@@ -2,7 +2,7 @@ import { LinkResolver } from 'alinea/backend/resolver/LinkResolver';
|
|
|
2
2
|
import * as Y from 'yjs';
|
|
3
3
|
import { Label } from '../Label.js';
|
|
4
4
|
import { Shape } from '../Shape.js';
|
|
5
|
-
import { TextDoc } from '../TextDoc.js';
|
|
5
|
+
import { TextDoc, TextNode } from '../TextDoc.js';
|
|
6
6
|
import { RecordShape } from './RecordShape.js';
|
|
7
7
|
export type RichTextMutator<R> = {
|
|
8
8
|
readOnly: boolean;
|
|
@@ -25,8 +25,9 @@ export declare class RichTextShape<Blocks> implements Shape<TextDoc<Blocks>, Ric
|
|
|
25
25
|
label: Label;
|
|
26
26
|
shapes?: Record<string, RecordShape<object>> | undefined;
|
|
27
27
|
initialValue?: TextDoc<Blocks> | undefined;
|
|
28
|
+
searchable?: boolean | undefined;
|
|
28
29
|
values: Record<string, RecordShape>;
|
|
29
|
-
constructor(label: Label, shapes?: Record<string, RecordShape<object>> | undefined, initialValue?: TextDoc<Blocks> | undefined);
|
|
30
|
+
constructor(label: Label, shapes?: Record<string, RecordShape<object>> | undefined, initialValue?: TextDoc<Blocks> | undefined, searchable?: boolean | undefined);
|
|
30
31
|
create(): TextDoc<Blocks>;
|
|
31
32
|
toXml(rows: TextDoc<Blocks>): (Y.XmlElement<{
|
|
32
33
|
[key: string]: string;
|
|
@@ -43,4 +44,6 @@ export declare class RichTextShape<Blocks> implements Shape<TextDoc<Blocks>, Ric
|
|
|
43
44
|
insert: (id: string, block: string) => void;
|
|
44
45
|
};
|
|
45
46
|
applyLinks(doc: TextDoc<Blocks>, loader: LinkResolver): Promise<void>;
|
|
47
|
+
searchableText(value: TextDoc<Blocks>): string;
|
|
48
|
+
textOf(node: TextNode<any>): string;
|
|
46
49
|
}
|
|
@@ -76,10 +76,11 @@ function unserialize(node) {
|
|
|
76
76
|
}
|
|
77
77
|
var linkInfoFields = void 0;
|
|
78
78
|
var RichTextShape = class {
|
|
79
|
-
constructor(label, shapes, initialValue) {
|
|
79
|
+
constructor(label, shapes, initialValue, searchable) {
|
|
80
80
|
this.label = label;
|
|
81
81
|
this.shapes = shapes;
|
|
82
82
|
this.initialValue = initialValue;
|
|
83
|
+
this.searchable = searchable;
|
|
83
84
|
this.values = shapes ? fromEntries(
|
|
84
85
|
entries(shapes).map(([key, value]) => {
|
|
85
86
|
return [
|
|
@@ -298,6 +299,30 @@ var RichTextShape = class {
|
|
|
298
299
|
)
|
|
299
300
|
);
|
|
300
301
|
}
|
|
302
|
+
searchableText(value) {
|
|
303
|
+
let res = "";
|
|
304
|
+
if (!this.searchable)
|
|
305
|
+
return res;
|
|
306
|
+
if (!Array.isArray(value))
|
|
307
|
+
return res;
|
|
308
|
+
return value.reduce((acc, node) => {
|
|
309
|
+
return acc + this.textOf(node);
|
|
310
|
+
}, "");
|
|
311
|
+
}
|
|
312
|
+
textOf(node) {
|
|
313
|
+
if (this.values[node.type]) {
|
|
314
|
+
const shape = this.values[node.type];
|
|
315
|
+
return shape.searchableText(node);
|
|
316
|
+
}
|
|
317
|
+
if (node.type === "text")
|
|
318
|
+
return " " + node.text;
|
|
319
|
+
if ("content" in node && Array.isArray(node.content)) {
|
|
320
|
+
return node.content.reduce((acc, node2) => {
|
|
321
|
+
return acc + this.textOf(node2);
|
|
322
|
+
}, "");
|
|
323
|
+
}
|
|
324
|
+
return "";
|
|
325
|
+
}
|
|
301
326
|
};
|
|
302
327
|
function iterMarks(doc, fn) {
|
|
303
328
|
for (const row of doc) {
|
|
@@ -5,7 +5,8 @@ export type ScalarMutator<T> = (value: T) => void;
|
|
|
5
5
|
export declare class ScalarShape<T> implements Shape<T, ScalarMutator<T>> {
|
|
6
6
|
label: Label;
|
|
7
7
|
initialValue?: T | undefined;
|
|
8
|
-
|
|
8
|
+
searchable?: boolean | undefined;
|
|
9
|
+
constructor(label: Label, initialValue?: T | undefined, searchable?: boolean | undefined);
|
|
9
10
|
create(): T;
|
|
10
11
|
toY(value: T): T;
|
|
11
12
|
fromY(yValue: any): any;
|
|
@@ -14,4 +15,5 @@ export declare class ScalarShape<T> implements Shape<T, ScalarMutator<T>> {
|
|
|
14
15
|
watch(parent: Y.Map<any>, key: string): (fun: () => void) => () => void;
|
|
15
16
|
mutator(parent: Y.Map<any>, key: string, readOnly?: boolean): (value: T) => void;
|
|
16
17
|
applyLinks(): Promise<void>;
|
|
18
|
+
searchableText(value: T): string;
|
|
17
19
|
}
|
|
@@ -2,9 +2,10 @@ import "../../chunks/chunk-U5RRZUYZ.js";
|
|
|
2
2
|
|
|
3
3
|
// src/core/shape/ScalarShape.ts
|
|
4
4
|
var ScalarShape = class {
|
|
5
|
-
constructor(label, initialValue) {
|
|
5
|
+
constructor(label, initialValue, searchable) {
|
|
6
6
|
this.label = label;
|
|
7
7
|
this.initialValue = initialValue;
|
|
8
|
+
this.searchable = searchable;
|
|
8
9
|
}
|
|
9
10
|
create() {
|
|
10
11
|
return this.initialValue;
|
|
@@ -43,6 +44,12 @@ var ScalarShape = class {
|
|
|
43
44
|
}
|
|
44
45
|
async applyLinks() {
|
|
45
46
|
}
|
|
47
|
+
searchableText(value) {
|
|
48
|
+
if (!this.searchable)
|
|
49
|
+
return "";
|
|
50
|
+
const stringified = String(value ?? "");
|
|
51
|
+
return stringified ? " " + stringified : "";
|
|
52
|
+
}
|
|
46
53
|
};
|
|
47
54
|
export {
|
|
48
55
|
ScalarShape
|
|
@@ -26,4 +26,5 @@ export declare class UnionShape<T extends UnionRow> implements Shape<T, UnionMut
|
|
|
26
26
|
watch(parent: Y.Map<any>, key: string): (fun: () => void) => () => void;
|
|
27
27
|
mutator(parent: Y.Map<any>, key: string, readOnly: boolean): UnionMutator<T>;
|
|
28
28
|
applyLinks(value: T, loader: LinkResolver): Promise<void>;
|
|
29
|
+
searchableText(value: T): string;
|
|
29
30
|
}
|
|
@@ -122,6 +122,22 @@ var UnionShape = class {
|
|
|
122
122
|
if (this.postProcess)
|
|
123
123
|
await this.postProcess(value, loader);
|
|
124
124
|
}
|
|
125
|
+
searchableText(value) {
|
|
126
|
+
let res = "";
|
|
127
|
+
if (Array.isArray(value))
|
|
128
|
+
value = value[0] ?? {};
|
|
129
|
+
else
|
|
130
|
+
value = value ?? {};
|
|
131
|
+
const type = value.type;
|
|
132
|
+
const shape = this.shapes[type];
|
|
133
|
+
const self = value || {};
|
|
134
|
+
if (!shape)
|
|
135
|
+
return "";
|
|
136
|
+
for (const [key, field] of entries(shape.properties)) {
|
|
137
|
+
res += field.searchableText(self[key]);
|
|
138
|
+
}
|
|
139
|
+
return res;
|
|
140
|
+
}
|
|
125
141
|
};
|
|
126
142
|
export {
|
|
127
143
|
UnionShape
|
|
@@ -8,12 +8,15 @@ import { entryFilepath, entryInfo, entryUrl } from "../EntryFilenames.js";
|
|
|
8
8
|
import { createRecord } from "../EntryRecord.js";
|
|
9
9
|
import { EntryPhase } from "../EntryRow.js";
|
|
10
10
|
import { Root } from "../Root.js";
|
|
11
|
+
import { Type } from "../Type.js";
|
|
11
12
|
async function createEntryRow(config, input) {
|
|
12
13
|
const record = createRecord(input);
|
|
13
14
|
const fileContents = JsonLoader.format(config.schema, record);
|
|
14
15
|
const fileHash = await createFileHash(fileContents);
|
|
15
16
|
const rowHash = await createRowHash({ ...input, fileHash });
|
|
16
|
-
|
|
17
|
+
const type = config.schema[input.type];
|
|
18
|
+
const searchableText = Type.searchableText(type, input.data);
|
|
19
|
+
return { ...input, searchableText, fileHash, rowHash };
|
|
17
20
|
}
|
|
18
21
|
function entryParentPaths(config, entry) {
|
|
19
22
|
const root = Root.data(config.workspaces[entry.workspace][entry.root]);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Field,
|
|
2
|
-
import { Atom
|
|
1
|
+
import { Field, FieldOptions, Type } from 'alinea/core';
|
|
2
|
+
import { Atom } from 'jotai';
|
|
3
3
|
import { PropsWithChildren } from 'react';
|
|
4
4
|
import * as Y from 'yjs';
|
|
5
5
|
export interface FieldInfo<Value = any, Mutator = any, Options extends FieldOptions<Value> = FieldOptions<Value>> {
|
|
@@ -13,16 +13,16 @@ export declare class FormAtoms<T = any> {
|
|
|
13
13
|
type: Type<T>;
|
|
14
14
|
container: Y.Map<any>;
|
|
15
15
|
private options;
|
|
16
|
-
|
|
16
|
+
private fields;
|
|
17
17
|
constructor(type: Type<T>, container: Y.Map<any>, options?: {
|
|
18
18
|
readOnly: boolean;
|
|
19
19
|
});
|
|
20
20
|
data(): Type.Infer<T>;
|
|
21
|
-
getter
|
|
21
|
+
private getter;
|
|
22
22
|
private valueAtom;
|
|
23
23
|
fieldByKey(key: string): Field;
|
|
24
24
|
keyOf(field: Field): string;
|
|
25
|
-
|
|
25
|
+
fieldInfo<Value, Mutator, Options extends FieldOptions<Value>>(field: Field<Value, Mutator, Options>): FieldInfo<Value, Mutator, Options>;
|
|
26
26
|
}
|
|
27
27
|
export interface UseFormOptions<T> {
|
|
28
28
|
doc?: Y.Doc;
|
|
@@ -51,7 +51,7 @@ var FormAtoms = class {
|
|
|
51
51
|
) : atom(defaultOptions);
|
|
52
52
|
const valueTracker = valueTrackerOf(field);
|
|
53
53
|
const value = this.valueAtom(field, key, valueTracker);
|
|
54
|
-
this.
|
|
54
|
+
this.fields.set(ref, {
|
|
55
55
|
key,
|
|
56
56
|
field,
|
|
57
57
|
value,
|
|
@@ -62,12 +62,12 @@ var FormAtoms = class {
|
|
|
62
62
|
}
|
|
63
63
|
}, "self");
|
|
64
64
|
}
|
|
65
|
-
|
|
65
|
+
fields = /* @__PURE__ */ new Map();
|
|
66
66
|
data() {
|
|
67
67
|
return Type.shape(this.type).fromY(this.container);
|
|
68
68
|
}
|
|
69
69
|
getter = (get) => (field) => {
|
|
70
|
-
const info = this.
|
|
70
|
+
const info = this.fields.get(Field.ref(field));
|
|
71
71
|
if (!info)
|
|
72
72
|
throw new Error(`Field not found: ${Field.label(field)}`);
|
|
73
73
|
return get(info.value);
|
|
@@ -91,20 +91,20 @@ var FormAtoms = class {
|
|
|
91
91
|
});
|
|
92
92
|
}
|
|
93
93
|
fieldByKey(key) {
|
|
94
|
-
for (const info of this.
|
|
94
|
+
for (const info of this.fields.values())
|
|
95
95
|
if (info.key === key)
|
|
96
96
|
return info.field;
|
|
97
97
|
throw new Error(`Field not found: "${key}"`);
|
|
98
98
|
}
|
|
99
99
|
keyOf(field) {
|
|
100
|
-
const res = this.
|
|
100
|
+
const res = this.fields.get(Field.ref(field));
|
|
101
101
|
const label = Field.label(field);
|
|
102
102
|
if (!res)
|
|
103
103
|
throw new Error(`Field not found: ${label}`);
|
|
104
104
|
return res.key;
|
|
105
105
|
}
|
|
106
|
-
|
|
107
|
-
const res = this.
|
|
106
|
+
fieldInfo(field) {
|
|
107
|
+
const res = this.fields.get(Field.ref(field));
|
|
108
108
|
const label = Field.label(field);
|
|
109
109
|
if (!res)
|
|
110
110
|
throw new Error(`Field not found: ${label}`);
|
|
@@ -28,17 +28,17 @@ function useFieldKey(field) {
|
|
|
28
28
|
}
|
|
29
29
|
function useFieldOptions(field) {
|
|
30
30
|
const atoms = useFormContext();
|
|
31
|
-
const atom = atoms.
|
|
31
|
+
const atom = atoms.fieldInfo(field);
|
|
32
32
|
return useAtomValue(atom.options);
|
|
33
33
|
}
|
|
34
34
|
function useFieldValue(field) {
|
|
35
35
|
const atoms = useFormContext();
|
|
36
|
-
const atom = atoms.
|
|
36
|
+
const atom = atoms.fieldInfo(field);
|
|
37
37
|
return useAtomValue(atom.value);
|
|
38
38
|
}
|
|
39
39
|
function useFieldMutator(field) {
|
|
40
40
|
const atoms = useFormContext();
|
|
41
|
-
const atom = atoms.
|
|
41
|
+
const atom = atoms.fieldInfo(field);
|
|
42
42
|
return atom.mutator;
|
|
43
43
|
}
|
|
44
44
|
export {
|
|
@@ -2,7 +2,7 @@ import "../../../chunks/chunk-U5RRZUYZ.js";
|
|
|
2
2
|
|
|
3
3
|
// src/dashboard/view/entry/EntrySummary.tsx
|
|
4
4
|
import { Entry, Type, view } from "alinea/core";
|
|
5
|
-
import { Chip, HStack, TextLabel, Typo, VStack, fromModule } from "alinea/ui";
|
|
5
|
+
import { Chip, HStack, TextLabel, Typo, VStack, fromModule, px } from "alinea/ui";
|
|
6
6
|
import { Ellipsis } from "alinea/ui/Ellipsis";
|
|
7
7
|
import { IcRoundKeyboardArrowRight } from "alinea/ui/icons/IcRoundKeyboardArrowRight";
|
|
8
8
|
import { Fragment } from "react";
|
|
@@ -59,7 +59,7 @@ var EntrySummaryRow = view(
|
|
|
59
59
|
return null;
|
|
60
60
|
return /* @__PURE__ */ jsxs(HStack, { center: true, full: true, gap: 10, className: styles.row(), children: [
|
|
61
61
|
/* @__PURE__ */ jsxs(VStack, { children: [
|
|
62
|
-
parents.length > 0 && /* @__PURE__ */ jsx(Ellipsis, { children: /* @__PURE__ */ jsx(Typo.Small, { children: /* @__PURE__ */ jsx(HStack, { center: true, gap: 3, children: parents.map(({ entryId: entryId2, title: title2 }) => /* @__PURE__ */ jsx(Fragment, { children: title2 }, entryId2)).reduce((prev, curr, i) => [
|
|
62
|
+
parents.length > 0 && /* @__PURE__ */ jsx(Ellipsis, { style: { marginTop: px(-1) }, children: /* @__PURE__ */ jsx(Typo.Small, { children: /* @__PURE__ */ jsx(HStack, { center: true, gap: 3, children: parents.map(({ entryId: entryId2, title: title2 }) => /* @__PURE__ */ jsx(Fragment, { children: title2 }, entryId2)).reduce((prev, curr, i) => [
|
|
63
63
|
prev,
|
|
64
64
|
/* @__PURE__ */ jsx(IcRoundKeyboardArrowRight, {}, `s${i}`),
|
|
65
65
|
curr
|
|
@@ -36,9 +36,10 @@ import { Modal } from "alinea/dashboard/view/Modal";
|
|
|
36
36
|
import { link } from "alinea/input/link";
|
|
37
37
|
import { select } from "alinea/input/select";
|
|
38
38
|
import { text } from "alinea/input/text";
|
|
39
|
+
import { entryFields, entryPicker } from "alinea/picker/entry/EntryPicker";
|
|
39
40
|
import { Button, Loader, fromModule } from "alinea/ui";
|
|
40
41
|
import { Link } from "alinea/ui/Link";
|
|
41
|
-
import { Suspense, useMemo, useState } from "react";
|
|
42
|
+
import { Suspense, useEffect, useMemo, useState } from "react";
|
|
42
43
|
import { changedEntriesAtom, graphAtom, useMutate } from "../../atoms/DbAtoms.js";
|
|
43
44
|
import { useConfig } from "../../hook/UseConfig.js";
|
|
44
45
|
import { useLocale } from "../../hook/UseLocale.js";
|
|
@@ -102,8 +103,8 @@ function NewEntryForm({ parentId }) {
|
|
|
102
103
|
return Type.meta(type2).isContainer;
|
|
103
104
|
}).map((pair) => pair[0]);
|
|
104
105
|
const root = useRoot();
|
|
105
|
-
const parentField = useMemo(
|
|
106
|
-
|
|
106
|
+
const parentField = useMemo(() => {
|
|
107
|
+
return link.entry("Parent", {
|
|
107
108
|
condition: Entry.type.isIn(containerTypes).and(Entry.workspace.is(workspace)).and(Entry.root.is(root.name)),
|
|
108
109
|
initialValue: preselectedId ? {
|
|
109
110
|
id: "parent",
|
|
@@ -111,26 +112,25 @@ function NewEntryForm({ parentId }) {
|
|
|
111
112
|
type: "entry",
|
|
112
113
|
entry: preselectedId
|
|
113
114
|
} : void 0
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
)
|
|
115
|
+
});
|
|
116
|
+
}, []);
|
|
117
|
+
async function allowedTypes(parentId2) {
|
|
118
|
+
if (!parentId2) {
|
|
119
|
+
return root.contains ?? [];
|
|
120
|
+
} else {
|
|
121
|
+
const parent = await graph.preferDraft.get(
|
|
122
|
+
Entry({ entryId: parentId2 }).select(parentData)
|
|
123
|
+
);
|
|
124
|
+
const parentType = parent && config.schema[parent.type];
|
|
125
|
+
return parentType && Type.meta(parentType).contains || keys(config.schema);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
117
128
|
const typeField = useMemo(() => {
|
|
118
|
-
const
|
|
119
|
-
track.options(
|
|
120
|
-
const
|
|
121
|
-
const
|
|
122
|
-
const
|
|
123
|
-
if (!parentId2) {
|
|
124
|
-
types.push(...root.contains ?? []);
|
|
125
|
-
} else {
|
|
126
|
-
const parent = await graph.preferDraft.get(
|
|
127
|
-
Entry({ entryId: parentId2 }).select(parentData)
|
|
128
|
-
);
|
|
129
|
-
const parentType = parent && config.schema[parent.type];
|
|
130
|
-
types.push(
|
|
131
|
-
...parentType && Type.meta(parentType).contains || keys(config.schema)
|
|
132
|
-
);
|
|
133
|
-
}
|
|
129
|
+
const typeField2 = select("Select type", {});
|
|
130
|
+
return track.options(typeField2, async (get) => {
|
|
131
|
+
const selectedParent2 = get(parentField);
|
|
132
|
+
const parentId2 = selectedParent2?.entry;
|
|
133
|
+
const types = await allowedTypes(parentId2);
|
|
134
134
|
return {
|
|
135
135
|
items: fromEntries(
|
|
136
136
|
types.map((key) => {
|
|
@@ -141,7 +141,25 @@ function NewEntryForm({ parentId }) {
|
|
|
141
141
|
)
|
|
142
142
|
};
|
|
143
143
|
});
|
|
144
|
-
|
|
144
|
+
}, []);
|
|
145
|
+
const copyFromField = useMemo(() => {
|
|
146
|
+
const copyFromField2 = link.entry("Copy content from");
|
|
147
|
+
return track.options(copyFromField2, (get) => {
|
|
148
|
+
const type2 = get(typeField);
|
|
149
|
+
return {
|
|
150
|
+
readOnly: !type2,
|
|
151
|
+
pickers: {
|
|
152
|
+
entry: entryPicker({
|
|
153
|
+
condition: Entry.type.is(type2),
|
|
154
|
+
withNavigation: false,
|
|
155
|
+
hint: void 0,
|
|
156
|
+
title: "Copy content from",
|
|
157
|
+
max: 1,
|
|
158
|
+
selection: entryFields
|
|
159
|
+
})
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
});
|
|
145
163
|
}, []);
|
|
146
164
|
const [isCreating, setIsCreating] = useState(false);
|
|
147
165
|
const updateEntries = useSetAtom(changedEntriesAtom);
|
|
@@ -149,11 +167,26 @@ function NewEntryForm({ parentId }) {
|
|
|
149
167
|
() => type({
|
|
150
168
|
parent: parentField,
|
|
151
169
|
title: titleField,
|
|
152
|
-
type: typeField
|
|
170
|
+
type: typeField,
|
|
171
|
+
copyFrom: copyFromField
|
|
153
172
|
}),
|
|
154
173
|
[]
|
|
155
174
|
);
|
|
156
175
|
const form = useForm(formType);
|
|
176
|
+
const parentAtoms = form.fieldInfo(parentField);
|
|
177
|
+
const typeAtoms = form.fieldInfo(typeField);
|
|
178
|
+
const copyFromAtoms = form.fieldInfo(copyFromField);
|
|
179
|
+
const selectedType = useAtomValue(typeAtoms.value);
|
|
180
|
+
const selectedParent = useAtomValue(parentAtoms.value);
|
|
181
|
+
useEffect(() => {
|
|
182
|
+
allowedTypes(selectedParent?.entry).then((types) => {
|
|
183
|
+
if (types.length > 0)
|
|
184
|
+
typeAtoms.mutator(types[0]);
|
|
185
|
+
});
|
|
186
|
+
}, [selectedParent]);
|
|
187
|
+
useEffect(() => {
|
|
188
|
+
copyFromAtoms.mutator.replace(void 0);
|
|
189
|
+
}, [selectedType]);
|
|
157
190
|
async function handleCreate(e) {
|
|
158
191
|
e.preventDefault();
|
|
159
192
|
const { title, type: selected } = form.data();
|
|
@@ -170,7 +203,7 @@ function NewEntryForm({ parentId }) {
|
|
|
170
203
|
phase: config.enableDrafts ? EntryPhase.Draft : EntryPhase.Published
|
|
171
204
|
};
|
|
172
205
|
const parentId2 = form.data().parent?.entry;
|
|
173
|
-
const parent = await graph.
|
|
206
|
+
const parent = await graph.preferPublished.get(
|
|
174
207
|
Entry({ entryId: parentId2 }).select(parentData)
|
|
175
208
|
);
|
|
176
209
|
const parentPaths = parent ? parent.parentPaths.concat(parent.path) : [];
|
|
@@ -179,6 +212,10 @@ function NewEntryForm({ parentId }) {
|
|
|
179
212
|
const parentDir = dirname(filePath);
|
|
180
213
|
const entryType = config.schema[selected];
|
|
181
214
|
const url = entryUrl(entryType, { ...data, parentPaths });
|
|
215
|
+
const copyFrom = form.data().copyFrom?.entry;
|
|
216
|
+
const entryData = copyFrom ? await graph.preferPublished.get(
|
|
217
|
+
Entry({ entryId: copyFrom }).select(Entry.data)
|
|
218
|
+
) : {};
|
|
182
219
|
const entry = await createEntryRow(config, {
|
|
183
220
|
entryId,
|
|
184
221
|
...data,
|
|
@@ -197,7 +234,7 @@ function NewEntryForm({ parentId }) {
|
|
|
197
234
|
modifiedAt: Date.now(),
|
|
198
235
|
active: true,
|
|
199
236
|
main: false,
|
|
200
|
-
data: { title, path },
|
|
237
|
+
data: { ...entryData, title, path },
|
|
201
238
|
searchableText: ""
|
|
202
239
|
});
|
|
203
240
|
return mutate({
|
|
@@ -19,6 +19,7 @@ export interface ExplorerProps {
|
|
|
19
19
|
toggleSelect?: (entry: ExporerItemSelect) => void;
|
|
20
20
|
onNavigate?: (entryId: string) => void;
|
|
21
21
|
showMedia?: boolean;
|
|
22
|
+
withNavigation?: boolean;
|
|
22
23
|
border?: boolean;
|
|
23
24
|
}
|
|
24
25
|
export declare function Explorer({ type, cursor, virtualized, max, selectable, selection, toggleSelect, onNavigate, showMedia, border }: ExplorerProps): import("react/jsx-runtime").JSX.Element;
|
package/dist/index.css
CHANGED
|
@@ -225,7 +225,7 @@ button {
|
|
|
225
225
|
/* src/dashboard/view/Create.module.scss */
|
|
226
226
|
.alinea-Create {
|
|
227
227
|
width: 100%;
|
|
228
|
-
padding: 0.
|
|
228
|
+
padding: 0.25rem 0.625rem;
|
|
229
229
|
gap: 0.625rem;
|
|
230
230
|
display: flex;
|
|
231
231
|
flex-wrap: wrap;
|
|
@@ -582,6 +582,7 @@ button {
|
|
|
582
582
|
min-width: 0;
|
|
583
583
|
font-size: 0.8125rem;
|
|
584
584
|
padding: 0 0.25rem;
|
|
585
|
+
min-height: 1.75rem;
|
|
585
586
|
}
|
|
586
587
|
.alinea-EntrySummary-thumb {
|
|
587
588
|
height: 100%;
|
|
@@ -3834,7 +3835,7 @@ h3.alinea-RichTextKit-heading:not(:last-child) {
|
|
|
3834
3835
|
display: flex;
|
|
3835
3836
|
align-items: center;
|
|
3836
3837
|
gap: 0.5rem;
|
|
3837
|
-
padding: 0.
|
|
3838
|
+
padding: 0.375rem 0.5rem;
|
|
3838
3839
|
}
|
|
3839
3840
|
.alinea-Sink-title {
|
|
3840
3841
|
font-size: 0.8125rem;
|
|
@@ -12,12 +12,8 @@ export interface RichTextOptions<Blocks extends Schema> extends FieldOptions<Tex
|
|
|
12
12
|
optional?: boolean;
|
|
13
13
|
/** Display a minimal version */
|
|
14
14
|
inline?: boolean;
|
|
15
|
-
/**
|
|
16
|
-
|
|
17
|
-
/** Hide this rich text field */
|
|
18
|
-
hidden?: boolean;
|
|
19
|
-
/** Make this rich text field read-only */
|
|
20
|
-
readOnly?: boolean;
|
|
15
|
+
/** Index the text value of this field */
|
|
16
|
+
searchable?: boolean;
|
|
21
17
|
}
|
|
22
18
|
/** Create a rich text field configuration */
|
|
23
19
|
export declare function richText<Blocks extends Schema = {}>(label: string, options?: WithoutLabel<RichTextOptions<Blocks>>): RichTextField<Blocks, RichTextOptions<Blocks>>;
|
|
@@ -19,6 +19,8 @@ export interface TextOptions extends FieldOptions<string> {
|
|
|
19
19
|
iconRight?: ComponentType;
|
|
20
20
|
/** Focus this input automatically */
|
|
21
21
|
autoFocus?: boolean;
|
|
22
|
+
/** Index the text value of this field */
|
|
23
|
+
searchable?: boolean;
|
|
22
24
|
}
|
|
23
25
|
export declare class TextField extends ScalarField<string, TextOptions> {
|
|
24
26
|
}
|