@kernhq/module-quire 0.7.4 → 0.9.0
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/README.md +93 -55
- package/dist/{server → client}/formula.d.ts +6 -0
- package/dist/client/formula.d.ts.map +1 -0
- package/dist/{server → client}/formula.js +6 -0
- package/dist/client/formula.js.map +1 -0
- package/dist/contract/properties.d.ts +26 -0
- package/dist/contract/properties.d.ts.map +1 -1
- package/dist/contract/properties.js +24 -0
- package/dist/contract/properties.js.map +1 -1
- package/dist/contract/router.d.ts +334 -0
- package/dist/contract/router.d.ts.map +1 -1
- package/dist/contract/router.js +43 -1
- package/dist/contract/router.js.map +1 -1
- package/dist/server/_impl.d.ts +341 -0
- package/dist/server/_impl.d.ts.map +1 -1
- package/dist/server/_impl.js +79 -10
- package/dist/server/_impl.js.map +1 -1
- package/dist/server/document.d.ts +13 -0
- package/dist/server/document.d.ts.map +1 -0
- package/dist/server/document.js +58 -0
- package/dist/server/document.js.map +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +26 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/render.d.ts +53 -0
- package/dist/server/render.d.ts.map +1 -0
- package/dist/server/render.js +358 -0
- package/dist/server/render.js.map +1 -0
- package/dist/server/services/databases.d.ts +73 -1
- package/dist/server/services/databases.d.ts.map +1 -1
- package/dist/server/services/databases.js +167 -10
- package/dist/server/services/databases.js.map +1 -1
- package/dist/server/services/pages.d.ts.map +1 -1
- package/dist/server/services/pages.js +11 -1
- package/dist/server/services/pages.js.map +1 -1
- package/dist/server/services/query.d.ts.map +1 -1
- package/dist/server/services/query.js +93 -37
- package/dist/server/services/query.js.map +1 -1
- package/dist/server/services/versions.d.ts.map +1 -1
- package/dist/server/services/versions.js +13 -1
- package/dist/server/services/versions.js.map +1 -1
- package/migrations/0006_rank_collation.sql +14 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +12 -9
- package/src/client/components/PageEditor.svelte +7 -0
- package/src/client/components/PageTreeRow.svelte +1 -1
- package/src/client/core-api.ts +38 -0
- package/src/client/database/BoardView.svelte +354 -0
- package/src/client/database/CalendarView.svelte +346 -0
- package/src/client/database/DatabaseView.svelte +785 -0
- package/src/client/database/FilterMenu.svelte +281 -0
- package/src/client/database/FilterValue.svelte +176 -0
- package/src/client/database/GalleryView.svelte +177 -0
- package/src/client/database/ListView.svelte +108 -0
- package/src/client/database/OptionChip.svelte +38 -0
- package/src/client/database/PropertyDialog.svelte +460 -0
- package/src/client/database/PropertyMenu.svelte +162 -0
- package/src/client/database/RowPanel.svelte +157 -0
- package/src/client/database/SortMenu.svelte +199 -0
- package/src/client/database/TableView.svelte +388 -0
- package/src/client/database/ViewDialog.svelte +229 -0
- package/src/client/database/cells/Cell.svelte +103 -0
- package/src/client/database/cells/CheckboxCell.svelte +33 -0
- package/src/client/database/cells/ComputedCell.svelte +100 -0
- package/src/client/database/cells/DateCell.svelte +97 -0
- package/src/client/database/cells/LinkCell.svelte +143 -0
- package/src/client/database/cells/NumberCell.svelte +131 -0
- package/src/client/database/cells/PersonCell.svelte +116 -0
- package/src/client/database/cells/RelationCell.svelte +222 -0
- package/src/client/database/cells/SelectCell.svelte +133 -0
- package/src/client/database/cells/TextCell.svelte +85 -0
- package/src/client/database/colours.ts +27 -0
- package/src/client/database/property-types.test.ts +64 -0
- package/src/client/database/property-types.ts +294 -0
- package/src/client/database/view-config.test.ts +148 -0
- package/src/client/database/view-config.ts +102 -0
- package/src/client/formula.test.ts +139 -0
- package/src/client/formula.ts +430 -0
- package/src/client/i18n.ts +1176 -0
- package/src/client/index.ts +31 -0
- package/src/client/mock.ts +511 -1
- package/src/client/pages/PageView.svelte +47 -17
- package/src/client/pages/SpacePage.svelte +8 -2
- package/src/client/query.ts +17 -4
- package/src/contract/properties.ts +28 -0
- package/src/contract/router.ts +46 -0
- package/dist/server/formula.d.ts.map +0 -1
- package/dist/server/formula.js.map +0 -1
|
@@ -1,30 +1,87 @@
|
|
|
1
1
|
import { KernError } from '@kernhq/kernel';
|
|
2
2
|
import { sql } from 'drizzle-orm';
|
|
3
|
+
import { pages } from '../schema.js';
|
|
3
4
|
/**
|
|
4
|
-
* Turning a view's filters and sorts into SQL over a row
|
|
5
|
+
* Turning a view's filters and sorts into SQL over a row.
|
|
5
6
|
*
|
|
6
7
|
* Done in SQL rather than in memory, because filtering after the fact breaks pagination: a page of
|
|
7
8
|
* fifty rows filtered down to three is not a page of three, and the caller has no way to ask for
|
|
8
|
-
* the rest. That means every comparison has to be expressible against
|
|
9
|
+
* the rest. That means every comparison has to be expressible against the row as it is stored.
|
|
9
10
|
*
|
|
10
11
|
* **A property key is never interpolated before it is looked up.** The key comes from the request,
|
|
11
12
|
* and `props->>'…'` is a string in the query text rather than a parameter — so the only safe path is
|
|
12
13
|
* to find the property first and use the key the *database* already knows about. An unknown key is
|
|
13
14
|
* refused rather than passed through.
|
|
15
|
+
*
|
|
16
|
+
* **A column's value is not always in `props`.** A formula and a rollup are written to `computed`
|
|
17
|
+
* by `recompute`, and the four audit types are real columns on the page. Reading `props` for those
|
|
18
|
+
* six types matches nothing and sorts nothing — silently, because an absent key is a valid absent
|
|
19
|
+
* value. `valueExpr` is the single place that knows where each type lives; nothing else may guess.
|
|
14
20
|
*/
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
const
|
|
21
|
+
/** The six types whose value is not in `props`. */
|
|
22
|
+
const COMPUTED = new Set(['formula', 'rollup']);
|
|
23
|
+
const AUDIT = new Set(['created_time', 'created_by', 'edited_time', 'edited_by']);
|
|
24
|
+
/** The raw value, as text, wherever it actually lives. */
|
|
25
|
+
function valueExpr(property) {
|
|
26
|
+
switch (property.type) {
|
|
27
|
+
case 'created_time':
|
|
28
|
+
return sql `${pages.createdAt}`;
|
|
29
|
+
case 'edited_time':
|
|
30
|
+
return sql `${pages.updatedAt}`;
|
|
31
|
+
case 'created_by':
|
|
32
|
+
return sql `${pages.createdBy}`;
|
|
33
|
+
case 'edited_by':
|
|
34
|
+
return sql `${pages.updatedBy}`;
|
|
35
|
+
default:
|
|
36
|
+
return COMPUTED.has(property.type) ? sql `computed->>${property.key}` : sql `props->>${property.key}`;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** The jsonb bag a property's value is stored in, for the containment and emptiness tests. */
|
|
40
|
+
const bagExpr = (property) => (COMPUTED.has(property.type) ? sql `computed` : sql `props`);
|
|
41
|
+
/**
|
|
42
|
+
* Casts are guarded rather than bare.
|
|
43
|
+
*
|
|
44
|
+
* `props` and `computed` are untyped: a number column can hold the text somebody pasted into it,
|
|
45
|
+
* and a broken formula stores `{"error":"…"}` where a number was expected. A bare `::numeric` on
|
|
46
|
+
* either raises, and the row that raises is the one nobody can filter past — the whole view 500s.
|
|
47
|
+
* A guard makes it null instead, which is what "no comparable value" means.
|
|
48
|
+
*/
|
|
49
|
+
const NUMBER_TEXT = String.raw `^\s*-?\d+(\.\d+)?([eE][-+]?\d+)?\s*$`;
|
|
50
|
+
const DATE_TEXT = String.raw `^\d{4}-\d{2}-\d{2}`;
|
|
51
|
+
function numeric(property) {
|
|
52
|
+
if (AUDIT.has(property.type))
|
|
53
|
+
return sql `null::numeric`;
|
|
54
|
+
const raw = valueExpr(property);
|
|
55
|
+
return sql `(case when ${raw} ~ ${NUMBER_TEXT} then (${raw})::numeric end)`;
|
|
56
|
+
}
|
|
57
|
+
function timestamp(property) {
|
|
58
|
+
if (property.type === 'created_time' || property.type === 'edited_time')
|
|
59
|
+
return valueExpr(property);
|
|
60
|
+
if (AUDIT.has(property.type))
|
|
61
|
+
return sql `null::timestamptz`;
|
|
62
|
+
const raw = valueExpr(property);
|
|
63
|
+
return sql `(case when ${raw} ~ ${DATE_TEXT} then (${raw})::timestamptz end)`;
|
|
64
|
+
}
|
|
65
|
+
const text = (property) => AUDIT.has(property.type) ? sql `(${valueExpr(property)})::text` : valueExpr(property);
|
|
66
|
+
function boolean(property) {
|
|
67
|
+
const raw = valueExpr(property);
|
|
68
|
+
return sql `coalesce((case when ${raw} in ('true','false') then (${raw})::boolean end), false)`;
|
|
69
|
+
}
|
|
18
70
|
/** Whether a value is "nothing" — absent, null, empty string, or an empty array. */
|
|
19
|
-
|
|
20
|
-
|
|
71
|
+
function emptyExpr(property) {
|
|
72
|
+
if (AUDIT.has(property.type))
|
|
73
|
+
return sql `${valueExpr(property)} is null`;
|
|
74
|
+
const bag = bagExpr(property);
|
|
21
75
|
const key = property.key;
|
|
76
|
+
return sql `(${bag}->${key} is null or ${bag}->>${key} = '' or ${bag}->${key} = '[]'::jsonb or ${bag}->${key} = 'null'::jsonb)`;
|
|
77
|
+
}
|
|
78
|
+
export function filterToSql(filter, property) {
|
|
22
79
|
const value = filter.value;
|
|
23
80
|
switch (filter.operator) {
|
|
24
81
|
case 'is_empty':
|
|
25
|
-
return emptyExpr(
|
|
82
|
+
return emptyExpr(property);
|
|
26
83
|
case 'is_not_empty':
|
|
27
|
-
return sql `not ${emptyExpr(
|
|
84
|
+
return sql `not ${emptyExpr(property)}`;
|
|
28
85
|
default:
|
|
29
86
|
break;
|
|
30
87
|
}
|
|
@@ -37,13 +94,13 @@ export function filterToSql(filter, property) {
|
|
|
37
94
|
return null;
|
|
38
95
|
switch (filter.operator) {
|
|
39
96
|
case 'equals':
|
|
40
|
-
return sql `${numeric(
|
|
97
|
+
return sql `${numeric(property)} = ${n}`;
|
|
41
98
|
case 'not_equals':
|
|
42
|
-
return sql `${numeric(
|
|
99
|
+
return sql `${numeric(property)} is distinct from ${n}`;
|
|
43
100
|
case 'greater_than':
|
|
44
|
-
return sql `${numeric(
|
|
101
|
+
return sql `${numeric(property)} > ${n}`;
|
|
45
102
|
case 'less_than':
|
|
46
|
-
return sql `${numeric(
|
|
103
|
+
return sql `${numeric(property)} < ${n}`;
|
|
47
104
|
default:
|
|
48
105
|
return null;
|
|
49
106
|
}
|
|
@@ -56,15 +113,15 @@ export function filterToSql(filter, property) {
|
|
|
56
113
|
return null;
|
|
57
114
|
switch (filter.operator) {
|
|
58
115
|
case 'equals':
|
|
59
|
-
return sql `date_trunc('day', ${timestamp(
|
|
116
|
+
return sql `date_trunc('day', ${timestamp(property)}) = date_trunc('day', ${at}::timestamptz)`;
|
|
60
117
|
case 'on_or_before':
|
|
61
|
-
return sql `${timestamp(
|
|
118
|
+
return sql `${timestamp(property)} <= ${at}::timestamptz`;
|
|
62
119
|
case 'on_or_after':
|
|
63
|
-
return sql `${timestamp(
|
|
120
|
+
return sql `${timestamp(property)} >= ${at}::timestamptz`;
|
|
64
121
|
case 'greater_than':
|
|
65
|
-
return sql `${timestamp(
|
|
122
|
+
return sql `${timestamp(property)} > ${at}::timestamptz`;
|
|
66
123
|
case 'less_than':
|
|
67
|
-
return sql `${timestamp(
|
|
124
|
+
return sql `${timestamp(property)} < ${at}::timestamptz`;
|
|
68
125
|
default:
|
|
69
126
|
return null;
|
|
70
127
|
}
|
|
@@ -73,23 +130,22 @@ export function filterToSql(filter, property) {
|
|
|
73
130
|
const wanted = value === true || value === 'true';
|
|
74
131
|
// An unset checkbox is false, not null: a filter for "not done" must include rows nobody has
|
|
75
132
|
// touched, which is most of them.
|
|
76
|
-
return wanted
|
|
77
|
-
? sql `(props->>${key})::boolean is true`
|
|
78
|
-
: sql `coalesce((props->>${key})::boolean, false) is false`;
|
|
133
|
+
return wanted ? sql `${boolean(property)} is true` : sql `${boolean(property)} is false`;
|
|
79
134
|
}
|
|
80
135
|
case 'multi_select':
|
|
81
136
|
case 'person':
|
|
82
137
|
case 'files':
|
|
83
138
|
case 'relation': {
|
|
84
|
-
// Array-valued.
|
|
139
|
+
// Array-valued. `?|` asks whether the array contains any of these strings.
|
|
85
140
|
const many = Array.isArray(value) ? value.map(String) : [String(value)];
|
|
141
|
+
const bag = bagExpr(property);
|
|
86
142
|
switch (filter.operator) {
|
|
87
143
|
case 'contains':
|
|
88
144
|
case 'is_any_of':
|
|
89
|
-
return sql
|
|
145
|
+
return sql `${bag}->${property.key} ?| ${sql.param(many)}::text[]`;
|
|
90
146
|
case 'not_contains':
|
|
91
147
|
case 'is_none_of':
|
|
92
|
-
return sql `not (
|
|
148
|
+
return sql `not coalesce(${bag}->${property.key} ?| ${sql.param(many)}::text[], false)`;
|
|
93
149
|
default:
|
|
94
150
|
return null;
|
|
95
151
|
}
|
|
@@ -97,23 +153,24 @@ export function filterToSql(filter, property) {
|
|
|
97
153
|
default: {
|
|
98
154
|
// Everything else compares as text.
|
|
99
155
|
const v = value === null || value === undefined ? '' : String(value);
|
|
156
|
+
const list = sql.param(Array.isArray(value) ? value.map(String) : [v]);
|
|
100
157
|
switch (filter.operator) {
|
|
101
158
|
case 'equals':
|
|
102
|
-
return sql `${text(
|
|
159
|
+
return sql `${text(property)} = ${v}`;
|
|
103
160
|
case 'not_equals':
|
|
104
|
-
return sql `${text(
|
|
161
|
+
return sql `${text(property)} is distinct from ${v}`;
|
|
105
162
|
case 'contains':
|
|
106
|
-
return sql `${text(
|
|
163
|
+
return sql `${text(property)} ilike ${`%${v}%`}`;
|
|
107
164
|
case 'not_contains':
|
|
108
|
-
return sql `coalesce(${text(
|
|
165
|
+
return sql `coalesce(${text(property)}, '') not ilike ${`%${v}%`}`;
|
|
109
166
|
case 'starts_with':
|
|
110
|
-
return sql `${text(
|
|
167
|
+
return sql `${text(property)} ilike ${`${v}%`}`;
|
|
111
168
|
case 'ends_with':
|
|
112
|
-
return sql `${text(
|
|
169
|
+
return sql `${text(property)} ilike ${`%${v}`}`;
|
|
113
170
|
case 'is_any_of':
|
|
114
|
-
return sql `${text(
|
|
171
|
+
return sql `${text(property)} = any(${list}::text[])`;
|
|
115
172
|
case 'is_none_of':
|
|
116
|
-
return sql `coalesce(${text(
|
|
173
|
+
return sql `coalesce(${text(property)}, '') <> all(${list}::text[])`;
|
|
117
174
|
default:
|
|
118
175
|
return null;
|
|
119
176
|
}
|
|
@@ -127,21 +184,20 @@ export function filterToSql(filter, property) {
|
|
|
127
184
|
* thing nobody reports as a bug and everybody works around.
|
|
128
185
|
*/
|
|
129
186
|
export function sortToSql(sort, property) {
|
|
130
|
-
const key = property.key;
|
|
131
187
|
const direction = sort.direction === 'desc' ? sql `desc` : sql `asc`;
|
|
132
188
|
switch (property.type) {
|
|
133
189
|
case 'number':
|
|
134
190
|
case 'formula':
|
|
135
191
|
case 'rollup':
|
|
136
|
-
return sql `${numeric(
|
|
192
|
+
return sql `${numeric(property)} ${direction} nulls last`;
|
|
137
193
|
case 'date':
|
|
138
194
|
case 'created_time':
|
|
139
195
|
case 'edited_time':
|
|
140
|
-
return sql `${timestamp(
|
|
196
|
+
return sql `${timestamp(property)} ${direction} nulls last`;
|
|
141
197
|
case 'checkbox':
|
|
142
|
-
return sql
|
|
198
|
+
return sql `${boolean(property)} ${direction}`;
|
|
143
199
|
default:
|
|
144
|
-
return sql `${text(
|
|
200
|
+
return sql `${text(property)} ${direction} nulls last`;
|
|
145
201
|
}
|
|
146
202
|
}
|
|
147
203
|
/** The property a filter or sort names, or a refusal. Never trust the key that arrived. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../../src/server/services/query.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAY,GAAG,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../../src/server/services/query.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"versions.d.ts","sourceRoot":"","sources":["../../../src/server/services/versions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAuB,SAAS,EAAE,MAAM,mBAAmB,CAAA;AACvE,OAAO,EAAa,KAAK,MAAM,EAAE,KAAK,EAAE,EAAU,MAAM,gBAAgB,CAAA;AAExE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;
|
|
1
|
+
{"version":3,"file":"versions.d.ts","sourceRoot":"","sources":["../../../src/server/services/versions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAuB,SAAS,EAAE,MAAM,mBAAmB,CAAA;AACvE,OAAO,EAAa,KAAK,MAAM,EAAE,KAAK,EAAE,EAAU,MAAM,gBAAgB,CAAA;AAExE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAG1D,OAAO,EAAS,YAAY,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAG9C,KAAK,UAAU,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA;AAKlD,wBAAgB,SAAS,CAAC,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,CAalF;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW;IAS7D;;;;;;OAMG;gBAEG,EAAE,eACO,MAAM,UACX,MAAM,QACR;QAAE,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GACnF,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;aA0Cd,EAAE,eAAe,MAAM,UAAU,MAAM,SAAS,MAAM,UAAU,MAAM,GAAG,IAAI;;;;;;;;;;;;;;;YAkB9E,EAAE,eAAe,MAAM,aAAa,MAAM;;;;;;;;;;;;;IAUxD;;;;;;;OAOG;gBACe,EAAE,aAAa,SAAS,eAAe,MAAM,aAAa,MAAM;;;;;;;;;;;;;IAsBlF,kEAAkE;gBAChD,EAAE,aAAa,SAAS,eAAe,MAAM,UAAU,MAAM,SAAS,MAAM,GAAG,IAAI;;;;;;;;;;;;;;;;;;;;;;;IAyBrG,wEAAwE;eACvD,EAAE,aAAa,SAAS,eAAe,MAAM,UAAU,MAAM;;;;;;;;;;;;;;;;;;;;;;;IAyB9E,2FAA2F;uBAClE,EAAE,eAAe,MAAM,UAAU,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAUvF,wFAAwF;+BAC7D,MAAM,UAAU,MAAM;;;;;;EAMpD;AACD,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAA"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { KernError, uuidv7 } from '@kernhq/kernel';
|
|
2
2
|
import { and, desc, eq, lt } from 'drizzle-orm';
|
|
3
|
+
import { pageDocFromBase64 } from '../document.js';
|
|
4
|
+
import { textFromPageDoc } from '../render.js';
|
|
3
5
|
import { pages, pageVersions } from '../schema.js';
|
|
4
6
|
import { documentNameOf } from './pages.js';
|
|
5
7
|
/** How much of the prose a version list shows without loading the document. */
|
|
@@ -46,6 +48,14 @@ export function quireVersions(kernel, access) {
|
|
|
46
48
|
.where(and(eq(pages.workspaceId, workspaceId), eq(pages.id, pageId)))
|
|
47
49
|
.limit(1);
|
|
48
50
|
const state = Buffer.from(taken.state, 'base64');
|
|
51
|
+
/*
|
|
52
|
+
* Flattened from the state that is being stored, not copied from `pages.text`.
|
|
53
|
+
*
|
|
54
|
+
* `pages.text` is what the collab service published, and its flatten renders marks as markup
|
|
55
|
+
* — a page with one link contributed `rel="noopener noreferrer nofollow"` to the preview and
|
|
56
|
+
* to search. Decoding here costs nothing extra: the bytes are already in hand.
|
|
57
|
+
*/
|
|
58
|
+
const decoded = pageDocFromBase64(taken.state);
|
|
49
59
|
const [version] = await tx
|
|
50
60
|
.insert(pageVersions)
|
|
51
61
|
.values({
|
|
@@ -56,7 +66,9 @@ export function quireVersions(kernel, access) {
|
|
|
56
66
|
label: opts.label ?? null,
|
|
57
67
|
state,
|
|
58
68
|
snapshot: Buffer.from(taken.snapshot, 'base64'),
|
|
59
|
-
|
|
69
|
+
// The mirrored column is the fallback, so a document that will not decode still gets a
|
|
70
|
+
// version — losing the preview is a small thing; not taking the version is somebody's work.
|
|
71
|
+
text: decoded ? textFromPageDoc(decoded) : (row?.text ?? ''),
|
|
60
72
|
size: state.length,
|
|
61
73
|
authorId: opts.authorId ?? null,
|
|
62
74
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"versions.js","sourceRoot":"","sources":["../../../src/server/services/versions.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAwB,MAAM,EAAE,MAAM,gBAAgB,CAAA;AACxE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,aAAa,CAAA;AAE/C,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAElD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAI3C,+EAA+E;AAC/E,MAAM,OAAO,GAAG,GAAG,CAAA;AAEnB,MAAM,UAAU,SAAS,CAAC,GAAe,EAAE,WAA0B;IACnE,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,WAAW,EAAE,GAAG,CAAC,WAAyC;QAC1D,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,IAAI,EAAE,GAAG,CAAC,IAA2B;QACrC,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC;QACnC,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,QAAQ,EAAE,GAAG,CAAC,QAAmC;QACjD,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,WAAW,EAAE;QACtC,SAAS,EAAE,WAAW,KAAK,GAAG,CAAC,EAAE;KAClC,CAAA;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAc,EAAE,MAAmB;IAC/D,kFAAkF;IAClF,KAAK,UAAU,UAAU,CAAC,WAAmB,EAAE,MAAc;QAC3D,OAAO,MAAM,CAAC,IAAI,CAAsC,0BAA0B,EAAE;YAClF,IAAI,EAAE,cAAc,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC;SAClD,CAAC,CAAA;IACJ,CAAC;IAED,OAAO;QACL;;;;;;WAMG;QACH,KAAK,CAAC,OAAO,CACX,EAAM,EACN,WAAmB,EACnB,MAAc,EACd,IAAoF;YAEpF,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;gBAChE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,EAAE,iCAAiC,CAAC,CAAA;gBAChF,OAAO,IAAI,CAAA;YACb,CAAC,CAAC,CAAA;YACF,IAAI,CAAC,KAAK;gBAAE,OAAO,IAAI,CAAA;YAEvB,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,EAAE;iBACnB,MAAM,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;iBAC5B,IAAI,CAAC,KAAK,CAAC;iBACX,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,WAAW,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;iBACpE,KAAK,CAAC,CAAC,CAAC,CAAA;YAEX,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;YAChD,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,EAAE;iBACvB,MAAM,CAAC,YAAY,CAAC;iBACpB,MAAM,CAAC;gBACN,EAAE,EAAE,MAAM,EAAE;gBACZ,WAAW;gBACX,MAAM;gBACN,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI;gBACzB,KAAK;gBACL,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ,CAAC;gBAC/C,IAAI,EAAE,GAAG,EAAE,IAAI,IAAI,EAAE;
|
|
1
|
+
{"version":3,"file":"versions.js","sourceRoot":"","sources":["../../../src/server/services/versions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
-- Column and view order are fractional indexes, and they only sort the way the algorithm intended
|
|
2
|
+
-- under byte comparison.
|
|
3
|
+
--
|
|
4
|
+
-- `pages.position` was declared `COLLATE "C"` in 0000 for exactly this reason; `properties.position`
|
|
5
|
+
-- and `views.position` were not, so on any database with a language-aware default collation
|
|
6
|
+
-- (en_US.UTF-8, which is what this project runs) `ORDER BY position` reorders them by letter and
|
|
7
|
+
-- ignores case. The keys the algorithm mints are 'V', 'k', 's' — so a database's second view sorted
|
|
8
|
+
-- in front of its first, and moving a column put it somewhere nobody asked for. Nothing failed:
|
|
9
|
+
-- the rows came back, in the wrong order.
|
|
10
|
+
--
|
|
11
|
+
-- Backward compatible: the column keeps its type and its data, and an older image reading it sees
|
|
12
|
+
-- the same strings. Only the comparison changes.
|
|
13
|
+
ALTER TABLE "mod_quire"."properties" ALTER COLUMN "position" TYPE text COLLATE "C";--> statement-breakpoint
|
|
14
|
+
ALTER TABLE "mod_quire"."views" ALTER COLUMN "position" TYPE text COLLATE "C";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kernhq/module-quire",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Kern Quire: collaborative documents, spaces and page trees",
|
|
5
5
|
"homepage": "https://github.com/KernAIO/module-quire#readme",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -42,16 +42,19 @@
|
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@kernhq/sdk": "^0.1.
|
|
45
|
+
"@kernhq/sdk": "^0.1.8",
|
|
46
46
|
"@orpc/contract": "^1.15.0",
|
|
47
47
|
"@orpc/server": "^1.15.0",
|
|
48
|
+
"@tiptap/y-tiptap": "^3.0.7",
|
|
48
49
|
"drizzle-orm": "^0.45.0",
|
|
50
|
+
"svelte-dnd-action": "^0.9.0",
|
|
51
|
+
"yjs": "^13.6.32",
|
|
49
52
|
"zod": "^4.1.0"
|
|
50
53
|
},
|
|
51
54
|
"peerDependencies": {
|
|
52
|
-
"@kernhq/contracts": "^0.
|
|
53
|
-
"@kernhq/kernel": "^0.7.
|
|
54
|
-
"@kernhq/ui": "^0.
|
|
55
|
+
"@kernhq/contracts": "^0.6.1",
|
|
56
|
+
"@kernhq/kernel": "^0.7.2",
|
|
57
|
+
"@kernhq/ui": "^0.9.0",
|
|
55
58
|
"@tanstack/svelte-query": "^6.1.0",
|
|
56
59
|
"svelte": "^5.46.0"
|
|
57
60
|
},
|
|
@@ -69,10 +72,10 @@
|
|
|
69
72
|
"devDependencies": {
|
|
70
73
|
"@biomejs/biome": "^2.0.0",
|
|
71
74
|
"@changesets/cli": "^2.27.0",
|
|
72
|
-
"@kernhq/contracts": "^0.
|
|
73
|
-
"@kernhq/kernel": "^0.7.
|
|
75
|
+
"@kernhq/contracts": "^0.6.1",
|
|
76
|
+
"@kernhq/kernel": "^0.7.2",
|
|
74
77
|
"@kernhq/tsconfig": "^0.1.0",
|
|
75
|
-
"@kernhq/ui": "^0.
|
|
78
|
+
"@kernhq/ui": "^0.9.0",
|
|
76
79
|
"@tanstack/svelte-query": "^6.1.0",
|
|
77
80
|
"@types/node": "^24.0.0",
|
|
78
81
|
"@types/pg": "^8.15.0",
|
|
@@ -92,7 +95,7 @@
|
|
|
92
95
|
"typecheck": "tsc -p tsconfig.json --noEmit && svelte-check --tsconfig ./tsconfig.client.json --threshold error",
|
|
93
96
|
"test": "vitest run",
|
|
94
97
|
"db:generate": "drizzle-kit generate",
|
|
95
|
-
"lint": "biome check . && node scripts/check-ranges.mjs package.json",
|
|
98
|
+
"lint": "biome check . && node scripts/check-ranges.mjs package.json && node scripts/check-icons.mjs && node scripts/check-i18n.mjs && node scripts/check-tokens.mjs",
|
|
96
99
|
"format": "biome check --write .",
|
|
97
100
|
"changeset": "changeset"
|
|
98
101
|
}
|
|
@@ -67,10 +67,17 @@ const user = $derived({
|
|
|
67
67
|
<EmptyState icon="triangle-alert" title={t('editor_no_session')} description={t('editor_no_session_desc')} />
|
|
68
68
|
{:else}
|
|
69
69
|
{#key name}
|
|
70
|
+
<!--
|
|
71
|
+
`page` is what selects the wide wiki schema — tables, callouts, toggles, task lists, images,
|
|
72
|
+
six heading levels. It is opt-in for a reason: a comment box shares this component and shares
|
|
73
|
+
the narrow schema with issue descriptions, and only a page has a reader (`renderPageDoc`) able
|
|
74
|
+
to draw all of this outside the browser.
|
|
75
|
+
-->
|
|
70
76
|
<CollaborativeEditor
|
|
71
77
|
{url}
|
|
72
78
|
{name}
|
|
73
79
|
{user}
|
|
80
|
+
page
|
|
74
81
|
placeholder={t('editor_placeholder')}
|
|
75
82
|
{onpeers}
|
|
76
83
|
{onstatus}
|
|
@@ -34,7 +34,7 @@ const indent = $derived(Math.min(depth, 2) as 0 | 1 | 2)
|
|
|
34
34
|
<div class="row">
|
|
35
35
|
<SidebarItem
|
|
36
36
|
label={title}
|
|
37
|
-
icon={node.kind === 'live' ? 'square-pen' : 'file-text'}
|
|
37
|
+
icon={node.kind === 'live' ? 'square-pen' : node.kind === 'database' ? 'database' : 'file-text'}
|
|
38
38
|
active={activeId === node.id}
|
|
39
39
|
{indent}
|
|
40
40
|
onclick={() => onOpen(node.id)}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The slice of core's API quire reaches for, named by shape.
|
|
3
|
+
*
|
|
4
|
+
* A `person` column stores user ids, so a database cell has to turn one into a face and a name.
|
|
5
|
+
* Typing the seam structurally keeps the dependency pointing one way: quire does not import core's
|
|
6
|
+
* router type, and core does not know quire exists.
|
|
7
|
+
*/
|
|
8
|
+
export interface CoreMember {
|
|
9
|
+
userId: string
|
|
10
|
+
user: {
|
|
11
|
+
id: string
|
|
12
|
+
name: string | null
|
|
13
|
+
email: string
|
|
14
|
+
avatarUrl?: string | null
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface CoreApi {
|
|
19
|
+
workspaces: {
|
|
20
|
+
members: {
|
|
21
|
+
list(input: { workspaceId: string; limit?: number }): Promise<{ items: CoreMember[] }>
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** A person as this module's cells and menus want them. */
|
|
27
|
+
export interface Person {
|
|
28
|
+
id: string
|
|
29
|
+
name: string
|
|
30
|
+
avatarUrl: string | null
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** A member with no display name still has to be pickable, so the address stands in for the name. */
|
|
34
|
+
export const toPerson = (member: CoreMember): Person => ({
|
|
35
|
+
id: member.user.id,
|
|
36
|
+
name: member.user.name ?? member.user.email,
|
|
37
|
+
avatarUrl: member.user.avatarUrl ?? null,
|
|
38
|
+
})
|