paseo-kanban 0.1.2 → 0.1.3
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/OVERVIEW.md +9 -0
- package/README.md +20 -44
- package/README.zh-CN.md +19 -45
- package/client/kanban-board.tsx +46 -6
- package/client/kanban-drag.ts +1 -21
- package/client/kanban-workspace-panel.tsx +13 -0
- package/index.client.tsx +28 -16
- package/package.json +3 -1
package/OVERVIEW.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Kanban
|
|
2
|
+
|
|
3
|
+
Organize tasks in customizable swimlanes, add descriptions and subtasks, and link tasks to Paseo projects. Drag cards to reorder them within a lane or move them between lanes.
|
|
4
|
+
|
|
5
|
+
Open the board from the sidebar or from a workspace's `+` menu. Workspace tabs initially filter to their project's tasks and can sit beside an agent or terminal using Paseo's native split controls. Each open board has its own project filter; all boards on the same host share tasks and lanes.
|
|
6
|
+
|
|
7
|
+
Board data is stored in Paseo's host-scoped plugin settings. Concurrent edits use revision checks so a stale edit cannot overwrite a newer board. If a project's name cannot be read, its stored ID remains available. If workspace project context is unavailable when the board opens, it initially shows all tasks.
|
|
8
|
+
|
|
9
|
+
Requires Paseo 0.8.0 or later. No accounts, tokens, or additional setup are required.
|
package/README.md
CHANGED
|
@@ -8,11 +8,12 @@ A lightweight, responsive Kanban board plugin for [Paseo](https://paseo.sh) work
|
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
|
-
- **Flexible Swimlanes**:
|
|
11
|
+
- **Flexible Swimlanes**: Three initial lanes that you can rename, with support for adding and deleting custom lanes.
|
|
12
12
|
- **Rich Task Cards**:
|
|
13
|
-
- Task title and multi-line
|
|
13
|
+
- Task title and multi-line description.
|
|
14
14
|
- Subtasks checklist with completion toggles and live progress tracking.
|
|
15
15
|
- Native Paseo project association.
|
|
16
|
+
- **Workspace Tabs and Splits**: Open the board beside an agent or terminal, initially filtered to the workspace's project. The sidebar remains available.
|
|
16
17
|
- **Project Filtering**: Instantly filter board cards by linked Paseo project to keep context focused.
|
|
17
18
|
- **Smooth Drag-and-Drop**: Real-time hit-testing for reordering cards within lanes and moving cards across lanes.
|
|
18
19
|
- **Versioned State Persistence**: Persists board data through Paseo's settings API with optimistic concurrency control (CAS) to prevent race conditions and accidental overwrites.
|
|
@@ -21,8 +22,8 @@ A lightweight, responsive Kanban board plugin for [Paseo](https://paseo.sh) work
|
|
|
21
22
|
|
|
22
23
|
## Requirements
|
|
23
24
|
|
|
24
|
-
- **Paseo
|
|
25
|
-
- **Development
|
|
25
|
+
- **Paseo host**: `>= 0.8.0` (declared in `paseo-plugin.json`). The host runs the plugin.
|
|
26
|
+
- **Development and CI**: Node.js 24 (pinned in `.nvmrc` and `.node-version`) for checks, TypeScript stripping, and native tests.
|
|
26
27
|
|
|
27
28
|
---
|
|
28
29
|
|
|
@@ -30,7 +31,7 @@ A lightweight, responsive Kanban board plugin for [Paseo](https://paseo.sh) work
|
|
|
30
31
|
|
|
31
32
|
### Quick Install (Recommended)
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
Install directly from npm or GitHub:
|
|
34
35
|
|
|
35
36
|
**Via NPM (Release package):**
|
|
36
37
|
|
|
@@ -56,7 +57,12 @@ Verify that the plugin is running:
|
|
|
56
57
|
paseo plugin ls
|
|
57
58
|
```
|
|
58
59
|
|
|
59
|
-
Once active, open
|
|
60
|
+
Once active, open the board from either entry:
|
|
61
|
+
|
|
62
|
+
- **Sidebar → Kanban**: shows all tasks by default.
|
|
63
|
+
- **Workspace → `+` → Kanban**: initially filters to the workspace's project, with other filters available. Use Paseo's native split controls to place it beside an agent or terminal.
|
|
64
|
+
|
|
65
|
+
Both entries share tasks and lanes with full editing support; their filters are independent. Closing and reopening the board or restarting restores the entry's default filter. If workspace project context is unavailable, the board silently shows all tasks and keeps that filter even if context arrives later. Narrow splits retain horizontal lane scrolling.
|
|
60
66
|
|
|
61
67
|
### Local Development
|
|
62
68
|
|
|
@@ -66,7 +72,7 @@ To contribute or debug locally:
|
|
|
66
72
|
# 1. Clone repository and install dependencies
|
|
67
73
|
git clone https://github.com/breathi3552/paseo-kanban.git
|
|
68
74
|
cd paseo-kanban
|
|
69
|
-
npm
|
|
75
|
+
npm ci
|
|
70
76
|
|
|
71
77
|
# 2. Link this directory into your local Paseo daemon
|
|
72
78
|
paseo plugin link .
|
|
@@ -76,56 +82,26 @@ paseo plugin link .
|
|
|
76
82
|
|
|
77
83
|
## Development & Testing
|
|
78
84
|
|
|
79
|
-
|
|
85
|
+
Install dependencies and run the full quality check:
|
|
80
86
|
|
|
81
87
|
```bash
|
|
82
|
-
npm install
|
|
83
|
-
# or clean install:
|
|
84
88
|
npm ci
|
|
89
|
+
npm run check
|
|
85
90
|
```
|
|
86
91
|
|
|
87
|
-
|
|
92
|
+
Individual commands (`npm test`, `npm run typecheck`, `npm run lint`, `npm run format:check`, `npm run check:package`) are defined in [`package.json`](./package.json). For tag-based publishing, release sources of truth, recovery, and host acceptance, see the [development guide](./docs/development.md#21-标签发布github-actions).
|
|
88
93
|
|
|
89
|
-
|
|
94
|
+
---
|
|
90
95
|
|
|
91
|
-
|
|
92
|
-
npm run check
|
|
93
|
-
```
|
|
96
|
+
## Releases
|
|
94
97
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
- **Package Verification**: Validates release package contents, entrypoints, and TypeScript AST relative imports:
|
|
98
|
-
```bash
|
|
99
|
-
npm run check:package
|
|
100
|
-
```
|
|
101
|
-
- **Run Tests**: Cross-platform auto-discovery of all `test/*.test.mjs` suites:
|
|
102
|
-
```bash
|
|
103
|
-
npm test
|
|
104
|
-
```
|
|
105
|
-
- **Type Checking**: Validates TypeScript types across client and server entry points:
|
|
106
|
-
```bash
|
|
107
|
-
npm run typecheck
|
|
108
|
-
```
|
|
109
|
-
- **Linting**: Static code analysis with ESLint:
|
|
110
|
-
```bash
|
|
111
|
-
npm run lint
|
|
112
|
-
```
|
|
113
|
-
- **Formatting**: Check or format code style with Prettier:
|
|
114
|
-
```bash
|
|
115
|
-
npm run format:check
|
|
116
|
-
npm run format
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
Maintainers can publish a new GitHub Release and npm package in one run of the **Release to GitHub and npm** GitHub Action: select `patch`, `minor`, or `major`. Configure `NPM_TOKEN` and repository write permissions first. For setup, recovery, and manual host acceptance, see the [Development & Acceptance Guide](./docs/development.md#24-一键发布github-actions).
|
|
98
|
+
See the [0.1.3 release notes](./docs/releases/0.1.3.md). Each release's npm package and GitHub Release share the same version tag; GitHub includes the verified npm tarball. `main` may contain changes beyond the latest release.
|
|
120
99
|
|
|
121
100
|
---
|
|
122
101
|
|
|
123
102
|
## Architecture & Design
|
|
124
103
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
- **Interactive Architecture Viewer**: Open [`docs/architecture/paseo-kanban.architecture.html`](./docs/architecture/paseo-kanban.architecture.html) in your browser.
|
|
128
|
-
- **Architecture Schema & Model**: [`docs/architecture/paseo-kanban.architecture.json`](./docs/architecture/paseo-kanban.architecture.json).
|
|
104
|
+
Core terminology and design decisions are documented in [`CONTEXT.md`](./CONTEXT.md) and [`docs/adr/`](./docs/adr/).
|
|
129
105
|
|
|
130
106
|
---
|
|
131
107
|
|
package/README.zh-CN.md
CHANGED
|
@@ -13,16 +13,17 @@
|
|
|
13
13
|
- 任务标题与多行描述编辑。
|
|
14
14
|
- 子步骤清单支持独立增删改、完成状态勾选及实时进度展示。
|
|
15
15
|
- 支持关联本地已有的 Paseo 项目。
|
|
16
|
+
- **工作区标签页与分屏**:与 Agent、Terminal 并排打开看板,默认筛选工作区所属项目;保留侧边栏入口。
|
|
16
17
|
- **项目维度筛选**:一键按关联的 Paseo 项目过滤看板卡片,聚焦当前目标。
|
|
17
18
|
- **流畅拖拽交互**:精准的拖拽命中测试(Hit-Testing),支持同泳道排序与跨泳道状态流转。
|
|
18
|
-
-
|
|
19
|
+
- **版本化数据持久化**:通过 Paseo settings API 存储看板,使用乐观并发版本控制(CAS)处理多会话写入冲突。
|
|
19
20
|
|
|
20
21
|
---
|
|
21
22
|
|
|
22
23
|
## 环境要求
|
|
23
24
|
|
|
24
|
-
- **Paseo
|
|
25
|
-
- **开发与 CI
|
|
25
|
+
- **Paseo 宿主**:`>= 0.8.0`(声明于 `paseo-plugin.json`),由 Paseo 运行插件。
|
|
26
|
+
- **开发与 CI**:使用 Node.js 24(声明于 `.nvmrc` 与 `.node-version`)执行质量检查、TypeScript 类型擦除和原生测试。
|
|
26
27
|
|
|
27
28
|
---
|
|
28
29
|
|
|
@@ -30,7 +31,7 @@
|
|
|
30
31
|
|
|
31
32
|
### 快速安装(推荐)
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
通过 Paseo CLI 从 npm 或 GitHub 安装:
|
|
34
35
|
|
|
35
36
|
**方式一:通过 NPM 官方包安装(推荐)**
|
|
36
37
|
|
|
@@ -56,7 +57,12 @@ paseo plugin add breathi3552/paseo-kanban --ref main
|
|
|
56
57
|
paseo plugin ls
|
|
57
58
|
```
|
|
58
59
|
|
|
59
|
-
状态显示为 `running`
|
|
60
|
+
状态显示为 `running` 后,可从两个入口打开看板:
|
|
61
|
+
|
|
62
|
+
- **侧边栏 → 看板**:默认展示全部任务。
|
|
63
|
+
- **工作区 → `+` → 看板**:默认筛选工作区所属项目,可切换范围;使用 Paseo 原生分屏操作与 Agent、Terminal 等并排显示。
|
|
64
|
+
|
|
65
|
+
两个入口共享任务和泳道,保留完整编辑能力,筛选互不影响。关闭重开或重启后恢复入口默认筛选。无法取得工作区所属项目时静默展示全部任务,本次打开期间不因项目上下文恢复而自动切换。窄分屏保持横向滚动浏览泳道。
|
|
60
66
|
|
|
61
67
|
### 本地开发与调试
|
|
62
68
|
|
|
@@ -66,7 +72,7 @@ paseo plugin ls
|
|
|
66
72
|
# 1. 克隆代码仓库并安装依赖
|
|
67
73
|
git clone https://github.com/breathi3552/paseo-kanban.git
|
|
68
74
|
cd paseo-kanban
|
|
69
|
-
npm
|
|
75
|
+
npm ci
|
|
70
76
|
|
|
71
77
|
# 2. 将当前开发目录软链接至本地 Paseo 守护进程
|
|
72
78
|
paseo plugin link .
|
|
@@ -76,58 +82,26 @@ paseo plugin link .
|
|
|
76
82
|
|
|
77
83
|
## 开发与测试
|
|
78
84
|
|
|
79
|
-
|
|
85
|
+
安装依赖并运行完整检查:
|
|
80
86
|
|
|
81
87
|
```bash
|
|
82
|
-
npm install
|
|
83
|
-
# 或干净安装验证:
|
|
84
88
|
npm ci
|
|
89
|
+
npm run check
|
|
85
90
|
```
|
|
86
91
|
|
|
87
|
-
|
|
92
|
+
单项命令(`npm test`、`npm run typecheck`、`npm run lint`、`npm run format:check`、`npm run check:package`)见 [`package.json`](./package.json)。标签发布、事实来源、失败重试与宿主验收见[开发指南](./docs/development.md#21-标签发布github-actions)。
|
|
88
93
|
|
|
89
|
-
|
|
94
|
+
---
|
|
90
95
|
|
|
91
|
-
|
|
92
|
-
npm run check
|
|
93
|
-
```
|
|
96
|
+
## 版本发布
|
|
94
97
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
- **发布包完整性检查**:静态校验发布包产物清单、入口完整性与 TypeScript AST 相对导入闭包:
|
|
98
|
-
```bash
|
|
99
|
-
npm run check:package
|
|
100
|
-
```
|
|
101
|
-
- **运行单元测试**:跨平台自动发现并执行所有 `test/*.test.mjs` 测试套件:
|
|
102
|
-
```bash
|
|
103
|
-
npm test
|
|
104
|
-
```
|
|
105
|
-
- **类型检查**:校验前端组件与服务端扩展的 TypeScript 类型完整性:
|
|
106
|
-
```bash
|
|
107
|
-
npm run typecheck
|
|
108
|
-
```
|
|
109
|
-
- **代码规范检查 (Lint)**:基于 ESLint 开展轻量静态检查:
|
|
110
|
-
```bash
|
|
111
|
-
npm run lint
|
|
112
|
-
```
|
|
113
|
-
- **代码格式检查与格式化 (Format)**:基于 Prettier 校验或自动格式化:
|
|
114
|
-
```bash
|
|
115
|
-
npm run format:check
|
|
116
|
-
npm run format
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
维护者可在 GitHub Actions 的 **Release to GitHub and npm** 工作流中选择 `patch` / `minor` / `major` 一键发布 GitHub Release 与 npm 包;首次使用需配置 `NPM_TOKEN` 和仓库写入权限。操作及失败重试说明见 [开发与宿主验收指南](./docs/development.md#24-一键发布github-actions)。
|
|
120
|
-
|
|
121
|
-
详细开发贡献流程、发布前检查机制与真实宿主环境手工验收指南,请参阅 [开发与宿主验收指南](./docs/development.md)。
|
|
98
|
+
参见 [0.1.3 版本说明](./docs/releases/0.1.3.md)。每版 npm 包与 GitHub Release 对应同一个版本 tag,GitHub 附带经过验证的 npm tarball。`main` 可能包含最新发布版之后的改动。
|
|
122
99
|
|
|
123
100
|
---
|
|
124
101
|
|
|
125
102
|
## 架构设计
|
|
126
103
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
- **交互式架构全景图**:直接使用浏览器打开 [`docs/architecture/paseo-kanban.architecture.html`](./docs/architecture/paseo-kanban.architecture.html) 查看。
|
|
130
|
-
- **架构定义元数据**:[`docs/architecture/paseo-kanban.architecture.json`](./docs/architecture/paseo-kanban.architecture.json)。
|
|
104
|
+
核心术语和架构决策见 [`CONTEXT.md`](./CONTEXT.md) 与 [`docs/adr/`](./docs/adr/)。
|
|
131
105
|
|
|
132
106
|
---
|
|
133
107
|
|
package/client/kanban-board.tsx
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
Pressable,
|
|
7
7
|
StyleSheet,
|
|
8
8
|
ActivityIndicator,
|
|
9
|
+
type LayoutChangeEvent,
|
|
9
10
|
} from "react-native";
|
|
10
11
|
import { useSettings } from "@getpaseo/plugin/client";
|
|
11
12
|
import type { PluginSurfaceProps } from "@getpaseo/plugin/client";
|
|
@@ -25,8 +26,23 @@ import {
|
|
|
25
26
|
} from "./kanban-session";
|
|
26
27
|
import { useI18n } from "./i18n";
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
interface KanbanBoardProps extends PluginSurfaceProps {
|
|
30
|
+
initialProjectId?: string | null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function KanbanBoardView(props: KanbanBoardProps) {
|
|
34
|
+
const { theme } = props;
|
|
35
|
+
const [panelWidth, setPanelWidth] = useState<number | null>(null);
|
|
36
|
+
const compact =
|
|
37
|
+
props.layout.compact || (panelWidth !== null && panelWidth < 600);
|
|
38
|
+
const layout = useMemo(
|
|
39
|
+
() => ({ ...props.layout, compact }),
|
|
40
|
+
[props.layout, compact],
|
|
41
|
+
);
|
|
42
|
+
const handleLayout = (event: LayoutChangeEvent) => {
|
|
43
|
+
const { width } = event.nativeEvent.layout;
|
|
44
|
+
if (width > 0) setPanelWidth(width);
|
|
45
|
+
};
|
|
30
46
|
const { t, language } = useI18n(props);
|
|
31
47
|
const settings = useSettings(kanbanSettings);
|
|
32
48
|
const {
|
|
@@ -35,13 +51,29 @@ export function KanbanBoardView(props: PluginSurfaceProps) {
|
|
|
35
51
|
isError: projectsError,
|
|
36
52
|
} = useProjects();
|
|
37
53
|
|
|
38
|
-
const [selectedProjectId, setSelectedProjectId] = useState
|
|
54
|
+
const [selectedProjectId, setSelectedProjectId] = useState(
|
|
55
|
+
props.initialProjectId || "all",
|
|
56
|
+
);
|
|
39
57
|
const [activeTaskSession, setActiveTaskSession] =
|
|
40
58
|
useState<TaskEditSession | null>(null);
|
|
41
59
|
const [activeLaneSession, setActiveLaneSession] =
|
|
42
60
|
useState<LaneEditSession | null>(null);
|
|
43
61
|
const [reorderError, setReorderError] = useState<string | null>(null);
|
|
44
62
|
|
|
63
|
+
const selectableProjects = useMemo(() => {
|
|
64
|
+
const missingIds = new Set([props.initialProjectId, selectedProjectId]);
|
|
65
|
+
const missingProjects = [...missingIds]
|
|
66
|
+
.filter(
|
|
67
|
+
(id): id is string =>
|
|
68
|
+
!!id &&
|
|
69
|
+
id !== "all" &&
|
|
70
|
+
id !== "unassigned" &&
|
|
71
|
+
!projects.some((project) => project.projectId === id),
|
|
72
|
+
)
|
|
73
|
+
.map((id) => ({ projectId: id, projectDisplayName: id }));
|
|
74
|
+
return [...projects, ...missingProjects];
|
|
75
|
+
}, [projects, props.initialProjectId, selectedProjectId]);
|
|
76
|
+
|
|
45
77
|
const isReady = settings.status === "ready";
|
|
46
78
|
const board = isReady ? settings.values : null;
|
|
47
79
|
const revision = isReady ? settings.revision : "";
|
|
@@ -154,6 +186,8 @@ export function KanbanBoardView(props: PluginSurfaceProps) {
|
|
|
154
186
|
StyleSheet.create({
|
|
155
187
|
container: {
|
|
156
188
|
flex: 1,
|
|
189
|
+
minWidth: 0,
|
|
190
|
+
minHeight: 0,
|
|
157
191
|
backgroundColor: theme.colors.surface0,
|
|
158
192
|
userSelect: "none",
|
|
159
193
|
},
|
|
@@ -174,6 +208,9 @@ export function KanbanBoardView(props: PluginSurfaceProps) {
|
|
|
174
208
|
},
|
|
175
209
|
titleRow: {
|
|
176
210
|
flexDirection: "row",
|
|
211
|
+
flexWrap: "wrap",
|
|
212
|
+
flexShrink: 1,
|
|
213
|
+
maxWidth: "100%",
|
|
177
214
|
alignItems: "center",
|
|
178
215
|
gap: 8,
|
|
179
216
|
},
|
|
@@ -184,6 +221,8 @@ export function KanbanBoardView(props: PluginSurfaceProps) {
|
|
|
184
221
|
},
|
|
185
222
|
headerActions: {
|
|
186
223
|
flexDirection: "row",
|
|
224
|
+
flexWrap: "wrap",
|
|
225
|
+
maxWidth: "100%",
|
|
187
226
|
alignItems: "center",
|
|
188
227
|
gap: 8,
|
|
189
228
|
},
|
|
@@ -270,6 +309,7 @@ export function KanbanBoardView(props: PluginSurfaceProps) {
|
|
|
270
309
|
},
|
|
271
310
|
lanesWrapper: {
|
|
272
311
|
flex: 1,
|
|
312
|
+
minHeight: 0,
|
|
273
313
|
position: "relative",
|
|
274
314
|
userSelect: "none",
|
|
275
315
|
},
|
|
@@ -370,7 +410,7 @@ export function KanbanBoardView(props: PluginSurfaceProps) {
|
|
|
370
410
|
if (!board) return null;
|
|
371
411
|
|
|
372
412
|
return (
|
|
373
|
-
<View style={styles.container}>
|
|
413
|
+
<View style={styles.container} onLayout={handleLayout}>
|
|
374
414
|
{/* Top Header */}
|
|
375
415
|
<View style={styles.header}>
|
|
376
416
|
<View style={styles.headerTopRow}>
|
|
@@ -462,7 +502,7 @@ export function KanbanBoardView(props: PluginSurfaceProps) {
|
|
|
462
502
|
</Text>
|
|
463
503
|
</Pressable>
|
|
464
504
|
|
|
465
|
-
{
|
|
505
|
+
{selectableProjects.map((proj) => {
|
|
466
506
|
const isSelected = selectedProjectId === proj.projectId;
|
|
467
507
|
return (
|
|
468
508
|
<Pressable
|
|
@@ -567,7 +607,7 @@ export function KanbanBoardView(props: PluginSurfaceProps) {
|
|
|
567
607
|
open={activeTaskSession !== null}
|
|
568
608
|
onClose={() => setActiveTaskSession(null)}
|
|
569
609
|
session={activeTaskSession}
|
|
570
|
-
projects={
|
|
610
|
+
projects={selectableProjects}
|
|
571
611
|
theme={theme}
|
|
572
612
|
layout={layout}
|
|
573
613
|
/>
|
package/client/kanban-drag.ts
CHANGED
|
@@ -90,7 +90,6 @@ export interface TaskPreviewItem {
|
|
|
90
90
|
|
|
91
91
|
export interface KanbanDragOptions {
|
|
92
92
|
lanes?: ({ id: string } | string)[];
|
|
93
|
-
onMoveTask?: (taskId: string, targetLaneId: string) => void | Promise<void>;
|
|
94
93
|
onReorderTask?: (
|
|
95
94
|
taskId: string,
|
|
96
95
|
targetLaneId: string,
|
|
@@ -175,10 +174,6 @@ export class KanbanDragController {
|
|
|
175
174
|
private containerRef: ContainerRefTarget | null = null;
|
|
176
175
|
private scrollX: number = 0;
|
|
177
176
|
private activeSession: ActiveDragSession | null = null;
|
|
178
|
-
private onMoveTask?: (
|
|
179
|
-
taskId: string,
|
|
180
|
-
targetLaneId: string,
|
|
181
|
-
) => void | Promise<void>;
|
|
182
177
|
private onReorderTask?: (
|
|
183
178
|
taskId: string,
|
|
184
179
|
targetLaneId: string,
|
|
@@ -231,9 +226,6 @@ export class KanbanDragController {
|
|
|
231
226
|
if (options?.lanes) {
|
|
232
227
|
this.setLanes(options.lanes);
|
|
233
228
|
}
|
|
234
|
-
if (options?.onMoveTask) {
|
|
235
|
-
this.setOnMoveTask(options.onMoveTask);
|
|
236
|
-
}
|
|
237
229
|
if (options?.onReorderTask) {
|
|
238
230
|
this.setOnReorderTask(options.onReorderTask);
|
|
239
231
|
}
|
|
@@ -253,12 +245,6 @@ export class KanbanDragController {
|
|
|
253
245
|
}
|
|
254
246
|
};
|
|
255
247
|
|
|
256
|
-
setOnMoveTask = (
|
|
257
|
-
fn: (taskId: string, targetLaneId: string) => void | Promise<void>,
|
|
258
|
-
) => {
|
|
259
|
-
this.onMoveTask = fn;
|
|
260
|
-
};
|
|
261
|
-
|
|
262
248
|
setOnReorderTask = (
|
|
263
249
|
fn: (
|
|
264
250
|
taskId: string,
|
|
@@ -908,8 +894,6 @@ export class KanbanDragController {
|
|
|
908
894
|
drop.targetLaneId,
|
|
909
895
|
drop.targetIndex,
|
|
910
896
|
);
|
|
911
|
-
} else if (this.onMoveTask && drop.targetLaneId !== drop.sourceLaneId) {
|
|
912
|
-
await this.onMoveTask(drop.taskId, drop.targetLaneId);
|
|
913
897
|
}
|
|
914
898
|
}
|
|
915
899
|
} finally {
|
|
@@ -1396,21 +1380,17 @@ export interface UseKanbanDragReturn {
|
|
|
1396
1380
|
export function useKanbanDrag(
|
|
1397
1381
|
options: KanbanDragOptions = {},
|
|
1398
1382
|
): UseKanbanDragReturn {
|
|
1399
|
-
const { lanes = [],
|
|
1383
|
+
const { lanes = [], onReorderTask, getTaskPreview } = options;
|
|
1400
1384
|
const controllerRef = useRef<KanbanDragController | null>(null);
|
|
1401
1385
|
if (!controllerRef.current) {
|
|
1402
1386
|
controllerRef.current = new KanbanDragController({
|
|
1403
1387
|
lanes,
|
|
1404
|
-
onMoveTask,
|
|
1405
1388
|
onReorderTask,
|
|
1406
1389
|
});
|
|
1407
1390
|
}
|
|
1408
1391
|
const controller = controllerRef.current;
|
|
1409
1392
|
|
|
1410
1393
|
controller.setLanes(lanes);
|
|
1411
|
-
if (onMoveTask) {
|
|
1412
|
-
controller.setOnMoveTask(onMoveTask);
|
|
1413
|
-
}
|
|
1414
1394
|
if (onReorderTask) {
|
|
1415
1395
|
controller.setOnReorderTask(onReorderTask);
|
|
1416
1396
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useWorkspace,
|
|
3
|
+
type PluginWorkspacePanelProps,
|
|
4
|
+
} from "@getpaseo/plugin/client";
|
|
5
|
+
import { KanbanBoardView } from "./kanban-board";
|
|
6
|
+
|
|
7
|
+
export function KanbanWorkspacePanel(props: PluginWorkspacePanelProps) {
|
|
8
|
+
const projectId = useWorkspace(
|
|
9
|
+
props.workspaceId,
|
|
10
|
+
(workspace) => workspace.projectId,
|
|
11
|
+
);
|
|
12
|
+
return <KanbanBoardView {...props} initialProjectId={projectId} />;
|
|
13
|
+
}
|
package/index.client.tsx
CHANGED
|
@@ -1,33 +1,45 @@
|
|
|
1
1
|
import type { PluginClientContext } from "@getpaseo/plugin/client";
|
|
2
2
|
import { KanbanBoardView } from "./client/kanban-board";
|
|
3
|
+
import { KanbanWorkspacePanel } from "./client/kanban-workspace-panel";
|
|
3
4
|
import { t, getLanguage, subscribeLanguage } from "./client/i18n";
|
|
4
5
|
|
|
5
6
|
export default function contribute(client: PluginClientContext) {
|
|
6
|
-
client.addSurface("kanban", KanbanBoardView);
|
|
7
|
-
|
|
7
|
+
const removeSurface = client.addSurface("kanban", KanbanBoardView);
|
|
8
8
|
let currentLang = getLanguage();
|
|
9
|
-
let removeSidebar = client.addSidebarItem({
|
|
10
|
-
id: "kanban",
|
|
11
|
-
title: t("kanban.sidebarTitle", currentLang),
|
|
12
|
-
icon: "PanelsTopLeft",
|
|
13
|
-
surface: "kanban",
|
|
14
|
-
});
|
|
15
9
|
|
|
10
|
+
const registerEntries = () => {
|
|
11
|
+
const title = t("kanban.sidebarTitle", currentLang);
|
|
12
|
+
const removeSidebar = client.addSidebarItem({
|
|
13
|
+
id: "kanban",
|
|
14
|
+
title,
|
|
15
|
+
icon: "PanelsTopLeft",
|
|
16
|
+
surface: "kanban",
|
|
17
|
+
});
|
|
18
|
+
const removePanel = client.addWorkspacePanel({
|
|
19
|
+
id: "kanban",
|
|
20
|
+
title,
|
|
21
|
+
icon: "PanelsTopLeft",
|
|
22
|
+
context: "workspace",
|
|
23
|
+
Component: KanbanWorkspacePanel,
|
|
24
|
+
});
|
|
25
|
+
return () => {
|
|
26
|
+
removeSidebar();
|
|
27
|
+
removePanel();
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
let removeEntries = registerEntries();
|
|
16
32
|
const unsubscribe = subscribeLanguage((newLang) => {
|
|
17
33
|
if (newLang !== currentLang) {
|
|
18
34
|
currentLang = newLang;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
id: "kanban",
|
|
22
|
-
title: t("kanban.sidebarTitle", newLang),
|
|
23
|
-
icon: "PanelsTopLeft",
|
|
24
|
-
surface: "kanban",
|
|
25
|
-
});
|
|
35
|
+
removeEntries();
|
|
36
|
+
removeEntries = registerEntries();
|
|
26
37
|
}
|
|
27
38
|
});
|
|
28
39
|
|
|
29
40
|
return () => {
|
|
30
41
|
unsubscribe();
|
|
31
|
-
|
|
42
|
+
removeEntries();
|
|
43
|
+
removeSurface();
|
|
32
44
|
};
|
|
33
45
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "paseo-kanban",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "A lightweight, responsive Kanban board plugin for Paseo workspaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"board"
|
|
21
21
|
],
|
|
22
22
|
"files": [
|
|
23
|
+
"OVERVIEW.md",
|
|
23
24
|
"paseo-plugin.json",
|
|
24
25
|
"index.client.tsx",
|
|
25
26
|
"index.server.ts",
|
|
@@ -33,6 +34,7 @@
|
|
|
33
34
|
"format:check": "prettier --check .",
|
|
34
35
|
"format": "prettier --write .",
|
|
35
36
|
"check:package": "node scripts/check-package.mjs",
|
|
37
|
+
"verify:release": "node scripts/verify-release.mjs",
|
|
36
38
|
"check": "npm run typecheck && npm run test && npm run lint && npm run format:check && npm run check:package"
|
|
37
39
|
},
|
|
38
40
|
"devDependencies": {
|