@unbrained/pm-web 1.0.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.
Files changed (150) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +107 -0
  3. package/dist/auth.js +20 -0
  4. package/dist/auth.js.map +1 -0
  5. package/dist/crypto.js +42 -0
  6. package/dist/crypto.js.map +1 -0
  7. package/dist/db.js +111 -0
  8. package/dist/db.js.map +1 -0
  9. package/dist/index.js +88 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/middleware/auth.js +16 -0
  12. package/dist/middleware/auth.js.map +1 -0
  13. package/dist/routes/admin.js +207 -0
  14. package/dist/routes/admin.js.map +1 -0
  15. package/dist/routes/auth.js +163 -0
  16. package/dist/routes/auth.js.map +1 -0
  17. package/dist/routes/github.js +354 -0
  18. package/dist/routes/github.js.map +1 -0
  19. package/dist/routes/groups.js +180 -0
  20. package/dist/routes/groups.js.map +1 -0
  21. package/dist/routes/pm.js +2446 -0
  22. package/dist/routes/pm.js.map +1 -0
  23. package/dist/routes/projects.js +151 -0
  24. package/dist/routes/projects.js.map +1 -0
  25. package/dist/routes/sharing.js +155 -0
  26. package/dist/routes/sharing.js.map +1 -0
  27. package/dist/server.js +64 -0
  28. package/dist/server.js.map +1 -0
  29. package/dist/services/pm-runner.js +190 -0
  30. package/dist/services/pm-runner.js.map +1 -0
  31. package/dist/services/sse.js +111 -0
  32. package/dist/services/sse.js.map +1 -0
  33. package/manifest.json +15 -0
  34. package/package.json +111 -0
  35. package/public/icons/icon-192.png +0 -0
  36. package/public/icons/icon-512.png +0 -0
  37. package/public/index.html +265 -0
  38. package/public/manifest.json +66 -0
  39. package/public/src/api.js +28 -0
  40. package/public/src/api.js.map +1 -0
  41. package/public/src/api.ts +29 -0
  42. package/public/src/app.js +926 -0
  43. package/public/src/app.js.map +1 -0
  44. package/public/src/app.ts +929 -0
  45. package/public/src/components/modals.js +62 -0
  46. package/public/src/components/modals.js.map +1 -0
  47. package/public/src/components/modals.ts +73 -0
  48. package/public/src/components/toast.js +10 -0
  49. package/public/src/components/toast.js.map +1 -0
  50. package/public/src/components/toast.ts +13 -0
  51. package/public/src/constants.js +30 -0
  52. package/public/src/constants.js.map +1 -0
  53. package/public/src/constants.ts +41 -0
  54. package/public/src/state.js +15 -0
  55. package/public/src/state.js.map +1 -0
  56. package/public/src/state.ts +19 -0
  57. package/public/src/types.js +5 -0
  58. package/public/src/types.js.map +1 -0
  59. package/public/src/types.ts +253 -0
  60. package/public/src/utils.js +57 -0
  61. package/public/src/utils.js.map +1 -0
  62. package/public/src/utils.ts +56 -0
  63. package/public/src/views/activity.js +47 -0
  64. package/public/src/views/activity.js.map +1 -0
  65. package/public/src/views/activity.ts +41 -0
  66. package/public/src/views/admin.js +435 -0
  67. package/public/src/views/admin.js.map +1 -0
  68. package/public/src/views/admin.ts +504 -0
  69. package/public/src/views/auth.js +81 -0
  70. package/public/src/views/auth.js.map +1 -0
  71. package/public/src/views/auth.ts +74 -0
  72. package/public/src/views/calendar.js +133 -0
  73. package/public/src/views/calendar.js.map +1 -0
  74. package/public/src/views/calendar.ts +129 -0
  75. package/public/src/views/comments-audit.js +109 -0
  76. package/public/src/views/comments-audit.js.map +1 -0
  77. package/public/src/views/comments-audit.ts +108 -0
  78. package/public/src/views/config.js +322 -0
  79. package/public/src/views/config.js.map +1 -0
  80. package/public/src/views/config.ts +344 -0
  81. package/public/src/views/context.js +98 -0
  82. package/public/src/views/context.js.map +1 -0
  83. package/public/src/views/context.ts +100 -0
  84. package/public/src/views/create.js +293 -0
  85. package/public/src/views/create.js.map +1 -0
  86. package/public/src/views/create.ts +246 -0
  87. package/public/src/views/dedupe.js +51 -0
  88. package/public/src/views/dedupe.js.map +1 -0
  89. package/public/src/views/dedupe.ts +43 -0
  90. package/public/src/views/export.js +300 -0
  91. package/public/src/views/export.js.map +1 -0
  92. package/public/src/views/export.ts +274 -0
  93. package/public/src/views/github.js +360 -0
  94. package/public/src/views/github.js.map +1 -0
  95. package/public/src/views/github.ts +308 -0
  96. package/public/src/views/graph-canvas.js +1986 -0
  97. package/public/src/views/graph-canvas.js.map +1 -0
  98. package/public/src/views/graph-canvas.ts +2218 -0
  99. package/public/src/views/graph.js +1824 -0
  100. package/public/src/views/graph.js.map +1 -0
  101. package/public/src/views/graph.ts +1891 -0
  102. package/public/src/views/groups.js +186 -0
  103. package/public/src/views/groups.js.map +1 -0
  104. package/public/src/views/groups.ts +172 -0
  105. package/public/src/views/guide.js +151 -0
  106. package/public/src/views/guide.js.map +1 -0
  107. package/public/src/views/guide.ts +162 -0
  108. package/public/src/views/health.js +105 -0
  109. package/public/src/views/health.js.map +1 -0
  110. package/public/src/views/health.ts +102 -0
  111. package/public/src/views/items.js +1306 -0
  112. package/public/src/views/items.js.map +1 -0
  113. package/public/src/views/items.ts +1196 -0
  114. package/public/src/views/normalize.js +67 -0
  115. package/public/src/views/normalize.js.map +1 -0
  116. package/public/src/views/normalize.ts +58 -0
  117. package/public/src/views/plan.js +454 -0
  118. package/public/src/views/plan.js.map +1 -0
  119. package/public/src/views/plan.ts +496 -0
  120. package/public/src/views/projects.js +204 -0
  121. package/public/src/views/projects.js.map +1 -0
  122. package/public/src/views/projects.ts +196 -0
  123. package/public/src/views/router.js +227 -0
  124. package/public/src/views/router.js.map +1 -0
  125. package/public/src/views/router.ts +188 -0
  126. package/public/src/views/search.js +103 -0
  127. package/public/src/views/search.js.map +1 -0
  128. package/public/src/views/search.ts +94 -0
  129. package/public/src/views/settings.js +272 -0
  130. package/public/src/views/settings.js.map +1 -0
  131. package/public/src/views/settings.ts +190 -0
  132. package/public/src/views/shared.js +49 -0
  133. package/public/src/views/shared.js.map +1 -0
  134. package/public/src/views/shared.ts +49 -0
  135. package/public/src/views/sharing.js +152 -0
  136. package/public/src/views/sharing.js.map +1 -0
  137. package/public/src/views/sharing.ts +139 -0
  138. package/public/src/views/stats.js +92 -0
  139. package/public/src/views/stats.js.map +1 -0
  140. package/public/src/views/stats.ts +88 -0
  141. package/public/src/views/templates.js +117 -0
  142. package/public/src/views/templates.js.map +1 -0
  143. package/public/src/views/templates.ts +113 -0
  144. package/public/src/views/validate.js +54 -0
  145. package/public/src/views/validate.js.map +1 -0
  146. package/public/src/views/validate.ts +48 -0
  147. package/public/styles.css +2231 -0
  148. package/public/sw.js +318 -0
  149. package/public/tsconfig.json +20 -0
  150. package/sql/schema.sql +105 -0
@@ -0,0 +1,62 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // MODALS
3
+ // ═══════════════════════════════════════════════════════════════
4
+ import { escHtml } from '../utils.js';
5
+ export function showModal(id) {
6
+ const modal = document.getElementById(id);
7
+ if (modal)
8
+ modal.style.display = 'flex';
9
+ }
10
+ export function hideModal(id) {
11
+ const modal = document.getElementById(id);
12
+ if (modal)
13
+ modal.style.display = 'none';
14
+ }
15
+ export function closeAllModals() {
16
+ document.querySelectorAll('.modal-backdrop').forEach(m => {
17
+ m.style.display = 'none';
18
+ });
19
+ }
20
+ export function createModal(id, title, bodyHtml, footerHtml, wide = false) {
21
+ let existing = document.getElementById(id);
22
+ if (existing)
23
+ existing.remove();
24
+ const el = document.createElement('div');
25
+ el.id = id;
26
+ el.className = 'modal-backdrop';
27
+ el.style.display = 'none';
28
+ el.innerHTML = `
29
+ <div class="modal${wide ? ' modal-wide' : ''}">
30
+ <div class="modal-header">
31
+ <div class="modal-title">${escHtml(title)}</div>
32
+ <button class="modal-close" onclick="window.__app.hideModal('${id}')">&times;</button>
33
+ </div>
34
+ <div class="modal-body">${bodyHtml}</div>
35
+ ${footerHtml ? `<div class="modal-footer">${footerHtml}</div>` : ''}
36
+ </div>`;
37
+ el.addEventListener('click', e => { if (e.target === el)
38
+ hideModal(id); });
39
+ const container = document.getElementById('modal-container');
40
+ if (container)
41
+ container.appendChild(el);
42
+ return el;
43
+ }
44
+ export function confirmDialog(title, desc, onConfirm, danger = false) {
45
+ const id = 'confirm-dialog-' + Date.now();
46
+ createModal(id, '', `
47
+ <div class="confirm-dialog">
48
+ <div class="confirm-dialog-icon">${danger ? '⚠' : '?'}</div>
49
+ <div class="confirm-dialog-title">${escHtml(title)}</div>
50
+ <div class="confirm-dialog-desc">${escHtml(desc)}</div>
51
+ <div class="confirm-dialog-actions">
52
+ <button class="btn btn-ghost" onclick="window.__app.hideModal('${id}')">Cancel</button>
53
+ <button class="btn ${danger ? 'btn-danger' : 'btn-primary'}" id="${id}-ok">${danger ? 'Delete' : 'Confirm'}</button>
54
+ </div>
55
+ </div>`, '');
56
+ showModal(id);
57
+ document.getElementById(`${id}-ok`)?.addEventListener('click', () => {
58
+ hideModal(id);
59
+ onConfirm();
60
+ });
61
+ }
62
+ //# sourceMappingURL=modals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modals.js","sourceRoot":"","sources":["modals.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // MODALS
3
+ // ═══════════════════════════════════════════════════════════════
4
+ import { escHtml } from '../utils.js';
5
+
6
+ export function showModal(id: string): void {
7
+ const modal = document.getElementById(id);
8
+ if (modal) modal.style.display = 'flex';
9
+ }
10
+
11
+ export function hideModal(id: string): void {
12
+ const modal = document.getElementById(id);
13
+ if (modal) modal.style.display = 'none';
14
+ }
15
+
16
+ export function closeAllModals(): void {
17
+ document.querySelectorAll('.modal-backdrop').forEach(m => {
18
+ (m as HTMLElement).style.display = 'none';
19
+ });
20
+ }
21
+
22
+ export function createModal(
23
+ id: string,
24
+ title: string,
25
+ bodyHtml: string,
26
+ footerHtml: string,
27
+ wide = false
28
+ ): HTMLElement {
29
+ let existing = document.getElementById(id);
30
+ if (existing) existing.remove();
31
+ const el = document.createElement('div');
32
+ el.id = id;
33
+ el.className = 'modal-backdrop';
34
+ el.style.display = 'none';
35
+ el.innerHTML = `
36
+ <div class="modal${wide ? ' modal-wide' : ''}">
37
+ <div class="modal-header">
38
+ <div class="modal-title">${escHtml(title)}</div>
39
+ <button class="modal-close" onclick="window.__app.hideModal('${id}')">&times;</button>
40
+ </div>
41
+ <div class="modal-body">${bodyHtml}</div>
42
+ ${footerHtml ? `<div class="modal-footer">${footerHtml}</div>` : ''}
43
+ </div>`;
44
+ el.addEventListener('click', e => { if (e.target === el) hideModal(id); });
45
+ const container = document.getElementById('modal-container');
46
+ if (container) container.appendChild(el);
47
+ return el;
48
+ }
49
+
50
+ export function confirmDialog(
51
+ title: string,
52
+ desc: string,
53
+ onConfirm: () => void,
54
+ danger = false
55
+ ): void {
56
+ const id = 'confirm-dialog-' + Date.now();
57
+ createModal(id, '', `
58
+ <div class="confirm-dialog">
59
+ <div class="confirm-dialog-icon">${danger ? '⚠' : '?'}</div>
60
+ <div class="confirm-dialog-title">${escHtml(title)}</div>
61
+ <div class="confirm-dialog-desc">${escHtml(desc)}</div>
62
+ <div class="confirm-dialog-actions">
63
+ <button class="btn btn-ghost" onclick="window.__app.hideModal('${id}')">Cancel</button>
64
+ <button class="btn ${danger ? 'btn-danger' : 'btn-primary'}" id="${id}-ok">${danger ? 'Delete' : 'Confirm'}</button>
65
+ </div>
66
+ </div>`
67
+ , '');
68
+ showModal(id);
69
+ document.getElementById(`${id}-ok`)?.addEventListener('click', () => {
70
+ hideModal(id);
71
+ onConfirm();
72
+ });
73
+ }
@@ -0,0 +1,10 @@
1
+ export function toast(msg, type = 'info') {
2
+ const el = document.createElement('div');
3
+ el.className = `toast toast-${type}`;
4
+ el.textContent = msg;
5
+ const container = document.getElementById('toast-container');
6
+ if (container)
7
+ container.appendChild(el);
8
+ setTimeout(() => el.remove(), 3500);
9
+ }
10
+ //# sourceMappingURL=toast.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toast.js","sourceRoot":"","sources":["toast.ts"],"names":[],"mappings":"AAKA,MAAM,UAAU,KAAK,CAAC,GAAW,EAAE,OAAkB,MAAM;IACzD,MAAM,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACzC,EAAE,CAAC,SAAS,GAAG,eAAe,IAAI,EAAE,CAAC;IACrC,EAAE,CAAC,WAAW,GAAG,GAAG,CAAC;IACrB,MAAM,SAAS,GAAG,QAAQ,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAC;IAC7D,IAAI,SAAS;QAAE,SAAS,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IACzC,UAAU,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,CAAC;AACtC,CAAC"}
@@ -0,0 +1,13 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // TOAST NOTIFICATIONS
3
+ // ═══════════════════════════════════════════════════════════════
4
+ import type { ToastType } from '../types.js';
5
+
6
+ export function toast(msg: string, type: ToastType = 'info'): void {
7
+ const el = document.createElement('div');
8
+ el.className = `toast toast-${type}`;
9
+ el.textContent = msg;
10
+ const container = document.getElementById('toast-container');
11
+ if (container) container.appendChild(el);
12
+ setTimeout(() => el.remove(), 3500);
13
+ }
@@ -0,0 +1,30 @@
1
+ // Fallback values — kept in sync with pm CLI builtins for offline resilience.
2
+ // The live schema is fetched from /api/projects/:id/pm/schema per project
3
+ // and injected via state.schema; use getTypes()/getStatuses() everywhere.
4
+ export const FALLBACK_TYPES = [
5
+ 'Task', 'Feature', 'Issue', 'Epic', 'Milestone', 'Decision', 'Chore', 'Event', 'Meeting', 'Reminder', 'Plan'
6
+ ];
7
+ export const FALLBACK_STATUSES = ['draft', 'open', 'in_progress', 'blocked', 'closed', 'canceled'];
8
+ // Back-compat aliases (avoid widespread refactors, prefer getTypes/getStatuses)
9
+ export const TYPES = FALLBACK_TYPES;
10
+ export const STATUSES = FALLBACK_STATUSES;
11
+ export function getTypes(schema) {
12
+ return schema?.types?.length ? schema.types : [...FALLBACK_TYPES];
13
+ }
14
+ export function getStatuses(schema) {
15
+ return schema?.statuses?.length ? schema.statuses : [...FALLBACK_STATUSES];
16
+ }
17
+ export const TYPE_ICONS = {
18
+ Task: '✓', Feature: '★', Issue: '⚠', Epic: '◈',
19
+ Milestone: '⚑', Decision: '⚖', Chore: '⚙', Event: '◷', Meeting: '◉', Reminder: '◉', Plan: '◧'
20
+ };
21
+ export const PRIORITY_LABELS = {
22
+ 0: 'Critical', 1: 'High', 2: 'Medium', 3: 'Low', 4: 'Minimal'
23
+ };
24
+ export const VIEW_NAMES = [
25
+ 'projects', 'items', 'create', 'activity', 'search', 'stats', 'calendar',
26
+ 'context', 'graph', 'sharing', 'groups', 'health', 'dedupe', 'validate', 'settings',
27
+ 'github', 'export', 'normalize', 'shared', 'templates', 'comments-audit', 'config', 'guide',
28
+ 'admin', 'plan'
29
+ ];
30
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["constants.ts"],"names":[],"mappings":"AAKA,8EAA8E;AAC9E,0EAA0E;AAC1E,0EAA0E;AAC1E,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,MAAM,EAAC,SAAS,EAAC,OAAO,EAAC,MAAM,EAAC,WAAW,EAAC,UAAU,EAAC,OAAO,EAAC,OAAO,EAAC,SAAS,EAAC,UAAU,EAAC,MAAM;CAC1F,CAAC;AAEX,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,OAAO,EAAC,MAAM,EAAC,aAAa,EAAC,SAAS,EAAC,QAAQ,EAAC,UAAU,CAAU,CAAC;AAEvG,gFAAgF;AAChF,MAAM,CAAC,MAAM,KAAK,GAAG,cAAc,CAAC;AACpC,MAAM,CAAC,MAAM,QAAQ,GAAG,iBAAiB,CAAC;AAE1C,MAAM,UAAU,QAAQ,CAAC,MAA6B;IACpD,OAAO,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAA6B;IACvD,OAAO,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,iBAAiB,CAAC,CAAC;AAC7E,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAA2B;IAChD,IAAI,EAAC,GAAG,EAAE,OAAO,EAAC,GAAG,EAAE,KAAK,EAAC,GAAG,EAAE,IAAI,EAAC,GAAG;IAC1C,SAAS,EAAC,GAAG,EAAE,QAAQ,EAAC,GAAG,EAAE,KAAK,EAAC,GAAG,EAAE,KAAK,EAAC,GAAG,EAAE,OAAO,EAAC,GAAG,EAAE,QAAQ,EAAC,GAAG,EAAE,IAAI,EAAC,GAAG;CACvF,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAA2B;IACrD,CAAC,EAAC,UAAU,EAAE,CAAC,EAAC,MAAM,EAAE,CAAC,EAAC,QAAQ,EAAE,CAAC,EAAC,KAAK,EAAE,CAAC,EAAC,SAAS;CACzD,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,UAAU,EAAC,OAAO,EAAC,QAAQ,EAAC,UAAU,EAAC,QAAQ,EAAC,OAAO,EAAC,UAAU;IAClE,SAAS,EAAC,OAAO,EAAC,SAAS,EAAC,QAAQ,EAAC,QAAQ,EAAC,QAAQ,EAAC,UAAU,EAAC,UAAU;IAC5E,QAAQ,EAAC,QAAQ,EAAC,WAAW,EAAC,QAAQ,EAAC,WAAW,EAAC,gBAAgB,EAAC,QAAQ,EAAC,OAAO;IACpF,OAAO,EAAC,MAAM;CACN,CAAC"}
@@ -0,0 +1,41 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // CONSTANTS
3
+ // ═══════════════════════════════════════════════════════════════
4
+ import type { ProjectSchema } from './types.js';
5
+
6
+ // Fallback values — kept in sync with pm CLI builtins for offline resilience.
7
+ // The live schema is fetched from /api/projects/:id/pm/schema per project
8
+ // and injected via state.schema; use getTypes()/getStatuses() everywhere.
9
+ export const FALLBACK_TYPES = [
10
+ 'Task','Feature','Issue','Epic','Milestone','Decision','Chore','Event','Meeting','Reminder','Plan'
11
+ ] as const;
12
+
13
+ export const FALLBACK_STATUSES = ['draft','open','in_progress','blocked','closed','canceled'] as const;
14
+
15
+ // Back-compat aliases (avoid widespread refactors, prefer getTypes/getStatuses)
16
+ export const TYPES = FALLBACK_TYPES;
17
+ export const STATUSES = FALLBACK_STATUSES;
18
+
19
+ export function getTypes(schema?: ProjectSchema | null): string[] {
20
+ return schema?.types?.length ? schema.types : [...FALLBACK_TYPES];
21
+ }
22
+
23
+ export function getStatuses(schema?: ProjectSchema | null): string[] {
24
+ return schema?.statuses?.length ? schema.statuses : [...FALLBACK_STATUSES];
25
+ }
26
+
27
+ export const TYPE_ICONS: Record<string, string> = {
28
+ Task:'✓', Feature:'★', Issue:'⚠', Epic:'◈',
29
+ Milestone:'⚑', Decision:'⚖', Chore:'⚙', Event:'◷', Meeting:'◉', Reminder:'◉', Plan:'◧'
30
+ };
31
+
32
+ export const PRIORITY_LABELS: Record<number, string> = {
33
+ 0:'Critical', 1:'High', 2:'Medium', 3:'Low', 4:'Minimal'
34
+ };
35
+
36
+ export const VIEW_NAMES = [
37
+ 'projects','items','create','activity','search','stats','calendar',
38
+ 'context','graph','sharing','groups','health','dedupe','validate','settings',
39
+ 'github','export','normalize','shared','templates','comments-audit','config','guide',
40
+ 'admin','plan'
41
+ ] as const;
@@ -0,0 +1,15 @@
1
+ export const state = {
2
+ user: null,
3
+ projects: [],
4
+ currentProject: null,
5
+ currentView: 'projects',
6
+ authTab: 'login',
7
+ items: [],
8
+ itemFilters: { status: '', type: '', priority: '', sprint: '', release: '', assignee: '' },
9
+ searchQuery: '',
10
+ searchResults: [],
11
+ searchMode: 'hybrid',
12
+ calOffset: 0,
13
+ schema: null,
14
+ };
15
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["state.ts"],"names":[],"mappings":"AAKA,MAAM,CAAC,MAAM,KAAK,GAAa;IAC7B,IAAI,EAAE,IAAI;IACV,QAAQ,EAAE,EAAE;IACZ,cAAc,EAAE,IAAI;IACpB,WAAW,EAAE,UAAU;IACvB,OAAO,EAAE,OAAO;IAChB,KAAK,EAAE,EAAE;IACT,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;IAC1F,WAAW,EAAE,EAAE;IACf,aAAa,EAAE,EAAE;IACjB,UAAU,EAAE,QAAQ;IACpB,SAAS,EAAE,CAAC;IACZ,MAAM,EAAE,IAAI;CACb,CAAC"}
@@ -0,0 +1,19 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // STATE
3
+ // ═══════════════════════════════════════════════════════════════
4
+ import type { AppState } from './types.js';
5
+
6
+ export const state: AppState = {
7
+ user: null,
8
+ projects: [],
9
+ currentProject: null,
10
+ currentView: 'projects',
11
+ authTab: 'login',
12
+ items: [],
13
+ itemFilters: { status: '', type: '', priority: '', sprint: '', release: '', assignee: '' },
14
+ searchQuery: '',
15
+ searchResults: [],
16
+ searchMode: 'hybrid',
17
+ calOffset: 0,
18
+ schema: null,
19
+ };
@@ -0,0 +1,5 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // TYPES
3
+ // ═══════════════════════════════════════════════════════════════
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,QAAQ;AACR,kEAAkE"}
@@ -0,0 +1,253 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // TYPES
3
+ // ═══════════════════════════════════════════════════════════════
4
+
5
+ export interface User {
6
+ id: string;
7
+ email: string;
8
+ display_name?: string;
9
+ is_admin?: boolean;
10
+ has_github_token?: boolean;
11
+ created_at?: string;
12
+ }
13
+
14
+ export interface Project {
15
+ id: string;
16
+ name: string;
17
+ slug: string;
18
+ prefix: string;
19
+ description?: string;
20
+ created_at: string;
21
+ updated_at?: string;
22
+ }
23
+
24
+ export interface Item {
25
+ id: string;
26
+ title: string;
27
+ type?: string;
28
+ status?: string;
29
+ priority?: number;
30
+ description?: string;
31
+ body?: string;
32
+ tags?: string[];
33
+ parent?: string;
34
+ deadline?: string;
35
+ assignee?: string;
36
+ sprint?: string;
37
+ release?: string;
38
+ estimated_minutes?: number;
39
+ acceptance_criteria?: string;
40
+ acceptanceCriteria?: string;
41
+ claimedBy?: string;
42
+ created_at?: string;
43
+ updated_at?: string;
44
+ reporter?: string;
45
+ component?: string;
46
+ severity?: string;
47
+ risk?: string;
48
+ goal?: string;
49
+ environment?: string;
50
+ blockedBy?: string;
51
+ blockedReason?: string;
52
+ reproSteps?: string;
53
+ expectedResult?: string;
54
+ 'blocked-by'?: string;
55
+ 'blocked-reason'?: string;
56
+ 'repro-steps'?: string;
57
+ 'expected-result'?: string;
58
+ }
59
+
60
+ export interface Comment {
61
+ text?: string;
62
+ content?: string;
63
+ body?: string;
64
+ timestamp?: string;
65
+ created_at?: string;
66
+ }
67
+
68
+ export interface HistoryEntry {
69
+ message?: string;
70
+ action?: string;
71
+ timestamp?: string;
72
+ created_at?: string;
73
+ }
74
+
75
+ export interface Dependency {
76
+ targetId?: string;
77
+ id?: string;
78
+ rel?: string;
79
+ relationship?: string;
80
+ targetTitle?: string;
81
+ title?: string;
82
+ }
83
+
84
+ export interface GraphNode {
85
+ id: string;
86
+ labels?: string[];
87
+ properties?: {
88
+ title?: string;
89
+ type?: string;
90
+ status?: string;
91
+ priority?: number | null;
92
+ [key: string]: unknown;
93
+ };
94
+ }
95
+
96
+ export interface GraphRelationship {
97
+ from: string;
98
+ to: string;
99
+ type: string;
100
+ properties?: Record<string, unknown>;
101
+ }
102
+
103
+ export interface ProjectGraph {
104
+ generatedAt?: string;
105
+ source?: string;
106
+ nodes?: GraphNode[];
107
+ relationships?: GraphRelationship[];
108
+ }
109
+
110
+ export interface Learning {
111
+ text?: string;
112
+ content?: string;
113
+ timestamp?: string;
114
+ created_at?: string;
115
+ }
116
+
117
+ export interface PresenceUser {
118
+ userId: string;
119
+ displayName: string;
120
+ currentView: string;
121
+ connectedAt: string;
122
+ }
123
+
124
+ export interface Note {
125
+ text?: string;
126
+ content?: string;
127
+ timestamp?: string;
128
+ created_at?: string;
129
+ }
130
+
131
+ export interface TestEntry {
132
+ command?: string;
133
+ cmd?: string;
134
+ description?: string;
135
+ }
136
+
137
+ export interface FileEntry {
138
+ path?: string;
139
+ name?: string;
140
+ scope?: string;
141
+ }
142
+
143
+ export interface Share {
144
+ id?: string;
145
+ shareId?: string;
146
+ email?: string;
147
+ groupName?: string;
148
+ groupId?: string;
149
+ userId?: string;
150
+ permission?: string;
151
+ }
152
+
153
+ export interface Group {
154
+ id: string;
155
+ name: string;
156
+ description?: string;
157
+ members?: GroupMember[];
158
+ memberCount?: number;
159
+ }
160
+
161
+ export interface GroupMember {
162
+ id?: string;
163
+ userId?: string;
164
+ displayName?: string;
165
+ email?: string;
166
+ }
167
+
168
+ export interface Stats {
169
+ total?: number;
170
+ byStatus?: Record<string, number>;
171
+ byType?: Record<string, number>;
172
+ }
173
+
174
+ export interface HealthData {
175
+ score?: number;
176
+ issues?: Array<{ message?: string; description?: string }>;
177
+ summary?: string;
178
+ }
179
+
180
+ export interface ItemFilters {
181
+ status: string;
182
+ type: string;
183
+ priority: string;
184
+ sprint: string;
185
+ release: string;
186
+ assignee: string;
187
+ }
188
+
189
+ export interface ProjectSchema {
190
+ types: string[];
191
+ statuses: string[];
192
+ openStatus: string;
193
+ closeStatus: string;
194
+ canceledStatus: string;
195
+ }
196
+
197
+ export interface AppState {
198
+ user: User | null;
199
+ projects: Project[];
200
+ currentProject: Project | null;
201
+ currentView: string;
202
+ authTab: string;
203
+ items: Item[];
204
+ itemFilters: ItemFilters;
205
+ searchQuery: string;
206
+ searchResults: Item[];
207
+ searchMode: string;
208
+ calOffset: number;
209
+ schema: ProjectSchema | null;
210
+ }
211
+
212
+ export interface AdminUser {
213
+ id: string;
214
+ email: string;
215
+ display_name?: string;
216
+ is_admin: boolean;
217
+ has_github_token: boolean;
218
+ created_at: string;
219
+ updated_at?: string;
220
+ }
221
+
222
+ export interface AdminProject {
223
+ id: string;
224
+ name: string;
225
+ slug: string;
226
+ prefix: string;
227
+ description?: string;
228
+ owner_email: string;
229
+ owner_display_name?: string;
230
+ github_owner?: string;
231
+ github_repo?: string;
232
+ github_sync_enabled?: boolean;
233
+ created_at: string;
234
+ updated_at?: string;
235
+ }
236
+
237
+ export interface AdminGroup {
238
+ id: string;
239
+ name: string;
240
+ description?: string;
241
+ owner_email: string;
242
+ member_count: number;
243
+ created_at: string;
244
+ }
245
+
246
+ export type ToastType = 'info' | 'success' | 'error';
247
+
248
+ export type ViewName =
249
+ | 'projects' | 'items' | 'create' | 'activity' | 'search'
250
+ | 'stats' | 'calendar' | 'context' | 'graph' | 'sharing' | 'groups'
251
+ | 'health' | 'dedupe' | 'validate' | 'settings' | 'github'
252
+ | 'export' | 'normalize' | 'shared' | 'templates' | 'comments-audit'
253
+ | 'config' | 'guide' | 'plan';
@@ -0,0 +1,57 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // UTILITIES
3
+ // ═══════════════════════════════════════════════════════════════
4
+ import { PRIORITY_LABELS, TYPE_ICONS } from './constants.js';
5
+ export function escHtml(s) {
6
+ if (!s)
7
+ return '';
8
+ return String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
9
+ }
10
+ export function statusBadge(s) {
11
+ const labels = { in_progress: 'In Progress' };
12
+ return `<span class="status-badge status-${s}">${labels[s] || s}</span>`;
13
+ }
14
+ export function priorityDot(p) {
15
+ return `<span class="priority-dot priority-${p}" title="P${p}: ${PRIORITY_LABELS[p] || ''}"></span>`;
16
+ }
17
+ export function typeIcon(t) {
18
+ return `<span class="item-type-icon" title="${t}">${TYPE_ICONS[t] || '·'}</span>`;
19
+ }
20
+ export function relTime(ts) {
21
+ if (!ts)
22
+ return '';
23
+ const d = new Date(ts);
24
+ const diff = Date.now() - d.getTime();
25
+ const s = Math.floor(diff / 1000);
26
+ if (s < 60)
27
+ return 'just now';
28
+ if (s < 3600)
29
+ return `${Math.floor(s / 60)}m ago`;
30
+ if (s < 86400)
31
+ return `${Math.floor(s / 3600)}h ago`;
32
+ if (s < 604800)
33
+ return `${Math.floor(s / 86400)}d ago`;
34
+ return d.toLocaleDateString();
35
+ }
36
+ export function fmtDate(ts) {
37
+ if (!ts)
38
+ return '';
39
+ return new Date(ts).toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' });
40
+ }
41
+ export function setLoading(btn, yes, text) {
42
+ btn.disabled = yes;
43
+ if (text) {
44
+ const span = btn.querySelector('span');
45
+ if (span)
46
+ span.textContent = text;
47
+ else
48
+ btn.textContent = text;
49
+ }
50
+ }
51
+ export function skeletonRows(n = 5) {
52
+ return Array.from({ length: n }, () => '<div class="skeleton skeleton-row"></div>').join('');
53
+ }
54
+ export function skeletonCards(n = 3) {
55
+ return Array.from({ length: n }, () => '<div class="skeleton skeleton-card"></div>').join('');
56
+ }
57
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["utils.ts"],"names":[],"mappings":"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"}