@fayz-ai/plugin-tasks 0.1.6 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/data/supabase.d.ts.map +1 -1
- package/dist/data/tables.d.ts +5 -0
- package/dist/data/tables.d.ts.map +1 -0
- package/dist/index.cjs +95 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +95 -52
- package/dist/index.js.map +1 -1
- package/dist/migrations/index.d.ts +7 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/registries.d.ts.map +1 -1
- package/package.json +7 -4
- package/src/data/capability.test.ts +1 -1
- package/src/data/supabase.ts +11 -10
- package/src/data/tables.ts +6 -0
- package/src/index.ts +9 -56
- package/src/migrations/000_plg_rename.sql +12 -0
- package/src/migrations/001_tasks_base.sql +34 -34
- package/src/migrations/index.ts +89 -0
- package/src/registries.ts +2 -1
package/src/data/supabase.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { TasksDataProvider } from './types'
|
|
|
2
2
|
import type { Task, TaskLabel, TasksSummary, TaskStatus } from '../types'
|
|
3
3
|
import { getSupabaseClientOptional, getActiveTenantId } from '@fayz-ai/core'
|
|
4
4
|
import { getTasksTenantId } from '../lib/tenant'
|
|
5
|
+
import { T } from './tables'
|
|
5
6
|
|
|
6
7
|
function getTenantId(): string | undefined {
|
|
7
8
|
// Local override wins; else use the app's active tenant so writes pass RLS.
|
|
@@ -35,7 +36,7 @@ export function createSupabaseTasksProvider(): TasksDataProvider {
|
|
|
35
36
|
const tenantId = getTenantId()
|
|
36
37
|
if (!tenantId) return []
|
|
37
38
|
let q = getClient()
|
|
38
|
-
.from(
|
|
39
|
+
.from(T.tasks)
|
|
39
40
|
.select('*')
|
|
40
41
|
.eq('tenant_id', tenantId)
|
|
41
42
|
|
|
@@ -72,7 +73,7 @@ export function createSupabaseTasksProvider(): TasksDataProvider {
|
|
|
72
73
|
|
|
73
74
|
async getTaskById(id) {
|
|
74
75
|
const { data } = await getClient()
|
|
75
|
-
.from(
|
|
76
|
+
.from(T.tasks)
|
|
76
77
|
.select('*')
|
|
77
78
|
.eq('id', id)
|
|
78
79
|
.maybeSingle()
|
|
@@ -81,7 +82,7 @@ export function createSupabaseTasksProvider(): TasksDataProvider {
|
|
|
81
82
|
|
|
82
83
|
async getSubtasks(parentId) {
|
|
83
84
|
const { data } = await getClient()
|
|
84
|
-
.from(
|
|
85
|
+
.from(T.tasks)
|
|
85
86
|
.select('*')
|
|
86
87
|
.eq('parent_id', parentId)
|
|
87
88
|
.order('position', { ascending: true })
|
|
@@ -94,7 +95,7 @@ export function createSupabaseTasksProvider(): TasksDataProvider {
|
|
|
94
95
|
|
|
95
96
|
// Get max position for the status group
|
|
96
97
|
const { data: maxData } = await getClient()
|
|
97
|
-
.from(
|
|
98
|
+
.from(T.tasks)
|
|
98
99
|
.select('position')
|
|
99
100
|
.eq('tenant_id', tenantId)
|
|
100
101
|
.eq('status', input.status ?? 'todo')
|
|
@@ -104,7 +105,7 @@ export function createSupabaseTasksProvider(): TasksDataProvider {
|
|
|
104
105
|
const maxPos = maxData?.[0]?.position ?? -1
|
|
105
106
|
|
|
106
107
|
const { data, error } = await getClient()
|
|
107
|
-
.from(
|
|
108
|
+
.from(T.tasks)
|
|
108
109
|
.insert({
|
|
109
110
|
tenant_id: tenantId,
|
|
110
111
|
title: input.title,
|
|
@@ -135,7 +136,7 @@ export function createSupabaseTasksProvider(): TasksDataProvider {
|
|
|
135
136
|
if (input.position !== undefined) payload.position = input.position
|
|
136
137
|
|
|
137
138
|
const { data, error } = await getClient()
|
|
138
|
-
.from(
|
|
139
|
+
.from(T.tasks)
|
|
139
140
|
.update(payload)
|
|
140
141
|
.eq('id', id)
|
|
141
142
|
.select('*')
|
|
@@ -145,12 +146,12 @@ export function createSupabaseTasksProvider(): TasksDataProvider {
|
|
|
145
146
|
},
|
|
146
147
|
|
|
147
148
|
async deleteTask(id) {
|
|
148
|
-
await getClient().from(
|
|
149
|
+
await getClient().from(T.tasks).delete().eq('id', id)
|
|
149
150
|
},
|
|
150
151
|
|
|
151
152
|
async reorderTask(id, newPosition, status) {
|
|
152
153
|
await getClient()
|
|
153
|
-
.from(
|
|
154
|
+
.from(T.tasks)
|
|
154
155
|
.update({ position: newPosition, status, updated_at: new Date().toISOString() })
|
|
155
156
|
.eq('id', id)
|
|
156
157
|
},
|
|
@@ -159,7 +160,7 @@ export function createSupabaseTasksProvider(): TasksDataProvider {
|
|
|
159
160
|
const tenantId = getTenantId()
|
|
160
161
|
if (!tenantId) return []
|
|
161
162
|
const { data } = await getClient()
|
|
162
|
-
.from(
|
|
163
|
+
.from(T.labels)
|
|
163
164
|
.select('*')
|
|
164
165
|
.eq('tenant_id', tenantId)
|
|
165
166
|
.eq('is_active', true)
|
|
@@ -172,7 +173,7 @@ export function createSupabaseTasksProvider(): TasksDataProvider {
|
|
|
172
173
|
if (!tenantId) return { total: 0, todo: 0, inProgress: 0, done: 0, overdue: 0, dueToday: 0, highPriority: 0 }
|
|
173
174
|
|
|
174
175
|
const { data } = await getClient()
|
|
175
|
-
.from(
|
|
176
|
+
.from(T.tasks)
|
|
176
177
|
.select('status, priority, due_date')
|
|
177
178
|
.eq('tenant_id', tenantId)
|
|
178
179
|
.is('parent_id', null)
|
package/src/index.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { tasksLocales } from './locales'
|
|
|
11
11
|
import { tasksRegistries } from './registries'
|
|
12
12
|
import { TasksGeneralSettings } from './components/TasksGeneralSettings'
|
|
13
13
|
import { TasksTopbarButton } from './components/TasksTopbarButton'
|
|
14
|
+
import { MIGRATION_000_PLG_RENAME, MIGRATION_001_TASKS_BASE } from './migrations'
|
|
14
15
|
|
|
15
16
|
// ---------------------------------------------------------------------------
|
|
16
17
|
// Public types
|
|
@@ -49,60 +50,6 @@ function resolveConfig(options?: TasksPluginOptions): ResolvedTasksConfig {
|
|
|
49
50
|
}
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
// ---------------------------------------------------------------------------
|
|
53
|
-
// Migration SQL
|
|
54
|
-
// ---------------------------------------------------------------------------
|
|
55
|
-
|
|
56
|
-
const MIGRATION_001 = `-- Tasks Plugin: Base Tables
|
|
57
|
-
CREATE TABLE IF NOT EXISTS public.tsk_labels (
|
|
58
|
-
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
59
|
-
tenant_id uuid NOT NULL REFERENCES saas_core.tenants(id) ON DELETE CASCADE,
|
|
60
|
-
name text NOT NULL,
|
|
61
|
-
color text NOT NULL DEFAULT '#6366f1',
|
|
62
|
-
is_active boolean NOT NULL DEFAULT true,
|
|
63
|
-
created_at timestamptz NOT NULL DEFAULT now()
|
|
64
|
-
);
|
|
65
|
-
ALTER TABLE public.tsk_labels ENABLE ROW LEVEL SECURITY;
|
|
66
|
-
CREATE INDEX IF NOT EXISTS idx_tsk_labels_tenant ON public.tsk_labels(tenant_id);
|
|
67
|
-
|
|
68
|
-
CREATE TABLE IF NOT EXISTS public.tsk_tasks (
|
|
69
|
-
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
70
|
-
tenant_id uuid NOT NULL REFERENCES saas_core.tenants(id) ON DELETE CASCADE,
|
|
71
|
-
title text NOT NULL,
|
|
72
|
-
description text,
|
|
73
|
-
status text NOT NULL DEFAULT 'todo' CHECK (status IN ('todo','in_progress','done','cancelled')),
|
|
74
|
-
priority text NOT NULL DEFAULT 'medium' CHECK (priority IN ('low','medium','high','urgent')),
|
|
75
|
-
due_date date,
|
|
76
|
-
assigned_to_id uuid,
|
|
77
|
-
assigned_to_name text,
|
|
78
|
-
parent_id uuid REFERENCES public.tsk_tasks(id) ON DELETE CASCADE,
|
|
79
|
-
labels jsonb NOT NULL DEFAULT '[]'::jsonb,
|
|
80
|
-
position integer NOT NULL DEFAULT 0,
|
|
81
|
-
created_by_id uuid,
|
|
82
|
-
created_by_name text,
|
|
83
|
-
created_at timestamptz NOT NULL DEFAULT now(),
|
|
84
|
-
updated_at timestamptz NOT NULL DEFAULT now()
|
|
85
|
-
);
|
|
86
|
-
ALTER TABLE public.tsk_tasks ENABLE ROW LEVEL SECURITY;
|
|
87
|
-
CREATE INDEX IF NOT EXISTS idx_tsk_tasks_tenant ON public.tsk_tasks(tenant_id);
|
|
88
|
-
CREATE INDEX IF NOT EXISTS idx_tsk_tasks_status ON public.tsk_tasks(tenant_id, status);
|
|
89
|
-
CREATE INDEX IF NOT EXISTS idx_tsk_tasks_parent ON public.tsk_tasks(parent_id);
|
|
90
|
-
CREATE INDEX IF NOT EXISTS idx_tsk_tasks_assigned ON public.tsk_tasks(assigned_to_id);
|
|
91
|
-
CREATE INDEX IF NOT EXISTS idx_tsk_tasks_due ON public.tsk_tasks(tenant_id, due_date) WHERE due_date IS NOT NULL;
|
|
92
|
-
|
|
93
|
-
-- RLS policies for tsk_tasks
|
|
94
|
-
CREATE POLICY tsk_tasks_select ON public.tsk_tasks FOR SELECT TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
|
|
95
|
-
CREATE POLICY tsk_tasks_insert ON public.tsk_tasks FOR INSERT TO authenticated WITH CHECK (tenant_id IN (SELECT public.user_tenant_ids()));
|
|
96
|
-
CREATE POLICY tsk_tasks_update ON public.tsk_tasks FOR UPDATE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
|
|
97
|
-
CREATE POLICY tsk_tasks_delete ON public.tsk_tasks FOR DELETE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
|
|
98
|
-
GRANT SELECT, INSERT, UPDATE, DELETE ON public.tsk_tasks TO authenticated;
|
|
99
|
-
|
|
100
|
-
-- RLS policies for tsk_labels
|
|
101
|
-
CREATE POLICY tsk_labels_select ON public.tsk_labels FOR SELECT TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
|
|
102
|
-
CREATE POLICY tsk_labels_insert ON public.tsk_labels FOR INSERT TO authenticated WITH CHECK (tenant_id IN (SELECT public.user_tenant_ids()));
|
|
103
|
-
CREATE POLICY tsk_labels_update ON public.tsk_labels FOR UPDATE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
|
|
104
|
-
CREATE POLICY tsk_labels_delete ON public.tsk_labels FOR DELETE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
|
|
105
|
-
GRANT SELECT, INSERT, UPDATE, DELETE ON public.tsk_labels TO authenticated;`
|
|
106
53
|
|
|
107
54
|
// ---------------------------------------------------------------------------
|
|
108
55
|
// Factory
|
|
@@ -193,11 +140,17 @@ export function createTasksPlugin(options?: TasksPluginOptions): PluginManifest
|
|
|
193
140
|
],
|
|
194
141
|
|
|
195
142
|
migrations: [
|
|
143
|
+
{
|
|
144
|
+
id: 'tasks-000-plg-rename',
|
|
145
|
+
version: '1.0.0',
|
|
146
|
+
sql: MIGRATION_000_PLG_RENAME,
|
|
147
|
+
description: 'Rename legacy tsk_* tables to plg_tasks_* in-place for pools provisioned before the industry-pool rename (guarded no-op on fresh pools)',
|
|
148
|
+
},
|
|
196
149
|
{
|
|
197
150
|
id: 'tasks-001-base-tables',
|
|
198
151
|
version: '1.0.0',
|
|
199
|
-
sql:
|
|
200
|
-
description: 'Create
|
|
152
|
+
sql: MIGRATION_001_TASKS_BASE,
|
|
153
|
+
description: 'Create plg_tasks_tasks and plg_tasks_labels',
|
|
201
154
|
},
|
|
202
155
|
],
|
|
203
156
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
-- 000_plg_rename.sql — rename legacy tasks tables to plg_tasks_* for pools
|
|
2
|
+
-- provisioned before the industry-pool rename. Guarded: fires only when legacy
|
|
3
|
+
-- name exists and target does not, so fresh pools skip every branch.
|
|
4
|
+
DO $$
|
|
5
|
+
BEGIN
|
|
6
|
+
IF to_regclass('public.tsk_tasks') IS NOT NULL AND to_regclass('public.plg_tasks_tasks') IS NULL THEN
|
|
7
|
+
ALTER TABLE public.tsk_tasks RENAME TO plg_tasks_tasks;
|
|
8
|
+
END IF;
|
|
9
|
+
IF to_regclass('public.tsk_labels') IS NOT NULL AND to_regclass('public.plg_tasks_labels') IS NULL THEN
|
|
10
|
+
ALTER TABLE public.tsk_labels RENAME TO plg_tasks_labels;
|
|
11
|
+
END IF;
|
|
12
|
+
END $$;
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
-- Tasks Plugin: Base Tables
|
|
2
|
-
-- Prefix:
|
|
2
|
+
-- Prefix: plg_tasks_
|
|
3
3
|
|
|
4
4
|
-- Label definitions for categorizing tasks
|
|
5
|
-
CREATE TABLE IF NOT EXISTS public.
|
|
5
|
+
CREATE TABLE IF NOT EXISTS public.plg_tasks_labels (
|
|
6
6
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
7
|
-
tenant_id uuid NOT NULL REFERENCES
|
|
7
|
+
tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
|
|
8
8
|
name text NOT NULL,
|
|
9
9
|
color text NOT NULL DEFAULT '#6366f1',
|
|
10
10
|
is_active boolean NOT NULL DEFAULT true,
|
|
11
11
|
created_at timestamptz NOT NULL DEFAULT now()
|
|
12
12
|
);
|
|
13
|
-
ALTER TABLE public.
|
|
14
|
-
CREATE INDEX IF NOT EXISTS
|
|
13
|
+
ALTER TABLE public.plg_tasks_labels ENABLE ROW LEVEL SECURITY;
|
|
14
|
+
CREATE INDEX IF NOT EXISTS idx_plg_tasks_labels_tenant ON public.plg_tasks_labels(tenant_id);
|
|
15
15
|
|
|
16
16
|
-- Main tasks table (subtasks via parent_id self-reference)
|
|
17
|
-
CREATE TABLE IF NOT EXISTS public.
|
|
17
|
+
CREATE TABLE IF NOT EXISTS public.plg_tasks_tasks (
|
|
18
18
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
19
|
-
tenant_id uuid NOT NULL REFERENCES
|
|
19
|
+
tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
|
|
20
20
|
title text NOT NULL,
|
|
21
21
|
description text,
|
|
22
22
|
status text NOT NULL DEFAULT 'todo'
|
|
@@ -26,7 +26,7 @@ CREATE TABLE IF NOT EXISTS public.tsk_tasks (
|
|
|
26
26
|
due_date date,
|
|
27
27
|
assigned_to_id uuid,
|
|
28
28
|
assigned_to_name text,
|
|
29
|
-
parent_id uuid REFERENCES public.
|
|
29
|
+
parent_id uuid REFERENCES public.plg_tasks_tasks(id) ON DELETE CASCADE,
|
|
30
30
|
labels jsonb NOT NULL DEFAULT '[]'::jsonb,
|
|
31
31
|
position integer NOT NULL DEFAULT 0,
|
|
32
32
|
created_by_id uuid,
|
|
@@ -34,32 +34,32 @@ CREATE TABLE IF NOT EXISTS public.tsk_tasks (
|
|
|
34
34
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
35
35
|
updated_at timestamptz NOT NULL DEFAULT now()
|
|
36
36
|
);
|
|
37
|
-
ALTER TABLE public.
|
|
38
|
-
CREATE INDEX IF NOT EXISTS
|
|
39
|
-
CREATE INDEX IF NOT EXISTS
|
|
40
|
-
CREATE INDEX IF NOT EXISTS
|
|
41
|
-
CREATE INDEX IF NOT EXISTS
|
|
42
|
-
CREATE INDEX IF NOT EXISTS
|
|
37
|
+
ALTER TABLE public.plg_tasks_tasks ENABLE ROW LEVEL SECURITY;
|
|
38
|
+
CREATE INDEX IF NOT EXISTS idx_plg_tasks_tasks_tenant ON public.plg_tasks_tasks(tenant_id);
|
|
39
|
+
CREATE INDEX IF NOT EXISTS idx_plg_tasks_tasks_status ON public.plg_tasks_tasks(tenant_id, status);
|
|
40
|
+
CREATE INDEX IF NOT EXISTS idx_plg_tasks_tasks_parent ON public.plg_tasks_tasks(parent_id);
|
|
41
|
+
CREATE INDEX IF NOT EXISTS idx_plg_tasks_tasks_assigned ON public.plg_tasks_tasks(assigned_to_id);
|
|
42
|
+
CREATE INDEX IF NOT EXISTS idx_plg_tasks_tasks_due ON public.plg_tasks_tasks(tenant_id, due_date)
|
|
43
43
|
WHERE due_date IS NOT NULL;
|
|
44
44
|
|
|
45
|
-
-- RLS policies for
|
|
46
|
-
DROP POLICY IF EXISTS
|
|
47
|
-
CREATE POLICY
|
|
48
|
-
DROP POLICY IF EXISTS
|
|
49
|
-
CREATE POLICY
|
|
50
|
-
DROP POLICY IF EXISTS
|
|
51
|
-
CREATE POLICY
|
|
52
|
-
DROP POLICY IF EXISTS
|
|
53
|
-
CREATE POLICY
|
|
54
|
-
GRANT SELECT, INSERT, UPDATE, DELETE ON public.
|
|
45
|
+
-- RLS policies for plg_tasks_tasks (idempotent — DROP IF EXISTS before CREATE)
|
|
46
|
+
DROP POLICY IF EXISTS plg_tasks_tasks_select ON public.plg_tasks_tasks;
|
|
47
|
+
CREATE POLICY plg_tasks_tasks_select ON public.plg_tasks_tasks FOR SELECT TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
|
|
48
|
+
DROP POLICY IF EXISTS plg_tasks_tasks_insert ON public.plg_tasks_tasks;
|
|
49
|
+
CREATE POLICY plg_tasks_tasks_insert ON public.plg_tasks_tasks FOR INSERT TO authenticated WITH CHECK (tenant_id IN (SELECT public.user_tenant_ids()));
|
|
50
|
+
DROP POLICY IF EXISTS plg_tasks_tasks_update ON public.plg_tasks_tasks;
|
|
51
|
+
CREATE POLICY plg_tasks_tasks_update ON public.plg_tasks_tasks FOR UPDATE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
|
|
52
|
+
DROP POLICY IF EXISTS plg_tasks_tasks_delete ON public.plg_tasks_tasks;
|
|
53
|
+
CREATE POLICY plg_tasks_tasks_delete ON public.plg_tasks_tasks FOR DELETE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
|
|
54
|
+
GRANT SELECT, INSERT, UPDATE, DELETE ON public.plg_tasks_tasks TO authenticated;
|
|
55
55
|
|
|
56
|
-
-- RLS policies for
|
|
57
|
-
DROP POLICY IF EXISTS
|
|
58
|
-
CREATE POLICY
|
|
59
|
-
DROP POLICY IF EXISTS
|
|
60
|
-
CREATE POLICY
|
|
61
|
-
DROP POLICY IF EXISTS
|
|
62
|
-
CREATE POLICY
|
|
63
|
-
DROP POLICY IF EXISTS
|
|
64
|
-
CREATE POLICY
|
|
65
|
-
GRANT SELECT, INSERT, UPDATE, DELETE ON public.
|
|
56
|
+
-- RLS policies for plg_tasks_labels (idempotent)
|
|
57
|
+
DROP POLICY IF EXISTS plg_tasks_labels_select ON public.plg_tasks_labels;
|
|
58
|
+
CREATE POLICY plg_tasks_labels_select ON public.plg_tasks_labels FOR SELECT TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
|
|
59
|
+
DROP POLICY IF EXISTS plg_tasks_labels_insert ON public.plg_tasks_labels;
|
|
60
|
+
CREATE POLICY plg_tasks_labels_insert ON public.plg_tasks_labels FOR INSERT TO authenticated WITH CHECK (tenant_id IN (SELECT public.user_tenant_ids()));
|
|
61
|
+
DROP POLICY IF EXISTS plg_tasks_labels_update ON public.plg_tasks_labels;
|
|
62
|
+
CREATE POLICY plg_tasks_labels_update ON public.plg_tasks_labels FOR UPDATE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
|
|
63
|
+
DROP POLICY IF EXISTS plg_tasks_labels_delete ON public.plg_tasks_labels;
|
|
64
|
+
CREATE POLICY plg_tasks_labels_delete ON public.plg_tasks_labels FOR DELETE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
|
|
65
|
+
GRANT SELECT, INSERT, UPDATE, DELETE ON public.plg_tasks_labels TO authenticated;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// AUTO-GENERATED from 000_plg_rename.sql, 001_tasks_base.sql — regenerate with scripts/embed-migrations.mjs
|
|
2
|
+
// SQL files are the source of truth; this inline copy lets the manifest declare
|
|
3
|
+
// migrations as data. Do not edit by hand — run the embed script instead.
|
|
4
|
+
|
|
5
|
+
export const MIGRATION_000_PLG_RENAME = `-- 000_plg_rename.sql — rename legacy tasks tables to plg_tasks_* for pools
|
|
6
|
+
-- provisioned before the industry-pool rename. Guarded: fires only when legacy
|
|
7
|
+
-- name exists and target does not, so fresh pools skip every branch.
|
|
8
|
+
DO $$
|
|
9
|
+
BEGIN
|
|
10
|
+
IF to_regclass('public.tsk_tasks') IS NOT NULL AND to_regclass('public.plg_tasks_tasks') IS NULL THEN
|
|
11
|
+
ALTER TABLE public.tsk_tasks RENAME TO plg_tasks_tasks;
|
|
12
|
+
END IF;
|
|
13
|
+
IF to_regclass('public.tsk_labels') IS NOT NULL AND to_regclass('public.plg_tasks_labels') IS NULL THEN
|
|
14
|
+
ALTER TABLE public.tsk_labels RENAME TO plg_tasks_labels;
|
|
15
|
+
END IF;
|
|
16
|
+
END $$;
|
|
17
|
+
`
|
|
18
|
+
|
|
19
|
+
export const MIGRATION_001_TASKS_BASE = `-- Tasks Plugin: Base Tables
|
|
20
|
+
-- Prefix: plg_tasks_
|
|
21
|
+
|
|
22
|
+
-- Label definitions for categorizing tasks
|
|
23
|
+
CREATE TABLE IF NOT EXISTS public.plg_tasks_labels (
|
|
24
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
25
|
+
tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
|
|
26
|
+
name text NOT NULL,
|
|
27
|
+
color text NOT NULL DEFAULT '#6366f1',
|
|
28
|
+
is_active boolean NOT NULL DEFAULT true,
|
|
29
|
+
created_at timestamptz NOT NULL DEFAULT now()
|
|
30
|
+
);
|
|
31
|
+
ALTER TABLE public.plg_tasks_labels ENABLE ROW LEVEL SECURITY;
|
|
32
|
+
CREATE INDEX IF NOT EXISTS idx_plg_tasks_labels_tenant ON public.plg_tasks_labels(tenant_id);
|
|
33
|
+
|
|
34
|
+
-- Main tasks table (subtasks via parent_id self-reference)
|
|
35
|
+
CREATE TABLE IF NOT EXISTS public.plg_tasks_tasks (
|
|
36
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
37
|
+
tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
|
|
38
|
+
title text NOT NULL,
|
|
39
|
+
description text,
|
|
40
|
+
status text NOT NULL DEFAULT 'todo'
|
|
41
|
+
CHECK (status IN ('todo', 'in_progress', 'done', 'cancelled')),
|
|
42
|
+
priority text NOT NULL DEFAULT 'medium'
|
|
43
|
+
CHECK (priority IN ('low', 'medium', 'high', 'urgent')),
|
|
44
|
+
due_date date,
|
|
45
|
+
assigned_to_id uuid,
|
|
46
|
+
assigned_to_name text,
|
|
47
|
+
parent_id uuid REFERENCES public.plg_tasks_tasks(id) ON DELETE CASCADE,
|
|
48
|
+
labels jsonb NOT NULL DEFAULT '[]'::jsonb,
|
|
49
|
+
position integer NOT NULL DEFAULT 0,
|
|
50
|
+
created_by_id uuid,
|
|
51
|
+
created_by_name text,
|
|
52
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
53
|
+
updated_at timestamptz NOT NULL DEFAULT now()
|
|
54
|
+
);
|
|
55
|
+
ALTER TABLE public.plg_tasks_tasks ENABLE ROW LEVEL SECURITY;
|
|
56
|
+
CREATE INDEX IF NOT EXISTS idx_plg_tasks_tasks_tenant ON public.plg_tasks_tasks(tenant_id);
|
|
57
|
+
CREATE INDEX IF NOT EXISTS idx_plg_tasks_tasks_status ON public.plg_tasks_tasks(tenant_id, status);
|
|
58
|
+
CREATE INDEX IF NOT EXISTS idx_plg_tasks_tasks_parent ON public.plg_tasks_tasks(parent_id);
|
|
59
|
+
CREATE INDEX IF NOT EXISTS idx_plg_tasks_tasks_assigned ON public.plg_tasks_tasks(assigned_to_id);
|
|
60
|
+
CREATE INDEX IF NOT EXISTS idx_plg_tasks_tasks_due ON public.plg_tasks_tasks(tenant_id, due_date)
|
|
61
|
+
WHERE due_date IS NOT NULL;
|
|
62
|
+
|
|
63
|
+
-- RLS policies for plg_tasks_tasks (idempotent — DROP IF EXISTS before CREATE)
|
|
64
|
+
DROP POLICY IF EXISTS plg_tasks_tasks_select ON public.plg_tasks_tasks;
|
|
65
|
+
CREATE POLICY plg_tasks_tasks_select ON public.plg_tasks_tasks FOR SELECT TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
|
|
66
|
+
DROP POLICY IF EXISTS plg_tasks_tasks_insert ON public.plg_tasks_tasks;
|
|
67
|
+
CREATE POLICY plg_tasks_tasks_insert ON public.plg_tasks_tasks FOR INSERT TO authenticated WITH CHECK (tenant_id IN (SELECT public.user_tenant_ids()));
|
|
68
|
+
DROP POLICY IF EXISTS plg_tasks_tasks_update ON public.plg_tasks_tasks;
|
|
69
|
+
CREATE POLICY plg_tasks_tasks_update ON public.plg_tasks_tasks FOR UPDATE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
|
|
70
|
+
DROP POLICY IF EXISTS plg_tasks_tasks_delete ON public.plg_tasks_tasks;
|
|
71
|
+
CREATE POLICY plg_tasks_tasks_delete ON public.plg_tasks_tasks FOR DELETE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
|
|
72
|
+
GRANT SELECT, INSERT, UPDATE, DELETE ON public.plg_tasks_tasks TO authenticated;
|
|
73
|
+
|
|
74
|
+
-- RLS policies for plg_tasks_labels (idempotent)
|
|
75
|
+
DROP POLICY IF EXISTS plg_tasks_labels_select ON public.plg_tasks_labels;
|
|
76
|
+
CREATE POLICY plg_tasks_labels_select ON public.plg_tasks_labels FOR SELECT TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
|
|
77
|
+
DROP POLICY IF EXISTS plg_tasks_labels_insert ON public.plg_tasks_labels;
|
|
78
|
+
CREATE POLICY plg_tasks_labels_insert ON public.plg_tasks_labels FOR INSERT TO authenticated WITH CHECK (tenant_id IN (SELECT public.user_tenant_ids()));
|
|
79
|
+
DROP POLICY IF EXISTS plg_tasks_labels_update ON public.plg_tasks_labels;
|
|
80
|
+
CREATE POLICY plg_tasks_labels_update ON public.plg_tasks_labels FOR UPDATE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
|
|
81
|
+
DROP POLICY IF EXISTS plg_tasks_labels_delete ON public.plg_tasks_labels;
|
|
82
|
+
CREATE POLICY plg_tasks_labels_delete ON public.plg_tasks_labels FOR DELETE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
|
|
83
|
+
GRANT SELECT, INSERT, UPDATE, DELETE ON public.plg_tasks_labels TO authenticated;
|
|
84
|
+
`
|
|
85
|
+
|
|
86
|
+
export const MIGRATIONS: Array<{ id: string; sql: string }> = [
|
|
87
|
+
{ id: "000_plg_rename", sql: MIGRATION_000_PLG_RENAME },
|
|
88
|
+
{ id: "001_tasks_base", sql: MIGRATION_001_TASKS_BASE },
|
|
89
|
+
]
|
package/src/registries.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { PluginRegistryDef } from '@fayz-ai/core'
|
|
2
2
|
import type { EntityDef } from '@fayz-ai/core'
|
|
3
|
+
import { T } from './data/tables'
|
|
3
4
|
|
|
4
5
|
const taskLabelEntity: EntityDef = {
|
|
5
6
|
name: 'Task Label',
|
|
@@ -12,7 +13,7 @@ const taskLabelEntity: EntityDef = {
|
|
|
12
13
|
{ key: 'color', label: 'Color', type: 'text', showInTable: true, defaultValue: '#6366f1' },
|
|
13
14
|
{ key: 'isActive', label: 'Active', type: 'boolean', showInTable: true, defaultValue: true },
|
|
14
15
|
],
|
|
15
|
-
data: { table:
|
|
16
|
+
data: { table: T.labels, tenantScoped: true },
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
export const tasksRegistries: PluginRegistryDef[] = [
|