@formicoidea/labre-core 1.0.0 → 2.0.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/architecture/code.c4 +48 -44
- package/architecture/likec4.config.json +3 -3
- package/dist/_pkgs/affine-block-root/configs/toolbar.d.ts +1 -1
- package/dist/_pkgs/affine-block-root/configs/toolbar.js +4 -2
- package/dist/_pkgs/affine-block-surface/extensions/reading-toolbar.js +12 -12
- package/dist/_pkgs/affine-components/context-menu/menu-all.d.ts +1 -0
- package/dist/_pkgs/affine-components/context-menu/menu-renderer.d.ts +3 -1
- package/dist/_pkgs/affine-components/context-menu/menu-renderer.js +9 -1
- package/dist/_pkgs/affine-components/context-menu/menu.d.ts +7 -0
- package/dist/_pkgs/affine-components/context-menu/menu.js +5 -0
- package/dist/_pkgs/affine-components/context-menu/sub-menu.d.ts +19 -1
- package/dist/_pkgs/affine-components/context-menu/sub-menu.js +46 -7
- package/dist/_pkgs/affine-components/highlight-dropdown-menu/highlight-duotone-icon.js +8 -8
- package/dist/_pkgs/affine-components/highlight-dropdown-menu/text-duotone-icon.js +11 -11
- package/dist/_pkgs/affine-database-block/configs/slash-menu.d.ts +24 -0
- package/dist/_pkgs/affine-database-block/configs/slash-menu.js +52 -37
- package/dist/_pkgs/affine-database-block/creation-menu.d.ts +6 -0
- package/dist/_pkgs/affine-database-block/data-source.d.ts +6 -0
- package/dist/_pkgs/affine-database-block/data-source.js +16 -0
- package/dist/_pkgs/affine-database-block/database-block-styles.js +4 -3
- package/dist/_pkgs/affine-database-block/database-block.d.ts +23 -0
- package/dist/_pkgs/affine-database-block/database-block.js +129 -19
- package/dist/_pkgs/affine-database-block/database-dnd-preview-block.js +5 -1
- package/dist/_pkgs/affine-database-block/detail-panel/block-renderer.js +5 -2
- package/dist/_pkgs/affine-database-block/detail-panel/note-renderer.js +3 -2
- package/dist/_pkgs/affine-database-block/external-data-source.d.ts +17 -0
- package/dist/_pkgs/affine-database-block/external-data-source.js +54 -4
- package/dist/_pkgs/affine-database-block/index.d.ts +3 -0
- package/dist/_pkgs/affine-database-block/index.js +5 -0
- package/dist/_pkgs/affine-database-block/linked-view.d.ts +59 -0
- package/dist/_pkgs/affine-database-block/linked-view.js +131 -1
- package/dist/_pkgs/affine-database-block/properties/created-time/define.js +3 -1
- package/dist/_pkgs/affine-database-block/properties/link/cell-renderer.js +3 -2
- package/dist/_pkgs/affine-database-block/properties/link/define.js +3 -1
- package/dist/_pkgs/affine-database-block/properties/rich-text/define.js +3 -1
- package/dist/_pkgs/affine-database-block/properties/text/hosted.js +1 -0
- package/dist/_pkgs/affine-database-block/properties/title/define.js +3 -1
- package/dist/_pkgs/affine-database-block/properties/title/hosted.js +1 -0
- package/dist/_pkgs/affine-database-block/service/new-row-menu.d.ts +1 -1
- package/dist/_pkgs/affine-database-block/service/new-row-menu.js +1 -1
- package/dist/_pkgs/affine-database-block/translations.d.ts +29 -0
- package/dist/_pkgs/affine-database-block/translations.js +104 -0
- package/dist/_pkgs/affine-database-block/turn-into-source.d.ts +38 -0
- package/dist/_pkgs/affine-database-block/turn-into-source.js +187 -0
- package/dist/_pkgs/affine-database-block/view-deletion.d.ts +15 -0
- package/dist/_pkgs/affine-database-block/view-deletion.js +113 -0
- package/dist/_pkgs/affine-database-block/views/index.d.ts +7 -9
- package/dist/_pkgs/affine-database-block/views/index.js +7 -10
- package/dist/_pkgs/affine-database-engine/core/common/properties.js +7 -7
- package/dist/_pkgs/affine-database-engine/core/common/property-menu.d.ts +18 -2
- package/dist/_pkgs/affine-database-engine/core/common/property-menu.js +78 -27
- package/dist/_pkgs/affine-database-engine/core/data-source/base.d.ts +11 -0
- package/dist/_pkgs/affine-database-engine/core/data-source/base.js +3 -0
- package/dist/_pkgs/affine-database-engine/core/detail/detail.js +8 -5
- package/dist/_pkgs/affine-database-engine/core/detail/field.js +14 -7
- package/dist/_pkgs/affine-database-engine/core/filter/add-filter.js +4 -2
- package/dist/_pkgs/affine-database-engine/core/filter/filter-fn/boolean.js +7 -4
- package/dist/_pkgs/affine-database-engine/core/filter/filter-fn/create.d.ts +9 -1
- package/dist/_pkgs/affine-database-engine/core/filter/filter-fn/create.js +2 -0
- package/dist/_pkgs/affine-database-engine/core/filter/filter-fn/date.js +7 -4
- package/dist/_pkgs/affine-database-engine/core/filter/filter-fn/multi-tag.js +17 -8
- package/dist/_pkgs/affine-database-engine/core/filter/filter-fn/number.js +6 -6
- package/dist/_pkgs/affine-database-engine/core/filter/filter-fn/string.js +19 -12
- package/dist/_pkgs/affine-database-engine/core/filter/filter-fn/tag.js +9 -4
- package/dist/_pkgs/affine-database-engine/core/filter/filter-fn/unknown.js +7 -4
- package/dist/_pkgs/affine-database-engine/core/filter/literal/define.js +6 -4
- package/dist/_pkgs/affine-database-engine/core/filter/literal/matcher.d.ts +2 -1
- package/dist/_pkgs/affine-database-engine/core/filter/literal/matcher.js +3 -2
- package/dist/_pkgs/affine-database-engine/core/filter/literal/types.d.ts +4 -1
- package/dist/_pkgs/affine-database-engine/core/filter/literal/types.js +1 -1
- package/dist/_pkgs/affine-database-engine/core/group-by/define.js +11 -9
- package/dist/_pkgs/affine-database-engine/core/group-by/group-title.js +16 -6
- package/dist/_pkgs/affine-database-engine/core/group-by/locate-row.d.ts +16 -0
- package/dist/_pkgs/affine-database-engine/core/group-by/locate-row.js +32 -0
- package/dist/_pkgs/affine-database-engine/core/group-by/renderer/date-group.js +10 -3
- package/dist/_pkgs/affine-database-engine/core/group-by/setting.d.ts +2 -0
- package/dist/_pkgs/affine-database-engine/core/group-by/setting.js +40 -28
- package/dist/_pkgs/affine-database-engine/core/group-by/trait.d.ts +3 -0
- package/dist/_pkgs/affine-database-engine/core/group-by/trait.js +8 -0
- package/dist/_pkgs/affine-database-engine/core/group-by/types.d.ts +3 -1
- package/dist/_pkgs/affine-database-engine/core/group-by/types.js +1 -1
- package/dist/_pkgs/affine-database-engine/core/property/types.d.ts +7 -0
- package/dist/_pkgs/affine-database-engine/core/property/types.js +1 -1
- package/dist/_pkgs/affine-database-engine/core/sort/add-sort.js +3 -1
- package/dist/_pkgs/affine-database-engine/core/statistics/any.js +43 -21
- package/dist/_pkgs/affine-database-engine/core/statistics/checkbox.js +29 -14
- package/dist/_pkgs/affine-database-engine/core/statistics/number.js +54 -31
- package/dist/_pkgs/affine-database-engine/core/statistics/types.d.ts +8 -0
- package/dist/_pkgs/affine-database-engine/core/statistics/types.js +2 -1
- package/dist/_pkgs/affine-database-engine/core/utils/wording.d.ts +20 -1
- package/dist/_pkgs/affine-database-engine/core/utils/wording.js +24 -0
- package/dist/_pkgs/affine-database-engine/core/view-manager/property.d.ts +7 -0
- package/dist/_pkgs/affine-database-engine/core/view-manager/property.js +29 -5
- package/dist/_pkgs/affine-database-engine/core/view-manager/single-view.d.ts +14 -0
- package/dist/_pkgs/affine-database-engine/core/view-manager/single-view.js +11 -0
- package/dist/_pkgs/affine-database-engine/property-presets/checkbox/define.js +3 -1
- package/dist/_pkgs/affine-database-engine/property-presets/date/define.js +3 -1
- package/dist/_pkgs/affine-database-engine/property-presets/multi-select/define.js +3 -1
- package/dist/_pkgs/affine-database-engine/property-presets/number/define.js +3 -1
- package/dist/_pkgs/affine-database-engine/property-presets/number/utils/formats.d.ts +3 -0
- package/dist/_pkgs/affine-database-engine/property-presets/number/utils/formats.js +56 -9
- package/dist/_pkgs/affine-database-engine/property-presets/progress/define.js +3 -1
- package/dist/_pkgs/affine-database-engine/property-presets/select/define.js +3 -1
- package/dist/_pkgs/affine-database-engine/property-presets/text/define.js +3 -1
- package/dist/_pkgs/affine-database-engine/translations.d.ts +133 -5
- package/dist/_pkgs/affine-database-engine/translations.js +625 -9
- package/dist/_pkgs/affine-database-engine/view-presets/convert.js +0 -28
- package/dist/_pkgs/affine-database-engine/view-presets/effect.js +0 -2
- package/dist/_pkgs/affine-database-engine/view-presets/flat/flat-converts.js +2 -4
- package/dist/_pkgs/affine-database-engine/view-presets/flat/flat-view-ui.d.ts +57 -0
- package/dist/_pkgs/affine-database-engine/view-presets/flat/flat-view-ui.js +113 -4
- package/dist/_pkgs/affine-database-engine/view-presets/gallery/gallery-view.js +2 -1
- package/dist/_pkgs/affine-database-engine/view-presets/index.d.ts +0 -2
- package/dist/_pkgs/affine-database-engine/view-presets/index.js +0 -3
- package/dist/_pkgs/affine-database-engine/view-presets/kanban/kanban-view-manager.js +2 -0
- package/dist/_pkgs/affine-database-engine/view-presets/kanban/mobile/group.js +7 -5
- package/dist/_pkgs/affine-database-engine/view-presets/kanban/mobile/kanban-view-ui-logic.d.ts +5 -0
- package/dist/_pkgs/affine-database-engine/view-presets/kanban/mobile/kanban-view-ui-logic.js +25 -3
- package/dist/_pkgs/affine-database-engine/view-presets/kanban/mobile/menu.js +12 -6
- package/dist/_pkgs/affine-database-engine/view-presets/kanban/pc/controller/selection.d.ts +8 -0
- package/dist/_pkgs/affine-database-engine/view-presets/kanban/pc/controller/selection.js +35 -12
- package/dist/_pkgs/affine-database-engine/view-presets/kanban/pc/group.js +7 -5
- package/dist/_pkgs/affine-database-engine/view-presets/kanban/pc/header.js +5 -1
- package/dist/_pkgs/affine-database-engine/view-presets/kanban/pc/kanban-view-ui-logic.d.ts +5 -0
- package/dist/_pkgs/affine-database-engine/view-presets/kanban/pc/kanban-view-ui-logic.js +8 -4
- package/dist/_pkgs/affine-database-engine/view-presets/kanban/pc/menu.js +12 -6
- package/dist/_pkgs/affine-database-engine/view-presets/list/list-view.js +2 -1
- package/dist/_pkgs/affine-database-engine/view-presets/table/mobile/column-header.js +6 -4
- package/dist/_pkgs/affine-database-engine/view-presets/table/mobile/group.js +6 -5
- package/dist/_pkgs/affine-database-engine/view-presets/table/mobile/header.js +2 -2
- package/dist/_pkgs/affine-database-engine/view-presets/table/mobile/table-view-ui-logic.d.ts +4 -3
- package/dist/_pkgs/affine-database-engine/view-presets/table/mobile/table-view-ui-logic.js +29 -5
- package/dist/_pkgs/affine-database-engine/view-presets/table/pc/controller/clipboard.js +6 -2
- package/dist/_pkgs/affine-database-engine/view-presets/table/pc/controller/selection.js +2 -0
- package/dist/_pkgs/affine-database-engine/view-presets/table/pc/group.js +6 -5
- package/dist/_pkgs/affine-database-engine/view-presets/table/pc/header/column-header.js +11 -7
- package/dist/_pkgs/affine-database-engine/view-presets/table/pc/header/database-header-column.js +16 -12
- package/dist/_pkgs/affine-database-engine/view-presets/table/pc/header/number-format-bar.js +4 -2
- package/dist/_pkgs/affine-database-engine/view-presets/table/pc/menu.js +9 -6
- package/dist/_pkgs/affine-database-engine/view-presets/table/pc/table-view-ui-logic.d.ts +8 -1
- package/dist/_pkgs/affine-database-engine/view-presets/table/pc/table-view-ui-logic.js +29 -7
- package/dist/_pkgs/affine-database-engine/view-presets/table/pc-virtual/controller/clipboard.js +6 -2
- package/dist/_pkgs/affine-database-engine/view-presets/table/pc-virtual/controller/selection.js +2 -0
- package/dist/_pkgs/affine-database-engine/view-presets/table/pc-virtual/group/bottom/group-footer.js +5 -2
- package/dist/_pkgs/affine-database-engine/view-presets/table/pc-virtual/group/bottom/stats/column-stats-column.d.ts +1 -1
- package/dist/_pkgs/affine-database-engine/view-presets/table/pc-virtual/group/bottom/stats/column-stats-column.js +14 -6
- package/dist/_pkgs/affine-database-engine/view-presets/table/pc-virtual/group/top/group-header.js +5 -2
- package/dist/_pkgs/affine-database-engine/view-presets/table/pc-virtual/group/top/group-title.js +5 -3
- package/dist/_pkgs/affine-database-engine/view-presets/table/pc-virtual/group/top/header/column-header.js +17 -10
- package/dist/_pkgs/affine-database-engine/view-presets/table/pc-virtual/group/top/header/number-format-bar.js +4 -2
- package/dist/_pkgs/affine-database-engine/view-presets/table/pc-virtual/group/top/header/single-column-header.js +20 -14
- package/dist/_pkgs/affine-database-engine/view-presets/table/pc-virtual/row/menu.js +9 -6
- package/dist/_pkgs/affine-database-engine/view-presets/table/pc-virtual/table-view-ui-logic.d.ts +6 -1
- package/dist/_pkgs/affine-database-engine/view-presets/table/pc-virtual/table-view-ui-logic.js +30 -3
- package/dist/_pkgs/affine-database-engine/view-presets/table/stats/column-stats-column.d.ts +1 -1
- package/dist/_pkgs/affine-database-engine/view-presets/table/stats/column-stats-column.js +14 -6
- package/dist/_pkgs/affine-database-engine/view-presets/table/table-view-manager.js +2 -0
- package/dist/_pkgs/affine-database-engine/widget-presets/quick-setting-bar/filter/condition-view.d.ts +2 -0
- package/dist/_pkgs/affine-database-engine/widget-presets/quick-setting-bar/filter/condition-view.js +13 -6
- package/dist/_pkgs/affine-database-engine/widget-presets/quick-setting-bar/filter/group-panel-view.js +20 -13
- package/dist/_pkgs/affine-database-engine/widget-presets/quick-setting-bar/filter/root-panel-view.js +10 -5
- package/dist/_pkgs/affine-database-engine/widget-presets/quick-setting-bar/sort/root-panel.js +8 -5
- package/dist/_pkgs/affine-database-engine/widget-presets/tools/presets/search/search.js +2 -2
- package/dist/_pkgs/affine-database-engine/widget-presets/tools/presets/table-add-row/add-row.d.ts +6 -0
- package/dist/_pkgs/affine-database-engine/widget-presets/tools/presets/table-add-row/add-row.js +49 -4
- package/dist/_pkgs/affine-database-engine/widget-presets/tools/presets/view-options/view-settings.d.ts +3 -3
- package/dist/_pkgs/affine-database-engine/widget-presets/tools/presets/view-options/view-settings.js +3 -3
- package/dist/_pkgs/affine-database-engine/widget-presets/views-bar/views-view.js +5 -0
- package/dist/_pkgs/affine-database-view-block/configs/slash-menu.js +6 -3
- package/dist/_pkgs/affine-database-view-block/data-view-block.js +5 -4
- package/dist/_pkgs/affine-fragment-doc-title/doc-title.d.ts +3 -2
- package/dist/_pkgs/affine-fragment-doc-title/doc-title.js +3 -2
- package/dist/_pkgs/affine-shared/services/data-source-picker-service.d.ts +130 -1
- package/dist/_pkgs/affine-widget-edgeless-zoom-toolbar/index.js +26 -26
- package/dist/_pkgs/affine-widget-keyboard-toolbar/config.js +10 -21
- package/dist/_pkgs/affine-widget-keyboard-toolbar/icons.js +98 -98
- package/dist/_pkgs/affine-widget-page-dragging-area/index.js +10 -10
- package/dist/_pkgs/affine-widget-viewport-overlay/index.js +13 -13
- package/package.json +1 -1
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/calendar-view-manager.d.ts +0 -70
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/calendar-view-manager.js +0 -449
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/define.d.ts +0 -10
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/define.js +0 -29
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/effect.d.ts +0 -1
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/effect.js +0 -4
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/index.d.ts +0 -6
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/index.js +0 -6
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/layout.d.ts +0 -37
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/layout.js +0 -138
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/pc/actions.d.ts +0 -7
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/pc/actions.js +0 -64
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/pc/dnd.d.ts +0 -32
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/pc/dnd.js +0 -159
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/pc/effect.d.ts +0 -1
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/pc/effect.js +0 -7
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/pc/hit-test.d.ts +0 -1
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/pc/hit-test.js +0 -28
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/pc/styles.d.ts +0 -1
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/pc/styles.js +0 -707
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/pc/view.d.ts +0 -89
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/pc/view.js +0 -849
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/renderer.d.ts +0 -2
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/renderer.js +0 -8
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/source.d.ts +0 -8
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/source.js +0 -3
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/types.d.ts +0 -79
- package/dist/_pkgs/affine-database-engine/view-presets/calendar/types.js +0 -1
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { toast } from '../affine-components/toast/index.js';
|
|
2
|
+
import { DataSourcePickerProvider, NotificationProvider, translateKey, } from '../affine-shared/services/index.js';
|
|
3
|
+
import { insertLinkedDatabaseView, moveDatabaseIntoSource, } from './linked-view.js';
|
|
4
|
+
import { DATABASE_TURN_INTO_FAILED, DATABASE_TURN_INTO_NESTED, } from './translations.js';
|
|
5
|
+
/**
|
|
6
|
+
* "Turn into a source" (ADR 0035 amendment of 2026-10-29): under a host that
|
|
7
|
+
* requires a source (`requireSource`), "Create Table" on selected paragraphs
|
|
8
|
+
* and "Move into a database" on a database with native rows hand their
|
|
9
|
+
* content to the host's `createDatabaseFrom`, then connect the block to the
|
|
10
|
+
* database it answers, in one undo step. Nothing is written until the host
|
|
11
|
+
* answers; a refusal, a rejection, a read-only document or content changed
|
|
12
|
+
* in the meantime writes nothing and says so with a fixed message.
|
|
13
|
+
*/
|
|
14
|
+
/** The id of the title property a conversion of paragraphs sends. */
|
|
15
|
+
export const TURN_INTO_TITLE_PROPERTY = 'title';
|
|
16
|
+
function notify(std, wording) {
|
|
17
|
+
const message = translateKey(std, ...wording);
|
|
18
|
+
const notification = std.getOptional(NotificationProvider);
|
|
19
|
+
if (notification)
|
|
20
|
+
notification.toast(message);
|
|
21
|
+
else
|
|
22
|
+
toast(std.host, message);
|
|
23
|
+
}
|
|
24
|
+
function rowOf(std, block, values = {}) {
|
|
25
|
+
const transformer = std.store.getTransformer();
|
|
26
|
+
return {
|
|
27
|
+
// A Y.Text delta holds inserts only; the guard narrows its type.
|
|
28
|
+
title: (block.text?.toDelta() ?? []).filter((op) => typeof op.insert === 'string'),
|
|
29
|
+
values,
|
|
30
|
+
body: block.children.flatMap(child => {
|
|
31
|
+
const snapshot = transformer.blockToSnapshot(child);
|
|
32
|
+
return snapshot ? [snapshot] : [];
|
|
33
|
+
}),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/** The blocks, less those nested in another of them: they ride in its body. */
|
|
37
|
+
export function outermostBlocks(blocks) {
|
|
38
|
+
const ids = new Set(blocks.map(block => block.id));
|
|
39
|
+
return blocks.filter(block => {
|
|
40
|
+
for (let parent = block.parent; parent; parent = parent.parent) {
|
|
41
|
+
if (ids.has(parent.id))
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
return true;
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/** One row per block, its title the block's text, its body its children. */
|
|
48
|
+
export function blocksContent(std, blocks) {
|
|
49
|
+
return {
|
|
50
|
+
title: '',
|
|
51
|
+
properties: [{ id: TURN_INTO_TITLE_PROPERTY, name: '', type: 'title' }],
|
|
52
|
+
rows: blocks.map(block => rowOf(std, block)),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* A native database's columns and rows. A value is sent as stored, a rich
|
|
57
|
+
* text as its delta; the title column is the row's own text.
|
|
58
|
+
*/
|
|
59
|
+
export function databaseContent(std, model) {
|
|
60
|
+
const columns = model.props.columns;
|
|
61
|
+
const title = columns.find(column => column.type === 'title');
|
|
62
|
+
const properties = [
|
|
63
|
+
title
|
|
64
|
+
? { id: title.id, name: title.name, type: 'title' }
|
|
65
|
+
: { id: TURN_INTO_TITLE_PROPERTY, name: '', type: 'title' },
|
|
66
|
+
...columns
|
|
67
|
+
.filter(column => column.type !== 'title')
|
|
68
|
+
.map(column => {
|
|
69
|
+
const options = column.data.options;
|
|
70
|
+
return {
|
|
71
|
+
id: column.id,
|
|
72
|
+
name: column.name,
|
|
73
|
+
type: column.type,
|
|
74
|
+
...(Array.isArray(options)
|
|
75
|
+
? {
|
|
76
|
+
options: options.map((option) => ({
|
|
77
|
+
id: option.id,
|
|
78
|
+
value: option.value,
|
|
79
|
+
})),
|
|
80
|
+
}
|
|
81
|
+
: {}),
|
|
82
|
+
};
|
|
83
|
+
}),
|
|
84
|
+
];
|
|
85
|
+
const rows = model.children.map(row => {
|
|
86
|
+
const values = {};
|
|
87
|
+
for (const column of columns) {
|
|
88
|
+
if (column.type === 'title')
|
|
89
|
+
continue;
|
|
90
|
+
const value = model.props.cells[row.id]?.[column.id]?.value;
|
|
91
|
+
if (value === undefined)
|
|
92
|
+
continue;
|
|
93
|
+
values[column.id] =
|
|
94
|
+
value && typeof value === 'object' && 'toDelta' in value
|
|
95
|
+
? value.toDelta()
|
|
96
|
+
: value;
|
|
97
|
+
}
|
|
98
|
+
return rowOf(std, row, values);
|
|
99
|
+
});
|
|
100
|
+
return { title: model.props.title.toString(), properties, rows };
|
|
101
|
+
}
|
|
102
|
+
/** Whether the host turns content into a source where one is required. */
|
|
103
|
+
export function canTurnIntoSource(std) {
|
|
104
|
+
const picker = std.getOptional(DataSourcePickerProvider);
|
|
105
|
+
return picker?.requireSource === true && !!picker.createDatabaseFrom;
|
|
106
|
+
}
|
|
107
|
+
/** The host's database for `content`, or `null` once the reader was told why. */
|
|
108
|
+
async function createFrom(std, content) {
|
|
109
|
+
const picker = std.getOptional(DataSourcePickerProvider);
|
|
110
|
+
const createDatabaseFrom = picker?.createDatabaseFrom;
|
|
111
|
+
if (!picker || !createDatabaseFrom || std.store.readonly)
|
|
112
|
+
return null;
|
|
113
|
+
if (!picker.rowBodies && content.rows.some(row => row.body.length > 0)) {
|
|
114
|
+
notify(std, DATABASE_TURN_INTO_NESTED);
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
const database = await createDatabaseFrom.call(picker, content);
|
|
119
|
+
if (database?.sources[0])
|
|
120
|
+
return database;
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
console.error(error);
|
|
124
|
+
}
|
|
125
|
+
notify(std, DATABASE_TURN_INTO_FAILED);
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* "Create Table" under a host that requires a source: the selected blocks
|
|
130
|
+
* become the rows of a new host database, and a view of its first source
|
|
131
|
+
* takes their place. Returns whether it was written.
|
|
132
|
+
*/
|
|
133
|
+
export async function turnBlocksIntoSource(std, selected, viewType) {
|
|
134
|
+
const blocks = outermostBlocks(selected);
|
|
135
|
+
const first = blocks[0];
|
|
136
|
+
if (!first || std.store.readonly)
|
|
137
|
+
return false;
|
|
138
|
+
const content = blocksContent(std, blocks);
|
|
139
|
+
const database = await createFrom(std, content);
|
|
140
|
+
const source = database?.sources[0];
|
|
141
|
+
if (!database || !source)
|
|
142
|
+
return false;
|
|
143
|
+
const unchanged = !std.store.readonly &&
|
|
144
|
+
blocks.every(block => std.store.getBlock(block.id)) &&
|
|
145
|
+
JSON.stringify(blocksContent(std, blocks)) === JSON.stringify(content);
|
|
146
|
+
if (!unchanged) {
|
|
147
|
+
notify(std, DATABASE_TURN_INTO_FAILED);
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
// `insertLinkedDatabaseView` opens the undo step; the deletions join it.
|
|
151
|
+
const id = insertLinkedDatabaseView(std, {
|
|
152
|
+
after: first,
|
|
153
|
+
database,
|
|
154
|
+
sourceId: source.id,
|
|
155
|
+
viewType,
|
|
156
|
+
});
|
|
157
|
+
if (!id) {
|
|
158
|
+
notify(std, DATABASE_TURN_INTO_FAILED);
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
for (const block of blocks)
|
|
162
|
+
std.store.deleteBlock(block);
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* "Move into a database" over native rows shown read-only: the database's
|
|
167
|
+
* columns and rows become a new host database, and the block reads its
|
|
168
|
+
* first source (`moveDatabaseIntoSource`). Returns whether it was written.
|
|
169
|
+
*/
|
|
170
|
+
export async function moveDatabaseRowsIntoSource(std, model) {
|
|
171
|
+
if (std.store.readonly || model.props.externalSourceId !== undefined) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
const content = databaseContent(std, model);
|
|
175
|
+
const database = await createFrom(std, content);
|
|
176
|
+
const source = database?.sources[0];
|
|
177
|
+
if (!database || !source)
|
|
178
|
+
return false;
|
|
179
|
+
const unchanged = !!std.store.getBlock(model.id) &&
|
|
180
|
+
JSON.stringify(databaseContent(std, model)) === JSON.stringify(content);
|
|
181
|
+
if (!unchanged ||
|
|
182
|
+
!moveDatabaseIntoSource(std, model, { database, sourceId: source.id })) {
|
|
183
|
+
notify(std, DATABASE_TURN_INTO_FAILED);
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DatabaseBlockModel } from '../affine-model/index.js';
|
|
2
|
+
import type { DataSourcePickerService } from '../affine-shared/services/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Deletes view `viewId` of `model`, through the host's `deleteView` when it
|
|
5
|
+
* has one and the block shows one of its databases; at once otherwise.
|
|
6
|
+
* `removeNow` is the 1.0 removal (one undo step); `afterRemove` runs after a
|
|
7
|
+
* removal the host asked for (the view to show next).
|
|
8
|
+
*/
|
|
9
|
+
export declare function deleteViewThroughHost(options: {
|
|
10
|
+
model: DatabaseBlockModel;
|
|
11
|
+
viewId: string;
|
|
12
|
+
picker: DataSourcePickerService | null;
|
|
13
|
+
removeNow: () => void;
|
|
14
|
+
afterRemove: () => void;
|
|
15
|
+
}): void;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A host decides what a deleted view takes with it (ADR 0035 amendment of
|
|
3
|
+
* 2026-10-29). Labre sends a source to its trash with the last view reading
|
|
4
|
+
* it, and must confirm that BEFORE the view goes, then restore it when the
|
|
5
|
+
* removal is undone. So the delete gesture of a view of a host database
|
|
6
|
+
* becomes a request (`DataSourcePickerService.deleteView`) whose `remove()`
|
|
7
|
+
* is the 1.0 removal, and the undo step it makes is tagged so an undo or a
|
|
8
|
+
* redo of it reaches `viewHistory`.
|
|
9
|
+
*
|
|
10
|
+
* The tag rides in the undo step's `meta`. Yjs builds a NEW step for the
|
|
11
|
+
* opposite stack while it pops one ('stack-item-added' with the undo manager
|
|
12
|
+
* as origin, fired inside the pop's transaction, before 'stack-item-popped'),
|
|
13
|
+
* so the tag is carried over to that step, and an undo, redo, undo… chain
|
|
14
|
+
* keeps reporting. Remote updates never pop a step: they report nothing.
|
|
15
|
+
*/
|
|
16
|
+
const VIEW_REMOVED = 'labre:database-view-removed';
|
|
17
|
+
// One listener pair per undo manager, whatever the number of blocks: the
|
|
18
|
+
// step outlives the block's data source (a block remounted after a mode
|
|
19
|
+
// switch, or unmounted, still has its removals undone).
|
|
20
|
+
const watches = new WeakMap();
|
|
21
|
+
function isViewRef(value) {
|
|
22
|
+
if (typeof value !== 'object' || value === null)
|
|
23
|
+
return false;
|
|
24
|
+
const ref = value;
|
|
25
|
+
return (typeof ref.databaseId === 'string' &&
|
|
26
|
+
typeof ref.viewId === 'string' &&
|
|
27
|
+
typeof ref.docId === 'string' &&
|
|
28
|
+
typeof ref.blockId === 'string');
|
|
29
|
+
}
|
|
30
|
+
function watchHistory(undoManager, picker) {
|
|
31
|
+
const known = watches.get(undoManager);
|
|
32
|
+
if (known) {
|
|
33
|
+
known.picker = picker;
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const watch = { picker };
|
|
37
|
+
watches.set(undoManager, watch);
|
|
38
|
+
let replay = null;
|
|
39
|
+
undoManager.on('stack-item-added', event => {
|
|
40
|
+
if (event.origin === undoManager)
|
|
41
|
+
replay = event.stackItem;
|
|
42
|
+
});
|
|
43
|
+
undoManager.on('stack-item-popped', event => {
|
|
44
|
+
const opposite = replay;
|
|
45
|
+
replay = null;
|
|
46
|
+
const ref = event.stackItem.meta.get(VIEW_REMOVED);
|
|
47
|
+
if (!isViewRef(ref))
|
|
48
|
+
return;
|
|
49
|
+
opposite?.meta.set(VIEW_REMOVED, ref);
|
|
50
|
+
try {
|
|
51
|
+
watch.picker.viewHistory?.(ref, event.type);
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
// A host failure must not break the undo itself.
|
|
55
|
+
console.error(error);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Deletes view `viewId` of `model`, through the host's `deleteView` when it
|
|
61
|
+
* has one and the block shows one of its databases; at once otherwise.
|
|
62
|
+
* `removeNow` is the 1.0 removal (one undo step); `afterRemove` runs after a
|
|
63
|
+
* removal the host asked for (the view to show next).
|
|
64
|
+
*/
|
|
65
|
+
export function deleteViewThroughHost(options) {
|
|
66
|
+
const { model, viewId, picker, removeNow, afterRemove } = options;
|
|
67
|
+
const store = model.store;
|
|
68
|
+
const databaseId = model.props.externalSourceId;
|
|
69
|
+
const deleteView = picker?.deleteView;
|
|
70
|
+
if (!picker || !deleteView || !databaseId || store.readonly) {
|
|
71
|
+
removeNow();
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const view = model.props.views.find(v => v.id === viewId);
|
|
75
|
+
if (!view)
|
|
76
|
+
return;
|
|
77
|
+
const ref = {
|
|
78
|
+
databaseId,
|
|
79
|
+
viewId,
|
|
80
|
+
docId: store.id,
|
|
81
|
+
blockId: model.id,
|
|
82
|
+
...(view.sourceId === undefined ? {} : { sourceId: view.sourceId }),
|
|
83
|
+
};
|
|
84
|
+
let used = false;
|
|
85
|
+
const request = {
|
|
86
|
+
...ref,
|
|
87
|
+
viewName: typeof view.name === 'string' ? view.name : '',
|
|
88
|
+
remove: () => {
|
|
89
|
+
if (used || store.readonly)
|
|
90
|
+
return false;
|
|
91
|
+
if (!model.props.views.some(v => v.id === viewId))
|
|
92
|
+
return false;
|
|
93
|
+
used = true;
|
|
94
|
+
const undoManager = store.history.undoManager;
|
|
95
|
+
watchHistory(undoManager, picker);
|
|
96
|
+
let added = null;
|
|
97
|
+
const grab = (event) => {
|
|
98
|
+
added = event.stackItem;
|
|
99
|
+
};
|
|
100
|
+
undoManager.on('stack-item-added', grab);
|
|
101
|
+
try {
|
|
102
|
+
removeNow();
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
undoManager.off('stack-item-added', grab);
|
|
106
|
+
}
|
|
107
|
+
added?.meta.set(VIEW_REMOVED, ref);
|
|
108
|
+
afterRemove();
|
|
109
|
+
return true;
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
deleteView.call(picker, request);
|
|
113
|
+
}
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import type { ViewMeta } from '../../affine-database-engine/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* Every preset a stored `affine:database` view can be drawn with (ADR 0035
|
|
4
|
-
* §6).
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* §6). A mode that leaves this list falls back to a table on every document
|
|
5
|
+
* that stores it, so shrinking it is a major and an ADR decision: calendar
|
|
6
|
+
* left it in 2.0 (ADR 0035 amendment of 2026-10-29), and a stored calendar
|
|
7
|
+
* now draws as a table through `databaseBlockViewMetaGet`.
|
|
8
8
|
*/
|
|
9
9
|
export declare const databaseBlockRenderableViews: ViewMeta[];
|
|
10
10
|
/**
|
|
11
11
|
* The presets a user can CREATE, a subset of the renderable ones: what the
|
|
12
12
|
* data source answers as `viewMetas`, so the views bar ("+", "Create …") and
|
|
13
|
-
* the Layout switch list only these.
|
|
14
|
-
* labre ADR-0046 §8): no new calendar, the stored ones still render.
|
|
13
|
+
* the Layout switch list only these.
|
|
15
14
|
*/
|
|
16
15
|
export declare const databaseBlockViews: ViewMeta[];
|
|
17
16
|
/** The preset a mode with none of its own is drawn with. */
|
|
@@ -26,8 +25,7 @@ export declare const databaseBlockViewMap: Record<string, ViewMeta | undefined>;
|
|
|
26
25
|
*/
|
|
27
26
|
export declare function databaseBlockViewMetaGet(mode: string): ViewMeta;
|
|
28
27
|
/**
|
|
29
|
-
* Conversions INTO a creatable preset only:
|
|
30
|
-
*
|
|
31
|
-
* stored calendar can still become a table or a board.
|
|
28
|
+
* Conversions INTO a creatable preset only: a layout switch never creates a
|
|
29
|
+
* view a user could not have added.
|
|
32
30
|
*/
|
|
33
31
|
export declare const databaseBlockViewConverts: import("../index.js").ViewConvertConfig[];
|
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
import { viewConverts, viewPresets, } from '../../affine-database-engine/view-presets/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* Every preset a stored `affine:database` view can be drawn with (ADR 0035
|
|
4
|
-
* §6).
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* §6). A mode that leaves this list falls back to a table on every document
|
|
5
|
+
* that stores it, so shrinking it is a major and an ADR decision: calendar
|
|
6
|
+
* left it in 2.0 (ADR 0035 amendment of 2026-10-29), and a stored calendar
|
|
7
|
+
* now draws as a table through `databaseBlockViewMetaGet`.
|
|
8
8
|
*/
|
|
9
9
|
export const databaseBlockRenderableViews = [
|
|
10
10
|
viewPresets.tableViewMeta,
|
|
11
11
|
viewPresets.kanbanViewMeta,
|
|
12
|
-
viewPresets.calendarViewMeta,
|
|
13
12
|
viewPresets.galleryViewMeta,
|
|
14
13
|
viewPresets.listViewMeta,
|
|
15
14
|
];
|
|
16
15
|
/**
|
|
17
16
|
* The presets a user can CREATE, a subset of the renderable ones: what the
|
|
18
17
|
* data source answers as `viewMetas`, so the views bar ("+", "Create …") and
|
|
19
|
-
* the Layout switch list only these.
|
|
20
|
-
* labre ADR-0046 §8): no new calendar, the stored ones still render.
|
|
18
|
+
* the Layout switch list only these.
|
|
21
19
|
*/
|
|
22
20
|
export const databaseBlockViews = [
|
|
23
21
|
viewPresets.tableViewMeta,
|
|
@@ -42,8 +40,7 @@ export function databaseBlockViewMetaGet(mode) {
|
|
|
42
40
|
}
|
|
43
41
|
const creatableModes = new Set(databaseBlockViews.map(view => view.type));
|
|
44
42
|
/**
|
|
45
|
-
* Conversions INTO a creatable preset only:
|
|
46
|
-
*
|
|
47
|
-
* stored calendar can still become a table or a board.
|
|
43
|
+
* Conversions INTO a creatable preset only: a layout switch never creates a
|
|
44
|
+
* view a user could not have added.
|
|
48
45
|
*/
|
|
49
46
|
export const databaseBlockViewConverts = viewConverts.filter(convert => creatableModes.has(convert.to));
|
|
@@ -42,7 +42,7 @@ import { css, html, nothing, unsafeCSS } from 'lit';
|
|
|
42
42
|
import { property, query } from 'lit/decorators.js';
|
|
43
43
|
import { classMap } from 'lit/directives/class-map.js';
|
|
44
44
|
import { repeat } from 'lit/directives/repeat.js';
|
|
45
|
-
import { DATA_VIEW_NEW_PROPERTY, DATA_VIEW_PROPERTIES, DATA_VIEW_PROPERTY_TYPE, } from '../../translations.js';
|
|
45
|
+
import { DATA_VIEW_NEW_PROPERTY, DATA_VIEW_PROPERTIES, DATA_VIEW_PROPERTY_TYPE, DATA_VIEW_HIDE_ALL, DATA_VIEW_SHOW_ALL, } from '../../translations.js';
|
|
46
46
|
import { dragHandler } from '../utils/wc-dnd/dnd-context.js';
|
|
47
47
|
import { defaultActivators } from '../utils/wc-dnd/sensors/index.js';
|
|
48
48
|
import { createSortContext, sortable, } from '../utils/wc-dnd/sort/sort-context.js';
|
|
@@ -214,8 +214,9 @@ let DataViewPropertiesSettingView = (() => {
|
|
|
214
214
|
get view() { return this.#view_accessor_storage; }
|
|
215
215
|
set view(value) { this.#view_accessor_storage = value; }
|
|
216
216
|
_renderNewProperty() {
|
|
217
|
-
if (this.view.readonly$.value)
|
|
217
|
+
if (this.view.readonly$.value || this.view.propertiesLocked$.value) {
|
|
218
218
|
return nothing;
|
|
219
|
+
}
|
|
219
220
|
return html `<div
|
|
220
221
|
class="property-item property-item-new"
|
|
221
222
|
data-testid="data-view-properties-new"
|
|
@@ -267,16 +268,15 @@ let DataViewPropertiesSettingView = (() => {
|
|
|
267
268
|
this._openMenu = (property, row) => {
|
|
268
269
|
if (this.view.readonly$.value)
|
|
269
270
|
return;
|
|
270
|
-
popPropertyMenu(popupTargetFromElement(row), property, {
|
|
271
|
-
wording: this.wording,
|
|
272
|
-
});
|
|
271
|
+
popPropertyMenu(popupTargetFromElement(row), property, { wording: this.wording }, { beside: true });
|
|
273
272
|
};
|
|
274
273
|
this._newProperty = (event) => {
|
|
275
|
-
if (this.view.readonly$.value)
|
|
274
|
+
if (this.view.readonly$.value || this.view.propertiesLocked$.value)
|
|
276
275
|
return;
|
|
277
276
|
const button = event.currentTarget;
|
|
278
277
|
popNewPropertyMenu(popupTargetFromElement(button), this.view, {
|
|
279
278
|
title: this.wording(DATA_VIEW_PROPERTY_TYPE),
|
|
279
|
+
wording: this.wording,
|
|
280
280
|
onAdd: id => {
|
|
281
281
|
this.updateComplete
|
|
282
282
|
.then(() => {
|
|
@@ -385,7 +385,7 @@ export const popPropertiesSetting = (target, props) => {
|
|
|
385
385
|
class="properties-group-op"
|
|
386
386
|
@click="${clickChangeAll}"
|
|
387
387
|
>
|
|
388
|
-
${isAllShowed ?
|
|
388
|
+
${(props.wording ?? englishWording)(isAllShowed ? DATA_VIEW_HIDE_ALL : DATA_VIEW_SHOW_ALL)}
|
|
389
389
|
</div>`;
|
|
390
390
|
},
|
|
391
391
|
},
|
|
@@ -2,7 +2,7 @@ import { type MenuConfig, type PopupTarget } from '../../../affine-components/co
|
|
|
2
2
|
import { type Wording } from '../utils/wording.js';
|
|
3
3
|
import type { Property } from '../view-manager/property.js';
|
|
4
4
|
import type { SingleView } from '../view-manager/single-view.js';
|
|
5
|
-
export declare const inputConfig: (property: Property, wording?: Wording) =>
|
|
5
|
+
export declare const inputConfig: (property: Property, wording?: Wording) => MenuConfig;
|
|
6
6
|
export declare const typeConfig: (property: Property, wording?: Wording) => (menu: import("../../../affine-components/context-menu/menu.js").Menu, index: number) => import("lit-html").TemplateResult | undefined;
|
|
7
7
|
/** What a property menu's opener adds around the shared entries. */
|
|
8
8
|
export type PropertyMenuSlots = {
|
|
@@ -32,7 +32,22 @@ export type PropertyMenuSlots = {
|
|
|
32
32
|
* own copy of these entries; point it here in a dedicated pass.
|
|
33
33
|
*/
|
|
34
34
|
export declare const propertyMenuItems: (property: Property, slots?: PropertyMenuSlots) => MenuConfig[];
|
|
35
|
-
|
|
35
|
+
/**
|
|
36
|
+
* A property menu opened from a list of properties sits BESIDE the list, on
|
|
37
|
+
* the side with more room, and stays inside the viewport: below the row it
|
|
38
|
+
* covered the list, and in a host's narrow sidebar (labre, about 470px) it
|
|
39
|
+
* hid the very rows it edits, its « Type » sub-menu half off screen (labre
|
|
40
|
+
* recette of 1.1). The sub-menu then opens on the same side
|
|
41
|
+
* (`nestedSubMenuPosition`).
|
|
42
|
+
*/
|
|
43
|
+
export declare const besideListMiddleware: () => {
|
|
44
|
+
name: string;
|
|
45
|
+
options?: any;
|
|
46
|
+
fn: (state: import("@floating-ui/dom").MiddlewareState) => import("@floating-ui/core").MiddlewareReturn | Promise<import("@floating-ui/core").MiddlewareReturn>;
|
|
47
|
+
}[];
|
|
48
|
+
export declare const popPropertyMenu: (target: PopupTarget, property: Property, slots?: PropertyMenuSlots, placement?: {
|
|
49
|
+
beside?: boolean;
|
|
50
|
+
}) => import("../../../affine-components/context-menu/menu-renderer.js").MenuHandler;
|
|
36
51
|
/**
|
|
37
52
|
* The type picker of a new property, as the virtual table header's "+" and
|
|
38
53
|
* the record detail's "Add property" draw it: one entry per type the source
|
|
@@ -43,4 +58,5 @@ export declare const popPropertyMenu: (target: PopupTarget, property: Property,
|
|
|
43
58
|
export declare const popNewPropertyMenu: (target: PopupTarget, view: SingleView, options: {
|
|
44
59
|
title: string;
|
|
45
60
|
onAdd: (id: string) => void;
|
|
61
|
+
wording?: Wording;
|
|
46
62
|
}) => import("../../../affine-components/context-menu/menu-renderer.js").MenuHandler;
|
|
@@ -1,11 +1,45 @@
|
|
|
1
1
|
import { menu, popMenu, } from '../../../affine-components/context-menu/index.js';
|
|
2
2
|
import { TOOLBAR_DELETE, TOOLBAR_DUPLICATE, } from '../../../affine-shared/services/index.js';
|
|
3
3
|
import { DeleteIcon, DuplicateIcon, ViewIcon } from '@blocksuite/icons/lit';
|
|
4
|
+
import { autoPlacement, offset, shift } from '@floating-ui/dom';
|
|
4
5
|
import { html } from 'lit/static-html.js';
|
|
5
|
-
import { DATA_VIEW_PROPERTY_HIDE_IN_VIEW, DATA_VIEW_PROPERTY_NAME, DATA_VIEW_PROPERTY_TYPE, DATA_VIEW_PROPERTY_TYPE_ENTRY, } from '../../translations.js';
|
|
6
|
+
import { DATA_VIEW_PROPERTIES_LOCKED, DATA_VIEW_PROPERTY_HIDE_IN_VIEW, DATA_VIEW_PROPERTY_NAME, DATA_VIEW_PROPERTY_TYPE, DATA_VIEW_PROPERTY_TYPE_ENTRY, } from '../../translations.js';
|
|
6
7
|
import { renderUniLit } from '../utils/uni-component/index.js';
|
|
7
|
-
import { englishWording } from '../utils/wording.js';
|
|
8
|
+
import { englishWording, propertyTypeName, } from '../utils/wording.js';
|
|
9
|
+
/** The name of the type `property` has, in the host language. */
|
|
10
|
+
const currentTypeName = (property, wording) => {
|
|
11
|
+
const meta = property.view.propertyMetas$.value.find(v => v.type === property.type$.value);
|
|
12
|
+
return meta ? propertyTypeName(wording, meta.config) : undefined;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* The name of a property whose source its host locked (ADR 0035 amendment
|
|
16
|
+
* of 2026-10-29): shown, not editable, with the reason under it, so a menu
|
|
17
|
+
* that lost its rename, type, duplicate and delete says why.
|
|
18
|
+
*/
|
|
19
|
+
const lockedNameConfig = (property, wording) => () => html `
|
|
20
|
+
<div
|
|
21
|
+
data-testid="dv-property-locked"
|
|
22
|
+
style="display:flex;flex-direction:column;gap:4px;padding:4px 6px;margin-bottom:8px;"
|
|
23
|
+
>
|
|
24
|
+
<div
|
|
25
|
+
style="display:flex;align-items:center;gap:4px;font-size:14px;line-height:22px;"
|
|
26
|
+
>
|
|
27
|
+
<div class="affine-database-column-type-menu-icon">
|
|
28
|
+
${renderUniLit(property.icon)}
|
|
29
|
+
</div>
|
|
30
|
+
<span>${property.name$.value}</span>
|
|
31
|
+
</div>
|
|
32
|
+
<div
|
|
33
|
+
style="font-size:12px;line-height:20px;color:var(--affine-text-secondary-color);"
|
|
34
|
+
>
|
|
35
|
+
${wording(DATA_VIEW_PROPERTIES_LOCKED)}
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
`;
|
|
8
39
|
export const inputConfig = (property, wording = englishWording) => {
|
|
40
|
+
if (property.nameCanSet === false) {
|
|
41
|
+
return lockedNameConfig(property, wording);
|
|
42
|
+
}
|
|
9
43
|
return menu.input({
|
|
10
44
|
prefix: html `
|
|
11
45
|
<div class="affine-database-column-type-menu-icon">
|
|
@@ -31,8 +65,7 @@ export const typeConfig = (property, wording = englishWording) => {
|
|
|
31
65
|
class="affine-database-column-type-icon"
|
|
32
66
|
style="color: var(--affine-text-secondary-color);gap:4px;font-size: 14px;"
|
|
33
67
|
>
|
|
34
|
-
${renderUniLit(property.icon)}
|
|
35
|
-
${property.view.propertyMetas$.value.find(v => v.type === property.type$.value)?.config.name}
|
|
68
|
+
${renderUniLit(property.icon)} ${currentTypeName(property, wording)}
|
|
36
69
|
</div>`,
|
|
37
70
|
options: {
|
|
38
71
|
title: {
|
|
@@ -43,7 +76,7 @@ export const typeConfig = (property, wording = englishWording) => {
|
|
|
43
76
|
items: property.view.propertyMetas$.value.map(config => {
|
|
44
77
|
return menu.action({
|
|
45
78
|
isSelected: config.type === property.type$.value,
|
|
46
|
-
name: config.config
|
|
79
|
+
name: propertyTypeName(wording, config.config),
|
|
47
80
|
prefix: renderUniLit(config.renderer.icon),
|
|
48
81
|
select: () => {
|
|
49
82
|
if (property.type$.value === config.type) {
|
|
@@ -122,8 +155,22 @@ export const propertyMenuItems = (property, slots = {}) => {
|
|
|
122
155
|
}),
|
|
123
156
|
];
|
|
124
157
|
};
|
|
125
|
-
|
|
158
|
+
/**
|
|
159
|
+
* A property menu opened from a list of properties sits BESIDE the list, on
|
|
160
|
+
* the side with more room, and stays inside the viewport: below the row it
|
|
161
|
+
* covered the list, and in a host's narrow sidebar (labre, about 470px) it
|
|
162
|
+
* hid the very rows it edits, its « Type » sub-menu half off screen (labre
|
|
163
|
+
* recette of 1.1). The sub-menu then opens on the same side
|
|
164
|
+
* (`nestedSubMenuPosition`).
|
|
165
|
+
*/
|
|
166
|
+
export const besideListMiddleware = () => [
|
|
167
|
+
autoPlacement({ allowedPlacements: ['right-start', 'left-start'] }),
|
|
168
|
+
offset(4),
|
|
169
|
+
shift({ padding: 8, crossAxis: true }),
|
|
170
|
+
];
|
|
171
|
+
export const popPropertyMenu = (target, property, slots, placement = {}) => popMenu(target, {
|
|
126
172
|
options: { items: propertyMenuItems(property, slots) },
|
|
173
|
+
middleware: placement.beside ? besideListMiddleware() : undefined,
|
|
127
174
|
});
|
|
128
175
|
/**
|
|
129
176
|
* The type picker of a new property, as the virtual table header's "+" and
|
|
@@ -132,24 +179,28 @@ export const popPropertyMenu = (target, property, slots) => popMenu(target, {
|
|
|
132
179
|
* source (every view), under the type's own name, and `onAdd` gets its id
|
|
133
180
|
* so the opener can open its menu for the rename.
|
|
134
181
|
*/
|
|
135
|
-
export const popNewPropertyMenu = (target, view, options) =>
|
|
136
|
-
options
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
})
|
|
182
|
+
export const popNewPropertyMenu = (target, view, options) => {
|
|
183
|
+
const wording = options.wording ?? englishWording;
|
|
184
|
+
return popMenu(target, {
|
|
185
|
+
options: {
|
|
186
|
+
title: { text: options.title },
|
|
187
|
+
items: [
|
|
188
|
+
menu.group({
|
|
189
|
+
items: view.propertyMetas$.value.map(meta => menu.action({
|
|
190
|
+
name: propertyTypeName(wording, meta.config),
|
|
191
|
+
prefix: renderUniLit(meta.renderer.icon),
|
|
192
|
+
select: () => {
|
|
193
|
+
// Written resolved: a stored name is never re-translated.
|
|
194
|
+
const id = view.propertyAdd('end', {
|
|
195
|
+
type: meta.type,
|
|
196
|
+
name: propertyTypeName(wording, meta.config),
|
|
197
|
+
});
|
|
198
|
+
if (id)
|
|
199
|
+
options.onAdd(id);
|
|
200
|
+
},
|
|
201
|
+
})),
|
|
202
|
+
}),
|
|
203
|
+
],
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
};
|
|
@@ -11,6 +11,14 @@ import type { ViewManager } from '../view-manager/view-manager.js';
|
|
|
11
11
|
import { type CellStatus, type DataSourceHydration, type ValuesState } from './hydration.js';
|
|
12
12
|
export interface DataSource extends DataSourceHydration {
|
|
13
13
|
readonly$: ReadonlySignal<boolean>;
|
|
14
|
+
/**
|
|
15
|
+
* The current view's source refuses new, renamed, deleted, duplicated or
|
|
16
|
+
* retyped properties (a host's policy, ADR 0035 amendment of 2026-10-29).
|
|
17
|
+
* Absent, nothing is locked. Read through `SingleView.propertiesLocked$`.
|
|
18
|
+
*/
|
|
19
|
+
propertiesLocked$?: ReadonlySignal<boolean>;
|
|
20
|
+
/** The current view's source refuses new rows; absent, it takes them. */
|
|
21
|
+
rowsLocked$?: ReadonlySignal<boolean>;
|
|
14
22
|
properties$: ReadonlySignal<string[]>;
|
|
15
23
|
featureFlags$: ReadonlySignal<DatabaseFlags>;
|
|
16
24
|
cellValueGet(rowId: string, propertyId: string): unknown;
|
|
@@ -69,6 +77,9 @@ export declare abstract class DataSourceBase implements DataSource {
|
|
|
69
77
|
/** Every cell is `ready` unless a source says otherwise (ADR 0035 §9e). */
|
|
70
78
|
cellStatus(_rowId: string, _propertyId: string): CellStatus;
|
|
71
79
|
valuesState$: ReadonlySignal<ValuesState>;
|
|
80
|
+
/** Nothing is locked unless a source says so (`HostedDataSourceBase`). */
|
|
81
|
+
readonly propertiesLocked$: ReadonlySignal<boolean>;
|
|
82
|
+
readonly rowsLocked$: ReadonlySignal<boolean>;
|
|
72
83
|
propertyTypeCanSet(propertyId: string): boolean;
|
|
73
84
|
propertyCanDuplicate(propertyId: string): boolean;
|
|
74
85
|
propertyCanDelete(propertyId: string): boolean;
|
|
@@ -5,6 +5,9 @@ export const DataSourceScope = createScope('data-source');
|
|
|
5
5
|
export class DataSourceBase {
|
|
6
6
|
constructor() {
|
|
7
7
|
this.valuesState$ = signal(VALUES_READY);
|
|
8
|
+
/** Nothing is locked unless a source says so (`HostedDataSourceBase`). */
|
|
9
|
+
this.propertiesLocked$ = signal(false);
|
|
10
|
+
this.rowsLocked$ = signal(false);
|
|
8
11
|
this.container = new Container();
|
|
9
12
|
this.fixedProperties$ = computed(() => {
|
|
10
13
|
return this.allPropertyMetas$.value
|