@axium/tasks 0.2.5 → 0.3.1

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/db.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "$schema": "../server/schemas/db.json",
3
+ "format": 0,
4
+ "versions": [
5
+ {
6
+ "delta": false,
7
+ "tables": {
8
+ "task_lists": {
9
+ "columns": {
10
+ "id": { "type": "uuid", "required": true, "primary": true, "default": "gen_random_uuid()" },
11
+ "userId": { "type": "uuid", "required": true, "references": "users.id", "onDelete": "cascade" },
12
+ "created": { "type": "timestamptz", "required": true, "default": "now()" },
13
+ "publicPermission": { "type": "integer", "required": true, "default": 0 },
14
+ "name": { "type": "text", "required": true },
15
+ "description": { "type": "text" }
16
+ }
17
+ },
18
+ "tasks": {
19
+ "columns": {
20
+ "id": { "type": "uuid", "required": true, "primary": true, "default": "gen_random_uuid()" },
21
+ "created": { "type": "timestamptz", "required": true, "default": "now()" },
22
+ "listId": { "type": "uuid", "required": true, "references": "task_lists.id", "onDelete": "cascade" },
23
+ "summary": { "type": "text", "required": true },
24
+ "description": { "type": "text" },
25
+ "parentId": { "type": "uuid", "references": "tasks.id", "onDelete": "cascade" },
26
+ "completed": { "type": "boolean", "required": true, "default": false },
27
+ "due": { "type": "timestamptz" }
28
+ }
29
+ },
30
+ "acl.task_lists": {
31
+ "columns": {
32
+ "userId": { "type": "uuid", "required": true, "references": "users.id", "onDelete": "cascade" },
33
+ "itemId": { "type": "uuid", "required": true, "references": "task_lists.id", "onDelete": "cascade" },
34
+ "createdAt": { "type": "timestamptz", "required": true, "default": "now()" },
35
+ "permission": { "type": "integer", "required": true, "check": "permission >= 0 AND permission <= 5" }
36
+ }
37
+ }
38
+ },
39
+ "indexes": ["task_lists:userId", "acl.task_lists:userId", "acl.task_lists:itemId", "tasks:listId", "tasks:parentId"]
40
+ },
41
+ {
42
+ "delta": true,
43
+ "alter_tables": {
44
+ "task_lists": {
45
+ "drop_columns": ["publicPermission"]
46
+ },
47
+ "acl.task_lists": {
48
+ "drop_constraints": ["PK_acl_task_lists"],
49
+ "drop_columns": ["permission"],
50
+ "add_columns": {
51
+ "role": { "type": "text" },
52
+ "tag": { "type": "text" },
53
+ "read": { "type": "boolean", "required": true, "default": false },
54
+ "edit": { "type": "boolean", "required": true, "default": false },
55
+ "manage": { "type": "boolean", "required": true, "default": false }
56
+ },
57
+ "alter_columns": {
58
+ "userId": { "ops": ["drop_required"] }
59
+ },
60
+ "add_constraints": {
61
+ "unique_task_lists": { "type": "unique", "on": ["itemId", "userId", "role", "tag"], "nulls_not_distinct": true }
62
+ }
63
+ }
64
+ }
65
+ }
66
+ ],
67
+ "wipe": ["task_lists", "tasks", "acl.task_lists"],
68
+ "acl_tables": {
69
+ "task_lists": "acl.task_lists"
70
+ }
71
+ }
package/dist/common.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- import type { Permission } from '@axium/core';
2
1
  import type { WithRequired } from 'utilium';
3
2
  import * as z from 'zod';
4
3
  export declare const TaskInit: z.ZodObject<{
@@ -27,7 +26,6 @@ export interface TaskList extends TaskListInit {
27
26
  id: string;
28
27
  userId: string;
29
28
  created: Date;
30
- publicPermission: Permission;
31
29
  tasks?: Task[];
32
30
  }
33
31
  declare module '@axium/core/api' {
package/dist/hooks.d.ts CHANGED
@@ -1,6 +1,3 @@
1
1
  import './common.js';
2
2
  import './server.js';
3
3
  export declare function statusText(): Promise<string>;
4
- export declare function db_init(): Promise<void>;
5
- export declare function db_wipe(): Promise<void>;
6
- export declare function remove(): Promise<void>;
package/dist/hooks.js CHANGED
@@ -1,56 +1,7 @@
1
- import { done, start } from '@axium/core/node/io';
2
- import * as acl from '@axium/server/acl';
3
- import { count, createIndex, database, warnExists } from '@axium/server/database';
4
- import { sql } from 'kysely';
1
+ import { count } from '@axium/server/database';
5
2
  import './common.js';
6
3
  import './server.js';
7
4
  export async function statusText() {
8
5
  const { tasks, task_lists } = await count('tasks', 'task_lists');
9
6
  return `${tasks} tasks, ${task_lists} lists`;
10
7
  }
11
- export async function db_init() {
12
- start('Creating table task_lists');
13
- await database.schema
14
- .createTable('task_lists')
15
- .addColumn('id', 'uuid', col => col.primaryKey().defaultTo(sql `gen_random_uuid()`))
16
- .addColumn('userId', 'uuid', col => col.notNull().references('users.id').onDelete('cascade'))
17
- .addColumn('created', 'timestamptz', col => col.notNull().defaultTo(sql `now()`))
18
- .addColumn('publicPermission', 'integer', col => col.notNull().defaultTo(0))
19
- .addColumn('name', 'text', col => col.notNull())
20
- .addColumn('description', 'text')
21
- .execute()
22
- .then(done)
23
- .catch(warnExists);
24
- await createIndex('task_lists', 'userId');
25
- await acl.createTable('task_lists');
26
- start('Creating table tasks');
27
- await database.schema
28
- .createTable('tasks')
29
- .addColumn('id', 'uuid', col => col.primaryKey().defaultTo(sql `gen_random_uuid()`))
30
- .addColumn('created', 'timestamptz', col => col.notNull().defaultTo(sql `now()`))
31
- .addColumn('listId', 'uuid', col => col.notNull().references('task_lists.id').onDelete('cascade'))
32
- .addColumn('summary', 'text', col => col.notNull())
33
- .addColumn('description', 'text')
34
- .addColumn('parentId', 'uuid', col => col.references('tasks.id').onDelete('cascade'))
35
- .addColumn('completed', 'boolean', col => col.notNull().defaultTo(false))
36
- .addColumn('due', 'timestamptz')
37
- .execute()
38
- .then(done)
39
- .catch(warnExists);
40
- await createIndex('tasks', 'listId');
41
- await createIndex('tasks', 'parentId');
42
- }
43
- export async function db_wipe() {
44
- start('Wiping data from tasks');
45
- await database.deleteFrom('tasks').execute().then(done);
46
- start('Wiping data from task_lists');
47
- await database.deleteFrom('task_lists').execute().then(done);
48
- await acl.wipeTable('task_lists');
49
- }
50
- export async function remove() {
51
- start('Dropping table tasks');
52
- await database.schema.dropTable('tasks').execute().then(done);
53
- start('Dropping table task_lists');
54
- await database.schema.dropTable('task_lists').execute().then(done);
55
- await acl.dropTable('task_lists');
56
- }
package/dist/server.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- import { Permission } from '@axium/core';
2
1
  import type { Generated, GeneratedAlways } from 'kysely';
3
2
  declare module '@axium/server/database' {
4
3
  interface Schema {
@@ -16,13 +15,9 @@ declare module '@axium/server/database' {
16
15
  id: GeneratedAlways<string>;
17
16
  userId: string;
18
17
  created: GeneratedAlways<Date>;
19
- publicPermission: Generated<Permission>;
20
18
  name: string;
21
19
  description?: string | null;
22
20
  };
23
- }
24
- interface ExpectedSchema {
25
- tasks: ColumnTypes<Schema['tasks']>;
26
- task_lists: ColumnTypes<Schema['task_lists']>;
21
+ 'acl.task_lists': DBAccessControl & DBBool<'read' | 'edit' | 'manage'>;
27
22
  }
28
23
  }
package/dist/server.js CHANGED
@@ -1,29 +1,10 @@
1
- import { Permission } from '@axium/core';
2
1
  import { checkAuthForItem, checkAuthForUser } from '@axium/server/auth';
3
- import { database, expectedTypes } from '@axium/server/database';
2
+ import { database } from '@axium/server/database';
4
3
  import { parseBody, withError } from '@axium/server/requests';
5
4
  import { addRoute } from '@axium/server/routes';
5
+ import { jsonArrayFrom } from 'kysely/helpers/postgres';
6
6
  import * as z from 'zod';
7
7
  import { TaskInit, TaskListInit, TaskListUpdate } from './common.js';
8
- import { jsonArrayFrom } from 'kysely/helpers/postgres';
9
- expectedTypes.tasks = {
10
- id: { type: 'uuid', required: true, hasDefault: true },
11
- created: { type: 'timestamptz', required: true, hasDefault: true },
12
- summary: { type: 'text', required: true },
13
- description: { type: 'text' },
14
- listId: { type: 'uuid', required: true },
15
- parentId: { type: 'uuid' },
16
- completed: { type: 'bool', required: true, hasDefault: true },
17
- due: { type: 'timestamptz' },
18
- };
19
- expectedTypes.task_lists = {
20
- id: { type: 'uuid', required: true, hasDefault: true },
21
- userId: { type: 'uuid', required: true },
22
- created: { type: 'timestamptz', required: true, hasDefault: true },
23
- publicPermission: { type: 'int4', required: true, hasDefault: true },
24
- name: { type: 'text', required: true },
25
- description: { type: 'text' },
26
- };
27
8
  addRoute({
28
9
  path: '/api/users/:id/task_lists',
29
10
  params: { id: z.uuid() },
@@ -56,7 +37,7 @@ addRoute({
56
37
  path: '/api/task_lists/:id',
57
38
  params: { id: z.uuid() },
58
39
  async GET(request, { id }) {
59
- const { item } = await checkAuthForItem(request, 'task_lists', id, Permission.Read);
40
+ const { item } = await checkAuthForItem(request, 'task_lists', id, { read: true });
60
41
  const tasks = await database
61
42
  .selectFrom('tasks')
62
43
  .selectAll()
@@ -67,7 +48,7 @@ addRoute({
67
48
  },
68
49
  async PUT(request, { id: listId }) {
69
50
  const init = await parseBody(request, TaskInit.omit({ listId: true }));
70
- await checkAuthForItem(request, 'task_lists', listId, Permission.Edit);
51
+ await checkAuthForItem(request, 'task_lists', listId, { edit: true });
71
52
  return await database
72
53
  .insertInto('tasks')
73
54
  .values({ summary: '', ...init, listId })
@@ -76,7 +57,7 @@ addRoute({
76
57
  .catch(withError('Could not update task list'));
77
58
  },
78
59
  async PATCH(request, { id }) {
79
- await checkAuthForItem(request, 'task_lists', id, Permission.Edit);
60
+ await checkAuthForItem(request, 'task_lists', id, { edit: true });
80
61
  const init = await parseBody(request, TaskListInit);
81
62
  return await database
82
63
  .updateTable('task_lists')
@@ -88,7 +69,7 @@ addRoute({
88
69
  },
89
70
  async POST(request, { id }) {
90
71
  const body = await parseBody(request, TaskListUpdate);
91
- await checkAuthForItem(request, 'task_lists', id, Permission.Edit);
72
+ await checkAuthForItem(request, 'task_lists', id, { edit: true });
92
73
  if (typeof body.all_completed == 'boolean') {
93
74
  await database
94
75
  .updateTable('tasks')
@@ -102,7 +83,7 @@ addRoute({
102
83
  return {};
103
84
  },
104
85
  async DELETE(request, { id }) {
105
- await checkAuthForItem(request, 'task_lists', id, Permission.Manage);
86
+ await checkAuthForItem(request, 'task_lists', id, { manage: true });
106
87
  return await database
107
88
  .deleteFrom('task_lists')
108
89
  .where('id', '=', id)
@@ -122,7 +103,7 @@ addRoute({
122
103
  .where('id', '=', id)
123
104
  .executeTakeFirstOrThrow()
124
105
  .catch(withError('Could not get task'));
125
- await checkAuthForItem(request, 'task_lists', task.listId, Permission.Edit);
106
+ await checkAuthForItem(request, 'task_lists', task.listId, { edit: true });
126
107
  return await database
127
108
  .updateTable('tasks')
128
109
  .set(init)
@@ -138,7 +119,7 @@ addRoute({
138
119
  .where('id', '=', id)
139
120
  .executeTakeFirstOrThrow()
140
121
  .catch(withError('Could not fetch task'));
141
- await checkAuthForItem(request, 'task_lists', task.listId, Permission.Manage);
122
+ await checkAuthForItem(request, 'task_lists', task.listId, { manage: true });
142
123
  return await database
143
124
  .deleteFrom('tasks')
144
125
  .where('id', '=', id)
@@ -50,7 +50,7 @@
50
50
  fetchAPI('PATCH', 'tasks/:id', { summary: task.summary }, task.id);
51
51
  }}
52
52
  />
53
- <Popover>
53
+ <Popover showToggle="hover">
54
54
  <div
55
55
  class="menu-item"
56
56
  onclick={() =>
@@ -187,14 +187,6 @@
187
187
  }
188
188
  }
189
189
 
190
- .task :global(.popover-toggle) {
191
- visibility: hidden;
192
- }
193
-
194
- .task:hover :global(.popover-toggle) {
195
- visibility: visible;
196
- }
197
-
198
190
  .task-list {
199
191
  display: flex;
200
192
  flex-direction: column;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axium/tasks",
3
- "version": "0.2.5",
3
+ "version": "0.3.1",
4
4
  "author": "James Prevett <axium@jamespre.dev>",
5
5
  "description": "Tasks for Axium",
6
6
  "funding": {
@@ -28,15 +28,16 @@
28
28
  "files": [
29
29
  "dist",
30
30
  "lib",
31
- "routes"
31
+ "routes",
32
+ "db.json"
32
33
  ],
33
34
  "scripts": {
34
35
  "build": "tsc"
35
36
  },
36
37
  "peerDependencies": {
37
- "@axium/client": ">=0.6.0",
38
- "@axium/core": ">=0.9.0",
39
- "@axium/server": ">=0.27.0",
38
+ "@axium/client": ">=0.9.6",
39
+ "@axium/core": ">=0.12.0",
40
+ "@axium/server": ">=0.28.0",
40
41
  "@sveltejs/kit": "^2.27.3",
41
42
  "utilium": "^2.3.8"
42
43
  },
@@ -46,7 +47,8 @@
46
47
  "axium": {
47
48
  "server": {
48
49
  "routes": "routes",
49
- "hooks": "./dist/hooks.js"
50
+ "hooks": "./dist/hooks.js",
51
+ "db": "./db.json"
50
52
  },
51
53
  "apps": [
52
54
  {
@@ -17,11 +17,11 @@
17
17
 
18
18
  <div class="tasks-main">
19
19
  <h1>Tasks</h1>
20
- <span>
21
- <button class="icon-text" onclick={() => dialog!.showModal()}>
22
- <Icon i="plus" /> New List
23
- </button>
24
- </span>
20
+
21
+ <button id="create-task-list" class="icon-text mobile-float-right" onclick={() => dialog!.showModal()}>
22
+ <Icon i="plus" /> New List
23
+ </button>
24
+
25
25
  <div class="lists-container">
26
26
  {#each lists as list}
27
27
  <TaskList {list} bind:lists />
@@ -58,6 +58,10 @@
58
58
  gap: 1em;
59
59
  }
60
60
 
61
+ #create-task-list {
62
+ width: fit-content;
63
+ }
64
+
61
65
  .lists-container {
62
66
  display: grid;
63
67
  grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));