alinea 1.1.1 → 1.2.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/dist/backend/Database.js +51 -27
- package/dist/backend/Store.d.ts +2 -2
- package/dist/backend/db/CreateEntrySearch.d.ts +1 -1
- package/dist/backend/resolver/EntryResolver.js +1 -1
- package/dist/chunks/{chunk-LRCCBBNL.js → chunk-76ZJ7RWJ.js} +1 -1
- package/dist/cli/Serve.js +1 -1
- package/dist/cli/bin.js +1 -1
- package/dist/cloud/CloudBackend.js +1 -1
- package/dist/core/CMS.js +2 -1
- package/dist/core/Graph.d.ts +1 -1
- package/dist/core/Transaction.d.ts +2 -0
- package/dist/core/Transaction.js +2 -1
- package/dist/core/Type.d.ts +3 -0
- package/dist/core/Type.js +4 -0
- package/dist/dashboard/Routes.d.ts +3 -0
- package/dist/dashboard/atoms/EntryEditorAtoms.d.ts +9 -0
- package/dist/dashboard/atoms/EntryEditorAtoms.js +13 -3
- package/dist/dashboard/util/PersistentStore.js +1 -1
- package/dist/dashboard/view/EntryEdit.js +3 -4
- package/dist/dashboard/view/entry/EntryHeader.js +4 -4
- package/dist/dashboard/view/entry/NewEntry.js +47 -8
- package/dist/field/richtext/RichTextField.view.js +2 -0
- package/package.json +1 -1
package/dist/backend/Database.js
CHANGED
|
@@ -150,7 +150,11 @@ ${JSON.stringify(mutation)}`
|
|
|
150
150
|
}
|
|
151
151
|
async updateChildren(tx, previous, next) {
|
|
152
152
|
const { childrenDir: dir } = previous;
|
|
153
|
-
|
|
153
|
+
const publishing = next.status === EntryStatus.Published;
|
|
154
|
+
const unarchive = previous.status === EntryStatus.Archived;
|
|
155
|
+
const pathChanged = dir !== next.childrenDir;
|
|
156
|
+
const needsUpdate = publishing && (unarchive || pathChanged);
|
|
157
|
+
if (!needsUpdate)
|
|
154
158
|
return [];
|
|
155
159
|
const children = await tx.select().from(EntryRow).where(
|
|
156
160
|
or(eq(EntryRow.parentDir, dir), like(EntryRow.childrenDir, `${dir}/%`))
|
|
@@ -166,11 +170,15 @@ ${JSON.stringify(mutation)}`
|
|
|
166
170
|
...child,
|
|
167
171
|
parentPaths
|
|
168
172
|
});
|
|
173
|
+
const extension = paths.extname(child.filePath);
|
|
174
|
+
const fileName = paths.basename(child.filePath, extension);
|
|
175
|
+
const [, status] = entryInfo(fileName);
|
|
169
176
|
await tx.update(EntryRow).set({
|
|
170
177
|
filePath,
|
|
171
178
|
childrenDir,
|
|
172
179
|
parentDir,
|
|
173
|
-
url
|
|
180
|
+
url,
|
|
181
|
+
status
|
|
174
182
|
}).where(
|
|
175
183
|
eq(EntryRow.id, child.id),
|
|
176
184
|
is(EntryRow.locale, child.locale),
|
|
@@ -180,20 +188,29 @@ ${JSON.stringify(mutation)}`
|
|
|
180
188
|
return children;
|
|
181
189
|
}
|
|
182
190
|
async logEntries() {
|
|
183
|
-
const entries2 = await this.store.select(
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
191
|
+
const entries2 = await this.store.select({
|
|
192
|
+
id: EntryRow.id,
|
|
193
|
+
url: EntryRow.url,
|
|
194
|
+
locale: EntryRow.locale,
|
|
195
|
+
status: EntryRow.status,
|
|
196
|
+
title: EntryRow.title,
|
|
197
|
+
filePath: EntryRow.filePath
|
|
198
|
+
}).from(EntryRow).orderBy(asc(EntryRow.url), asc(EntryRow.index));
|
|
199
|
+
console.table(entries2);
|
|
193
200
|
}
|
|
194
201
|
async applyMutation(tx, mutation) {
|
|
195
202
|
switch (mutation.type) {
|
|
196
203
|
case MutationType.Create: {
|
|
204
|
+
const { entry } = mutation;
|
|
205
|
+
let status = entry.status;
|
|
206
|
+
if (entry.parentId) {
|
|
207
|
+
const parent = await tx.select().from(EntryRow).where(
|
|
208
|
+
eq(EntryRow.id, entry.parentId),
|
|
209
|
+
is(EntryRow.locale, mutation.locale),
|
|
210
|
+
is(EntryRow.main, true)
|
|
211
|
+
).get();
|
|
212
|
+
status = parent?.status ?? status;
|
|
213
|
+
}
|
|
197
214
|
const condition = and(
|
|
198
215
|
eq(EntryRow.id, mutation.entryId),
|
|
199
216
|
eq(EntryRow.status, mutation.entry.status),
|
|
@@ -202,7 +219,7 @@ ${JSON.stringify(mutation)}`
|
|
|
202
219
|
const current = await tx.select().from(EntryRow).where(condition).get();
|
|
203
220
|
if (current)
|
|
204
221
|
return;
|
|
205
|
-
await tx.insert(EntryRow).values(mutation.entry);
|
|
222
|
+
await tx.insert(EntryRow).values({ ...mutation.entry, status });
|
|
206
223
|
return () => this.updateHash(tx, condition);
|
|
207
224
|
}
|
|
208
225
|
case MutationType.Edit: {
|
|
@@ -216,10 +233,8 @@ ${JSON.stringify(mutation)}`
|
|
|
216
233
|
await tx.delete(EntryRow).where(condition);
|
|
217
234
|
await tx.insert(EntryRow).values(entry);
|
|
218
235
|
let children = [];
|
|
219
|
-
if (entry.status === EntryStatus.Published)
|
|
220
|
-
|
|
221
|
-
children = await this.updateChildren(tx, current, entry);
|
|
222
|
-
}
|
|
236
|
+
if (entry.status === EntryStatus.Published && current)
|
|
237
|
+
children = await this.updateChildren(tx, current, entry);
|
|
223
238
|
return () => {
|
|
224
239
|
return this.updateHash(tx, condition).then(
|
|
225
240
|
(self) => this.updateHash(
|
|
@@ -263,11 +278,15 @@ ${JSON.stringify(mutation)}`
|
|
|
263
278
|
return;
|
|
264
279
|
const filePath = published.filePath.slice(0, -5) + `.${EntryStatus.Archived}.json`;
|
|
265
280
|
await tx.delete(EntryRow).where(archived);
|
|
266
|
-
await tx.update(EntryRow).set({
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
281
|
+
await tx.update(EntryRow).set({ status: EntryStatus.Archived, filePath }).where(condition);
|
|
282
|
+
const children = await tx.update(EntryRow).set({ status: EntryStatus.Archived }).where(
|
|
283
|
+
eq(EntryRow.status, EntryStatus.Published),
|
|
284
|
+
or(
|
|
285
|
+
eq(EntryRow.parentDir, published.childrenDir),
|
|
286
|
+
like(EntryRow.childrenDir, published.childrenDir + "/%")
|
|
287
|
+
)
|
|
288
|
+
).returning(EntryRow.id);
|
|
289
|
+
return () => this.updateHash(tx, or(archived, inArray(EntryRow.id, children)));
|
|
271
290
|
}
|
|
272
291
|
case MutationType.Publish: {
|
|
273
292
|
const promoting = await tx.select().from(EntryRow).where(
|
|
@@ -582,9 +601,8 @@ ${JSON.stringify(mutation)}`
|
|
|
582
601
|
try {
|
|
583
602
|
const raw = JsonLoader.parse(this.config.schema, file.contents);
|
|
584
603
|
const { meta, data, v0Id } = parseRecord(raw);
|
|
585
|
-
if (v0Id)
|
|
604
|
+
if (v0Id)
|
|
586
605
|
v0Ids.set(v0Id, meta.id);
|
|
587
|
-
}
|
|
588
606
|
const seeded = meta.seeded;
|
|
589
607
|
const key = seedKey(
|
|
590
608
|
file.workspace,
|
|
@@ -718,12 +736,18 @@ ${JSON.stringify(mutation)}`
|
|
|
718
736
|
EntryRow.locale,
|
|
719
737
|
sql`'null'`
|
|
720
738
|
)}, ${EntryRow.status}) in ${values(...inserted)}`;
|
|
739
|
+
const archivedPaths = await tx.select(EntryRow.childrenDir).from(EntryRow).where(eq(EntryRow.status, EntryStatus.Archived));
|
|
740
|
+
for (const archivedPath of archivedPaths) {
|
|
741
|
+
const isChildOf = or(
|
|
742
|
+
eq(EntryRow.parentDir, archivedPath),
|
|
743
|
+
like(EntryRow.childrenDir, archivedPath + "/%")
|
|
744
|
+
);
|
|
745
|
+
await tx.update(EntryRow).set({ status: EntryStatus.Archived }).where(isChildOf, eq(EntryRow.status, EntryStatus.Published));
|
|
746
|
+
}
|
|
721
747
|
const entries2 = await tx.select().from(EntryRow).where(isInserted);
|
|
722
748
|
for (const entry of entries2) {
|
|
723
749
|
const rowHash = await createRowHash(entry);
|
|
724
|
-
await tx.update(EntryRow).set({
|
|
725
|
-
rowHash
|
|
726
|
-
}).where(
|
|
750
|
+
await tx.update(EntryRow).set({ rowHash }).where(
|
|
727
751
|
eq(EntryRow.id, entry.id),
|
|
728
752
|
is(EntryRow.locale, entry.locale),
|
|
729
753
|
eq(EntryRow.status, entry.status)
|
package/dist/backend/Store.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export type Store =
|
|
1
|
+
import { SyncDatabase } from 'rado';
|
|
2
|
+
export type Store = SyncDatabase<'sqlite'>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { Store } from '../Store.js';
|
|
2
|
-
export declare function createEntrySearch(db: Store): import("rado").QueryBatch<unknown, import("rado/core/MetaData.js").
|
|
2
|
+
export declare function createEntrySearch(db: Store): import("rado").QueryBatch<unknown, import("rado/core/MetaData.js").Sync<"sqlite">>;
|
|
@@ -152,7 +152,7 @@ var EntryResolver = class {
|
|
|
152
152
|
const name = this.scope.nameOf(field);
|
|
153
153
|
if (!name)
|
|
154
154
|
throw new Error(`Expression has no name ${field}`);
|
|
155
|
-
const isEntryField = name === "path" || name === "
|
|
155
|
+
const isEntryField = name === "path" || name === "title";
|
|
156
156
|
if (isEntryField)
|
|
157
157
|
return table[name];
|
|
158
158
|
return table.data[name];
|
package/dist/cli/Serve.js
CHANGED
package/dist/cli/bin.js
CHANGED
package/dist/core/CMS.js
CHANGED
package/dist/core/Graph.d.ts
CHANGED
|
@@ -61,7 +61,7 @@ export interface Order {
|
|
|
61
61
|
type InferSelection<Selection> = Selection extends GraphQuery & Edge ? Expand<AnyQueryResult<Selection>> : Selection extends Expr<infer V> ? V : {
|
|
62
62
|
[K in keyof Selection]: Selection[K] extends Type<infer V> ? Type.Infer<V> : InferSelection<Selection[K]>;
|
|
63
63
|
};
|
|
64
|
-
type InferResult<Selection, Types, Include> = Selection extends
|
|
64
|
+
type InferResult<Selection, Types, Include> = Selection extends undefined ? Types extends undefined ? EntryFields & (Include extends undefined ? {} : InferSelection<Include>) : EntryFields & Infer<Types> & (Include extends undefined ? {} : InferSelection<Include>) : Selection extends Expr<infer Value> ? Value : InferSelection<Selection>;
|
|
65
65
|
type QueryResult<Selection, Types, Include> = Expand<InferResult<Selection, Types, Include>>;
|
|
66
66
|
interface CountQuery<Selection, Types, Include> extends GraphQuery<Selection, Types, Include> {
|
|
67
67
|
count: true;
|
|
@@ -3,6 +3,7 @@ import { StoredRow } from 'alinea/core/Infer';
|
|
|
3
3
|
import { ImagePreviewDetails } from 'alinea/core/media/CreatePreview';
|
|
4
4
|
import type { CMS } from './CMS.js';
|
|
5
5
|
import { Config } from './Config.js';
|
|
6
|
+
import { EntryStatus } from './EntryRow.js';
|
|
6
7
|
import { Status } from './Graph.js';
|
|
7
8
|
import { Mutation } from './Mutation.js';
|
|
8
9
|
import { Type } from './Type.js';
|
|
@@ -48,6 +49,7 @@ export interface CreateQuery<Fields> {
|
|
|
48
49
|
root?: string;
|
|
49
50
|
parentId?: string | null;
|
|
50
51
|
locale?: string;
|
|
52
|
+
status?: EntryStatus;
|
|
51
53
|
set?: Partial<StoredRow<Fields>>;
|
|
52
54
|
}
|
|
53
55
|
export declare class CreateOperation<Definition> extends Operation {
|
package/dist/core/Transaction.js
CHANGED
|
@@ -238,7 +238,7 @@ var CreateOperation = class extends Operation {
|
|
|
238
238
|
}
|
|
239
239
|
];
|
|
240
240
|
async function entryRow() {
|
|
241
|
-
const { workspace, root, parentId, locale, set } = query;
|
|
241
|
+
const { workspace, root, parentId, locale, set, status } = query;
|
|
242
242
|
const typeName = getScope(cms.config).nameOf(query.type);
|
|
243
243
|
if (!typeName)
|
|
244
244
|
throw new Error(
|
|
@@ -246,6 +246,7 @@ var CreateOperation = class extends Operation {
|
|
|
246
246
|
);
|
|
247
247
|
const partial = {
|
|
248
248
|
id: entryId,
|
|
249
|
+
status,
|
|
249
250
|
type: typeName,
|
|
250
251
|
workspace,
|
|
251
252
|
root,
|
package/dist/core/Type.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ export declare namespace Type {
|
|
|
25
25
|
type Infer<Definition> = TypeRow<Definition>;
|
|
26
26
|
function label(type: Type): Label;
|
|
27
27
|
function contains(type: Type): Array<string | Type>;
|
|
28
|
+
function insertOrder(type: Type): 'first' | 'last' | 'free';
|
|
28
29
|
function isHidden(type: Type): boolean;
|
|
29
30
|
function shape(type: Type): RecordShape;
|
|
30
31
|
function searchableText(type: Type, value: any): string;
|
|
@@ -58,6 +59,8 @@ export interface TypeConfig<Definition> {
|
|
|
58
59
|
summaryRow?: View<SummaryProps>;
|
|
59
60
|
/** A React component used to view a thumbnail of this type in the dashboard */
|
|
60
61
|
summaryThumb?: View<SummaryProps>;
|
|
62
|
+
/** The position where new children will be inserted */
|
|
63
|
+
insertOrder?: 'first' | 'last' | 'free';
|
|
61
64
|
entryUrl?: (meta: EntryUrlMeta) => string;
|
|
62
65
|
}
|
|
63
66
|
export interface TypeInternal extends TypeConfig<FieldsDefinition> {
|
package/dist/core/Type.js
CHANGED
|
@@ -21,6 +21,10 @@ var Type;
|
|
|
21
21
|
return getType(type2).contains ?? [];
|
|
22
22
|
}
|
|
23
23
|
Type2.contains = contains;
|
|
24
|
+
function insertOrder(type2) {
|
|
25
|
+
return getType(type2).insertOrder ?? "free";
|
|
26
|
+
}
|
|
27
|
+
Type2.insertOrder = insertOrder;
|
|
24
28
|
function isHidden(type2) {
|
|
25
29
|
return Boolean(getType(type2).hidden);
|
|
26
30
|
}
|
|
@@ -83,6 +83,7 @@ export declare const entryRoute: Route<{
|
|
|
83
83
|
parents: Array<{
|
|
84
84
|
id: string;
|
|
85
85
|
path: string;
|
|
86
|
+
status: import("alinea/core/EntryRow").EntryStatus;
|
|
86
87
|
}>;
|
|
87
88
|
client: import("alinea/core/Connection").Connection;
|
|
88
89
|
config: import("alinea/core/Config").Config;
|
|
@@ -94,6 +95,8 @@ export declare const entryRoute: Route<{
|
|
|
94
95
|
locale: string;
|
|
95
96
|
entryId: string;
|
|
96
97
|
}>;
|
|
98
|
+
untranslated: boolean;
|
|
99
|
+
canPublish: boolean;
|
|
97
100
|
parentNeedsTranslation: boolean;
|
|
98
101
|
edits: import("./atoms/Edits.js").Edits;
|
|
99
102
|
} | undefined;
|
|
@@ -111,6 +111,7 @@ export declare const entryEditorAtoms: import("jotai/vanilla/utils/atomFamily.js
|
|
|
111
111
|
parents: Array<{
|
|
112
112
|
id: string;
|
|
113
113
|
path: string;
|
|
114
|
+
status: EntryStatus;
|
|
114
115
|
}>;
|
|
115
116
|
client: Connection;
|
|
116
117
|
config: Config;
|
|
@@ -122,6 +123,8 @@ export declare const entryEditorAtoms: import("jotai/vanilla/utils/atomFamily.js
|
|
|
122
123
|
locale: string;
|
|
123
124
|
entryId: string;
|
|
124
125
|
}>;
|
|
126
|
+
untranslated: boolean;
|
|
127
|
+
canPublish: boolean;
|
|
125
128
|
parentNeedsTranslation: boolean;
|
|
126
129
|
edits: Edits;
|
|
127
130
|
} | undefined>>>;
|
|
@@ -129,6 +132,7 @@ export interface EntryData {
|
|
|
129
132
|
parents: Array<{
|
|
130
133
|
id: string;
|
|
131
134
|
path: string;
|
|
135
|
+
status: EntryStatus;
|
|
132
136
|
}>;
|
|
133
137
|
client: Connection;
|
|
134
138
|
config: Config;
|
|
@@ -140,6 +144,8 @@ export interface EntryData {
|
|
|
140
144
|
locale: string;
|
|
141
145
|
entryId: string;
|
|
142
146
|
}>;
|
|
147
|
+
untranslated: boolean;
|
|
148
|
+
canPublish: boolean;
|
|
143
149
|
parentNeedsTranslation: boolean;
|
|
144
150
|
edits: Edits;
|
|
145
151
|
}
|
|
@@ -227,6 +233,7 @@ export declare function createEntryEditor(entryData: EntryData): {
|
|
|
227
233
|
parents: Array<{
|
|
228
234
|
id: string;
|
|
229
235
|
path: string;
|
|
236
|
+
status: EntryStatus;
|
|
230
237
|
}>;
|
|
231
238
|
client: Connection;
|
|
232
239
|
config: Config;
|
|
@@ -238,6 +245,8 @@ export declare function createEntryEditor(entryData: EntryData): {
|
|
|
238
245
|
locale: string;
|
|
239
246
|
entryId: string;
|
|
240
247
|
}>;
|
|
248
|
+
untranslated: boolean;
|
|
249
|
+
canPublish: boolean;
|
|
241
250
|
parentNeedsTranslation: boolean;
|
|
242
251
|
edits: Edits;
|
|
243
252
|
};
|
|
@@ -139,7 +139,8 @@ var entryEditorAtoms = atomFamily(
|
|
|
139
139
|
edge: "parents",
|
|
140
140
|
select: {
|
|
141
141
|
id: Entry.id,
|
|
142
|
-
path: Entry.path
|
|
142
|
+
path: Entry.path,
|
|
143
|
+
status: Entry.status
|
|
143
144
|
}
|
|
144
145
|
}
|
|
145
146
|
},
|
|
@@ -164,7 +165,14 @@ var entryEditorAtoms = atomFamily(
|
|
|
164
165
|
locale: searchLocale,
|
|
165
166
|
status: "preferDraft"
|
|
166
167
|
});
|
|
168
|
+
const untranslated = Boolean(
|
|
169
|
+
entry.locale && searchLocale !== entry.locale
|
|
170
|
+
);
|
|
167
171
|
const parentNeedsTranslation = entry.parentId ? !parentLink : false;
|
|
172
|
+
const parents = withParents?.parents ?? [];
|
|
173
|
+
const canPublish = parents.every(
|
|
174
|
+
(parent) => parent.status === EntryStatus.Published
|
|
175
|
+
);
|
|
168
176
|
if (versions.length === 0)
|
|
169
177
|
return void 0;
|
|
170
178
|
const statuses = fromEntries(
|
|
@@ -174,8 +182,10 @@ var entryEditorAtoms = atomFamily(
|
|
|
174
182
|
(status) => statuses[status] !== void 0
|
|
175
183
|
);
|
|
176
184
|
return createEntryEditor({
|
|
177
|
-
parents
|
|
185
|
+
parents,
|
|
186
|
+
canPublish,
|
|
178
187
|
translations,
|
|
188
|
+
untranslated,
|
|
179
189
|
parentNeedsTranslation,
|
|
180
190
|
client,
|
|
181
191
|
config,
|
|
@@ -640,7 +650,7 @@ function createEntryEditor(entryData) {
|
|
|
640
650
|
});
|
|
641
651
|
const form = atom((get) => {
|
|
642
652
|
const doc = get(currentDoc);
|
|
643
|
-
const readOnly = doc !== edits.doc ? true :
|
|
653
|
+
const readOnly = doc !== edits.doc ? true : !entryData.canPublish;
|
|
644
654
|
return new FormAtoms(type, doc.getMap(DOC_KEY), "", { readOnly });
|
|
645
655
|
});
|
|
646
656
|
const yUpdate = debounceAtom(edits.yUpdate, 250);
|
|
@@ -74,10 +74,9 @@ function EntryEdit({ editor }) {
|
|
|
74
74
|
useEffect(() => {
|
|
75
75
|
ref.current?.scrollTo({ top: 0 });
|
|
76
76
|
}, [editor.entryId, mode, selectedStatus]);
|
|
77
|
-
const untranslated = locale && locale !== editor.activeVersion.locale;
|
|
78
77
|
const { isBlocking, nextRoute, confirm, cancel } = useRouteBlocker(
|
|
79
78
|
"Are you sure you want to discard changes?",
|
|
80
|
-
!untranslated && hasChanges
|
|
79
|
+
!editor.untranslated && hasChanges
|
|
81
80
|
);
|
|
82
81
|
const isNavigationChange = nextRoute?.data.editor?.entryId !== editor.entryId;
|
|
83
82
|
const form = useAtomValue(editor.form);
|
|
@@ -99,7 +98,7 @@ function EntryEdit({ editor }) {
|
|
|
99
98
|
alert("todo");
|
|
100
99
|
return;
|
|
101
100
|
}
|
|
102
|
-
if (untranslated && hasChanges) {
|
|
101
|
+
if (editor.untranslated && hasChanges) {
|
|
103
102
|
translate();
|
|
104
103
|
} else if (config.enableDrafts) {
|
|
105
104
|
if (hasChanges)
|
|
@@ -214,7 +213,7 @@ function EntryEdit({ editor }) {
|
|
|
214
213
|
}
|
|
215
214
|
),
|
|
216
215
|
/* @__PURE__ */ jsxs(Main.Container, { children: [
|
|
217
|
-
untranslated && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
|
|
216
|
+
editor.untranslated && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
|
|
218
217
|
EntryNotice,
|
|
219
218
|
{
|
|
220
219
|
icon: IcRoundTranslate,
|
|
@@ -120,6 +120,7 @@ var variantIcon = {
|
|
|
120
120
|
function EntryHeader({ editor, editable = true }) {
|
|
121
121
|
const config = useConfig();
|
|
122
122
|
const locale = useLocale();
|
|
123
|
+
const { canPublish, untranslated, parentNeedsTranslation } = editor;
|
|
123
124
|
const statusInUrl = useAtomValue(editor.statusInUrl);
|
|
124
125
|
const selectedStatus = useAtomValue(editor.selectedStatus);
|
|
125
126
|
const previewRevision = useAtomValue(editor.previewRevision);
|
|
@@ -128,7 +129,6 @@ function EntryHeader({ editor, editable = true }) {
|
|
|
128
129
|
const isMediaLibrary = editor.activeVersion.type === "MediaLibrary";
|
|
129
130
|
const hasChanges = useAtomValue(editor.hasChanges);
|
|
130
131
|
const currentTransition = useAtomValue(editor.transition)?.transition;
|
|
131
|
-
const untranslated = locale && locale !== editor.activeVersion.locale;
|
|
132
132
|
const variant = currentTransition ? "transition" : previewRevision ? "revision" : untranslated ? "untranslated" : hasChanges && !statusInUrl ? "editing" : selectedStatus;
|
|
133
133
|
const saveDraft = useSetAtom(editor.saveDraft);
|
|
134
134
|
const publishEdits = useSetAtom(editor.publishEdits);
|
|
@@ -224,7 +224,7 @@ function EntryHeader({ editor, editable = true }) {
|
|
|
224
224
|
children: "Archive"
|
|
225
225
|
}
|
|
226
226
|
) : variant === EntryStatus.Archived ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
227
|
-
/* @__PURE__ */ jsx(
|
|
227
|
+
canPublish && /* @__PURE__ */ jsx(
|
|
228
228
|
DropdownMenu.Item,
|
|
229
229
|
{
|
|
230
230
|
className: styles.root.action(),
|
|
@@ -283,7 +283,7 @@ function EntryHeader({ editor, editable = true }) {
|
|
|
283
283
|
})
|
|
284
284
|
] })
|
|
285
285
|
] }),
|
|
286
|
-
editable && !currentTransition && !hasChanges && isActiveStatus && !untranslated && !previewRevision && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
286
|
+
editable && !currentTransition && !hasChanges && isActiveStatus && !untranslated && !previewRevision && canPublish && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
287
287
|
/* @__PURE__ */ jsx("span", { className: styles.root.description.separator() }),
|
|
288
288
|
/* @__PURE__ */ jsx("div", { className: styles.root.description.action(), children: "Edit to create a new draft" })
|
|
289
289
|
] }),
|
|
@@ -291,7 +291,7 @@ function EntryHeader({ editor, editable = true }) {
|
|
|
291
291
|
/* @__PURE__ */ jsx("span", { className: styles.root.description.separator() }),
|
|
292
292
|
/* @__PURE__ */ jsx("div", { className: styles.root.description.action(), children: "A newer draft version is available" })
|
|
293
293
|
] }),
|
|
294
|
-
!currentTransition && untranslated && !
|
|
294
|
+
!currentTransition && untranslated && !parentNeedsTranslation && !hasChanges && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
295
295
|
/* @__PURE__ */ jsx("span", { className: styles.root.description.separator() }),
|
|
296
296
|
/* @__PURE__ */ jsx("div", { className: styles.root.description.action(), children: /* @__PURE__ */ jsxs(HStack, { center: true, children: [
|
|
297
297
|
/* @__PURE__ */ jsx("span", { style: { marginRight: px(8) }, children: "Translate from" }),
|
|
@@ -40,6 +40,7 @@ import { select } from "alinea/field/select";
|
|
|
40
40
|
import { text } from "alinea/field/text";
|
|
41
41
|
import { entryPicker } from "alinea/picker/entry/EntryPicker";
|
|
42
42
|
import { EntryReference } from "alinea/picker/entry/EntryReference";
|
|
43
|
+
import { children, parents } from "alinea/query";
|
|
43
44
|
import { Button, Loader } from "alinea/ui";
|
|
44
45
|
import { Link } from "alinea/ui/Link";
|
|
45
46
|
import { Suspense, useEffect, useMemo, useState } from "react";
|
|
@@ -74,16 +75,19 @@ var parentData = {
|
|
|
74
75
|
url: Entry.url,
|
|
75
76
|
level: Entry.level,
|
|
76
77
|
parent: Entry.parentId,
|
|
77
|
-
parentPaths: {
|
|
78
|
-
edge: "parents",
|
|
78
|
+
parentPaths: parents({
|
|
79
79
|
select: Entry.path
|
|
80
|
-
},
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
edge: "children",
|
|
80
|
+
}),
|
|
81
|
+
firstChildIndex: children({
|
|
82
|
+
take: 1,
|
|
84
83
|
select: Entry.index,
|
|
85
84
|
orderBy: { asc: Entry.index, caseSensitive: true }
|
|
86
|
-
}
|
|
85
|
+
}),
|
|
86
|
+
lastChildIndex: children({
|
|
87
|
+
take: 1,
|
|
88
|
+
select: Entry.index,
|
|
89
|
+
orderBy: { desc: Entry.index, caseSensitive: true }
|
|
90
|
+
})
|
|
87
91
|
};
|
|
88
92
|
var titleField = text("Title", { autoFocus: true });
|
|
89
93
|
function NewEntryForm({ parentId }) {
|
|
@@ -158,6 +162,34 @@ function NewEntryForm({ parentId }) {
|
|
|
158
162
|
};
|
|
159
163
|
});
|
|
160
164
|
}, []);
|
|
165
|
+
const insertOrderField = useMemo(() => {
|
|
166
|
+
const insertOrderField2 = select(
|
|
167
|
+
"Insert order",
|
|
168
|
+
{
|
|
169
|
+
initialValue: "last",
|
|
170
|
+
options: {
|
|
171
|
+
first: "At the top of the list",
|
|
172
|
+
last: "At the bottom of the list"
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
);
|
|
176
|
+
return track.options(insertOrderField2, async (get) => {
|
|
177
|
+
const selectedParent2 = get(parentField);
|
|
178
|
+
const parentId2 = selectedParent2?.[EntryReference.entry];
|
|
179
|
+
const parent = await graph.get({
|
|
180
|
+
select: {
|
|
181
|
+
type: Entry.type
|
|
182
|
+
},
|
|
183
|
+
id: parentId2,
|
|
184
|
+
status: "preferDraft"
|
|
185
|
+
});
|
|
186
|
+
const parentType = parent && config.schema[parent.type];
|
|
187
|
+
const parentInsertOrder = Type.insertOrder(parentType);
|
|
188
|
+
return {
|
|
189
|
+
hidden: parentInsertOrder !== "free"
|
|
190
|
+
};
|
|
191
|
+
});
|
|
192
|
+
}, []);
|
|
161
193
|
const copyFromField = useMemo(() => {
|
|
162
194
|
const copyFromField2 = entry("Copy content from");
|
|
163
195
|
return track.options(copyFromField2, (get) => {
|
|
@@ -183,6 +215,7 @@ function NewEntryForm({ parentId }) {
|
|
|
183
215
|
parent: parentField,
|
|
184
216
|
title: titleField,
|
|
185
217
|
type: typeField,
|
|
218
|
+
order: insertOrderField,
|
|
186
219
|
copyFrom: copyFromField
|
|
187
220
|
}
|
|
188
221
|
}),
|
|
@@ -225,6 +258,7 @@ function NewEntryForm({ parentId }) {
|
|
|
225
258
|
locale,
|
|
226
259
|
status: "preferPublished"
|
|
227
260
|
}) : null;
|
|
261
|
+
const parentType = parent && config.schema[parent.type];
|
|
228
262
|
const parentPaths = parent ? parent.parentPaths.concat(parent.path) : [];
|
|
229
263
|
const filePath = entryFilepath(config, data, parentPaths);
|
|
230
264
|
const childrenDir = entryChildrenDir(config, data, parentPaths);
|
|
@@ -237,6 +271,11 @@ function NewEntryForm({ parentId }) {
|
|
|
237
271
|
id: copyFrom,
|
|
238
272
|
status: "preferPublished"
|
|
239
273
|
}) : Type.initialValue(entryType);
|
|
274
|
+
const parentInsertOrder = parentType ? Type.insertOrder(parentType) : "free";
|
|
275
|
+
let index = generateKeyBetween(null, parent?.firstChildIndex[0] || null);
|
|
276
|
+
if (parentInsertOrder === "last" || parentInsertOrder === "free" && form.data().order === "last") {
|
|
277
|
+
index = generateKeyBetween(parent?.lastChildIndex[0] || null, null);
|
|
278
|
+
}
|
|
240
279
|
const entry2 = await createEntryRow(config, {
|
|
241
280
|
id,
|
|
242
281
|
...data,
|
|
@@ -245,7 +284,7 @@ function NewEntryForm({ parentId }) {
|
|
|
245
284
|
path,
|
|
246
285
|
title,
|
|
247
286
|
url,
|
|
248
|
-
index
|
|
287
|
+
index,
|
|
249
288
|
parentId: parent?.id ?? null,
|
|
250
289
|
seeded: null,
|
|
251
290
|
level: parent ? parent.level + 1 : 0,
|
|
@@ -1675,6 +1675,8 @@ function typeExtension(field, name, type) {
|
|
|
1675
1675
|
const { [BlockNode.id]: id } = node.attrs;
|
|
1676
1676
|
const meta = getType(type);
|
|
1677
1677
|
const { readOnly } = useFieldOptions(field);
|
|
1678
|
+
if (!id)
|
|
1679
|
+
return null;
|
|
1678
1680
|
return /* @__PURE__ */ jsx(FormRow, { field, type, rowId: id, readOnly, children: /* @__PURE__ */ jsx(NodeViewWrapper, { children: /* @__PURE__ */ jsxs(Sink.Root, { style: { margin: `${px(18)} 0` }, children: [
|
|
1679
1681
|
/* @__PURE__ */ jsxs(Sink.Header, { children: [
|
|
1680
1682
|
/* @__PURE__ */ jsx(Sink.Options, { children: /* @__PURE__ */ jsx(
|