@sensolus/create-snt-agent-app 0.1.0 → 0.1.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.
Files changed (42) hide show
  1. package/package.json +1 -1
  2. package/template/CLAUDE.md +218 -0
  3. package/template/Dockerfile +32 -0
  4. package/template/Jenkinsfile +28 -0
  5. package/template/README.md +477 -16
  6. package/template/_env.example +4 -0
  7. package/template/backend/app.py +630 -49
  8. package/template/backend/db_config.py +16 -0
  9. package/template/backend/extensions.py +3 -0
  10. package/template/backend/init_db.py +75 -0
  11. package/template/backend/migrations/README +1 -0
  12. package/template/backend/migrations/alembic.ini +50 -0
  13. package/template/backend/migrations/env.py +113 -0
  14. package/template/backend/migrations/script.py.mako +24 -0
  15. package/template/backend/migrations/versions/001_add_favourite_organisations.py +31 -0
  16. package/template/backend/migrations/versions/002_add_org_daily_stats.py +36 -0
  17. package/template/backend/models.py +31 -0
  18. package/template/backend/requirements.txt +8 -2
  19. package/template/eslint.config.js +6 -2
  20. package/template/index.html +11 -8
  21. package/template/infra/docker-compose.yml +15 -0
  22. package/template/openapi.json +40357 -0
  23. package/template/package.json +8 -1
  24. package/template/scripts/create-ecr-repo.sh +42 -0
  25. package/template/src/App.jsx +12 -34
  26. package/template/src/hooks/useFavourites.js +44 -0
  27. package/template/src/i18n/index.js +3 -0
  28. package/template/src/i18n/messages.js +8 -14
  29. package/template/src/i18n/translations/de.js +96 -0
  30. package/template/src/i18n/translations/en.js +103 -0
  31. package/template/src/i18n/translations/es.js +96 -0
  32. package/template/src/i18n/translations/fr.js +96 -0
  33. package/template/src/i18n/translations/nl.js +96 -0
  34. package/template/src/main.jsx +2 -3
  35. package/template/src/pages/Home.jsx +170 -0
  36. package/template/src/pages/OrganisationDetail.jsx +259 -0
  37. package/template/src/pages/OrganisationList.jsx +457 -0
  38. package/template/src/pages/Overview.jsx +199 -0
  39. package/template/src/pages/WidgetShowcase.jsx +522 -0
  40. package/template/src/styles/app.css +543 -4
  41. package/template/start-backend.sh +4 -0
  42. package/template/start-frontend.sh +3 -0
@@ -1,6 +1,545 @@
1
- /* App-specific styles. Theme variables (--snt-*) come from @sensolus/snt-agent-kit/theme.css */
2
- .app-container {
3
- max-width: 1200px;
4
- margin: 0 auto;
1
+ /* App-specific styles */
2
+
3
+ * {
4
+ box-sizing: border-box;
5
+ margin: 0;
6
+ padding: 0;
7
+ }
8
+
9
+ body {
10
+ font-family: var(--snt-font-family);
11
+ background-color: var(--snt-white);
12
+ }
13
+
14
+ .container {
15
+ max-width: 100%;
5
16
  padding: 16px;
6
17
  }
18
+
19
+ .top-bar {
20
+ display: flex;
21
+ justify-content: space-between;
22
+ align-items: center;
23
+ gap: 16px;
24
+ margin-bottom: 16px;
25
+ flex-wrap: wrap;
26
+ }
27
+
28
+ .search-section {
29
+ display: flex;
30
+ align-items: center;
31
+ gap: 12px;
32
+ flex: 1;
33
+ }
34
+
35
+ .search-section .snt-input {
36
+ max-width: 300px;
37
+ }
38
+
39
+ .auth-toggle {
40
+ display: flex;
41
+ align-items: center;
42
+ gap: 8px;
43
+ font-size: 12px;
44
+ color: var(--snt-grey);
45
+ }
46
+
47
+ .auth-toggle select {
48
+ padding: 4px 8px;
49
+ border: 1px solid var(--snt-grey-light);
50
+ border-radius: var(--snt-border-radius);
51
+ background: var(--snt-white);
52
+ color: var(--snt-blue-darkest);
53
+ font-size: 12px;
54
+ cursor: pointer;
55
+ }
56
+
57
+ .auth-toggle select:focus {
58
+ outline: none;
59
+ border-color: var(--snt-blue);
60
+ }
61
+
62
+ .auth-toggle .snt-input {
63
+ width: 200px;
64
+ padding: 4px 8px;
65
+ font-size: 12px;
66
+ }
67
+
68
+ .auth-toggle .snt-btn {
69
+ padding: 4px 12px;
70
+ font-size: 12px;
71
+ }
72
+
73
+ .error {
74
+ background: var(--snt-blush);
75
+ color: var(--snt-red);
76
+ padding: 12px 16px;
77
+ border-radius: var(--snt-border-radius);
78
+ margin-bottom: 20px;
79
+ }
80
+
81
+ .total-count {
82
+ color: var(--snt-grey);
83
+ margin-bottom: 16px;
84
+ font-size: 14px;
85
+ }
86
+
87
+ /* Card View */
88
+ .org-grid {
89
+ display: grid;
90
+ grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
91
+ gap: 20px;
92
+ }
93
+
94
+ .org-card {
95
+ background: var(--snt-bg-zebra);
96
+ border-radius: var(--snt-border-radius-lg);
97
+ padding: 20px;
98
+ border: 1px solid var(--snt-grey-lightest);
99
+ transition: all 0.2s;
100
+ }
101
+
102
+ .org-card:hover {
103
+ transform: translateY(-4px);
104
+ box-shadow: 0 8px 25px var(--snt-black-10);
105
+ }
106
+
107
+ .org-name {
108
+ font-size: 1.25rem;
109
+ font-weight: 600;
110
+ color: var(--snt-blue-darkest);
111
+ margin-bottom: 8px;
112
+ }
113
+
114
+ .org-type {
115
+ display: inline-block;
116
+ margin-bottom: 12px;
117
+ }
118
+
119
+ .org-details {
120
+ font-size: 14px;
121
+ color: var(--snt-grey);
122
+ }
123
+
124
+ .org-details p {
125
+ margin-bottom: 6px;
126
+ }
127
+
128
+ .org-stat {
129
+ display: flex;
130
+ justify-content: space-between;
131
+ padding: 8px 0;
132
+ border-top: 1px solid var(--snt-grey-lightest);
133
+ }
134
+
135
+ .org-stat:first-of-type {
136
+ margin-top: 12px;
137
+ }
138
+
139
+ .stat-label {
140
+ color: var(--snt-grey);
141
+ }
142
+
143
+ .stat-value {
144
+ font-weight: 600;
145
+ color: var(--snt-blue-darkest);
146
+ }
147
+
148
+ .empty-state {
149
+ text-align: center;
150
+ padding: 60px 20px;
151
+ color: var(--snt-grey);
152
+ }
153
+
154
+ .empty-state svg {
155
+ width: 80px;
156
+ height: 80px;
157
+ margin-bottom: 20px;
158
+ opacity: 0.5;
159
+ }
160
+
161
+ /* Page container */
162
+ .page-container {
163
+ max-width: 100%;
164
+ padding: 24px;
165
+ }
166
+
167
+ /* Header actions */
168
+ .header-actions {
169
+ display: flex;
170
+ align-items: center;
171
+ gap: 12px;
172
+ }
173
+
174
+ .header-actions .snt-select {
175
+ width: 120px;
176
+ }
177
+
178
+ .header-actions .snt-input {
179
+ width: 200px;
180
+ }
181
+
182
+ /* Toolbar row */
183
+ .toolbar-row {
184
+ display: flex;
185
+ align-items: center;
186
+ gap: 16px;
187
+ margin-bottom: 20px;
188
+ }
189
+
190
+ .toolbar-row .snt-input {
191
+ max-width: 300px;
192
+ }
193
+
194
+ /* Org card header with star */
195
+ .org-card-header {
196
+ display: flex;
197
+ justify-content: space-between;
198
+ align-items: flex-start;
199
+ gap: 8px;
200
+ }
201
+
202
+ /* Star favourite button */
203
+ .star-btn {
204
+ background: none;
205
+ border: none;
206
+ cursor: pointer;
207
+ font-size: 1.875rem;
208
+ color: var(--snt-grey-light);
209
+ padding: 2px 4px;
210
+ line-height: 1;
211
+ transition: color 0.15s, transform 0.15s;
212
+ flex-shrink: 0;
213
+ }
214
+
215
+ .star-btn:hover {
216
+ color: var(--snt-yellow);
217
+ transform: scale(1.2);
218
+ }
219
+
220
+ .star-btn.star-active {
221
+ color: var(--snt-yellow);
222
+ }
223
+
224
+ /* Clickable org card */
225
+ .org-card-clickable {
226
+ cursor: pointer;
227
+ }
228
+
229
+ /* Link button style */
230
+ .link-button {
231
+ background: none;
232
+ border: none;
233
+ color: var(--snt-blue);
234
+ cursor: pointer;
235
+ font: inherit;
236
+ padding: 0;
237
+ text-decoration: underline;
238
+ }
239
+
240
+ .link-button:hover {
241
+ color: var(--snt-blue-darker);
242
+ }
243
+
244
+ /* Detail page SntCard spacing */
245
+ .page-container .snt-card {
246
+ margin-bottom: 24px;
247
+ }
248
+
249
+ .page-container .snt-card:last-child {
250
+ margin-bottom: 0;
251
+ }
252
+
253
+ /* Summary Stats Row */
254
+ .summary-stats-row {
255
+ display: flex;
256
+ gap: 16px;
257
+ margin-bottom: 24px;
258
+ flex-wrap: wrap;
259
+ }
260
+
261
+ .summary-stats-row .summary-stat {
262
+ flex: 1;
263
+ min-width: 150px;
264
+ background: var(--snt-bg-zebra);
265
+ border: 1px solid var(--snt-grey-lightest);
266
+ border-radius: var(--snt-border-radius-lg);
267
+ padding: 16px 20px;
268
+ text-align: center;
269
+ }
270
+
271
+ .summary-stats-row .summary-value {
272
+ font-size: 1.75rem;
273
+ font-weight: 700;
274
+ color: var(--snt-blue-darkest);
275
+ display: block;
276
+ }
277
+
278
+ .summary-stats-row .summary-label {
279
+ font-size: 0.875rem;
280
+ color: var(--snt-grey);
281
+ display: block;
282
+ margin-top: 4px;
283
+ }
284
+
285
+ .summary-stats-row .summary-stat-info .summary-value {
286
+ color: var(--snt-infra);
287
+ }
288
+
289
+ .summary-stats-row .summary-stat-success .summary-value {
290
+ color: var(--snt-green);
291
+ }
292
+
293
+ .summary-stats-row .summary-stat-warning .summary-value {
294
+ color: var(--snt-yellow-dark, #CC9900);
295
+ }
296
+
297
+ .summary-stats-row .summary-stat-danger .summary-value {
298
+ color: var(--snt-red);
299
+ }
300
+
301
+ .summary-stats-row .summary-stat-warning .summary-value {
302
+ color: var(--snt-yellow);
303
+ }
304
+
305
+ .summary-stat-clickable {
306
+ cursor: pointer;
307
+ transition: box-shadow 0.15s, border-color 0.15s, transform 0.1s;
308
+ user-select: none;
309
+ }
310
+
311
+ .summary-stat-clickable:hover {
312
+ box-shadow: 0 2px 8px var(--snt-black-10);
313
+ }
314
+
315
+ .summary-stat-clickable:active {
316
+ transform: scale(0.97);
317
+ }
318
+
319
+ .summary-stat-active {
320
+ border-color: var(--snt-blue);
321
+ box-shadow: 0 0 0 2px var(--snt-blue-light);
322
+ }
323
+
324
+ /* Page with Sidepanel Layout */
325
+ .page-with-sidepanel {
326
+ display: flex;
327
+ gap: 24px;
328
+ align-items: flex-start;
329
+ }
330
+
331
+ .page-main-content {
332
+ flex: 1;
333
+ min-width: 0;
334
+ transition: opacity 0.15s;
335
+ }
336
+
337
+ .page-main-content.content-pending {
338
+ opacity: 0.5;
339
+ pointer-events: none;
340
+ }
341
+
342
+ /* Filter count text */
343
+ .filter-count {
344
+ color: var(--snt-grey);
345
+ font-size: 14px;
346
+ }
347
+
348
+ .toolbar-row {
349
+ display: flex;
350
+ align-items: center;
351
+ justify-content: space-between;
352
+ gap: 16px;
353
+ margin-bottom: 20px;
354
+ }
355
+
356
+ /* Slider styling */
357
+ .snt-slider {
358
+ width: 100%;
359
+ height: 6px;
360
+ border-radius: 3px;
361
+ background: var(--snt-grey-light);
362
+ outline: none;
363
+ -webkit-appearance: none;
364
+ appearance: none;
365
+ cursor: pointer;
366
+ }
367
+
368
+ .snt-slider::-webkit-slider-thumb {
369
+ -webkit-appearance: none;
370
+ appearance: none;
371
+ width: 18px;
372
+ height: 18px;
373
+ border-radius: 50%;
374
+ background: var(--snt-blue);
375
+ cursor: pointer;
376
+ border: 2px solid var(--snt-white);
377
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
378
+ }
379
+
380
+ .snt-slider::-moz-range-thumb {
381
+ width: 18px;
382
+ height: 18px;
383
+ border-radius: 50%;
384
+ background: var(--snt-blue);
385
+ cursor: pointer;
386
+ border: 2px solid var(--snt-white);
387
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
388
+ }
389
+
390
+ .snt-slider:hover::-webkit-slider-thumb {
391
+ background: var(--snt-blue-darker);
392
+ }
393
+
394
+ .snt-slider:hover::-moz-range-thumb {
395
+ background: var(--snt-blue-darker);
396
+ }
397
+
398
+ /* Map widget */
399
+ .snt-map-container {
400
+ border: 1px solid var(--snt-grey-light);
401
+ border-radius: var(--snt-border-radius-lg);
402
+ overflow: hidden;
403
+ }
404
+
405
+ .snt-map-container .leaflet-container {
406
+ font-family: var(--snt-font-family);
407
+ }
408
+
409
+ .snt-cluster {
410
+ position: absolute;
411
+ top: 0;
412
+ left: 0;
413
+ color: #fff;
414
+ font-size: 11px;
415
+ font-weight: bold;
416
+ text-align: center;
417
+ width: 100%;
418
+ height: 100%;
419
+ display: flex;
420
+ align-items: center;
421
+ justify-content: center;
422
+ line-height: 1;
423
+ }
424
+
425
+ .snt-device-label {
426
+ background: none;
427
+ border: none;
428
+ box-shadow: none;
429
+ color: var(--snt-blue-darkest);
430
+ font-size: 11px;
431
+ font-weight: 600;
432
+ white-space: nowrap;
433
+ padding: 0;
434
+ }
435
+
436
+ .snt-device-label::before {
437
+ display: none;
438
+ }
439
+
440
+ /* Widget Showcase page */
441
+ .widget-showcase .snt-card {
442
+ margin-bottom: 24px;
443
+ }
444
+
445
+ .showcase-section-body {
446
+ display: flex;
447
+ flex-direction: column;
448
+ gap: 16px;
449
+ }
450
+
451
+ .showcase-example {
452
+ display: flex;
453
+ flex-direction: column;
454
+ gap: 6px;
455
+ }
456
+
457
+ .showcase-example-label {
458
+ font-size: 12px;
459
+ font-weight: 600;
460
+ text-transform: uppercase;
461
+ letter-spacing: 0.04em;
462
+ color: var(--snt-grey);
463
+ }
464
+
465
+ .showcase-row {
466
+ display: flex;
467
+ flex-wrap: wrap;
468
+ gap: 8px;
469
+ align-items: flex-start;
470
+ }
471
+
472
+ .showcase-stack {
473
+ display: flex;
474
+ flex-direction: column;
475
+ gap: 8px;
476
+ max-width: 320px;
477
+ }
478
+
479
+ .showcase-grid-cell {
480
+ background: var(--snt-bg-zebra);
481
+ border: 1px solid var(--snt-grey-lightest);
482
+ border-radius: var(--snt-border-radius);
483
+ padding: 16px;
484
+ text-align: center;
485
+ color: var(--snt-grey);
486
+ font-size: 13px;
487
+ }
488
+
489
+ .showcase-sidepanel-demo {
490
+ display: flex;
491
+ gap: 16px;
492
+ align-items: stretch;
493
+ min-height: 240px;
494
+ }
495
+
496
+ .showcase-sidepanel-content {
497
+ flex: 1;
498
+ background: var(--snt-bg-zebra);
499
+ border: 1px solid var(--snt-grey-lightest);
500
+ border-radius: var(--snt-border-radius);
501
+ padding: 16px;
502
+ color: var(--snt-grey);
503
+ }
504
+
505
+ .showcase-color-grid {
506
+ display: grid;
507
+ grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
508
+ gap: 8px;
509
+ }
510
+
511
+ .showcase-color-swatch {
512
+ display: flex;
513
+ align-items: center;
514
+ gap: 10px;
515
+ padding: 6px;
516
+ border: 1px solid var(--snt-grey-lightest);
517
+ border-radius: var(--snt-border-radius);
518
+ background: var(--snt-white);
519
+ }
520
+
521
+ .showcase-color-chip {
522
+ width: 36px;
523
+ height: 36px;
524
+ border-radius: 6px;
525
+ border: 1px solid var(--snt-grey-lightest);
526
+ flex-shrink: 0;
527
+ }
528
+
529
+ .showcase-color-meta {
530
+ display: flex;
531
+ flex-direction: column;
532
+ min-width: 0;
533
+ }
534
+
535
+ .showcase-color-name {
536
+ font-size: 13px;
537
+ font-weight: 600;
538
+ color: var(--snt-blue-darkest);
539
+ }
540
+
541
+ .showcase-color-value {
542
+ font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
543
+ font-size: 11px;
544
+ color: var(--snt-grey);
545
+ }
@@ -0,0 +1,4 @@
1
+ #!/bin/bash
2
+ cd "$(dirname "$0")/backend"
3
+ source .venv/bin/activate
4
+ python app.py
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+ cd "$(dirname "$0")"
3
+ npm run dev