@dxos/plugin-kanban 0.9.1-staging.ee54ba693a → 0.11.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/lib/KanbanPlugin.mjs +18 -0
- package/dist/lib/KanbanPlugin.mjs.map +1 -0
- package/dist/lib/KanbanPlugin.node.mjs +11 -0
- package/dist/lib/KanbanPlugin.node.mjs.map +1 -0
- package/dist/lib/KanbanPlugin.workerd.mjs +11 -0
- package/dist/lib/KanbanPlugin.workerd.mjs.map +1 -0
- package/dist/lib/capabilities/node.mjs +10 -0
- package/dist/lib/capabilities/node.mjs.map +1 -0
- package/dist/lib/capabilities.mjs +11 -0
- package/dist/lib/capabilities.mjs.map +1 -0
- package/dist/lib/chunk-KanbanArticle.mjs +121 -0
- package/dist/lib/chunk-KanbanArticle.mjs.map +1 -0
- package/dist/lib/chunk-KanbanProperties.mjs +73 -0
- package/dist/lib/chunk-KanbanProperties.mjs.map +1 -0
- package/dist/lib/chunk-create-object.mjs +42 -0
- package/dist/lib/chunk-create-object.mjs.map +1 -0
- package/dist/lib/chunk-delete-card-field.mjs +50 -0
- package/dist/lib/chunk-delete-card-field.mjs.map +1 -0
- package/dist/lib/chunk-delete-card.mjs +23 -0
- package/dist/lib/chunk-delete-card.mjs.map +1 -0
- package/dist/lib/{neutral/chunk-V4AVOJVU.mjs → chunk-meta.mjs} +21 -29
- package/dist/lib/chunk-meta.mjs.map +1 -0
- package/dist/lib/chunk-operation-handler.mjs +11 -0
- package/dist/lib/chunk-operation-handler.mjs.map +1 -0
- package/dist/lib/chunk-react-surface.mjs +67 -0
- package/dist/lib/chunk-react-surface.mjs.map +1 -0
- package/dist/lib/chunk-restore-card-field.mjs +48 -0
- package/dist/lib/chunk-restore-card-field.mjs.map +1 -0
- package/dist/lib/chunk-restore-card.mjs +22 -0
- package/dist/lib/chunk-restore-card.mjs.map +1 -0
- package/dist/lib/chunk-skill-definition.mjs +10 -0
- package/dist/lib/chunk-skill-definition.mjs.map +1 -0
- package/dist/lib/chunk-skills.mjs +20 -0
- package/dist/lib/chunk-skills.mjs.map +1 -0
- package/dist/lib/chunk-types.mjs +231 -0
- package/dist/lib/chunk-types.mjs.map +1 -0
- package/dist/lib/chunk-undo-mappings.mjs +25 -0
- package/dist/lib/chunk-undo-mappings.mjs.map +1 -0
- package/dist/lib/components.mjs +227 -0
- package/dist/lib/components.mjs.map +1 -0
- package/dist/lib/containers.mjs +8 -0
- package/dist/lib/containers.mjs.map +1 -0
- package/dist/lib/hooks.mjs +394 -0
- package/dist/lib/hooks.mjs.map +1 -0
- package/dist/lib/index.mjs +5 -0
- package/dist/lib/meta.mjs +2 -0
- package/dist/lib/operations.mjs +7 -0
- package/dist/lib/operations.mjs.map +1 -0
- package/dist/lib/plugin.mjs +9 -0
- package/dist/lib/plugin.mjs.map +1 -0
- package/dist/lib/skills.mjs +2 -0
- package/dist/lib/testing.mjs +72 -0
- package/dist/lib/testing.mjs.map +1 -0
- package/dist/lib/translations.mjs +38 -0
- package/dist/lib/translations.mjs.map +1 -0
- package/dist/lib/types.mjs +2 -0
- package/dist/types/src/capabilities/PivotColumnField.d.ts +12 -0
- package/dist/types/src/capabilities/PivotColumnField.d.ts.map +1 -0
- package/dist/types/src/capabilities/artifact-definition.d.ts +1 -1
- package/dist/types/src/capabilities/create-object.d.ts +1 -1
- package/dist/types/src/capabilities/node.d.ts +7 -0
- package/dist/types/src/capabilities/node.d.ts.map +1 -0
- package/dist/types/src/capabilities/operation-handler.d.ts +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/capabilities/undo-mappings.d.ts +1 -1
- package/dist/types/src/components/KanbanBoard/KanbanBoard.d.ts +3 -4
- package/dist/types/src/components/KanbanBoard/KanbanBoard.d.ts.map +1 -1
- package/dist/types/src/components/KanbanBoard/KanbanBoard.stories.d.ts.map +1 -1
- package/dist/types/src/components/KanbanBoard/KanbanCard.d.ts.map +1 -1
- package/dist/types/src/components/KanbanBoard/index.d.ts +1 -0
- package/dist/types/src/components/KanbanBoard/index.d.ts.map +1 -1
- package/dist/types/src/containers/KanbanArticle/KanbanArticle.d.ts +4 -1
- package/dist/types/src/containers/KanbanArticle/KanbanArticle.d.ts.map +1 -1
- package/dist/types/src/containers/KanbanArticle/KanbanArticle.stories.d.ts.map +1 -1
- package/dist/types/src/containers/KanbanProperties/KanbanProperties.d.ts +4 -8
- package/dist/types/src/containers/KanbanProperties/KanbanProperties.d.ts.map +1 -1
- package/dist/types/src/hooks/useKanbanBoardModel.d.ts +1 -1
- package/dist/types/src/hooks/useKanbanBoardModel.d.ts.map +1 -1
- package/dist/types/src/hooks/useKanbanColumnEventHandler.d.ts +4 -3
- package/dist/types/src/hooks/useKanbanColumnEventHandler.d.ts.map +1 -1
- package/dist/types/src/hooks/useKanbanItemEventHandler.d.ts +4 -3
- package/dist/types/src/hooks/useKanbanItemEventHandler.d.ts.map +1 -1
- package/dist/types/src/hooks/useProjectionModel.d.ts +1 -1
- package/dist/types/src/hooks/useProjectionModel.d.ts.map +1 -1
- package/dist/types/src/testing/KanbanCardTileSimple.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/dx.config.ts +1 -0
- package/package.json +58 -51
- package/src/capabilities/PivotColumnField.tsx +56 -0
- package/src/capabilities/node.ts +18 -0
- package/src/capabilities/react-surface.ts +45 -0
- package/src/components/KanbanBoard/KanbanBoard.stories.tsx +15 -4
- package/src/components/KanbanBoard/KanbanBoard.tsx +0 -3
- package/src/components/KanbanBoard/KanbanCard.tsx +5 -3
- package/src/components/KanbanBoard/index.ts +2 -0
- package/src/containers/KanbanArticle/KanbanArticle.stories.tsx +2 -1
- package/src/containers/KanbanArticle/KanbanArticle.tsx +3 -1
- package/src/containers/KanbanProperties/KanbanProperties.tsx +3 -1
- package/src/hooks/useItemsProjection.ts +1 -1
- package/src/hooks/useKanbanBoardModel.browser.test.ts +1 -1
- package/src/hooks/useKanbanBoardModel.ts +1 -1
- package/src/hooks/useKanbanColumnEventHandler.ts +6 -5
- package/src/hooks/useKanbanItemEventHandler.ts +6 -7
- package/src/hooks/useProjectionModel.ts +1 -1
- package/src/testing/KanbanCardTileSimple.tsx +2 -1
- package/dist/lib/neutral/KanbanArticle-JQMQQHRB.mjs +0 -132
- package/dist/lib/neutral/KanbanArticle-JQMQQHRB.mjs.map +0 -7
- package/dist/lib/neutral/KanbanPlugin.mjs +0 -44
- package/dist/lib/neutral/KanbanPlugin.mjs.map +0 -7
- package/dist/lib/neutral/KanbanPlugin.node.mjs +0 -27
- package/dist/lib/neutral/KanbanPlugin.node.mjs.map +0 -7
- package/dist/lib/neutral/KanbanPlugin.workerd.mjs +0 -21
- package/dist/lib/neutral/KanbanPlugin.workerd.mjs.map +0 -7
- package/dist/lib/neutral/KanbanProperties-W7MZNZVJ.mjs +0 -83
- package/dist/lib/neutral/KanbanProperties-W7MZNZVJ.mjs.map +0 -7
- package/dist/lib/neutral/capabilities/index.mjs +0 -17
- package/dist/lib/neutral/capabilities/index.mjs.map +0 -7
- package/dist/lib/neutral/chunk-7TVVF45P.mjs +0 -247
- package/dist/lib/neutral/chunk-7TVVF45P.mjs.map +0 -7
- package/dist/lib/neutral/chunk-7YLGUKDJ.mjs +0 -8
- package/dist/lib/neutral/chunk-7YLGUKDJ.mjs.map +0 -7
- package/dist/lib/neutral/chunk-CFPH5R6P.mjs +0 -26
- package/dist/lib/neutral/chunk-CFPH5R6P.mjs.map +0 -7
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs +0 -10
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +0 -7
- package/dist/lib/neutral/chunk-V4AVOJVU.mjs.map +0 -7
- package/dist/lib/neutral/components/index.mjs +0 -245
- package/dist/lib/neutral/components/index.mjs.map +0 -7
- package/dist/lib/neutral/containers/index.mjs +0 -11
- package/dist/lib/neutral/containers/index.mjs.map +0 -7
- package/dist/lib/neutral/create-object-DIIFRS57.mjs +0 -45
- package/dist/lib/neutral/create-object-DIIFRS57.mjs.map +0 -7
- package/dist/lib/neutral/delete-card-TK2G6YHX.mjs +0 -24
- package/dist/lib/neutral/delete-card-TK2G6YHX.mjs.map +0 -7
- package/dist/lib/neutral/delete-card-field-LGWPBOUW.mjs +0 -39
- package/dist/lib/neutral/delete-card-field-LGWPBOUW.mjs.map +0 -7
- package/dist/lib/neutral/hooks/index.mjs +0 -431
- package/dist/lib/neutral/hooks/index.mjs.map +0 -7
- package/dist/lib/neutral/index.mjs +0 -34
- package/dist/lib/neutral/index.mjs.map +0 -7
- package/dist/lib/neutral/meta.json +0 -1
- package/dist/lib/neutral/meta.mjs +0 -8
- package/dist/lib/neutral/meta.mjs.map +0 -7
- package/dist/lib/neutral/operation-handler-B7IW6MXU.mjs +0 -13
- package/dist/lib/neutral/operation-handler-B7IW6MXU.mjs.map +0 -7
- package/dist/lib/neutral/operations/index.mjs +0 -8
- package/dist/lib/neutral/operations/index.mjs.map +0 -7
- package/dist/lib/neutral/plugin.mjs +0 -16
- package/dist/lib/neutral/plugin.mjs.map +0 -7
- package/dist/lib/neutral/react-surface-FQGXRR3X.mjs +0 -89
- package/dist/lib/neutral/react-surface-FQGXRR3X.mjs.map +0 -7
- package/dist/lib/neutral/restore-card-3O6PVN7J.mjs +0 -21
- package/dist/lib/neutral/restore-card-3O6PVN7J.mjs.map +0 -7
- package/dist/lib/neutral/restore-card-field-5G4DVYYY.mjs +0 -37
- package/dist/lib/neutral/restore-card-field-5G4DVYYY.mjs.map +0 -7
- package/dist/lib/neutral/skill-definition-YGTCKXGP.mjs +0 -15
- package/dist/lib/neutral/skill-definition-YGTCKXGP.mjs.map +0 -7
- package/dist/lib/neutral/skills/index.mjs +0 -8
- package/dist/lib/neutral/skills/index.mjs.map +0 -7
- package/dist/lib/neutral/testing/index.mjs +0 -64
- package/dist/lib/neutral/testing/index.mjs.map +0 -7
- package/dist/lib/neutral/translations.mjs +0 -44
- package/dist/lib/neutral/translations.mjs.map +0 -7
- package/dist/lib/neutral/types/index.mjs +0 -22
- package/dist/lib/neutral/types/index.mjs.map +0 -7
- package/dist/lib/neutral/undo-mappings-EZTHO4UL.mjs +0 -42
- package/dist/lib/neutral/undo-mappings-EZTHO4UL.mjs.map +0 -7
- package/src/capabilities/react-surface.tsx +0 -95
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Plugin } from "@dxos/app-framework";
|
|
2
|
+
import { meta } from "#meta";
|
|
3
|
+
import { AppPlugin } from "@dxos/app-toolkit";
|
|
4
|
+
import { CreateObject, OperationHandler, ReactSurface, SkillDefinition, UndoMappings } from "#capabilities";
|
|
5
|
+
import { translations } from "#translations";
|
|
6
|
+
import { Kanban } from "#types";
|
|
7
|
+
//#endregion
|
|
8
|
+
//#region src/KanbanPlugin.tsx
|
|
9
|
+
var KanbanPlugin = Plugin.define(meta).pipe(AppPlugin.addSkillDefinitionModule({ activate: SkillDefinition }), AppPlugin.addCreateObjectModule({ activate: CreateObject }), AppPlugin.addOperationHandlerModule({ activate: OperationHandler }), AppPlugin.addUndoMappingsModule({ activate: UndoMappings }), AppPlugin.addSchemaModule({ schema: [Kanban.Kanban] }), AppPlugin.addSurfaceModule({ activate: ReactSurface }), AppPlugin.addTranslationsModule({ translations }), AppPlugin.addPluginAssetModule({ asset: {
|
|
10
|
+
pluginId: meta.profile.key,
|
|
11
|
+
path: "PLUGIN.mdl",
|
|
12
|
+
content: "---\nid: org.dxos.plugin.kanban\nname: KanbanPlugin\nversion: 0.1.0\n---\n\nVisual project management plugin for `DXOS` Composer — organise any ECHO type into drag-and-drop columns driven by a single-select field, with full local-first persistence and real-time peer replication.\n\n## Extensions\n\nThe following extension dialects are used in this document.\nEach extension is defined in the Appendix or resolved via its URI.\n\n| Term | URI |\n|-------------|--------------------------------|\n| `type` | `org.dxos.mdl.type@1.0` |\n| `feat` | `org.dxos.mdl.feat@1.0` |\n| `test` | `org.dxos.mdl.test@1.0` |\n| `component` | `org.dxos.mdl.component@1.0` |\n| `op` | `org.dxos.mdl.op@1.0` |\n\n## Types\n\n```mdl\ntype ArrangementColumnEntry\n fields:\n ids: string[] # ordered card ids within the column\n hidden?: boolean # when true the column is hidden from the board\n```\n\n```mdl\ntype Arrangement\n fields:\n order: string[] # ordered column values\n columns: Map<string, ArrangementColumnEntry>\n```\n\n```mdl\ntype KanbanViewSpec\n fields:\n kind: \"view\" # discriminator — items sourced from a View query\n view: Ref<View> # the View whose query drives card membership\n```\n\n```mdl\ntype KanbanItemsSpec\n fields:\n kind: \"items\" # discriminator — kanban owns items explicitly\n pivotField: string # property path that drives column membership\n items: Ref<object>[] # items owned directly by the kanban\n```\n\n```mdl\ntype KanbanSpec\n desc: Discriminated union of item-source strategies.\n literals: KanbanViewSpec | KanbanItemsSpec\n```\n\n```mdl\ntype Kanban\n desc: Root ECHO object for a kanban board. Stored with typename org.dxos.type.kanban v0.2.0.\n fields:\n name?: string\n arrangement: Arrangement\n spec: KanbanSpec # discriminated by spec.kind\n```\n\n```mdl\ntype KanbanSettings\n fields:\n hideUncategorized?: boolean # hides items with no pivot value\n```\n\n```mdl\ntype KanbanViewSettings\n fields:\n columnFieldId: string # id of the View field used as pivot column\n hideUncategorized?: boolean\n```\n\n```mdl\ntype CreateKanbanInput\n fields:\n name?: string\n typename?: string # ECHO typename of card objects\n initialPivotColumn?: string # initial single-select field to pivot on\n```\n\n## Components\n\n```mdl\ncomponent KanbanArticle\n desc: Main article surface for a Kanban. Branches internally on spec.kind — view-variant runs a typename query via the linked View; items-variant dereferences spec.items directly.\n props:\n subject: Kanban\n role: \"article\" | \"section\"\n state:\n projection: ProjectionModel # column/field projection derived from View + schema\n items: AtomQuery # reactive card query (view-variant) or array (items-variant)\n actions:\n addCard(columnValue: string) → string # returns new card id\n removeCard(card: object)\n moveCard(card: object, toColumn: string, toIndex: number)\n deleteCardField(fieldId: string)\n layout: |\n ┌──────────────────────────────────────┐\n │ [toolbar slot] │\n ├──────────────────────────────────────┤\n │ Col A │ Col B │ Col C │\n │ ┌─────────┐ │ ┌─────────┐ │ … │\n │ │ card │ │ │ card │ │ │\n │ └─────────┘ │ └─────────┘ │ │\n │ [+ Add card]│ │ │\n └──────────────────────────────────────┘\n```\n\n```mdl\ncomponent KanbanSettings\n desc: Properties panel for a Kanban. View-variant shows a column-field picker plus common settings; items-variant shows only common settings.\n props:\n subject: Kanban\n state:\n selectFields: { value: string; label: string }[] # single-select fields available as pivot\n actions:\n changeColumnField(fieldId: string)\n toggleHideUncategorized(hidden: boolean)\n```\n\n## Operations\n\n```mdl\nop deleteCard\n desc: Removes a card object from the ECHO database.\n input:\n card: object # the card to remove\n output: DeleteCardOutput # { card } snapshot of the removed card\n effects: [echo:write]\n```\n\n```mdl\nop deleteCardField\n desc: Removes a field projection from the View's schema; returns enough data to undo.\n input:\n view: View\n fieldId: string\n output: DeleteCardFieldOutput # { field, props, index }\n effects: [echo:write]\n requires: [AtomRegistry, Database]\n```\n\n```mdl\nop restoreCard\n desc: Undo counterpart to deleteCard — re-adds a previously removed card to the database.\n input:\n card: object # the card snapshot to restore\n output: void\n effects: [echo:write]\n```\n\n```mdl\nop restoreCardField\n desc: Undo counterpart to deleteCardField — re-inserts a field projection at its original index.\n input:\n view: View\n field: FieldSchema\n props: object # field properties\n index: number # position to restore at\n output: void\n effects: [echo:write]\n requires: [AtomRegistry, Database]\n```\n\n## Features\n\n```mdl\nfeat F-1: Board Layout\n\n req F-1.1: Columns are ordered by Arrangement.order; each column contains its cards in Arrangement.columns[value].ids order.\n req F-1.2: Cards within a column are rendered in the stored id order.\n req F-1.3:\n when: settings.hideUncategorized is true\n then: the uncategorized column is not rendered\n```\n\n```mdl\nfeat F-2: Drag and Drop\n\n req F-2.1:\n when: user drags a card to a different column\n then: card's pivot field is updated to the target column value; Arrangement updated\n\n req F-2.2:\n when: user drags a card within the same column\n then: card ids are reordered in Arrangement.columns[value].ids\n\n req F-2.3:\n when: user drags a column header\n then: Arrangement.order is updated to reflect the new column order\n```\n\n```mdl\nfeat F-3: Card Management\n\n req F-3.1:\n when: user clicks Add Card in a column\n then: a new ECHO object of the board's card type is created with the pivot field set to that column's value\n\n req F-3.2:\n when: user removes a card\n then: op:deleteCard runs; card is removed from the ECHO database and from the board\n\n req F-3.3:\n when: user undoes a delete-card action\n then: op:restoreCard re-adds the card; board reflects restored state\n```\n\n```mdl\nfeat F-4: Column Configuration\n\n req F-4.1:\n when: user opens KanbanSettings for a view-variant board\n then: column-field picker shows all single-select fields from the card schema\n\n req F-4.2:\n when: user selects a different column field\n then: View.projection.pivotFieldId is updated; board re-renders with new columns\n\n req F-4.3:\n when: user removes a column field\n then: op:deleteCardField removes the projection; op:restoreCardField can reverse it\n```\n\n```mdl\nfeat F-5: Item Source Variants\n\n req F-5.1:\n when: spec.kind === \"view\"\n then: items come from running the View's typename query against the ECHO database\n\n req F-5.2:\n when: spec.kind === \"items\"\n then: items come from spec.items (explicit ref array); used by externally-synced boards (e.g. Linear, GitHub)\n\n req F-5.3: Both variants share the same Arrangement persistence and drag-and-drop logic.\n```\n\n```mdl\nfeat F-6: ECHO Persistence and Collaboration\n\n req F-6.1: All Kanban, Arrangement, and card mutations are written to ECHO and replicated to peers.\n req F-6.2:\n when: a peer updates a card or moves it\n then: KanbanArticle re-renders reactively via AtomQuery / AtomObj subscriptions\n\n req F-6.3: View-variant kanbans own an associated View object that is hidden from the space browser.\n```\n\n```mdl\nfeat F-7: AI Skill\n\n req F-7.1: Plugin contributes a Kanban skill that lets an AI agent create and update kanban boards.\n req F-7.2:\n when: an AI agent calls the skill\n then: agent can create boards, place cards in columns, and update card fields\n```\n\n## Acceptance\n\n```mdl\ntest T-1: Create kanban board\n given: a space with a custom ECHO type that has a single-select field \"status\"\n when: user creates a new Kanban selecting that type and \"status\" as the pivot column\n then:\n - Kanban object written to ECHO with spec.kind === \"view\"\n - columns correspond to the \"status\" field's enum values\n - existing objects appear as cards in their respective columns\n```\n\n```mdl\ntest T-2: Drag card between columns\n given: a Kanban with columns \"todo\", \"in-progress\", \"done\" and a card in \"todo\"\n when: user drags the card to \"in-progress\"\n then:\n - card's \"status\" field updated to \"in-progress\"\n - Arrangement reflects card in \"in-progress\" column\n - change replicated to peers via ECHO\n```\n\n```mdl\ntest T-3: Reorder cards within a column\n given: a column with cards [A, B, C] in order\n when: user drags card C above card A\n then:\n - Arrangement.columns[\"col\"].ids === [C, A, B]\n - board renders in new order\n```\n\n```mdl\ntest T-4: Add card to column\n given: a board with a \"todo\" column\n when: user clicks Add Card in \"todo\"\n then:\n - new ECHO object created with pivot field set to \"todo\"\n - card appears at the bottom of the \"todo\" column\n```\n\n```mdl\ntest T-5: Delete and restore card\n given: a board with card X in column \"todo\"\n when: user deletes card X, then undoes\n then:\n - after delete: card X absent from board and ECHO database\n - after undo: card X restored to ECHO and reappears in \"todo\"\n```\n\n```mdl\ntest T-6: Hide uncategorized column\n given: a board with some cards that have no pivot value (uncategorized)\n when: user enables \"Hide uncategorized column\" in KanbanSettings\n then:\n - uncategorized column no longer rendered\n - Arrangement.columns[UNCATEGORIZED].hidden === true\n```\n\n```mdl\ntest T-7: Switch pivot column field\n given: a view-variant board currently pivoting on \"status\"\n when: user opens settings and selects \"priority\" as the column field\n then:\n - View.projection.pivotFieldId updated to \"priority\"\n - board re-renders with columns derived from \"priority\" enum values\n```\n\n---\n\n## Appendix: Extension Definitions\n\n```mdl\next type\n uri: org.dxos.mdl.type@1.0\n desc: A named data structure with typed fields and optional literals.\n fields:\n desc?: Prose\n fields?: FieldMap\n literals?: UnionList\n extends?: TypeRef[]\n```\n\n```mdl\next feat\n uri: org.dxos.mdl.feat@1.0\n desc: A named feature grouping one or more requirements.\n fields:\n desc?: Prose\n req: RequirementList\n nesting: self\n```\n\n```mdl\next test\n uri: org.dxos.mdl.test@1.0\n desc: An acceptance scenario expressed as given / when / then steps.\n fields:\n given?: Step | Step[]\n when?: Step | Step[]\n then: Step | Step[]\n tags?: TagList\n```\n\n```mdl\next component\n uri: org.dxos.mdl.component@1.0\n desc: A UI component with props, internal state, slots, actions, and events.\n fields:\n desc?: Prose\n props?: FieldMap\n state?: FieldMap\n slots?: FieldMap\n actions?: ActionMap\n emits?: EventMap\n layout?: CodeBlock\n```\n\n```mdl\next op\n uri: org.dxos.mdl.op@1.0\n desc: |\n A named operation with typed inputs, outputs, and declared errors.\n Pure ops have no effects or requires. Effectful ops declare both.\n fields:\n desc?: Prose\n input?: FieldMap\n output?: TypeExpr\n errors?: ErrorMap\n effects?: EffectList\n requires?: ServiceList\n note?: Prose\n```\n",
|
|
13
|
+
mimeType: "application/x-mdl"
|
|
14
|
+
} }), Plugin.make);
|
|
15
|
+
//#endregion
|
|
16
|
+
export { KanbanPlugin, KanbanPlugin as default };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=KanbanPlugin.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KanbanPlugin.mjs","names":[],"sources":["../../src/KanbanPlugin.tsx"],"sourcesContent":["//\n// Copyright 2023 DXOS.org\n//\n\nimport { Plugin } from '@dxos/app-framework';\nimport { AppPlugin } from '@dxos/app-toolkit';\n\nimport { CreateObject, OperationHandler, ReactSurface, SkillDefinition, UndoMappings } from '#capabilities';\nimport { meta } from '#meta';\nimport { translations } from '#translations';\nimport { Kanban } from '#types';\n\n// eslint-disable-next-line import/no-relative-packages\nimport pluginSpec from '../PLUGIN.mdl?raw';\n\nexport const KanbanPlugin = Plugin.define(meta).pipe(\n AppPlugin.addSkillDefinitionModule({ activate: SkillDefinition }),\n AppPlugin.addCreateObjectModule({ activate: CreateObject }),\n AppPlugin.addOperationHandlerModule({ activate: OperationHandler }),\n AppPlugin.addUndoMappingsModule({ activate: UndoMappings }),\n AppPlugin.addSchemaModule({ schema: [Kanban.Kanban] }),\n AppPlugin.addSurfaceModule({ activate: ReactSurface }),\n AppPlugin.addTranslationsModule({ translations }),\n AppPlugin.addPluginAssetModule({\n asset: { pluginId: meta.profile.key, path: 'PLUGIN.mdl', content: pluginSpec, mimeType: 'application/x-mdl' },\n }),\n Plugin.make,\n);\n\nexport default KanbanPlugin;\n"],"mappings":";;;;;;;;AAeA,IAAa,eAAe,OAAO,OAAO,IAAI,CAAC,CAAC,KAC9C,UAAU,yBAAyB,EAAE,UAAU,gBAAgB,CAAC,GAChE,UAAU,sBAAsB,EAAE,UAAU,aAAa,CAAC,GAC1D,UAAU,0BAA0B,EAAE,UAAU,iBAAiB,CAAC,GAClE,UAAU,sBAAsB,EAAE,UAAU,aAAa,CAAC,GAC1D,UAAU,gBAAgB,EAAE,QAAQ,CAAC,OAAO,MAAM,EAAE,CAAC,GACrD,UAAU,iBAAiB,EAAE,UAAU,aAAa,CAAC,GACrD,UAAU,sBAAsB,EAAE,aAAa,CAAC,GAChD,UAAU,qBAAqB,EAC7B,OAAO;CAAE,UAAU,KAAK,QAAQ;CAAK,MAAM;CAAc,SAAS;CAAY,UAAU;AAAoB,EAC9G,CAAC,GACD,OAAO,IACT"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Plugin } from "@dxos/app-framework";
|
|
2
|
+
import { meta } from "#meta";
|
|
3
|
+
import { AppPlugin } from "@dxos/app-toolkit";
|
|
4
|
+
import { CreateObject, OperationHandler, SkillDefinition, UndoMappings } from "#capabilities";
|
|
5
|
+
import { Kanban } from "#types";
|
|
6
|
+
//#region src/KanbanPlugin.node.ts
|
|
7
|
+
var KanbanPlugin = Plugin.define(meta).pipe(AppPlugin.addSkillDefinitionModule({ activate: SkillDefinition }), AppPlugin.addCreateObjectModule({ activate: CreateObject }), AppPlugin.addOperationHandlerModule({ activate: OperationHandler }), AppPlugin.addUndoMappingsModule({ activate: UndoMappings }), AppPlugin.addSchemaModule({ schema: [Kanban.Kanban] }), Plugin.make);
|
|
8
|
+
//#endregion
|
|
9
|
+
export { KanbanPlugin, KanbanPlugin as default };
|
|
10
|
+
|
|
11
|
+
//# sourceMappingURL=KanbanPlugin.node.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KanbanPlugin.node.mjs","names":[],"sources":["../../src/KanbanPlugin.node.ts"],"sourcesContent":["//\n// Copyright 2023 DXOS.org\n//\n\nimport { Plugin } from '@dxos/app-framework';\nimport { AppPlugin } from '@dxos/app-toolkit';\n\nimport { CreateObject, OperationHandler, SkillDefinition, UndoMappings } from '#capabilities';\nimport { meta } from '#meta';\nimport { Kanban } from '#types';\n\nexport const KanbanPlugin = Plugin.define(meta).pipe(\n AppPlugin.addSkillDefinitionModule({ activate: SkillDefinition }),\n AppPlugin.addCreateObjectModule({ activate: CreateObject }),\n AppPlugin.addOperationHandlerModule({ activate: OperationHandler }),\n AppPlugin.addUndoMappingsModule({ activate: UndoMappings }),\n AppPlugin.addSchemaModule({ schema: [Kanban.Kanban] }),\n Plugin.make,\n);\n\nexport default KanbanPlugin;\n"],"mappings":";;;;;;AAWA,IAAa,eAAe,OAAO,OAAO,IAAI,CAAC,CAAC,KAC9C,UAAU,yBAAyB,EAAE,UAAU,gBAAgB,CAAC,GAChE,UAAU,sBAAsB,EAAE,UAAU,aAAa,CAAC,GAC1D,UAAU,0BAA0B,EAAE,UAAU,iBAAiB,CAAC,GAClE,UAAU,sBAAsB,EAAE,UAAU,aAAa,CAAC,GAC1D,UAAU,gBAAgB,EAAE,QAAQ,CAAC,OAAO,MAAM,EAAE,CAAC,GACrD,OAAO,IACT"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Plugin } from "@dxos/app-framework";
|
|
2
|
+
import { meta } from "#meta";
|
|
3
|
+
import { AppPlugin } from "@dxos/app-toolkit";
|
|
4
|
+
import { OperationHandler } from "#capabilities";
|
|
5
|
+
import { Kanban } from "#types";
|
|
6
|
+
//#region src/KanbanPlugin.workerd.ts
|
|
7
|
+
var KanbanPlugin = Plugin.define(meta).pipe(AppPlugin.addOperationHandlerModule({ activate: OperationHandler }), AppPlugin.addSchemaModule({ schema: [Kanban.Kanban] }), Plugin.make);
|
|
8
|
+
//#endregion
|
|
9
|
+
export { KanbanPlugin, KanbanPlugin as default };
|
|
10
|
+
|
|
11
|
+
//# sourceMappingURL=KanbanPlugin.workerd.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KanbanPlugin.workerd.mjs","names":[],"sources":["../../src/KanbanPlugin.workerd.ts"],"sourcesContent":["//\n// Copyright 2023 DXOS.org\n//\n\nimport { Plugin } from '@dxos/app-framework';\nimport { AppPlugin } from '@dxos/app-toolkit';\n\nimport { OperationHandler } from '#capabilities';\nimport { meta } from '#meta';\nimport { Kanban } from '#types';\n\nexport const KanbanPlugin = Plugin.define(meta).pipe(\n AppPlugin.addOperationHandlerModule({ activate: OperationHandler }),\n AppPlugin.addSchemaModule({ schema: [Kanban.Kanban] }),\n Plugin.make,\n);\n\nexport default KanbanPlugin;\n"],"mappings":";;;;;;AAWA,IAAa,eAAe,OAAO,OAAO,IAAI,CAAC,CAAC,KAC9C,UAAU,0BAA0B,EAAE,UAAU,iBAAiB,CAAC,GAClE,UAAU,gBAAgB,EAAE,QAAQ,CAAC,OAAO,MAAM,EAAE,CAAC,GACrD,OAAO,IACT"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Capability } from "@dxos/app-framework";
|
|
2
|
+
//#region src/capabilities/node.ts
|
|
3
|
+
var SkillDefinition = Capability.lazy("SkillDefinition", () => import("../chunk-skill-definition.mjs"));
|
|
4
|
+
var CreateObject = Capability.lazy("CreateObject", () => import("../chunk-create-object.mjs"));
|
|
5
|
+
var OperationHandler = Capability.lazy("OperationHandler", () => import("../chunk-operation-handler.mjs"));
|
|
6
|
+
var UndoMappings = Capability.lazy("UndoMappings", () => import("../chunk-undo-mappings.mjs"));
|
|
7
|
+
//#endregion
|
|
8
|
+
export { CreateObject, OperationHandler, SkillDefinition, UndoMappings };
|
|
9
|
+
|
|
10
|
+
//# sourceMappingURL=node.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.mjs","names":[],"sources":["../../../src/capabilities/node.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport { Capability } from '@dxos/app-framework';\nimport type { OperationHandlerSet } from '@dxos/compute';\n\n// The capabilities `KanbanPlugin.node` activates, and only those. `Capability.lazy` defers the\n// import at runtime but a bundler still walks it, so listing the React surfaces here would pull\n// the plugin's components into every node and bun build.\n\nexport const SkillDefinition = Capability.lazy('SkillDefinition', () => import('./skill-definition'));\nexport const CreateObject = Capability.lazy('CreateObject', () => import('./create-object'));\nexport const OperationHandler = Capability.lazy<OperationHandlerSet.OperationHandlerSet>(\n 'OperationHandler',\n () => import('./operation-handler'),\n);\nexport const UndoMappings = Capability.lazy('UndoMappings', () => import('./undo-mappings'));\n"],"mappings":";;AAWA,IAAa,kBAAkB,WAAW,KAAK,yBAAyB,OAAO,gCAAqB;AACpG,IAAa,eAAe,WAAW,KAAK,sBAAsB,OAAO,6BAAkB;AAC3F,IAAa,mBAAmB,WAAW,KACzC,0BACM,OAAO,iCACf;AACA,IAAa,eAAe,WAAW,KAAK,sBAAsB,OAAO,6BAAkB"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Capability } from "@dxos/app-framework";
|
|
2
|
+
//#region src/capabilities/index.ts
|
|
3
|
+
var SkillDefinition = Capability.lazy("SkillDefinition", () => import("./chunk-skill-definition.mjs"));
|
|
4
|
+
var CreateObject = Capability.lazy("CreateObject", () => import("./chunk-create-object.mjs"));
|
|
5
|
+
var OperationHandler = Capability.lazy("OperationHandler", () => import("./chunk-operation-handler.mjs"));
|
|
6
|
+
var ReactSurface = Capability.lazy("ReactSurface", () => import("./chunk-react-surface.mjs"));
|
|
7
|
+
var UndoMappings = Capability.lazy("UndoMappings", () => import("./chunk-undo-mappings.mjs"));
|
|
8
|
+
//#endregion
|
|
9
|
+
export { CreateObject, OperationHandler, ReactSurface, SkillDefinition, UndoMappings };
|
|
10
|
+
|
|
11
|
+
//# sourceMappingURL=capabilities.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.mjs","names":[],"sources":["../../src/capabilities/index.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport { Capability } from '@dxos/app-framework';\nimport type { OperationHandlerSet } from '@dxos/compute';\n\nexport const SkillDefinition = Capability.lazy('SkillDefinition', () => import('./skill-definition'));\nexport const CreateObject = Capability.lazy('CreateObject', () => import('./create-object'));\nexport const OperationHandler = Capability.lazy<OperationHandlerSet.OperationHandlerSet>(\n 'OperationHandler',\n () => import('./operation-handler'),\n);\nexport const ReactSurface = Capability.lazy('ReactSurface', () => import('./react-surface'));\nexport const UndoMappings = Capability.lazy('UndoMappings', () => import('./undo-mappings'));\n"],"mappings":";;AAOA,IAAa,kBAAkB,WAAW,KAAK,yBAAyB,OAAO,+BAAqB;AACpG,IAAa,eAAe,WAAW,KAAK,sBAAsB,OAAO,4BAAkB;AAC3F,IAAa,mBAAmB,WAAW,KACzC,0BACM,OAAO,gCACf;AACA,IAAa,eAAe,WAAW,KAAK,sBAAsB,OAAO,4BAAkB;AAC3F,IAAa,eAAe,WAAW,KAAK,sBAAsB,OAAO,4BAAkB"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { Filter, Obj, Query, Type } from "@dxos/echo";
|
|
2
|
+
import { getTagFromQuery, getTypeURIFromQuery } from "@dxos/schema";
|
|
3
|
+
import { AppCapabilities } from "@dxos/app-toolkit";
|
|
4
|
+
import { Kanban, KanbanOperation } from "#types";
|
|
5
|
+
import { Atom, RegistryContext } from "@effect-atom/atom-react";
|
|
6
|
+
import { useCallback, useContext, useMemo } from "react";
|
|
7
|
+
import { Panel, Toolbar } from "@dxos/react-ui";
|
|
8
|
+
import { useEchoChangeCallback, useItemsProjection, useProjectionModel } from "#hooks";
|
|
9
|
+
import { useCapabilities, useOperationInvoker } from "@dxos/app-framework/ui";
|
|
10
|
+
import { useSchemaFilter } from "@dxos/app-toolkit/ui";
|
|
11
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
12
|
+
import { KanbanBoard } from "#components";
|
|
13
|
+
import { useObject, useType } from "@dxos/echo-react";
|
|
14
|
+
//#region src/containers/KanbanArticle/KanbanArticle.tsx
|
|
15
|
+
var KanbanArticle = (props) => {
|
|
16
|
+
return Kanban.isKanbanItems(props.subject) ? /* @__PURE__ */ jsx(ItemsKanbanArticle, {
|
|
17
|
+
...props,
|
|
18
|
+
subject: props.subject
|
|
19
|
+
}) : /* @__PURE__ */ jsx(ViewKanbanArticle, { ...props });
|
|
20
|
+
};
|
|
21
|
+
var ViewKanbanArticle = ({ role, subject: object }) => {
|
|
22
|
+
const registry = useContext(RegistryContext);
|
|
23
|
+
const schemas = useCapabilities(AppCapabilities.Schema);
|
|
24
|
+
const db = Obj.getDatabase(object);
|
|
25
|
+
const { invokePromise } = useOperationInvoker();
|
|
26
|
+
const [view] = useObject(object.spec.kind === "view" ? object.spec.view : void 0);
|
|
27
|
+
const typeUri = view?.query ? getTypeURIFromQuery(view.query.ast) : void 0;
|
|
28
|
+
const tag = view?.query ? getTagFromQuery(view.query.ast) : void 0;
|
|
29
|
+
const schemaFromDb = useType(db, typeUri);
|
|
30
|
+
const cardSchema = useMemo(() => schemaFromDb ?? schemas.flat().find((schema) => Type.getURI(schema) === typeUri), [
|
|
31
|
+
schemaFromDb,
|
|
32
|
+
schemas,
|
|
33
|
+
typeUri
|
|
34
|
+
]);
|
|
35
|
+
const baseFilter = useSchemaFilter(cardSchema);
|
|
36
|
+
const items = useMemo(() => {
|
|
37
|
+
if (!db) return null;
|
|
38
|
+
const query = tag ? Query.select(baseFilter).select(Filter.tag(tag)) : Query.select(baseFilter);
|
|
39
|
+
return db.query(query).atom;
|
|
40
|
+
}, [
|
|
41
|
+
db,
|
|
42
|
+
baseFilter,
|
|
43
|
+
tag
|
|
44
|
+
]);
|
|
45
|
+
const projection = useProjectionModel(cardSchema, object, registry);
|
|
46
|
+
const change = useEchoChangeCallback(object);
|
|
47
|
+
const pivotFieldId = view?.projection?.pivotFieldId;
|
|
48
|
+
const columnFieldPath = projection && pivotFieldId ? projection.tryGetFieldProjection(pivotFieldId)?.props.property : void 0;
|
|
49
|
+
const handleCardAdd = useCallback((columnValue) => {
|
|
50
|
+
if (db && cardSchema && columnFieldPath) {
|
|
51
|
+
const card = Obj.make(Type.assertObject(cardSchema), { [columnFieldPath]: columnValue });
|
|
52
|
+
db.add(card);
|
|
53
|
+
return card.id;
|
|
54
|
+
}
|
|
55
|
+
}, [
|
|
56
|
+
db,
|
|
57
|
+
cardSchema,
|
|
58
|
+
columnFieldPath
|
|
59
|
+
]);
|
|
60
|
+
const handleCardRemove = useCallback((card) => {
|
|
61
|
+
invokePromise(KanbanOperation.DeleteCard, { card });
|
|
62
|
+
}, [invokePromise]);
|
|
63
|
+
if (!object || !db || !items || !projection || !change) return null;
|
|
64
|
+
return /* @__PURE__ */ jsxs(Panel.Root, {
|
|
65
|
+
role,
|
|
66
|
+
children: [/* @__PURE__ */ jsx(Panel.Toolbar, {
|
|
67
|
+
asChild: true,
|
|
68
|
+
children: /* @__PURE__ */ jsx(Toolbar.Root, {})
|
|
69
|
+
}), /* @__PURE__ */ jsx(KanbanBoard.Root, {
|
|
70
|
+
kanban: object,
|
|
71
|
+
projection,
|
|
72
|
+
items,
|
|
73
|
+
change,
|
|
74
|
+
onCardAdd: handleCardAdd,
|
|
75
|
+
onCardRemove: handleCardRemove,
|
|
76
|
+
children: /* @__PURE__ */ jsx(Panel.Content, {
|
|
77
|
+
asChild: true,
|
|
78
|
+
children: /* @__PURE__ */ jsx(KanbanBoard.Content, {})
|
|
79
|
+
})
|
|
80
|
+
})]
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
var ItemsKanbanArticle = ({ role, subject: object }) => {
|
|
84
|
+
const db = Obj.getDatabase(object);
|
|
85
|
+
const projection = useItemsProjection(object);
|
|
86
|
+
const change = useEchoChangeCallback(object);
|
|
87
|
+
const itemsAtom = useMemo(() => Atom.make((get) => {
|
|
88
|
+
const out = [];
|
|
89
|
+
for (const ref of object.spec.items) {
|
|
90
|
+
const target = get(Obj.atom(ref));
|
|
91
|
+
if (target == null) continue;
|
|
92
|
+
if (Obj.isDeleted(target)) continue;
|
|
93
|
+
out.push(target);
|
|
94
|
+
}
|
|
95
|
+
return out;
|
|
96
|
+
}), [object.spec.items]);
|
|
97
|
+
const handleCardRemove = useCallback(() => void 0, []);
|
|
98
|
+
if (!object || !db || !change) return null;
|
|
99
|
+
return /* @__PURE__ */ jsxs(Panel.Root, {
|
|
100
|
+
role,
|
|
101
|
+
children: [/* @__PURE__ */ jsx(Panel.Toolbar, {
|
|
102
|
+
asChild: true,
|
|
103
|
+
children: /* @__PURE__ */ jsx(Toolbar.Root, {})
|
|
104
|
+
}), /* @__PURE__ */ jsx(KanbanBoard.Root, {
|
|
105
|
+
kanban: object,
|
|
106
|
+
projection,
|
|
107
|
+
items: itemsAtom,
|
|
108
|
+
change,
|
|
109
|
+
onCardRemove: handleCardRemove,
|
|
110
|
+
children: /* @__PURE__ */ jsx(Panel.Content, {
|
|
111
|
+
asChild: true,
|
|
112
|
+
children: /* @__PURE__ */ jsx(KanbanBoard.Content, {})
|
|
113
|
+
})
|
|
114
|
+
})]
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
KanbanArticle.displayName = "KanbanArticle";
|
|
118
|
+
//#endregion
|
|
119
|
+
export { KanbanArticle as default };
|
|
120
|
+
|
|
121
|
+
//# sourceMappingURL=chunk-KanbanArticle.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-KanbanArticle.mjs","names":[],"sources":["../../src/containers/KanbanArticle/KanbanArticle.tsx"],"sourcesContent":["//\n// Copyright 2024 DXOS.org\n//\n\nimport { Atom, RegistryContext } from '@effect-atom/atom-react';\nimport React, { useCallback, useContext, useMemo } from 'react';\n\nimport { useCapabilities, useOperationInvoker } from '@dxos/app-framework/ui';\nimport { AppCapabilities } from '@dxos/app-toolkit';\nimport { type AppSurface, useSchemaFilter } from '@dxos/app-toolkit/ui';\nimport { Filter, Obj, Query, type Ref, Type } from '@dxos/echo';\nimport { useObject, useType } from '@dxos/echo-react';\nimport { Panel, Toolbar } from '@dxos/react-ui';\nimport { getTagFromQuery, getTypeURIFromQuery } from '@dxos/schema';\n\nimport { KanbanBoard } from '#components';\nimport { useEchoChangeCallback, useItemsProjection, useProjectionModel } from '#hooks';\nimport { KanbanOperation } from '#types';\nimport { Kanban } from '#types';\n\nexport type KanbanArticleProps = AppSurface.ObjectArticleProps<Kanban.Kanban>;\n\nexport const KanbanArticle = (props: KanbanArticleProps) => {\n // Branch on `kanban.spec.kind`: view-variant runs a typename query through\n // `useProjectionModel`; items-variant dereferences `kanban.spec.items` and\n // uses a stub projection from `useItemsProjection`.\n return Kanban.isKanbanItems(props.subject) ? (\n <ItemsKanbanArticle {...props} subject={props.subject} />\n ) : (\n <ViewKanbanArticle {...props} />\n );\n};\n\nconst ViewKanbanArticle = ({ role, subject: object }: KanbanArticleProps) => {\n const registry = useContext(RegistryContext);\n const schemas = useCapabilities(AppCapabilities.Schema);\n const db = Obj.getDatabase(object);\n const { invokePromise } = useOperationInvoker();\n const [view] = useObject(object.spec.kind === 'view' ? object.spec.view : undefined);\n const typeUri = view?.query ? getTypeURIFromQuery(view.query.ast) : undefined;\n const tag = view?.query ? getTagFromQuery(view.query.ast) : undefined;\n\n const schemaFromDb = useType(db, typeUri);\n const cardSchema = useMemo(\n () => schemaFromDb ?? schemas.flat().find((schema) => Type.getURI(schema) === typeUri),\n [schemaFromDb, schemas, typeUri],\n );\n\n const baseFilter = useSchemaFilter(cardSchema);\n const items = useMemo(() => {\n if (!db) {\n return null;\n }\n const query = tag ? Query.select(baseFilter).select(Filter.tag(tag)) : Query.select(baseFilter);\n return db.query(query).atom;\n }, [db, baseFilter, tag]);\n\n const projection = useProjectionModel(cardSchema, object, registry);\n const change = useEchoChangeCallback(object);\n\n const pivotFieldId = view?.projection?.pivotFieldId;\n const columnFieldPath =\n projection && pivotFieldId ? projection.tryGetFieldProjection(pivotFieldId)?.props.property : undefined;\n\n const handleCardAdd = useCallback(\n (columnValue: string | undefined) => {\n if (db && cardSchema && columnFieldPath) {\n const card = Obj.make(Type.assertObject(cardSchema), {\n [columnFieldPath]: columnValue,\n });\n db.add(card);\n return card.id;\n }\n },\n [db, cardSchema, columnFieldPath],\n );\n\n const handleCardRemove = useCallback(\n (card: { id: string }) => {\n void invokePromise(KanbanOperation.DeleteCard, { card });\n },\n [invokePromise],\n );\n\n if (!object || !db || !items || !projection || !change) {\n return null;\n }\n\n return (\n <Panel.Root role={role}>\n <Panel.Toolbar asChild>\n <Toolbar.Root />\n </Panel.Toolbar>\n <KanbanBoard.Root\n kanban={object}\n projection={projection}\n items={items}\n change={change}\n onCardAdd={handleCardAdd}\n onCardRemove={handleCardRemove}\n >\n <Panel.Content asChild>\n <KanbanBoard.Content />\n </Panel.Content>\n </KanbanBoard.Root>\n </Panel.Root>\n );\n};\n\ntype ItemsKanbanArticleProps = Omit<KanbanArticleProps, 'subject'> & { subject: Kanban.KanbanItems };\n\nconst ItemsKanbanArticle = ({ role, subject: object }: ItemsKanbanArticleProps) => {\n const db = Obj.getDatabase(object);\n const projection = useItemsProjection(object);\n const change = useEchoChangeCallback(object);\n\n // TODO(wittjosiah): pass refs (not loaded objects) through to the kanban\n // board and let `KanbanCard` subscribe to its own ref via `useObject`.\n // Today this atom subscribes to *every* item — any one changing causes the\n // container (and the model's per-column atoms) to recompute. With cards\n // subscribing themselves, the container only needs the refs and the\n // per-card render is independent. Requires:\n // - `KanbanCard` to accept `Ref<Obj.Unknown>` as `data` and call\n // `useObject(ref)` internally.\n // - The model to handle a ref-bearing item shape (id from\n // `ref.dxn.asEchoDXN()?.echoUri`) and use arrangement-only ordering\n // for items-variant (no pivot-value fallback, since refs don't expose\n // the pivot field without loading).\n // - `Mosaic.isItem` to accept the ref wrapper alongside `Obj.isObject`.\n const itemsAtom = useMemo(\n () =>\n Atom.make((get) => {\n const out: Obj.Unknown[] = [];\n for (const ref of object.spec.items as ReadonlyArray<Ref.Ref<Obj.Unknown>>) {\n const target = get(Obj.atom(ref));\n if (target == null) {\n continue;\n }\n // Drop soft-deleted cards (e.g. Trello-closed cards). The ref\n // stays in `spec.items` so arrangement is preserved, but the card\n // shouldn't render.\n if (Obj.isDeleted(target)) {\n continue;\n }\n out.push(target as unknown as Obj.Unknown);\n }\n return out;\n }),\n [object.spec.items],\n );\n\n const handleCardRemove = useCallback(() => undefined, []);\n\n if (!object || !db || !change) {\n return null;\n }\n\n // TODO(wittjosiah): wire `onCardAdd` to the create-object flow so\n // users can add items directly from the kanban (currently the column's\n // \"+\" button is hidden because `onCardAdd` is undefined).\n return (\n <Panel.Root role={role}>\n <Panel.Toolbar asChild>\n <Toolbar.Root />\n </Panel.Toolbar>\n <KanbanBoard.Root\n kanban={object}\n projection={projection}\n items={itemsAtom}\n change={change}\n onCardRemove={handleCardRemove}\n >\n <Panel.Content asChild>\n <KanbanBoard.Content />\n </Panel.Content>\n </KanbanBoard.Root>\n </Panel.Root>\n );\n};\n\nKanbanArticle.displayName = 'KanbanArticle';\n"],"mappings":";;;;;;;;;;;;;;AAsBA,IAAa,iBAAiB,UAA8B;CAI1D,OAAO,OAAO,cAAc,MAAM,OAAO,IACvC,oBAAC,oBAAD;EAAoB,GAAI;EAAO,SAAS,MAAM;CAAU,CAAA,IAExD,oBAAC,mBAAD,EAAmB,GAAI,MAAQ,CAAA;AAEnC;AAEA,IAAM,qBAAqB,EAAE,MAAM,SAAS,aAAiC;CAC3E,MAAM,WAAW,WAAW,eAAe;CAC3C,MAAM,UAAU,gBAAgB,gBAAgB,MAAM;CACtD,MAAM,KAAK,IAAI,YAAY,MAAM;CACjC,MAAM,EAAE,kBAAkB,oBAAoB;CAC9C,MAAM,CAAC,QAAQ,UAAU,OAAO,KAAK,SAAS,SAAS,OAAO,KAAK,OAAO,KAAA,CAAS;CACnF,MAAM,UAAU,MAAM,QAAQ,oBAAoB,KAAK,MAAM,GAAG,IAAI,KAAA;CACpE,MAAM,MAAM,MAAM,QAAQ,gBAAgB,KAAK,MAAM,GAAG,IAAI,KAAA;CAE5D,MAAM,eAAe,QAAQ,IAAI,OAAO;CACxC,MAAM,aAAa,cACX,gBAAgB,QAAQ,KAAK,CAAC,CAAC,MAAM,WAAW,KAAK,OAAO,MAAM,MAAM,OAAO,GACrF;EAAC;EAAc;EAAS;CAAO,CACjC;CAEA,MAAM,aAAa,gBAAgB,UAAU;CAC7C,MAAM,QAAQ,cAAc;EAC1B,IAAI,CAAC,IACH,OAAO;EAET,MAAM,QAAQ,MAAM,MAAM,OAAO,UAAU,CAAC,CAAC,OAAO,OAAO,IAAI,GAAG,CAAC,IAAI,MAAM,OAAO,UAAU;EAC9F,OAAO,GAAG,MAAM,KAAK,CAAC,CAAC;CACzB,GAAG;EAAC;EAAI;EAAY;CAAG,CAAC;CAExB,MAAM,aAAa,mBAAmB,YAAY,QAAQ,QAAQ;CAClE,MAAM,SAAS,sBAAsB,MAAM;CAE3C,MAAM,eAAe,MAAM,YAAY;CACvC,MAAM,kBACJ,cAAc,eAAe,WAAW,sBAAsB,YAAY,CAAC,EAAE,MAAM,WAAW,KAAA;CAEhG,MAAM,gBAAgB,aACnB,gBAAoC;EACnC,IAAI,MAAM,cAAc,iBAAiB;GACvC,MAAM,OAAO,IAAI,KAAK,KAAK,aAAa,UAAU,GAAG,GAClD,kBAAkB,YACrB,CAAC;GACD,GAAG,IAAI,IAAI;GACX,OAAO,KAAK;EACd;CACF,GACA;EAAC;EAAI;EAAY;CAAe,CAClC;CAEA,MAAM,mBAAmB,aACtB,SAAyB;EACxB,cAAmB,gBAAgB,YAAY,EAAE,KAAK,CAAC;CACzD,GACA,CAAC,aAAa,CAChB;CAEA,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,QAC9C,OAAO;CAGT,OACE,qBAAC,MAAM,MAAP;EAAkB;YAAlB,CACE,oBAAC,MAAM,SAAP;GAAe,SAAA;aACb,oBAAC,QAAQ,MAAT,CAAe,CAAA;EACF,CAAA,GACf,oBAAC,YAAY,MAAb;GACE,QAAQ;GACI;GACL;GACC;GACR,WAAW;GACX,cAAc;aAEd,oBAAC,MAAM,SAAP;IAAe,SAAA;cACb,oBAAC,YAAY,SAAb,CAAsB,CAAA;GACT,CAAA;EACC,CAAA,CACR;;AAEhB;AAIA,IAAM,sBAAsB,EAAE,MAAM,SAAS,aAAsC;CACjF,MAAM,KAAK,IAAI,YAAY,MAAM;CACjC,MAAM,aAAa,mBAAmB,MAAM;CAC5C,MAAM,SAAS,sBAAsB,MAAM;CAe3C,MAAM,YAAY,cAEd,KAAK,MAAM,QAAQ;EACjB,MAAM,MAAqB,CAAC;EAC5B,KAAK,MAAM,OAAO,OAAO,KAAK,OAA8C;GAC1E,MAAM,SAAS,IAAI,IAAI,KAAK,GAAG,CAAC;GAChC,IAAI,UAAU,MACZ;GAKF,IAAI,IAAI,UAAU,MAAM,GACtB;GAEF,IAAI,KAAK,MAAgC;EAC3C;EACA,OAAO;CACT,CAAC,GACH,CAAC,OAAO,KAAK,KAAK,CACpB;CAEA,MAAM,mBAAmB,kBAAkB,KAAA,GAAW,CAAC,CAAC;CAExD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,QACrB,OAAO;CAMT,OACE,qBAAC,MAAM,MAAP;EAAkB;YAAlB,CACE,oBAAC,MAAM,SAAP;GAAe,SAAA;aACb,oBAAC,QAAQ,MAAT,CAAe,CAAA;EACF,CAAA,GACf,oBAAC,YAAY,MAAb;GACE,QAAQ;GACI;GACZ,OAAO;GACC;GACR,cAAc;aAEd,oBAAC,MAAM,SAAP;IAAe,SAAA;cACb,oBAAC,YAAY,SAAb,CAAsB,CAAA;GACT,CAAA;EACC,CAAA,CACR;;AAEhB;AAEA,cAAc,cAAc"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Obj } from "@dxos/echo";
|
|
2
|
+
import { getTypeURIFromQuery } from "@dxos/schema";
|
|
3
|
+
import { KanbanSettingsSchema, KanbanViewSettingsSchema, UNCATEGORIZED_VALUE } from "#types";
|
|
4
|
+
import { RegistryContext } from "@effect-atom/atom-react";
|
|
5
|
+
import { useCallback, useContext, useMemo } from "react";
|
|
6
|
+
import { useProjectionModel } from "#hooks";
|
|
7
|
+
import { jsx } from "react/jsx-runtime";
|
|
8
|
+
import { Form, SelectField } from "@dxos/react-ui-form";
|
|
9
|
+
import { useObject, useType } from "@dxos/echo-react";
|
|
10
|
+
import { Format } from "@dxos/echo/Format";
|
|
11
|
+
//#region src/containers/KanbanProperties/KanbanProperties.tsx
|
|
12
|
+
/**
|
|
13
|
+
* Object-properties panel for a Kanban. Renders fields common to every kanban
|
|
14
|
+
* (currently the "Hide uncategorized column" toggle); for view-variant
|
|
15
|
+
* kanbans an additional "Column field" picker drives the View's pivot
|
|
16
|
+
* field. Items-variant kanbans use a hardcoded `spec.pivotField`, so that
|
|
17
|
+
* field is omitted there.
|
|
18
|
+
*/
|
|
19
|
+
var KanbanProperties = ({ subject: object }) => {
|
|
20
|
+
const registry = useContext(RegistryContext);
|
|
21
|
+
const db = Obj.getDatabase(object);
|
|
22
|
+
const isView = object.spec.kind === "view";
|
|
23
|
+
const [view, updateView] = useObject(object.spec.kind === "view" ? object.spec.view : void 0);
|
|
24
|
+
const [, updateKanban] = useObject(object);
|
|
25
|
+
const fieldProjections = useProjectionModel(useType(db, view?.query ? getTypeURIFromQuery(view.query.ast) : void 0), object, registry)?.getFieldProjections() ?? [];
|
|
26
|
+
const selectFields = useMemo(() => fieldProjections.filter((field) => field.props.format === Format.TypeFormat.SingleSelect).map(({ field }) => ({
|
|
27
|
+
value: field.id,
|
|
28
|
+
label: field.path
|
|
29
|
+
})), [fieldProjections]);
|
|
30
|
+
const hideUncategorized = object.arrangement.columns[UNCATEGORIZED_VALUE]?.hidden ?? false;
|
|
31
|
+
const handleValuesChanged = useCallback((values) => {
|
|
32
|
+
if (isView && values.columnFieldId != null) updateView((view) => {
|
|
33
|
+
view.projection.pivotFieldId = values.columnFieldId;
|
|
34
|
+
});
|
|
35
|
+
if (values.hideUncategorized !== void 0) updateKanban((kanban) => {
|
|
36
|
+
const existing = kanban.arrangement.columns[UNCATEGORIZED_VALUE];
|
|
37
|
+
if (existing) existing.hidden = values.hideUncategorized;
|
|
38
|
+
else kanban.arrangement.columns[UNCATEGORIZED_VALUE] = {
|
|
39
|
+
ids: [],
|
|
40
|
+
hidden: values.hideUncategorized
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
}, [
|
|
44
|
+
isView,
|
|
45
|
+
updateView,
|
|
46
|
+
updateKanban
|
|
47
|
+
]);
|
|
48
|
+
const initialValues = useMemo(() => ({
|
|
49
|
+
...isView ? { columnFieldId: view?.projection.pivotFieldId } : {},
|
|
50
|
+
hideUncategorized
|
|
51
|
+
}), [
|
|
52
|
+
isView,
|
|
53
|
+
view?.projection.pivotFieldId,
|
|
54
|
+
hideUncategorized
|
|
55
|
+
]);
|
|
56
|
+
const fieldMap = useMemo(() => ({ columnFieldId: (props) => /* @__PURE__ */ jsx(SelectField, {
|
|
57
|
+
...props,
|
|
58
|
+
options: selectFields
|
|
59
|
+
}) }), [selectFields]);
|
|
60
|
+
const settingsSchema = isView ? KanbanViewSettingsSchema : KanbanSettingsSchema;
|
|
61
|
+
return /* @__PURE__ */ jsx(Form.Section, { children: /* @__PURE__ */ jsx(Form.Root, {
|
|
62
|
+
schema: settingsSchema,
|
|
63
|
+
values: initialValues,
|
|
64
|
+
fieldMap,
|
|
65
|
+
onValuesChanged: handleValuesChanged,
|
|
66
|
+
children: /* @__PURE__ */ jsx(Form.FieldSet, {})
|
|
67
|
+
}) });
|
|
68
|
+
};
|
|
69
|
+
KanbanProperties.displayName = "KanbanProperties";
|
|
70
|
+
//#endregion
|
|
71
|
+
export { KanbanProperties as default };
|
|
72
|
+
|
|
73
|
+
//# sourceMappingURL=chunk-KanbanProperties.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-KanbanProperties.mjs","names":[],"sources":["../../src/containers/KanbanProperties/KanbanProperties.tsx"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport { RegistryContext } from '@effect-atom/atom-react';\nimport React, { useCallback, useContext, useMemo } from 'react';\n\nimport { type AppSurface } from '@dxos/app-toolkit/ui';\nimport { Obj } from '@dxos/echo';\nimport { useObject, useType } from '@dxos/echo-react';\nimport { Format } from '@dxos/echo/Format';\nimport { Form, type FormFieldMap, SelectField } from '@dxos/react-ui-form';\nimport { getTypeURIFromQuery } from '@dxos/schema';\n\nimport { useProjectionModel } from '#hooks';\nimport { type Kanban, KanbanSettingsSchema, KanbanViewSettingsSchema, UNCATEGORIZED_VALUE } from '#types';\n\nexport type KanbanPropertiesProps = AppSurface.ObjectPropertiesProps<Kanban.Kanban>;\n\n/**\n * Object-properties panel for a Kanban. Renders fields common to every kanban\n * (currently the \"Hide uncategorized column\" toggle); for view-variant\n * kanbans an additional \"Column field\" picker drives the View's pivot\n * field. Items-variant kanbans use a hardcoded `spec.pivotField`, so that\n * field is omitted there.\n */\nexport const KanbanProperties = ({ subject: object }: KanbanPropertiesProps) => {\n const registry = useContext(RegistryContext);\n const db = Obj.getDatabase(object);\n const isView = object.spec.kind === 'view';\n const [view, updateView] = useObject(object.spec.kind === 'view' ? object.spec.view : undefined);\n const [, updateKanban] = useObject(object);\n const currentTypeUri = view?.query ? getTypeURIFromQuery(view.query.ast) : undefined;\n const schema = useType(db, currentTypeUri);\n const projection = useProjectionModel(schema, object, registry);\n\n const fieldProjections = projection?.getFieldProjections() ?? [];\n const selectFields = useMemo(\n () =>\n fieldProjections\n .filter((field) => field.props.format === Format.TypeFormat.SingleSelect)\n .map(({ field }) => ({ value: field.id, label: field.path })),\n [fieldProjections],\n );\n\n const hideUncategorized = object.arrangement.columns[UNCATEGORIZED_VALUE]?.hidden ?? false;\n\n const handleValuesChanged = useCallback(\n (values: Partial<{ columnFieldId: string; hideUncategorized: boolean }>) => {\n if (isView && values.columnFieldId != null) {\n updateView((view) => {\n view.projection.pivotFieldId = values.columnFieldId!;\n });\n }\n if (values.hideUncategorized !== undefined) {\n updateKanban((kanban) => {\n const existing = kanban.arrangement.columns[UNCATEGORIZED_VALUE];\n if (existing) {\n existing.hidden = values.hideUncategorized;\n } else {\n kanban.arrangement.columns[UNCATEGORIZED_VALUE] = {\n ids: [],\n hidden: values.hideUncategorized,\n };\n }\n });\n }\n },\n [isView, updateView, updateKanban],\n );\n\n const initialValues = useMemo(\n () => ({\n ...(isView ? { columnFieldId: view?.projection.pivotFieldId } : {}),\n hideUncategorized,\n }),\n [isView, view?.projection.pivotFieldId, hideUncategorized],\n );\n\n const fieldMap: FormFieldMap = useMemo(\n () => ({ columnFieldId: (props) => <SelectField {...props} options={selectFields} /> }),\n [selectFields],\n );\n\n // Schema is picked by `kanban.spec.kind` — they have different shapes,\n // so cast for `Form.Root`'s single-schema prop.\n const settingsSchema = (isView ? KanbanViewSettingsSchema : KanbanSettingsSchema) as any;\n\n return (\n <Form.Section>\n <Form.Root\n schema={settingsSchema}\n values={initialValues}\n fieldMap={fieldMap}\n onValuesChanged={handleValuesChanged}\n >\n <Form.FieldSet />\n </Form.Root>\n </Form.Section>\n );\n};\n\nKanbanProperties.displayName = 'KanbanProperties';\n"],"mappings":";;;;;;;;;;;;;;;;;;AA0BA,IAAa,oBAAoB,EAAE,SAAS,aAAoC;CAC9E,MAAM,WAAW,WAAW,eAAe;CAC3C,MAAM,KAAK,IAAI,YAAY,MAAM;CACjC,MAAM,SAAS,OAAO,KAAK,SAAS;CACpC,MAAM,CAAC,MAAM,cAAc,UAAU,OAAO,KAAK,SAAS,SAAS,OAAO,KAAK,OAAO,KAAA,CAAS;CAC/F,MAAM,GAAG,gBAAgB,UAAU,MAAM;CAKzC,MAAM,mBAFa,mBADJ,QAAQ,IADA,MAAM,QAAQ,oBAAoB,KAAK,MAAM,GAAG,IAAI,KAAA,CAErC,GAAQ,QAAQ,QAE7B,CAAA,EAAY,oBAAoB,KAAK,CAAC;CAC/D,MAAM,eAAe,cAEjB,iBACG,QAAQ,UAAU,MAAM,MAAM,WAAW,OAAO,WAAW,YAAY,CAAA,CACvE,KAAK,EAAE,aAAa;EAAE,OAAO,MAAM;EAAI,OAAO,MAAM;CAAK,EAAE,GAChE,CAAC,gBAAgB,CACnB;CAEA,MAAM,oBAAoB,OAAO,YAAY,QAAQ,oBAAoB,EAAE,UAAU;CAErF,MAAM,sBAAsB,aACzB,WAA2E;EAC1E,IAAI,UAAU,OAAO,iBAAiB,MACpC,YAAY,SAAS;GACnB,KAAK,WAAW,eAAe,OAAO;EACxC,CAAC;EAEH,IAAI,OAAO,sBAAsB,KAAA,GAC/B,cAAc,WAAW;GACvB,MAAM,WAAW,OAAO,YAAY,QAAQ;GAC5C,IAAI,UACF,SAAS,SAAS,OAAO;QAEzB,OAAO,YAAY,QAAQ,uBAAuB;IAChD,KAAK,CAAC;IACN,QAAQ,OAAO;GACjB;EAEJ,CAAC;CAEL,GACA;EAAC;EAAQ;EAAY;CAAY,CACnC;CAEA,MAAM,gBAAgB,eACb;EACL,GAAI,SAAS,EAAE,eAAe,MAAM,WAAW,aAAa,IAAI,CAAC;EACjE;CACF,IACA;EAAC;EAAQ,MAAM,WAAW;EAAc;CAAiB,CAC3D;CAEA,MAAM,WAAyB,eACtB,EAAE,gBAAgB,UAAU,oBAAC,aAAD;EAAa,GAAI;EAAO,SAAS;CAAe,CAAA,EAAE,IACrF,CAAC,YAAY,CACf;CAIA,MAAM,iBAAkB,SAAS,2BAA2B;CAE5D,OACE,oBAAC,KAAK,SAAN,EAAA,UACE,oBAAC,KAAK,MAAN;EACE,QAAQ;EACR,QAAQ;EACE;EACV,iBAAiB;YAEjB,oBAAC,KAAK,UAAN,CAAgB,CAAA;CACP,CAAA,EACC,CAAA;AAElB;AAEA,iBAAiB,cAAc"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Operation } from "@dxos/compute";
|
|
2
|
+
import { Capability } from "@dxos/app-framework";
|
|
3
|
+
import { SpaceCapabilities, SpaceOperation } from "@dxos/plugin-space";
|
|
4
|
+
import { Type } from "@dxos/echo";
|
|
5
|
+
import { ViewModel } from "@dxos/schema";
|
|
6
|
+
import { CreateKanbanSchema, Kanban } from "#types";
|
|
7
|
+
import * as Effect from "effect/Effect";
|
|
8
|
+
//#region src/capabilities/create-object.ts
|
|
9
|
+
var create_object_default = Capability.makeModule(Effect.fnUntraced(function* () {
|
|
10
|
+
return Capability.contributes(SpaceCapabilities.CreateObjectEntry, {
|
|
11
|
+
id: Type.getTypename(Kanban.Kanban),
|
|
12
|
+
inputSchema: CreateKanbanSchema,
|
|
13
|
+
createObject: (props, options) => Effect.gen(function* () {
|
|
14
|
+
const object = yield* Effect.promise(async () => {
|
|
15
|
+
if (props.typename) {
|
|
16
|
+
const { view } = await ViewModel.makeFromDatabase({
|
|
17
|
+
db: options.db,
|
|
18
|
+
typename: props.typename,
|
|
19
|
+
pivotFieldName: props.initialPivotColumn
|
|
20
|
+
});
|
|
21
|
+
return Kanban.make({
|
|
22
|
+
name: props.name,
|
|
23
|
+
view
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return Kanban.makeItems({
|
|
27
|
+
name: props.name,
|
|
28
|
+
pivotField: props.initialPivotColumn ?? ""
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
return yield* Operation.invoke(SpaceOperation.AddObject, {
|
|
32
|
+
object,
|
|
33
|
+
target: options.target,
|
|
34
|
+
targetNodeId: options.targetNodeId
|
|
35
|
+
});
|
|
36
|
+
})
|
|
37
|
+
});
|
|
38
|
+
}));
|
|
39
|
+
//#endregion
|
|
40
|
+
export { create_object_default as default };
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=chunk-create-object.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-create-object.mjs","names":[],"sources":["../../src/capabilities/create-object.ts"],"sourcesContent":["//\n// Copyright 2023 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport { Capability } from '@dxos/app-framework';\nimport { Operation } from '@dxos/compute';\nimport { Type } from '@dxos/echo';\nimport { SpaceOperation } from '@dxos/plugin-space';\nimport { SpaceCapabilities } from '@dxos/plugin-space';\nimport { ViewModel } from '@dxos/schema';\n\nimport { CreateKanbanSchema, Kanban } from '#types';\n\nexport default Capability.makeModule(\n Effect.fnUntraced(function* () {\n return Capability.contributes(SpaceCapabilities.CreateObjectEntry, {\n id: Type.getTypename(Kanban.Kanban),\n inputSchema: CreateKanbanSchema,\n createObject: (props, options) =>\n Effect.gen(function* () {\n const object = yield* Effect.promise(async () => {\n if (props.typename) {\n const { view } = await ViewModel.makeFromDatabase({\n db: options.db,\n typename: props.typename,\n pivotFieldName: props.initialPivotColumn,\n });\n return Kanban.make({ name: props.name, view });\n }\n return Kanban.makeItems({ name: props.name, pivotField: props.initialPivotColumn ?? '' });\n });\n return yield* Operation.invoke(SpaceOperation.AddObject, {\n object,\n target: options.target,\n targetNodeId: options.targetNodeId,\n });\n }),\n });\n }),\n);\n"],"mappings":";;;;;;;;AAeA,IAAA,wBAAe,WAAW,WACxB,OAAO,WAAW,aAAa;CAC7B,OAAO,WAAW,YAAY,kBAAkB,mBAAmB;EACjE,IAAI,KAAK,YAAY,OAAO,MAAM;EAClC,aAAa;EACb,eAAe,OAAO,YACpB,OAAO,IAAI,aAAa;GACtB,MAAM,SAAS,OAAO,OAAO,QAAQ,YAAY;IAC/C,IAAI,MAAM,UAAU;KAClB,MAAM,EAAE,SAAS,MAAM,UAAU,iBAAiB;MAChD,IAAI,QAAQ;MACZ,UAAU,MAAM;MAChB,gBAAgB,MAAM;KACxB,CAAC;KACD,OAAO,OAAO,KAAK;MAAE,MAAM,MAAM;MAAM;KAAK,CAAC;IAC/C;IACA,OAAO,OAAO,UAAU;KAAE,MAAM,MAAM;KAAM,YAAY,MAAM,sBAAsB;IAAG,CAAC;GAC1F,CAAC;GACD,OAAO,OAAO,UAAU,OAAO,eAAe,WAAW;IACvD;IACA,QAAQ,QAAQ;IAChB,cAAc,QAAQ;GACxB,CAAC;EACH,CAAC;CACL,CAAC;AACH,CAAC,CACH"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { n as DeleteCardField } from "./chunk-types.mjs";
|
|
2
|
+
import { Operation } from "@dxos/compute";
|
|
3
|
+
import { Capabilities, Capability } from "@dxos/app-framework";
|
|
4
|
+
import { Obj, Type } from "@dxos/echo";
|
|
5
|
+
import { ProjectionModel, createEchoChangeCallback, getTypeURIFromQuery } from "@dxos/schema";
|
|
6
|
+
import * as Effect from "effect/Effect";
|
|
7
|
+
import { invariant } from "@dxos/invariant";
|
|
8
|
+
//#region src/operations/delete-card-field.ts
|
|
9
|
+
var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-kanban/src/operations/delete-card-field.ts";
|
|
10
|
+
var handler = DeleteCardField.pipe(Operation.withHandler(Effect.fnUntraced(function* ({ view, fieldId }) {
|
|
11
|
+
const registry = yield* Capability.get(Capabilities.AtomRegistry);
|
|
12
|
+
const db = Obj.getDatabase(view);
|
|
13
|
+
invariant(db, "Database not found", {
|
|
14
|
+
"~LogMeta": "~LogMeta",
|
|
15
|
+
F: __dxlog_file,
|
|
16
|
+
L: 18,
|
|
17
|
+
S: this,
|
|
18
|
+
A: ["db", "'Database not found'"]
|
|
19
|
+
});
|
|
20
|
+
const schema = (yield* Effect.sync(() => db.graph.registry.list().filter(Type.isType))).find((t) => Type.getURI(t) === getTypeURIFromQuery(view.query.ast));
|
|
21
|
+
invariant(schema, "Schema not found", {
|
|
22
|
+
"~LogMeta": "~LogMeta",
|
|
23
|
+
F: __dxlog_file,
|
|
24
|
+
L: 21,
|
|
25
|
+
S: this,
|
|
26
|
+
A: ["schema", "'Schema not found'"]
|
|
27
|
+
});
|
|
28
|
+
invariant(Type.isType(schema), "expected stored Type.Type for card schema", {
|
|
29
|
+
"~LogMeta": "~LogMeta",
|
|
30
|
+
F: __dxlog_file,
|
|
31
|
+
L: 23,
|
|
32
|
+
S: this,
|
|
33
|
+
A: ["Type.isType(schema)", "'expected stored Type.Type for card schema'"]
|
|
34
|
+
});
|
|
35
|
+
const result = new ProjectionModel({
|
|
36
|
+
registry,
|
|
37
|
+
view,
|
|
38
|
+
baseSchema: schema.jsonSchema,
|
|
39
|
+
change: createEchoChangeCallback(view, schema)
|
|
40
|
+
}).deleteFieldProjection(fieldId);
|
|
41
|
+
return {
|
|
42
|
+
field: result.deleted.field,
|
|
43
|
+
props: result.deleted.props,
|
|
44
|
+
index: result.index
|
|
45
|
+
};
|
|
46
|
+
})));
|
|
47
|
+
//#endregion
|
|
48
|
+
export { handler as default };
|
|
49
|
+
|
|
50
|
+
//# sourceMappingURL=chunk-delete-card-field.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-delete-card-field.mjs","names":[],"sources":["../../src/operations/delete-card-field.ts"],"sourcesContent":["// Copyright 2025 DXOS.org\n\nimport * as Effect from 'effect/Effect';\n\nimport { Capabilities, Capability } from '@dxos/app-framework';\nimport { Operation } from '@dxos/compute';\nimport { Obj, Type } from '@dxos/echo';\nimport { invariant } from '@dxos/invariant';\nimport { ProjectionModel, createEchoChangeCallback, getTypeURIFromQuery } from '@dxos/schema';\n\nimport { KanbanOperation } from '../types';\n\nconst handler: Operation.WithHandler<typeof KanbanOperation.DeleteCardField> = KanbanOperation.DeleteCardField.pipe(\n Operation.withHandler(\n Effect.fnUntraced(function* ({ view, fieldId }) {\n const registry = yield* Capability.get(Capabilities.AtomRegistry);\n const db = Obj.getDatabase(view);\n invariant(db, 'Database not found');\n const types = yield* Effect.sync(() => db.graph.registry.list().filter(Type.isType));\n const schema = types.find((t) => Type.getURI(t) === getTypeURIFromQuery(view.query.ast));\n invariant(schema, 'Schema not found');\n\n invariant(Type.isType(schema), 'expected stored Type.Type for card schema');\n const projection = new ProjectionModel({\n registry,\n view,\n baseSchema: schema.jsonSchema,\n change: createEchoChangeCallback(view, schema),\n });\n\n const result = projection.deleteFieldProjection(fieldId);\n\n return {\n field: result.deleted.field,\n props: result.deleted.props,\n index: result.index,\n };\n }),\n ),\n);\n\nexport default handler;\n"],"mappings":";;;;;;;;;AAYA,IAAM,UAAA,gBAAyG,KAC7G,UAAU,YACR,OAAO,WAAW,WAAW,EAAE,MAAM,WAAW;CAC9C,MAAM,WAAW,OAAO,WAAW,IAAI,aAAa,YAAY;CAChE,MAAM,KAAK,IAAI,YAAY,IAAI;CAC/B,UAAU,IAAI,sBAAmB;EAAA,YAAA;EAAA,GAAA;EAAA,GAAA;EAAA,GAAA;EAAA,GAAA,CAAA,MAAA,sBAAA;CAAA,CAAC;CAElC,MAAM,UAAS,OADM,OAAO,WAAW,GAAG,MAAM,SAAS,KAAK,CAAC,CAAC,OAAO,KAAK,MAAM,CAAC,EAAA,CAC9D,MAAM,MAAM,KAAK,OAAO,CAAC,MAAM,oBAAoB,KAAK,MAAM,GAAG,CAAC;CACvF,UAAU,QAAQ,oBAAiB;EAAA,YAAA;EAAA,GAAA;EAAA,GAAA;EAAA,GAAA;EAAA,GAAA,CAAA,UAAA,oBAAA;CAAA,CAAC;CAEpC,UAAU,KAAK,OAAO,MAAM,GAAG,6CAA0C;EAAA,YAAA;EAAA,GAAA;EAAA,GAAA;EAAA,GAAA;EAAA,GAAA,CAAA,uBAAA,6CAAA;CAAA,CAAC;CAQ1E,MAAM,SAAS,IAPQ,gBAAgB;EACrC;EACA;EACA,YAAY,OAAO;EACnB,QAAQ,yBAAyB,MAAM,MAAM;CAC/C,CAEe,CAAA,CAAW,sBAAsB,OAAO;CAEvD,OAAO;EACL,OAAO,OAAO,QAAQ;EACtB,OAAO,OAAO,QAAQ;EACtB,OAAO,OAAO;CAChB;AACF,CAAC,CACH,CACF"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { t as DeleteCard } from "./chunk-types.mjs";
|
|
2
|
+
import { Operation } from "@dxos/compute";
|
|
3
|
+
import { Obj } from "@dxos/echo";
|
|
4
|
+
import * as Effect from "effect/Effect";
|
|
5
|
+
import { invariant } from "@dxos/invariant";
|
|
6
|
+
//#region src/operations/delete-card.ts
|
|
7
|
+
var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-kanban/src/operations/delete-card.ts";
|
|
8
|
+
var handler = DeleteCard.pipe(Operation.withHandler(({ card }) => Effect.sync(() => {
|
|
9
|
+
const db = Obj.getDatabase(card);
|
|
10
|
+
invariant(db, void 0, {
|
|
11
|
+
"~LogMeta": "~LogMeta",
|
|
12
|
+
F: __dxlog_file,
|
|
13
|
+
L: 15,
|
|
14
|
+
S: void 0,
|
|
15
|
+
A: ["db", ""]
|
|
16
|
+
});
|
|
17
|
+
db.remove(card);
|
|
18
|
+
return { card };
|
|
19
|
+
})));
|
|
20
|
+
//#endregion
|
|
21
|
+
export { handler as default };
|
|
22
|
+
|
|
23
|
+
//# sourceMappingURL=chunk-delete-card.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-delete-card.mjs","names":[],"sources":["../../src/operations/delete-card.ts"],"sourcesContent":["// Copyright 2025 DXOS.org\n\nimport * as Effect from 'effect/Effect';\n\nimport { Operation } from '@dxos/compute';\nimport { Obj } from '@dxos/echo';\nimport { invariant } from '@dxos/invariant';\n\nimport { KanbanOperation } from '../types';\n\nconst handler: Operation.WithHandler<typeof KanbanOperation.DeleteCard> = KanbanOperation.DeleteCard.pipe(\n Operation.withHandler(({ card }) =>\n Effect.sync(() => {\n const db = Obj.getDatabase(card);\n invariant(db);\n db.remove(card);\n\n return { card };\n }),\n ),\n);\n\nexport default handler;\n"],"mappings":";;;;;;;AAUA,IAAM,UAAA,WAA+F,KACnG,UAAU,aAAa,EAAE,WACvB,OAAO,WAAW;CAChB,MAAM,KAAK,IAAI,YAAY,IAAI;CAC/B,UAAU,IAAC,KAAA,GAAA;EAAA,YAAA;EAAA,GAAA;EAAA,GAAA;EAAA,GAAA,KAAA;EAAA,GAAA,CAAA,MAAA,EAAA;CAAA,CAAC;CACZ,GAAG,OAAO,IAAI;CAEd,OAAO,EAAE,KAAK;AAChB,CAAC,CACH,CACF"}
|
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
import { trim } from "@dxos/util";
|
|
2
2
|
import { Plugin } from "@dxos/app-framework";
|
|
3
|
-
|
|
4
|
-
// dx.config.ts
|
|
5
3
|
import { Config2 } from "@dxos/app-framework/config";
|
|
6
|
-
|
|
7
|
-
var dx_config_default = Config2.make({
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
description: trim`
|
|
4
|
+
//#region dx.config.ts
|
|
5
|
+
var dx_config_default = Config2.make({ plugin: {
|
|
6
|
+
key: "org.dxos.plugin.kanban",
|
|
7
|
+
name: "Kanban",
|
|
8
|
+
author: "DXOS",
|
|
9
|
+
description: trim`
|
|
13
10
|
Visual project management using customizable kanban boards to track workflow progress.
|
|
14
11
|
Organize any ECHO type into drag-and-drop columns defined by a single-select field, move cards
|
|
15
12
|
between stages, and reorder both columns and cards — all changes are persisted to ECHO and
|
|
@@ -27,24 +24,19 @@ var dx_config_default = Config2.make({
|
|
|
27
24
|
The plugin contributes a Kanban skill that exposes board creation and card management
|
|
28
25
|
to AI agents, enabling automated project tracking workflows.
|
|
29
26
|
`,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
// src/meta.ts
|
|
27
|
+
source: "https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-kanban",
|
|
28
|
+
icon: {
|
|
29
|
+
key: "ph--kanban--regular",
|
|
30
|
+
hue: "green"
|
|
31
|
+
},
|
|
32
|
+
spec: "PLUGIN.mdl",
|
|
33
|
+
screenshots: [{ dark: "https://dxos.network/plugin-details-kanban-dark.png" }],
|
|
34
|
+
tags: ["beta"]
|
|
35
|
+
} });
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/meta.ts
|
|
45
38
|
var meta = Plugin.getMetaFromConfig(dx_config_default);
|
|
39
|
+
//#endregion
|
|
40
|
+
export { meta as t };
|
|
46
41
|
|
|
47
|
-
|
|
48
|
-
meta
|
|
49
|
-
};
|
|
50
|
-
//# sourceMappingURL=chunk-V4AVOJVU.mjs.map
|
|
42
|
+
//# sourceMappingURL=chunk-meta.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-meta.mjs","names":[],"sources":["../../dx.config.ts","../../src/meta.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport { Config2 } from '@dxos/app-framework/config';\nimport { trim } from '@dxos/util';\n\nexport default Config2.make({\n plugin: {\n key: 'org.dxos.plugin.kanban',\n name: 'Kanban',\n author: 'DXOS',\n description: trim`\n Visual project management using customizable kanban boards to track workflow progress.\n Organize any ECHO type into drag-and-drop columns defined by a single-select field, move cards\n between stages, and reorder both columns and cards — all changes are persisted to ECHO and\n replicated to collaborators in real time.\n\n Kanban boards come in two variants: view-variant boards source their cards through a linked\n View query (any ECHO type can be pivoted on a single-select field), while items-variant boards\n own their cards explicitly and are used by external sync integrations such as Linear or GitHub.\n Both variants share the same arrangement storage and drag-and-drop mechanics.\n\n Board settings let users choose which single-select field drives the column layout and\n optionally hide the uncategorized column for items that have no pivot value.\n Field-level undo support allows deleted card fields to be restored without data loss.\n\n The plugin contributes a Kanban skill that exposes board creation and card management\n to AI agents, enabling automated project tracking workflows.\n `,\n source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-kanban',\n icon: { key: 'ph--kanban--regular', hue: 'green' },\n spec: 'PLUGIN.mdl',\n screenshots: [{ dark: 'https://dxos.network/plugin-details-kanban-dark.png' }],\n tags: ['beta'],\n },\n});\n","//\n// Copyright 2023 DXOS.org\n//\n\nimport { Plugin } from '@dxos/app-framework';\n\nimport config from '../dx.config';\n\nexport const meta = Plugin.getMetaFromConfig(config);\n"],"mappings":";;;;AAOA,IAAA,oBAAe,QAAQ,KAAK,EAC1B,QAAQ;CACN,KAAK;CACL,MAAM;CACN,QAAQ;CACR,aAAa,IAAI;;;;;;;;;;;;;;;;;;CAkBjB,QAAQ;CACR,MAAM;EAAE,KAAK;EAAuB,KAAK;CAAQ;CACjD,MAAM;CACN,aAAa,CAAC,EAAE,MAAM,sDAAsD,CAAC;CAC7E,MAAM,CAAC,MAAM;AACf,EACF,CAAC;;;AC5BD,IAAa,OAAO,OAAO,kBAAkB,iBAAM"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Capabilities, Capability } from "@dxos/app-framework";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import { KanbanOperationHandlerSet } from "#operations";
|
|
4
|
+
//#region src/capabilities/operation-handler.ts
|
|
5
|
+
var operation_handler_default = Capability.makeModule(Effect.fnUntraced(function* () {
|
|
6
|
+
return Capability.contributes(Capabilities.OperationHandler, KanbanOperationHandlerSet);
|
|
7
|
+
}));
|
|
8
|
+
//#endregion
|
|
9
|
+
export { operation_handler_default as default };
|
|
10
|
+
|
|
11
|
+
//# sourceMappingURL=chunk-operation-handler.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-operation-handler.mjs","names":[],"sources":["../../src/capabilities/operation-handler.ts"],"sourcesContent":["// Copyright 2025 DXOS.org\n\nimport * as Effect from 'effect/Effect';\n\nimport { Capabilities, Capability } from '@dxos/app-framework';\nimport type { OperationHandlerSet } from '@dxos/compute';\n\nimport { KanbanOperationHandlerSet } from '#operations';\n\nexport default Capability.makeModule<OperationHandlerSet.OperationHandlerSet>(\n Effect.fnUntraced(function* () {\n return Capability.contributes(Capabilities.OperationHandler, KanbanOperationHandlerSet);\n }),\n);\n"],"mappings":";;;;AASA,IAAA,4BAAe,WAAW,WACxB,OAAO,WAAW,aAAa;CAC7B,OAAO,WAAW,YAAY,aAAa,kBAAkB,yBAAyB;AACxF,CAAC,CACH"}
|