@autocode-cli/autocode 0.1.15 → 0.1.18

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 (212) hide show
  1. package/README.md +38 -38
  2. package/dist/cli/commands/comment.d.ts +1 -1
  3. package/dist/cli/commands/comment.js +11 -11
  4. package/dist/cli/commands/comment.js.map +1 -1
  5. package/dist/cli/commands/init.js +1 -1
  6. package/dist/cli/commands/init.js.map +1 -1
  7. package/dist/cli/commands/list.d.ts +1 -1
  8. package/dist/cli/commands/list.d.ts.map +1 -1
  9. package/dist/cli/commands/list.js +65 -22
  10. package/dist/cli/commands/list.js.map +1 -1
  11. package/dist/cli/commands/move.d.ts +1 -1
  12. package/dist/cli/commands/move.js +12 -12
  13. package/dist/cli/commands/move.js.map +1 -1
  14. package/dist/cli/commands/new.d.ts +1 -1
  15. package/dist/cli/commands/new.d.ts.map +1 -1
  16. package/dist/cli/commands/new.js +26 -13
  17. package/dist/cli/commands/new.js.map +1 -1
  18. package/dist/cli/commands/next.d.ts +1 -1
  19. package/dist/cli/commands/next.js +15 -15
  20. package/dist/cli/commands/next.js.map +1 -1
  21. package/dist/cli/commands/parent.d.ts +9 -0
  22. package/dist/cli/commands/parent.d.ts.map +1 -0
  23. package/dist/cli/commands/parent.js +94 -0
  24. package/dist/cli/commands/parent.js.map +1 -0
  25. package/dist/cli/commands/serve.js +8 -8
  26. package/dist/cli/commands/serve.js.map +1 -1
  27. package/dist/cli/commands/show.d.ts +1 -1
  28. package/dist/cli/commands/show.d.ts.map +1 -1
  29. package/dist/cli/commands/show.js +51 -31
  30. package/dist/cli/commands/show.js.map +1 -1
  31. package/dist/cli/commands/stats.js +2 -2
  32. package/dist/cli/commands/stats.js.map +1 -1
  33. package/dist/cli/commands/sync.js +3 -3
  34. package/dist/cli/commands/sync.js.map +1 -1
  35. package/dist/cli/parser.d.ts.map +1 -1
  36. package/dist/cli/parser.js +5 -3
  37. package/dist/cli/parser.js.map +1 -1
  38. package/dist/core/column.js +2 -2
  39. package/dist/core/column.js.map +1 -1
  40. package/dist/core/hierarchy.d.ts +97 -0
  41. package/dist/core/hierarchy.d.ts.map +1 -0
  42. package/dist/core/hierarchy.js +274 -0
  43. package/dist/core/hierarchy.js.map +1 -0
  44. package/dist/core/issue.d.ts +62 -0
  45. package/dist/core/issue.d.ts.map +1 -0
  46. package/dist/core/issue.js +247 -0
  47. package/dist/core/issue.js.map +1 -0
  48. package/dist/core/sync.d.ts +9 -9
  49. package/dist/core/sync.d.ts.map +1 -1
  50. package/dist/core/sync.js +61 -58
  51. package/dist/core/sync.js.map +1 -1
  52. package/dist/core/workflow.d.ts +22 -20
  53. package/dist/core/workflow.d.ts.map +1 -1
  54. package/dist/core/workflow.js +68 -51
  55. package/dist/core/workflow.js.map +1 -1
  56. package/dist/index.d.ts +1 -1
  57. package/dist/index.js +1 -1
  58. package/dist/server/api-autocomplete.test.d.ts +6 -0
  59. package/dist/server/api-autocomplete.test.d.ts.map +1 -0
  60. package/dist/server/api-autocomplete.test.js +249 -0
  61. package/dist/server/api-autocomplete.test.js.map +1 -0
  62. package/dist/server/api.d.ts.map +1 -1
  63. package/dist/server/api.js +216 -106
  64. package/dist/server/api.js.map +1 -1
  65. package/dist/server/dashboard/pages/column-prompt.d.ts +1 -1
  66. package/dist/server/dashboard/pages/column-prompt.d.ts.map +1 -1
  67. package/dist/server/dashboard/pages/column-prompt.js +11 -11
  68. package/dist/server/dashboard/pages/column-prompt.js.map +1 -1
  69. package/dist/server/dashboard/pages/column-terminal.d.ts +1 -1
  70. package/dist/server/dashboard/pages/column-terminal.d.ts.map +1 -1
  71. package/dist/server/dashboard/pages/column-terminal.js +14 -14
  72. package/dist/server/dashboard/pages/column-terminal.js.map +1 -1
  73. package/dist/server/dashboard/pages/index.d.ts +3 -1
  74. package/dist/server/dashboard/pages/index.d.ts.map +1 -1
  75. package/dist/server/dashboard/pages/index.js +3 -1
  76. package/dist/server/dashboard/pages/index.js.map +1 -1
  77. package/dist/server/dashboard/pages/issue-graph.d.ts +9 -0
  78. package/dist/server/dashboard/pages/issue-graph.d.ts.map +1 -0
  79. package/dist/server/dashboard/pages/issue-graph.js +581 -0
  80. package/dist/server/dashboard/pages/issue-graph.js.map +1 -0
  81. package/dist/server/dashboard/pages/issue-view.d.ts +8 -0
  82. package/dist/server/dashboard/pages/issue-view.d.ts.map +1 -0
  83. package/dist/server/dashboard/pages/{ticket-view.js → issue-view.js} +128 -128
  84. package/dist/server/dashboard/pages/issue-view.js.map +1 -0
  85. package/dist/server/dashboard/pages/main-dashboard.d.ts.map +1 -1
  86. package/dist/server/dashboard/pages/main-dashboard.js +23 -22
  87. package/dist/server/dashboard/pages/main-dashboard.js.map +1 -1
  88. package/dist/server/dashboard/pages/new-issue.d.ts +8 -0
  89. package/dist/server/dashboard/pages/new-issue.d.ts.map +1 -0
  90. package/dist/server/dashboard/pages/new-issue.js +648 -0
  91. package/dist/server/dashboard/pages/new-issue.js.map +1 -0
  92. package/dist/server/dashboard/pages/new-issue.test.d.ts +6 -0
  93. package/dist/server/dashboard/pages/new-issue.test.d.ts.map +1 -0
  94. package/dist/server/dashboard/pages/new-issue.test.js +349 -0
  95. package/dist/server/dashboard/pages/new-issue.test.js.map +1 -0
  96. package/dist/server/dashboard/pages/pipeline-configurator.js +1 -1
  97. package/dist/server/dashboard/pages/shared.d.ts +2 -2
  98. package/dist/server/dashboard/pages/shared.d.ts.map +1 -1
  99. package/dist/server/dashboard/pages/shared.js +5 -5
  100. package/dist/server/dashboard/pages/shared.js.map +1 -1
  101. package/dist/server/dashboard/pages/stats-page.js +11 -11
  102. package/dist/server/dashboard/scripts/index.js +134 -134
  103. package/dist/server/dashboard/styles/base.js +2 -2
  104. package/dist/server/dashboard/styles/board.d.ts +1 -1
  105. package/dist/server/dashboard/styles/board.js +10 -10
  106. package/dist/server/dashboard.d.ts +1 -1
  107. package/dist/server/dashboard.d.ts.map +1 -1
  108. package/dist/server/dashboard.js +1 -1
  109. package/dist/server/dashboard.js.map +1 -1
  110. package/dist/server/index.d.ts.map +1 -1
  111. package/dist/server/index.js +40 -24
  112. package/dist/server/index.js.map +1 -1
  113. package/dist/server/websocket.d.ts +6 -6
  114. package/dist/server/websocket.d.ts.map +1 -1
  115. package/dist/server/websocket.js +10 -10
  116. package/dist/server/websocket.js.map +1 -1
  117. package/dist/services/claude.d.ts +13 -13
  118. package/dist/services/claude.d.ts.map +1 -1
  119. package/dist/services/claude.js +98 -98
  120. package/dist/services/claude.js.map +1 -1
  121. package/dist/services/issue-io.d.ts +81 -0
  122. package/dist/services/issue-io.d.ts.map +1 -0
  123. package/dist/services/{ticket-io.js → issue-io.js} +54 -53
  124. package/dist/services/issue-io.js.map +1 -0
  125. package/dist/services/stats.d.ts +1 -1
  126. package/dist/services/stats.d.ts.map +1 -1
  127. package/dist/types/index.d.ts +6 -4
  128. package/dist/types/index.d.ts.map +1 -1
  129. package/dist/utils/fs.d.ts +2 -2
  130. package/dist/utils/fs.d.ts.map +1 -1
  131. package/dist/utils/fs.js +2 -2
  132. package/dist/utils/fs.js.map +1 -1
  133. package/package.json +3 -3
  134. package/templates/catalog.yaml +2 -2
  135. package/templates/prompts/api-endpoints-test.en.md +2 -2
  136. package/templates/prompts/api-endpoints-test.fr.md +2 -2
  137. package/templates/prompts/backlog.en.md +6 -6
  138. package/templates/prompts/backlog.fr.md +1 -1
  139. package/templates/prompts/changelog.en.md +6 -6
  140. package/templates/prompts/changelog.fr.md +3 -3
  141. package/templates/prompts/dashboard-responsive.en.md +1 -1
  142. package/templates/prompts/deploy-prod.en.md +3 -3
  143. package/templates/prompts/deploy-prod.fr.md +3 -3
  144. package/templates/prompts/deploy-staging.en.md +3 -3
  145. package/templates/prompts/deploy-staging.fr.md +3 -3
  146. package/templates/prompts/design.en.md +5 -5
  147. package/templates/prompts/design.fr.md +3 -3
  148. package/templates/prompts/dev.en.md +4 -4
  149. package/templates/prompts/dev.fr.md +3 -3
  150. package/templates/prompts/done.en.md +5 -5
  151. package/templates/prompts/done.fr.md +2 -2
  152. package/templates/prompts/error-handling-review.en.md +1 -1
  153. package/templates/prompts/error-handling-review.fr.md +1 -1
  154. package/templates/prompts/file-watcher-test.en.md +4 -4
  155. package/templates/prompts/file-watcher-test.fr.md +1 -1
  156. package/templates/prompts/git-commit.en.md +5 -5
  157. package/templates/prompts/git-commit.fr.md +3 -3
  158. package/templates/prompts/git-push.en.md +3 -3
  159. package/templates/prompts/git-push.fr.md +3 -3
  160. package/templates/prompts/git-tag.en.md +3 -3
  161. package/templates/prompts/git-tag.fr.md +3 -3
  162. package/templates/prompts/in-progress.en.md +6 -6
  163. package/templates/prompts/in-progress.fr.md +3 -3
  164. package/templates/prompts/qualification.en.md +8 -8
  165. package/templates/prompts/qualification.fr.md +3 -3
  166. package/templates/prompts/retest-cypress.en.md +3 -3
  167. package/templates/prompts/retest-cypress.fr.md +3 -3
  168. package/templates/prompts/retest-playwright.en.md +4 -4
  169. package/templates/prompts/retest-playwright.fr.md +3 -3
  170. package/templates/prompts/retest.en.md +4 -4
  171. package/templates/prompts/retest.fr.md +3 -3
  172. package/templates/prompts/review-best-practices.en.md +3 -3
  173. package/templates/prompts/review-best-practices.fr.md +3 -3
  174. package/templates/prompts/review-code.en.md +4 -4
  175. package/templates/prompts/review-code.fr.md +3 -3
  176. package/templates/prompts/review-consistency.en.md +3 -3
  177. package/templates/prompts/review-consistency.fr.md +3 -3
  178. package/templates/prompts/review-no-duplication.en.md +3 -3
  179. package/templates/prompts/review-no-duplication.fr.md +3 -3
  180. package/templates/prompts/review-security.en.md +4 -4
  181. package/templates/prompts/review-security.fr.md +3 -3
  182. package/templates/prompts/specification.en.md +5 -5
  183. package/templates/prompts/specification.fr.md +3 -3
  184. package/templates/prompts/splitter.en.md +13 -13
  185. package/templates/prompts/splitter.fr.md +3 -3
  186. package/templates/prompts/template-validation.en.md +1 -1
  187. package/templates/prompts/template-validation.fr.md +1 -1
  188. package/templates/prompts/testing-coverage.en.md +1 -1
  189. package/templates/prompts/testing-coverage.fr.md +1 -1
  190. package/templates/prompts/testing-cypress.en.md +4 -4
  191. package/templates/prompts/testing-cypress.fr.md +3 -3
  192. package/templates/prompts/testing-integration.en.md +4 -4
  193. package/templates/prompts/testing-integration.fr.md +3 -3
  194. package/templates/prompts/testing-playwright.en.md +4 -4
  195. package/templates/prompts/testing-playwright.fr.md +3 -3
  196. package/templates/prompts/testing-unit.en.md +4 -4
  197. package/templates/prompts/testing-unit.fr.md +3 -3
  198. package/templates/prompts/update-docs.en.md +3 -3
  199. package/templates/prompts/update-docs.fr.md +3 -3
  200. package/templates/prompts/validate-staging.en.md +3 -3
  201. package/templates/prompts/validate-staging.fr.md +3 -3
  202. package/templates/prompts/websocket-test.en.md +1 -1
  203. package/dist/core/ticket.d.ts +0 -50
  204. package/dist/core/ticket.d.ts.map +0 -1
  205. package/dist/core/ticket.js +0 -224
  206. package/dist/core/ticket.js.map +0 -1
  207. package/dist/server/dashboard/pages/ticket-view.d.ts +0 -8
  208. package/dist/server/dashboard/pages/ticket-view.d.ts.map +0 -1
  209. package/dist/server/dashboard/pages/ticket-view.js.map +0 -1
  210. package/dist/services/ticket-io.d.ts +0 -80
  211. package/dist/services/ticket-io.d.ts.map +0 -1
  212. package/dist/services/ticket-io.js.map +0 -1
@@ -0,0 +1,648 @@
1
+ /**
2
+ * New issue page generator
3
+ */
4
+ import { getColumns } from '../../../core/column.js';
5
+ /**
6
+ * Generate the new issue page
7
+ */
8
+ export function generateNewIssuePage(lang) {
9
+ const columns = getColumns();
10
+ const firstColumn = columns.length > 0 ? columns[0].slug : 'backlog';
11
+ return `<!DOCTYPE html>
12
+ <html lang="${lang}">
13
+ <head>
14
+ <meta charset="UTF-8">
15
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
16
+ <title>New Issue - AutoCode</title>
17
+ <style>
18
+ :root {
19
+ --bg: #0d1117;
20
+ --bg-card: #161b22;
21
+ --border: #30363d;
22
+ --fg: #c9d1d9;
23
+ --muted: #8b949e;
24
+ --accent: #7c3aed;
25
+ --blue: #4dabf7;
26
+ --green: #22c55e;
27
+ --red: #ef4444;
28
+ --yellow: #facc15;
29
+ --orange: #fb923c;
30
+ }
31
+ * { margin: 0; padding: 0; box-sizing: border-box; }
32
+ body {
33
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
34
+ background: var(--bg);
35
+ color: var(--fg);
36
+ min-height: 100vh;
37
+ }
38
+ .header {
39
+ background: var(--bg-card);
40
+ border-bottom: 1px solid var(--border);
41
+ padding: 16px 24px;
42
+ display: flex;
43
+ align-items: center;
44
+ gap: 16px;
45
+ }
46
+ .back-btn {
47
+ background: none;
48
+ border: 1px solid var(--border);
49
+ color: var(--fg);
50
+ padding: 8px 12px;
51
+ border-radius: 6px;
52
+ cursor: pointer;
53
+ font-size: 14px;
54
+ display: flex;
55
+ align-items: center;
56
+ gap: 6px;
57
+ text-decoration: none;
58
+ }
59
+ .back-btn:hover { border-color: var(--accent); color: var(--accent); }
60
+ .title {
61
+ flex: 1;
62
+ font-size: 18px;
63
+ font-weight: 600;
64
+ }
65
+ .lang-selector {
66
+ display: flex;
67
+ gap: 4px;
68
+ }
69
+ .lang-btn {
70
+ background: var(--bg);
71
+ border: 1px solid var(--border);
72
+ color: var(--muted);
73
+ padding: 6px 12px;
74
+ border-radius: 4px;
75
+ cursor: pointer;
76
+ font-size: 13px;
77
+ font-weight: 600;
78
+ }
79
+ .lang-btn.active { background: var(--accent); color: white; border-color: var(--accent); }
80
+ .lang-btn:hover:not(.active) { border-color: var(--accent); color: var(--fg); }
81
+ .container {
82
+ max-width: 800px;
83
+ margin: 0 auto;
84
+ padding: 32px 24px;
85
+ }
86
+ .form-card {
87
+ background: var(--bg-card);
88
+ border: 1px solid var(--border);
89
+ border-radius: 12px;
90
+ padding: 24px;
91
+ }
92
+ .form-group {
93
+ margin-bottom: 20px;
94
+ }
95
+ .form-group label {
96
+ display: block;
97
+ font-size: 14px;
98
+ font-weight: 500;
99
+ margin-bottom: 8px;
100
+ color: var(--fg);
101
+ }
102
+ .form-group input[type="text"],
103
+ .form-group textarea,
104
+ .form-group select {
105
+ width: 100%;
106
+ padding: 12px;
107
+ background: var(--bg);
108
+ border: 1px solid var(--border);
109
+ border-radius: 8px;
110
+ color: var(--fg);
111
+ font-size: 14px;
112
+ font-family: inherit;
113
+ }
114
+ .form-group input:focus,
115
+ .form-group textarea:focus,
116
+ .form-group select:focus {
117
+ outline: none;
118
+ border-color: var(--accent);
119
+ }
120
+ .form-group textarea {
121
+ min-height: 120px;
122
+ resize: vertical;
123
+ }
124
+ .form-row {
125
+ display: grid;
126
+ grid-template-columns: 1fr 1fr;
127
+ gap: 16px;
128
+ }
129
+ .labels-container {
130
+ display: flex;
131
+ flex-wrap: wrap;
132
+ gap: 8px;
133
+ margin-top: 8px;
134
+ }
135
+ .label-tag {
136
+ display: inline-flex;
137
+ align-items: center;
138
+ gap: 6px;
139
+ background: var(--bg);
140
+ border: 1px solid var(--border);
141
+ padding: 6px 10px;
142
+ border-radius: 16px;
143
+ font-size: 12px;
144
+ }
145
+ .label-tag .remove {
146
+ cursor: pointer;
147
+ opacity: 0.6;
148
+ }
149
+ .label-tag .remove:hover { opacity: 1; }
150
+ .criteria-list {
151
+ display: flex;
152
+ flex-direction: column;
153
+ gap: 8px;
154
+ }
155
+ .criteria-item {
156
+ display: flex;
157
+ align-items: center;
158
+ gap: 8px;
159
+ }
160
+ .criteria-item input {
161
+ flex: 1;
162
+ padding: 10px 12px;
163
+ background: var(--bg);
164
+ border: 1px solid var(--border);
165
+ border-radius: 6px;
166
+ color: var(--fg);
167
+ font-size: 14px;
168
+ }
169
+ .criteria-item input:focus {
170
+ outline: none;
171
+ border-color: var(--accent);
172
+ }
173
+ .criteria-item .remove-btn {
174
+ background: none;
175
+ border: none;
176
+ color: var(--red);
177
+ cursor: pointer;
178
+ font-size: 18px;
179
+ padding: 4px 8px;
180
+ opacity: 0.6;
181
+ }
182
+ .criteria-item .remove-btn:hover { opacity: 1; }
183
+ .btn-add {
184
+ background: none;
185
+ border: 1px dashed var(--border);
186
+ color: var(--muted);
187
+ padding: 10px 16px;
188
+ border-radius: 6px;
189
+ cursor: pointer;
190
+ font-size: 13px;
191
+ display: flex;
192
+ align-items: center;
193
+ gap: 6px;
194
+ margin-top: 8px;
195
+ width: 100%;
196
+ justify-content: center;
197
+ }
198
+ .btn-add:hover {
199
+ border-color: var(--accent);
200
+ color: var(--accent);
201
+ }
202
+ .form-actions {
203
+ display: flex;
204
+ gap: 12px;
205
+ margin-top: 24px;
206
+ padding-top: 24px;
207
+ border-top: 1px solid var(--border);
208
+ }
209
+ .btn {
210
+ padding: 12px 24px;
211
+ border-radius: 8px;
212
+ font-size: 14px;
213
+ font-weight: 500;
214
+ cursor: pointer;
215
+ border: none;
216
+ text-decoration: none;
217
+ text-align: center;
218
+ }
219
+ .btn-primary {
220
+ background: var(--accent);
221
+ color: white;
222
+ flex: 1;
223
+ }
224
+ .btn-primary:hover { opacity: 0.9; }
225
+ .btn-primary:disabled { opacity: 0.5; cursor: not-allowed; }
226
+ .btn-autocomplete {
227
+ background: linear-gradient(135deg, var(--accent), #9333ea);
228
+ color: white;
229
+ border: none;
230
+ padding: 10px 16px;
231
+ border-radius: 6px;
232
+ cursor: pointer;
233
+ font-size: 13px;
234
+ font-weight: 500;
235
+ display: flex;
236
+ align-items: center;
237
+ gap: 6px;
238
+ transition: all 0.2s;
239
+ }
240
+ .btn-autocomplete:hover { opacity: 0.9; transform: translateY(-1px); }
241
+ .btn-autocomplete:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }
242
+ .btn-autocomplete .spinner {
243
+ width: 14px;
244
+ height: 14px;
245
+ border: 2px solid transparent;
246
+ border-top-color: white;
247
+ border-radius: 50%;
248
+ animation: spin 0.8s linear infinite;
249
+ }
250
+ @keyframes spin { to { transform: rotate(360deg); } }
251
+ .title-row {
252
+ display: flex;
253
+ gap: 12px;
254
+ align-items: flex-end;
255
+ }
256
+ .title-row .form-group { flex: 1; margin-bottom: 0; }
257
+ .btn-secondary {
258
+ background: var(--bg);
259
+ color: var(--fg);
260
+ border: 1px solid var(--border);
261
+ }
262
+ .btn-secondary:hover { border-color: var(--accent); }
263
+ .notification {
264
+ position: fixed;
265
+ bottom: 24px;
266
+ right: 24px;
267
+ background: var(--bg-card);
268
+ border: 1px solid var(--border);
269
+ border-left: 3px solid var(--green);
270
+ padding: 12px 16px;
271
+ border-radius: 6px;
272
+ font-size: 14px;
273
+ opacity: 0;
274
+ transform: translateY(10px);
275
+ transition: all 0.3s;
276
+ z-index: 100;
277
+ }
278
+ .notification.show { opacity: 1; transform: translateY(0); }
279
+ .notification.error { border-left-color: var(--red); }
280
+ </style>
281
+ </head>
282
+ <body>
283
+ <header class="header">
284
+ <a href="/" class="back-btn">← Dashboard</a>
285
+ <h1 class="title" id="page-title" data-i18n="newIssue.title">New Issue</h1>
286
+ <div class="lang-selector" id="lang-selector">
287
+ <button class="lang-btn" data-lang="en">EN</button>
288
+ <button class="lang-btn" data-lang="fr">FR</button>
289
+ </div>
290
+ </header>
291
+
292
+ <div class="container">
293
+ <div class="form-card">
294
+ <div class="title-row">
295
+ <div class="form-group">
296
+ <label for="issue-title" data-i18n="newIssue.titleLabel">Title *</label>
297
+ <input type="text" id="issue-title" placeholder="E.g.: Fix the login bug" data-i18n-placeholder="newIssue.titlePlaceholder">
298
+ </div>
299
+ <button type="button" class="btn-autocomplete" id="btn-autocomplete" onclick="autocomplete()" title="Auto-fill fields using AI">
300
+ <span id="autocomplete-icon">&#10024;</span>
301
+ <span data-i18n="btn.autocomplete">AutoComplete</span>
302
+ </button>
303
+ </div>
304
+
305
+ <div class="form-group">
306
+ <label for="issue-description" data-i18n="newIssue.description">Description</label>
307
+ <textarea id="issue-description" placeholder="Describe the context and details..." data-i18n-placeholder="newIssue.descriptionPlaceholder"></textarea>
308
+ </div>
309
+
310
+ <div class="form-row">
311
+ <div class="form-group">
312
+ <label for="issue-priority" data-i18n="newIssue.priority">Priority</label>
313
+ <select id="issue-priority">
314
+ <option value="P2" data-i18n="priority.p2">P2 - Normal</option>
315
+ <option value="P0" data-i18n="priority.p0">P0 - Critical</option>
316
+ <option value="P1" data-i18n="priority.p1">P1 - High</option>
317
+ <option value="P3" data-i18n="priority.p3">P3 - Low</option>
318
+ </select>
319
+ </div>
320
+ <div class="form-group">
321
+ <label for="issue-semver" data-i18n="newIssue.releaseType">Release type</label>
322
+ <select id="issue-semver">
323
+ <option value="patch" data-i18n="semver.patch">Patch (x.x.X) - Bug fix</option>
324
+ <option value="minor" data-i18n="semver.minor">Minor (x.X.0) - Feature</option>
325
+ <option value="major" data-i18n="semver.major">Major (X.0.0) - Breaking</option>
326
+ <option value="none" data-i18n="semver.none">No deployment</option>
327
+ </select>
328
+ </div>
329
+ </div>
330
+
331
+ <div class="form-row">
332
+ <div class="form-group">
333
+ <label for="issue-column" data-i18n="newIssue.column">Target column</label>
334
+ <select id="issue-column">
335
+ ${columns.map(col => `<option value="${col.slug}"${col.slug === firstColumn ? ' selected' : ''}>${col.name}</option>`).join('\n ')}
336
+ </select>
337
+ </div>
338
+ <div class="form-group">
339
+ <label for="issue-labels" data-i18n="newIssue.labels">Labels</label>
340
+ <select id="issue-labels" onchange="addLabel(this)">
341
+ <option value="" data-i18n="newIssue.selectLabel">Select a label...</option>
342
+ <option value="bug">bug</option>
343
+ <option value="feature">feature</option>
344
+ <option value="enhancement">enhancement</option>
345
+ <option value="documentation">documentation</option>
346
+ <option value="urgent">urgent</option>
347
+ <option value="refactoring">refactoring</option>
348
+ <option value="security">security</option>
349
+ <option value="performance">performance</option>
350
+ <option value="ui">ui</option>
351
+ <option value="api">api</option>
352
+ </select>
353
+ <div class="labels-container" id="selected-labels"></div>
354
+ </div>
355
+ </div>
356
+
357
+ <div class="form-group">
358
+ <label data-i18n="newIssue.acceptanceCriteria">Acceptance criteria</label>
359
+ <div class="criteria-list" id="criteria-list"></div>
360
+ <button type="button" class="btn-add" onclick="addCriteria()">
361
+ <span>+</span> <span data-i18n="newIssue.addCriteria">Add criteria</span>
362
+ </button>
363
+ </div>
364
+
365
+ <div class="form-actions">
366
+ <a href="/" class="btn btn-secondary" data-i18n="btn.cancel">Cancel</a>
367
+ <button class="btn btn-primary" id="btn-create" onclick="createIssue()" data-i18n="btn.createIssue">Create issue</button>
368
+ </div>
369
+ </div>
370
+ </div>
371
+
372
+ <div class="notification" id="notification"></div>
373
+
374
+ <script>
375
+ const STORAGE_KEY = 'autocode-lang';
376
+ let currentLang = localStorage.getItem(STORAGE_KEY) || 'fr';
377
+ let selectedLabels = [];
378
+
379
+ const translations = {
380
+ en: {
381
+ 'newIssue.title': 'New Issue',
382
+ 'newIssue.titleLabel': 'Title *',
383
+ 'newIssue.titlePlaceholder': 'E.g.: Fix the login bug',
384
+ 'newIssue.description': 'Description',
385
+ 'newIssue.descriptionPlaceholder': 'Describe the context and details...',
386
+ 'newIssue.priority': 'Priority',
387
+ 'newIssue.releaseType': 'Release type',
388
+ 'newIssue.column': 'Target column',
389
+ 'newIssue.labels': 'Labels',
390
+ 'newIssue.selectLabel': 'Select a label...',
391
+ 'newIssue.acceptanceCriteria': 'Acceptance criteria',
392
+ 'newIssue.addCriteria': 'Add criteria',
393
+ 'priority.p0': 'P0 - Critical',
394
+ 'priority.p1': 'P1 - High',
395
+ 'priority.p2': 'P2 - Normal',
396
+ 'priority.p3': 'P3 - Low',
397
+ 'semver.patch': 'Patch (x.x.X) - Bug fix',
398
+ 'semver.minor': 'Minor (x.X.0) - Feature',
399
+ 'semver.major': 'Major (X.0.0) - Breaking',
400
+ 'semver.none': 'No deployment',
401
+ 'btn.cancel': 'Cancel',
402
+ 'btn.createIssue': 'Create issue',
403
+ 'btn.creating': 'Creating...',
404
+ 'btn.autocomplete': 'AutoComplete',
405
+ 'btn.autocompleting': 'Generating...',
406
+ 'notify.created': 'Issue created successfully!',
407
+ 'notify.error': 'Error',
408
+ 'notify.titleRequired': 'Title is required',
409
+ 'notify.autocompleteSuccess': 'Fields auto-filled!',
410
+ 'notify.autocompleteTitleRequired': 'Enter a title first'
411
+ },
412
+ fr: {
413
+ 'newIssue.title': 'Nouveau ticket',
414
+ 'newIssue.titleLabel': 'Titre *',
415
+ 'newIssue.titlePlaceholder': 'Ex: Corriger le bug de connexion',
416
+ 'newIssue.description': 'Description',
417
+ 'newIssue.descriptionPlaceholder': 'Décrivez le contexte et les détails...',
418
+ 'newIssue.priority': 'Priorité',
419
+ 'newIssue.releaseType': 'Type de release',
420
+ 'newIssue.column': 'Colonne cible',
421
+ 'newIssue.labels': 'Labels',
422
+ 'newIssue.selectLabel': 'Sélectionner un label...',
423
+ 'newIssue.acceptanceCriteria': "Critères d'acceptation",
424
+ 'newIssue.addCriteria': 'Ajouter un critère',
425
+ 'priority.p0': 'P0 - Critique',
426
+ 'priority.p1': 'P1 - Haute',
427
+ 'priority.p2': 'P2 - Normale',
428
+ 'priority.p3': 'P3 - Basse',
429
+ 'semver.patch': 'Patch (x.x.X) - Correction',
430
+ 'semver.minor': 'Minor (x.X.0) - Fonctionnalité',
431
+ 'semver.major': 'Major (X.0.0) - Rupture',
432
+ 'semver.none': 'Pas de déploiement',
433
+ 'btn.cancel': 'Annuler',
434
+ 'btn.createIssue': 'Créer le ticket',
435
+ 'btn.creating': 'Création...',
436
+ 'btn.autocomplete': 'AutoComplete',
437
+ 'btn.autocompleting': 'Génération...',
438
+ 'notify.created': 'Ticket créé avec succès !',
439
+ 'notify.error': 'Erreur',
440
+ 'notify.titleRequired': 'Le titre est requis',
441
+ 'notify.autocompleteSuccess': 'Champs remplis automatiquement !',
442
+ 'notify.autocompleteTitleRequired': 'Entrez un titre d\\'abord'
443
+ }
444
+ };
445
+
446
+ function t(key) {
447
+ return translations[currentLang]?.[key] || translations['en'][key] || key;
448
+ }
449
+
450
+ function updateLangUI() {
451
+ document.querySelectorAll('.lang-btn').forEach(btn => {
452
+ btn.classList.toggle('active', btn.dataset.lang === currentLang);
453
+ });
454
+ document.querySelectorAll('[data-i18n]').forEach(el => {
455
+ el.textContent = t(el.dataset.i18n);
456
+ });
457
+ document.querySelectorAll('[data-i18n-placeholder]').forEach(el => {
458
+ el.placeholder = t(el.dataset.i18nPlaceholder);
459
+ });
460
+ }
461
+
462
+ function addLabel(select) {
463
+ const value = select.value;
464
+ if (value && !selectedLabels.includes(value)) {
465
+ selectedLabels.push(value);
466
+ renderLabels();
467
+ }
468
+ select.value = '';
469
+ }
470
+
471
+ function removeLabel(label) {
472
+ selectedLabels = selectedLabels.filter(l => l !== label);
473
+ renderLabels();
474
+ }
475
+
476
+ function escapeHtml(str) {
477
+ if (!str) return '';
478
+ return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
479
+ }
480
+
481
+ function renderLabels() {
482
+ const container = document.getElementById('selected-labels');
483
+ container.innerHTML = selectedLabels.map(label => {
484
+ const escaped = escapeHtml(label);
485
+ return '<span class="label-tag">' + escaped + ' <span class="remove" onclick="removeLabel(\\'' + escaped + '\\')">×</span></span>';
486
+ }).join('');
487
+ }
488
+
489
+ function addCriteria() {
490
+ const list = document.getElementById('criteria-list');
491
+ const div = document.createElement('div');
492
+ div.className = 'criteria-item';
493
+ div.innerHTML = '<input type="text" placeholder="' + t('newIssue.addCriteria') + '" class="criteria-input"><button class="remove-btn" onclick="this.parentElement.remove()">×</button>';
494
+ list.appendChild(div);
495
+ div.querySelector('input').focus();
496
+ }
497
+
498
+ function getCriteria() {
499
+ return Array.from(document.querySelectorAll('.criteria-input'))
500
+ .map(input => input.value.trim())
501
+ .filter(v => v);
502
+ }
503
+
504
+ async function createIssue() {
505
+ const title = document.getElementById('issue-title').value.trim();
506
+ if (!title) {
507
+ showNotification(t('notify.titleRequired'), true);
508
+ return;
509
+ }
510
+
511
+ const btn = document.getElementById('btn-create');
512
+ btn.disabled = true;
513
+ btn.textContent = t('btn.creating');
514
+
515
+ const payload = {
516
+ title,
517
+ description: document.getElementById('issue-description').value.trim(),
518
+ priority: document.getElementById('issue-priority').value,
519
+ semver: document.getElementById('issue-semver').value,
520
+ column_slug: document.getElementById('issue-column').value,
521
+ labels: selectedLabels,
522
+ acceptance_criteria: getCriteria()
523
+ };
524
+
525
+ try {
526
+ const res = await fetch('/api/issues', {
527
+ method: 'POST',
528
+ headers: { 'Content-Type': 'application/json' },
529
+ body: JSON.stringify(payload)
530
+ });
531
+ const result = await res.json();
532
+ if (result.success) {
533
+ showNotification(t('notify.created'));
534
+ setTimeout(() => {
535
+ window.location.href = '/issue/' + result.data.key;
536
+ }, 1000);
537
+ } else {
538
+ showNotification(t('notify.error') + ': ' + result.error, true);
539
+ btn.disabled = false;
540
+ btn.textContent = t('btn.createIssue');
541
+ }
542
+ } catch (e) {
543
+ showNotification(t('notify.error') + ': ' + e.message, true);
544
+ btn.disabled = false;
545
+ btn.textContent = t('btn.createIssue');
546
+ }
547
+ }
548
+
549
+ function showNotification(msg, isError) {
550
+ const notification = document.getElementById('notification');
551
+ notification.textContent = msg;
552
+ notification.className = 'notification show' + (isError ? ' error' : '');
553
+ setTimeout(() => notification.className = 'notification', 3000);
554
+ }
555
+
556
+ // Language switcher
557
+ document.querySelectorAll('.lang-btn').forEach(btn => {
558
+ btn.addEventListener('click', () => {
559
+ const newLang = btn.dataset.lang;
560
+ if (newLang !== currentLang) {
561
+ currentLang = newLang;
562
+ localStorage.setItem(STORAGE_KEY, newLang);
563
+ updateLangUI();
564
+ }
565
+ });
566
+ });
567
+
568
+ async function autocomplete() {
569
+ const title = document.getElementById('issue-title').value.trim();
570
+ if (!title) {
571
+ showNotification(t('notify.autocompleteTitleRequired'), true);
572
+ return;
573
+ }
574
+
575
+ const btn = document.getElementById('btn-autocomplete');
576
+ const icon = document.getElementById('autocomplete-icon');
577
+ const textSpan = btn.querySelector('[data-i18n="btn.autocomplete"]');
578
+
579
+ btn.disabled = true;
580
+ icon.innerHTML = '<div class="spinner"></div>';
581
+ textSpan.textContent = t('btn.autocompleting');
582
+
583
+ try {
584
+ const res = await fetch('/api/issues/autocomplete', {
585
+ method: 'POST',
586
+ headers: { 'Content-Type': 'application/json' },
587
+ body: JSON.stringify({ title, lang: currentLang })
588
+ });
589
+ const result = await res.json();
590
+
591
+ if (result.success && result.data) {
592
+ const data = result.data;
593
+
594
+ // Fill description
595
+ if (data.description) {
596
+ document.getElementById('issue-description').value = data.description;
597
+ }
598
+
599
+ // Fill priority
600
+ if (data.priority) {
601
+ document.getElementById('issue-priority').value = data.priority;
602
+ }
603
+
604
+ // Fill semver
605
+ if (data.semver) {
606
+ document.getElementById('issue-semver').value = data.semver;
607
+ }
608
+
609
+ // Fill labels
610
+ if (data.labels && Array.isArray(data.labels)) {
611
+ selectedLabels = data.labels.filter(l =>
612
+ ['bug', 'feature', 'enhancement', 'documentation', 'urgent', 'refactoring', 'security', 'performance', 'ui', 'api'].includes(l)
613
+ );
614
+ renderLabels();
615
+ }
616
+
617
+ // Fill acceptance criteria
618
+ if (data.acceptance_criteria && Array.isArray(data.acceptance_criteria)) {
619
+ const list = document.getElementById('criteria-list');
620
+ list.innerHTML = '';
621
+ data.acceptance_criteria.forEach(criterion => {
622
+ const div = document.createElement('div');
623
+ div.className = 'criteria-item';
624
+ div.innerHTML = '<input type="text" class="criteria-input" value="' + escapeHtml(criterion) + '"><button class="remove-btn" onclick="this.parentElement.remove()">×</button>';
625
+ list.appendChild(div);
626
+ });
627
+ }
628
+
629
+ showNotification(t('notify.autocompleteSuccess'));
630
+ } else {
631
+ showNotification(t('notify.error') + ': ' + (result.error || 'Unknown error'), true);
632
+ }
633
+ } catch (e) {
634
+ showNotification(t('notify.error') + ': ' + e.message, true);
635
+ } finally {
636
+ btn.disabled = false;
637
+ icon.innerHTML = '&#10024;';
638
+ textSpan.textContent = t('btn.autocomplete');
639
+ }
640
+ }
641
+
642
+ // Init
643
+ updateLangUI();
644
+ </script>
645
+ </body>
646
+ </html>`;
647
+ }
648
+ //# sourceMappingURL=new-issue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"new-issue.js","sourceRoot":"","sources":["../../../../src/server/dashboard/pages/new-issue.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IAErE,OAAO;cACK,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAmUJ,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,kBAAkB,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,IAAI,GAAG,CAAC,IAAI,WAAW,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAuTjJ,CAAC;AACT,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Unit tests for new-issue.ts
3
+ * Tests for the /issue/new page generation
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=new-issue.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"new-issue.test.d.ts","sourceRoot":"","sources":["../../../../src/server/dashboard/pages/new-issue.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}