@fayz-ai/plugin-tasks 0.1.7 → 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 CHANGED
@@ -5,6 +5,8 @@
5
5
  [![npm](https://img.shields.io/npm/v/@fayz-ai/plugin-tasks.svg)](https://www.npmjs.com/package/@fayz-ai/plugin-tasks)
6
6
  [![license](https://img.shields.io/npm/l/@fayz-ai/plugin-tasks.svg)](https://github.com/FayaLabs/fayz-sdk/blob/main/LICENSE)
7
7
 
8
+ **Status:** beta — capability-complete (Supabase/mock data provider, bundled migration, end-to-end tests). Pre-1.0: APIs may change before 1.0.
9
+
8
10
  Work happens between the records. A salon owner needs to "call the supplier," a clinic admin needs to "follow up on lab results" — small things that never fit neatly into a booking or an invoice. `plugin-tasks` gives every Fayz app a lightweight, always-available task list: a topbar button that opens a drawer for quick-add, statuses, priorities, due dates, labels, and assignees.
9
11
 
10
12
  It's deliberately small and zero-config. Drop it in and it owns its own tables (via a bundled migration), picks Supabase or an in-memory mock automatically, and exposes its summary to the AI assistant — so "what's overdue?" just works. No page to wire, no nav slot to claim; tasks ride along with whatever vertical you compose.
@@ -1 +1 @@
1
- {"version":3,"file":"supabase.d.ts","sourceRoot":"","sources":["../../src/data/supabase.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AA+BhD,wBAAgB,2BAA2B,IAAI,iBAAiB,CAiK/D"}
1
+ {"version":3,"file":"supabase.d.ts","sourceRoot":"","sources":["../../src/data/supabase.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAgChD,wBAAgB,2BAA2B,IAAI,iBAAiB,CAiK/D"}
@@ -0,0 +1,5 @@
1
+ export declare const T: {
2
+ readonly tasks: "plg_tasks_tasks";
3
+ readonly labels: "plg_tasks_labels";
4
+ };
5
+ //# sourceMappingURL=tables.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tables.d.ts","sourceRoot":"","sources":["../../src/data/tables.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,CAAC;;;CAGJ,CAAA"}
package/dist/index.cjs CHANGED
@@ -152,6 +152,12 @@ function createMockTasksProvider() {
152
152
  };
153
153
  }
154
154
 
155
+ // src/data/tables.ts
156
+ var T = {
157
+ tasks: "plg_tasks_tasks",
158
+ labels: "plg_tasks_labels"
159
+ };
160
+
155
161
  // src/data/supabase.ts
156
162
  function getTenantId() {
157
163
  return core.getActiveTenantId();
@@ -178,7 +184,7 @@ function createSupabaseTasksProvider() {
178
184
  async getTasks(query) {
179
185
  const tenantId = getTenantId();
180
186
  if (!tenantId) return [];
181
- let q = getClient().from("tsk_tasks").select("*").eq("tenant_id", tenantId);
187
+ let q = getClient().from(T.tasks).select("*").eq("tenant_id", tenantId);
182
188
  if (query.parentId === null) {
183
189
  q = q.is("parent_id", null);
184
190
  } else if (query.parentId) {
@@ -206,19 +212,19 @@ function createSupabaseTasksProvider() {
206
212
  return (data ?? []).map(toTask);
207
213
  },
208
214
  async getTaskById(id) {
209
- const { data } = await getClient().from("tsk_tasks").select("*").eq("id", id).maybeSingle();
215
+ const { data } = await getClient().from(T.tasks).select("*").eq("id", id).maybeSingle();
210
216
  return data ? toTask(data) : null;
211
217
  },
212
218
  async getSubtasks(parentId) {
213
- const { data } = await getClient().from("tsk_tasks").select("*").eq("parent_id", parentId).order("position", { ascending: true });
219
+ const { data } = await getClient().from(T.tasks).select("*").eq("parent_id", parentId).order("position", { ascending: true });
214
220
  return (data ?? []).map(toTask);
215
221
  },
216
222
  async createTask(input) {
217
223
  const tenantId = getTenantId();
218
224
  if (!tenantId) throw new Error("No active tenant");
219
- const { data: maxData } = await getClient().from("tsk_tasks").select("position").eq("tenant_id", tenantId).eq("status", input.status ?? "todo").is("parent_id", input.parentId ?? null).order("position", { ascending: false }).limit(1);
225
+ const { data: maxData } = await getClient().from(T.tasks).select("position").eq("tenant_id", tenantId).eq("status", input.status ?? "todo").is("parent_id", input.parentId ?? null).order("position", { ascending: false }).limit(1);
220
226
  const maxPos = maxData?.[0]?.position ?? -1;
221
- const { data, error } = await getClient().from("tsk_tasks").insert({
227
+ const { data, error } = await getClient().from(T.tasks).insert({
222
228
  tenant_id: tenantId,
223
229
  title: input.title,
224
230
  description: input.description ?? null,
@@ -243,26 +249,26 @@ function createSupabaseTasksProvider() {
243
249
  if (input.assignedToId !== void 0) payload.assigned_to_id = input.assignedToId;
244
250
  if (input.labels !== void 0) payload.labels = input.labels;
245
251
  if (input.position !== void 0) payload.position = input.position;
246
- const { data, error } = await getClient().from("tsk_tasks").update(payload).eq("id", id).select("*").single();
252
+ const { data, error } = await getClient().from(T.tasks).update(payload).eq("id", id).select("*").single();
247
253
  if (error) throw error;
248
254
  return toTask(data);
249
255
  },
250
256
  async deleteTask(id) {
251
- await getClient().from("tsk_tasks").delete().eq("id", id);
257
+ await getClient().from(T.tasks).delete().eq("id", id);
252
258
  },
253
259
  async reorderTask(id, newPosition, status) {
254
- await getClient().from("tsk_tasks").update({ position: newPosition, status, updated_at: (/* @__PURE__ */ new Date()).toISOString() }).eq("id", id);
260
+ await getClient().from(T.tasks).update({ position: newPosition, status, updated_at: (/* @__PURE__ */ new Date()).toISOString() }).eq("id", id);
255
261
  },
256
262
  async getLabels() {
257
263
  const tenantId = getTenantId();
258
264
  if (!tenantId) return [];
259
- const { data } = await getClient().from("tsk_labels").select("*").eq("tenant_id", tenantId).eq("is_active", true).order("name");
265
+ const { data } = await getClient().from(T.labels).select("*").eq("tenant_id", tenantId).eq("is_active", true).order("name");
260
266
  return (data ?? []).map((r) => snakeToCamel(r));
261
267
  },
262
268
  async getSummary() {
263
269
  const tenantId = getTenantId();
264
270
  if (!tenantId) return { total: 0, todo: 0, inProgress: 0, done: 0, overdue: 0, dueToday: 0, highPriority: 0 };
265
- const { data } = await getClient().from("tsk_tasks").select("status, priority, due_date").eq("tenant_id", tenantId).is("parent_id", null);
271
+ const { data } = await getClient().from(T.tasks).select("status, priority, due_date").eq("tenant_id", tenantId).is("parent_id", null);
266
272
  const tasks = data ?? [];
267
273
  const today2 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
268
274
  return {
@@ -473,7 +479,7 @@ var taskLabelEntity = {
473
479
  { key: "color", label: "Color", type: "text", showInTable: true, defaultValue: "#6366f1" },
474
480
  { key: "isActive", label: "Active", type: "boolean", showInTable: true, defaultValue: true }
475
481
  ],
476
- data: { table: "tsk_labels", tenantScoped: true }
482
+ data: { table: T.labels, tenantScoped: true }
477
483
  };
478
484
  var tasksRegistries = [
479
485
  {
@@ -955,40 +961,49 @@ function TasksTopbarButtonInner({ store }) {
955
961
  );
956
962
  }
957
963
 
958
- // src/index.ts
959
- var DEFAULT_LABELS = {
960
- drawerTitle: "Tasks",
961
- settingsTitle: "Tasks",
962
- quickAddPlaceholder: "Add a task..."
963
- };
964
- function resolveConfig(options) {
965
- return {
966
- labels: { ...DEFAULT_LABELS, ...options?.labels }
967
- };
968
- }
969
- var MIGRATION_001 = `-- Tasks Plugin: Base Tables
970
- CREATE TABLE IF NOT EXISTS public.tsk_labels (
964
+ // src/migrations/index.ts
965
+ var MIGRATION_000_PLG_RENAME = `-- 000_plg_rename.sql \u2014 rename legacy tasks tables to plg_tasks_* for pools
966
+ -- provisioned before the industry-pool rename. Guarded: fires only when legacy
967
+ -- name exists and target does not, so fresh pools skip every branch.
968
+ DO $$
969
+ BEGIN
970
+ IF to_regclass('public.tsk_tasks') IS NOT NULL AND to_regclass('public.plg_tasks_tasks') IS NULL THEN
971
+ ALTER TABLE public.tsk_tasks RENAME TO plg_tasks_tasks;
972
+ END IF;
973
+ IF to_regclass('public.tsk_labels') IS NOT NULL AND to_regclass('public.plg_tasks_labels') IS NULL THEN
974
+ ALTER TABLE public.tsk_labels RENAME TO plg_tasks_labels;
975
+ END IF;
976
+ END $$;
977
+ `;
978
+ var MIGRATION_001_TASKS_BASE = `-- Tasks Plugin: Base Tables
979
+ -- Prefix: plg_tasks_
980
+
981
+ -- Label definitions for categorizing tasks
982
+ CREATE TABLE IF NOT EXISTS public.plg_tasks_labels (
971
983
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
972
- tenant_id uuid NOT NULL REFERENCES saas_core.tenants(id) ON DELETE CASCADE,
984
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
973
985
  name text NOT NULL,
974
986
  color text NOT NULL DEFAULT '#6366f1',
975
987
  is_active boolean NOT NULL DEFAULT true,
976
988
  created_at timestamptz NOT NULL DEFAULT now()
977
989
  );
978
- ALTER TABLE public.tsk_labels ENABLE ROW LEVEL SECURITY;
979
- CREATE INDEX IF NOT EXISTS idx_tsk_labels_tenant ON public.tsk_labels(tenant_id);
990
+ ALTER TABLE public.plg_tasks_labels ENABLE ROW LEVEL SECURITY;
991
+ CREATE INDEX IF NOT EXISTS idx_plg_tasks_labels_tenant ON public.plg_tasks_labels(tenant_id);
980
992
 
981
- CREATE TABLE IF NOT EXISTS public.tsk_tasks (
993
+ -- Main tasks table (subtasks via parent_id self-reference)
994
+ CREATE TABLE IF NOT EXISTS public.plg_tasks_tasks (
982
995
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
983
- tenant_id uuid NOT NULL REFERENCES saas_core.tenants(id) ON DELETE CASCADE,
996
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
984
997
  title text NOT NULL,
985
998
  description text,
986
- status text NOT NULL DEFAULT 'todo' CHECK (status IN ('todo','in_progress','done','cancelled')),
987
- priority text NOT NULL DEFAULT 'medium' CHECK (priority IN ('low','medium','high','urgent')),
999
+ status text NOT NULL DEFAULT 'todo'
1000
+ CHECK (status IN ('todo', 'in_progress', 'done', 'cancelled')),
1001
+ priority text NOT NULL DEFAULT 'medium'
1002
+ CHECK (priority IN ('low', 'medium', 'high', 'urgent')),
988
1003
  due_date date,
989
1004
  assigned_to_id uuid,
990
1005
  assigned_to_name text,
991
- parent_id uuid REFERENCES public.tsk_tasks(id) ON DELETE CASCADE,
1006
+ parent_id uuid REFERENCES public.plg_tasks_tasks(id) ON DELETE CASCADE,
992
1007
  labels jsonb NOT NULL DEFAULT '[]'::jsonb,
993
1008
  position integer NOT NULL DEFAULT 0,
994
1009
  created_by_id uuid,
@@ -996,26 +1011,48 @@ CREATE TABLE IF NOT EXISTS public.tsk_tasks (
996
1011
  created_at timestamptz NOT NULL DEFAULT now(),
997
1012
  updated_at timestamptz NOT NULL DEFAULT now()
998
1013
  );
999
- ALTER TABLE public.tsk_tasks ENABLE ROW LEVEL SECURITY;
1000
- CREATE INDEX IF NOT EXISTS idx_tsk_tasks_tenant ON public.tsk_tasks(tenant_id);
1001
- CREATE INDEX IF NOT EXISTS idx_tsk_tasks_status ON public.tsk_tasks(tenant_id, status);
1002
- CREATE INDEX IF NOT EXISTS idx_tsk_tasks_parent ON public.tsk_tasks(parent_id);
1003
- CREATE INDEX IF NOT EXISTS idx_tsk_tasks_assigned ON public.tsk_tasks(assigned_to_id);
1004
- CREATE INDEX IF NOT EXISTS idx_tsk_tasks_due ON public.tsk_tasks(tenant_id, due_date) WHERE due_date IS NOT NULL;
1014
+ ALTER TABLE public.plg_tasks_tasks ENABLE ROW LEVEL SECURITY;
1015
+ CREATE INDEX IF NOT EXISTS idx_plg_tasks_tasks_tenant ON public.plg_tasks_tasks(tenant_id);
1016
+ CREATE INDEX IF NOT EXISTS idx_plg_tasks_tasks_status ON public.plg_tasks_tasks(tenant_id, status);
1017
+ CREATE INDEX IF NOT EXISTS idx_plg_tasks_tasks_parent ON public.plg_tasks_tasks(parent_id);
1018
+ CREATE INDEX IF NOT EXISTS idx_plg_tasks_tasks_assigned ON public.plg_tasks_tasks(assigned_to_id);
1019
+ CREATE INDEX IF NOT EXISTS idx_plg_tasks_tasks_due ON public.plg_tasks_tasks(tenant_id, due_date)
1020
+ WHERE due_date IS NOT NULL;
1021
+
1022
+ -- RLS policies for plg_tasks_tasks (idempotent \u2014 DROP IF EXISTS before CREATE)
1023
+ DROP POLICY IF EXISTS plg_tasks_tasks_select ON public.plg_tasks_tasks;
1024
+ CREATE POLICY plg_tasks_tasks_select ON public.plg_tasks_tasks FOR SELECT TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
1025
+ DROP POLICY IF EXISTS plg_tasks_tasks_insert ON public.plg_tasks_tasks;
1026
+ 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()));
1027
+ DROP POLICY IF EXISTS plg_tasks_tasks_update ON public.plg_tasks_tasks;
1028
+ CREATE POLICY plg_tasks_tasks_update ON public.plg_tasks_tasks FOR UPDATE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
1029
+ DROP POLICY IF EXISTS plg_tasks_tasks_delete ON public.plg_tasks_tasks;
1030
+ CREATE POLICY plg_tasks_tasks_delete ON public.plg_tasks_tasks FOR DELETE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
1031
+ GRANT SELECT, INSERT, UPDATE, DELETE ON public.plg_tasks_tasks TO authenticated;
1005
1032
 
1006
- -- RLS policies for tsk_tasks
1007
- CREATE POLICY tsk_tasks_select ON public.tsk_tasks FOR SELECT TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
1008
- CREATE POLICY tsk_tasks_insert ON public.tsk_tasks FOR INSERT TO authenticated WITH CHECK (tenant_id IN (SELECT public.user_tenant_ids()));
1009
- CREATE POLICY tsk_tasks_update ON public.tsk_tasks FOR UPDATE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
1010
- CREATE POLICY tsk_tasks_delete ON public.tsk_tasks FOR DELETE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
1011
- GRANT SELECT, INSERT, UPDATE, DELETE ON public.tsk_tasks TO authenticated;
1033
+ -- RLS policies for plg_tasks_labels (idempotent)
1034
+ DROP POLICY IF EXISTS plg_tasks_labels_select ON public.plg_tasks_labels;
1035
+ CREATE POLICY plg_tasks_labels_select ON public.plg_tasks_labels FOR SELECT TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
1036
+ DROP POLICY IF EXISTS plg_tasks_labels_insert ON public.plg_tasks_labels;
1037
+ 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()));
1038
+ DROP POLICY IF EXISTS plg_tasks_labels_update ON public.plg_tasks_labels;
1039
+ CREATE POLICY plg_tasks_labels_update ON public.plg_tasks_labels FOR UPDATE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
1040
+ DROP POLICY IF EXISTS plg_tasks_labels_delete ON public.plg_tasks_labels;
1041
+ CREATE POLICY plg_tasks_labels_delete ON public.plg_tasks_labels FOR DELETE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
1042
+ GRANT SELECT, INSERT, UPDATE, DELETE ON public.plg_tasks_labels TO authenticated;
1043
+ `;
1012
1044
 
1013
- -- RLS policies for tsk_labels
1014
- CREATE POLICY tsk_labels_select ON public.tsk_labels FOR SELECT TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
1015
- CREATE POLICY tsk_labels_insert ON public.tsk_labels FOR INSERT TO authenticated WITH CHECK (tenant_id IN (SELECT public.user_tenant_ids()));
1016
- CREATE POLICY tsk_labels_update ON public.tsk_labels FOR UPDATE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
1017
- CREATE POLICY tsk_labels_delete ON public.tsk_labels FOR DELETE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()));
1018
- GRANT SELECT, INSERT, UPDATE, DELETE ON public.tsk_labels TO authenticated;`;
1045
+ // src/index.ts
1046
+ var DEFAULT_LABELS = {
1047
+ drawerTitle: "Tasks",
1048
+ settingsTitle: "Tasks",
1049
+ quickAddPlaceholder: "Add a task..."
1050
+ };
1051
+ function resolveConfig(options) {
1052
+ return {
1053
+ labels: { ...DEFAULT_LABELS, ...options?.labels }
1054
+ };
1055
+ }
1019
1056
  function createTasksPlugin(options) {
1020
1057
  const config = resolveConfig(options);
1021
1058
  core.registerTranslations(tasksLocales);
@@ -1092,11 +1129,17 @@ function createTasksPlugin(options) {
1092
1129
  }
1093
1130
  ],
1094
1131
  migrations: [
1132
+ {
1133
+ id: "tasks-000-plg-rename",
1134
+ version: "1.0.0",
1135
+ sql: MIGRATION_000_PLG_RENAME,
1136
+ description: "Rename legacy tsk_* tables to plg_tasks_* in-place for pools provisioned before the industry-pool rename (guarded no-op on fresh pools)"
1137
+ },
1095
1138
  {
1096
1139
  id: "tasks-001-base-tables",
1097
1140
  version: "1.0.0",
1098
- sql: MIGRATION_001,
1099
- description: "Create tsk_tasks and tsk_labels tables"
1141
+ sql: MIGRATION_001_TASKS_BASE,
1142
+ description: "Create plg_tasks_tasks and plg_tasks_labels"
1100
1143
  }
1101
1144
  ],
1102
1145
  locales: tasksLocales