@mxtommy/kip 4.5.0-beta.1 → 4.5.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 (102) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +11 -7
  3. package/package.json +21 -8
  4. package/plugin/duckdb-parquet-storage.service.js +1182 -0
  5. package/plugin/history-series.service.js +439 -0
  6. package/plugin/index.js +705 -30
  7. package/plugin/openApi.json +253 -3
  8. package/plugin/plugin-auth.service.js +75 -0
  9. package/public/assets/help-docs/chartplotter.md +5 -18
  10. package/public/assets/help-docs/community.md +0 -3
  11. package/public/assets/help-docs/configuration.md +1 -1
  12. package/public/assets/help-docs/contact-us.md +0 -4
  13. package/public/assets/help-docs/dashboards.md +20 -18
  14. package/public/assets/help-docs/datainspector.md +7 -5
  15. package/public/assets/help-docs/history-api.md +116 -0
  16. package/public/assets/help-docs/menu.json +18 -6
  17. package/public/assets/help-docs/nodered-control-flows.md +125 -0
  18. package/public/assets/help-docs/putcontrols.md +101 -60
  19. package/public/assets/help-docs/welcome.md +6 -7
  20. package/public/assets/help-docs/widget-historical-series.md +66 -0
  21. package/public/assets/help-docs/zones.md +5 -10
  22. package/public/chunk-A6DQJFP4.js +16 -0
  23. package/public/chunk-B75MT7ND.js +1 -0
  24. package/public/{chunk-T6TFVZVM.js → chunk-CEB42O2C.js} +1 -1
  25. package/public/chunk-CHGXAEKT.js +2 -0
  26. package/public/chunk-D7VDX7ZF.js +5 -0
  27. package/public/{chunk-ZQER6AIQ.js → chunk-DEGYRCMI.js} +1 -1
  28. package/public/{chunk-M2B5OYGO.js → chunk-DEM56G4S.js} +1 -1
  29. package/public/chunk-DYTBBUMI.js +4 -0
  30. package/public/chunk-EQ2N7KDA.js +3 -0
  31. package/public/chunk-FNF7M3AE.js +1 -0
  32. package/public/chunk-IHURI4IH.js +5 -0
  33. package/public/{chunk-YIYYVDFO.js → chunk-IYRLINL7.js} +2 -2
  34. package/public/{chunk-5FEX27I4.js → chunk-JB4YVVNW.js} +1 -1
  35. package/public/chunk-JGGMFMY5.js +1 -0
  36. package/public/chunk-KPHICV76.js +5 -0
  37. package/public/{chunk-QZKCRH3H.js → chunk-KZ5DUKAX.js} +1 -1
  38. package/public/{chunk-HMOOTAEA.js → chunk-LQDSU4WS.js} +3 -3
  39. package/public/{chunk-IXQ7KIFY.js → chunk-MGPPVLZ7.js} +1 -1
  40. package/public/{chunk-QVCLOCEC.js → chunk-R7RQHWKJ.js} +1 -1
  41. package/public/chunk-RONXIZ2U.js +9 -0
  42. package/public/chunk-S72JTJPN.js +6 -0
  43. package/public/{chunk-KFFAA7DL.js → chunk-VCY32MWT.js} +8 -8
  44. package/public/chunk-YCEXTKGG.js +1 -0
  45. package/public/chunk-YKJKIWXO.js +6 -0
  46. package/public/chunk-ZV7IYYEQ.js +50 -0
  47. package/public/index.html +1 -1
  48. package/public/main-FQESQQV6.js +1 -0
  49. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -84
  50. package/.github/ISSUE_TEMPLATE/config.yml +0 -5
  51. package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -35
  52. package/.github/copilot-instructions.md +0 -205
  53. package/.github/instructions/angular.instructions.md +0 -123
  54. package/.github/instructions/best-practices.instructions.md +0 -59
  55. package/.github/instructions/project.instructions.md +0 -432
  56. package/.github/workflows/ci.yml +0 -37
  57. package/docs/widget-schematic.md +0 -102
  58. package/images/ActionSidenav.png +0 -0
  59. package/images/ChartplotterMode.png +0 -0
  60. package/images/KIPDemo.png +0 -0
  61. package/images/KipBrightness-1024.png +0 -0
  62. package/images/KipConfig-Units-1024.png +0 -0
  63. package/images/KipConfig-display-1024x488.png +0 -0
  64. package/images/KipFreeboard-SK-1024.png +0 -0
  65. package/images/KipGaugeSample1-1024x545.png +0 -0
  66. package/images/KipGaugeSample2-1024x488.png +0 -0
  67. package/images/KipGaugeSample3-1024x508.png +0 -0
  68. package/images/KipNightMode-1024.png +0 -0
  69. package/images/KipWidgetConfig-layout-1024.png +0 -0
  70. package/images/KipWidgetConfig-paths-1024x488.png +0 -0
  71. package/images/Options.png +0 -0
  72. package/images/exterior_user_installs.png +0 -0
  73. package/images/formfactor.png +0 -0
  74. package/public/assets/help-docs/datasets.md +0 -95
  75. package/public/chunk-2OB7ZJBR.js +0 -3
  76. package/public/chunk-6GGJZDRE.js +0 -1
  77. package/public/chunk-6V4GGGXE.js +0 -2
  78. package/public/chunk-A5BW6BUM.js +0 -1
  79. package/public/chunk-DGE5YFPU.js +0 -5
  80. package/public/chunk-G6M3Z3BY.js +0 -53
  81. package/public/chunk-GMGZLXY7.js +0 -4
  82. package/public/chunk-GUZ3BDVZ.js +0 -2
  83. package/public/chunk-ICDGHQFP.js +0 -6
  84. package/public/chunk-JCNE4QHQ.js +0 -15
  85. package/public/chunk-K6XYUNG4.js +0 -8
  86. package/public/chunk-LGCQEN7V.js +0 -4
  87. package/public/chunk-O3JH7UTR.js +0 -1
  88. package/public/chunk-Q3USFT4F.js +0 -2
  89. package/public/chunk-VIKU7BH7.js +0 -1
  90. package/public/chunk-XMQPXXLW.js +0 -8
  91. package/public/main-4URMGBQS.js +0 -1
  92. package/rm-npmjs-beta.sh +0 -50
  93. package/tools/schematics/collection.json +0 -9
  94. package/tools/schematics/create-host2-widget/files/readme/README.md.template +0 -109
  95. package/tools/schematics/create-host2-widget/files/spec/widget-__name@dasherize__.component.spec.ts +0 -38
  96. package/tools/schematics/create-host2-widget/files/widget/widget-__name@dasherize__.component.html +0 -6
  97. package/tools/schematics/create-host2-widget/files/widget/widget-__name@dasherize__.component.scss +0 -5
  98. package/tools/schematics/create-host2-widget/files/widget/widget-__name@dasherize__.component.ts.template +0 -94
  99. package/tools/schematics/create-host2-widget/index.js +0 -138
  100. package/tools/schematics/create-host2-widget/schema.json +0 -89
  101. package/tools/schematics/create-host2-widget/test/create-host2-widget.spec.ts +0 -70
  102. package/tools/schematics/create-host2-widget/utils/formatting.js +0 -119
@@ -1,70 +0,0 @@
1
- import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
2
- import { Tree } from '@angular-devkit/schematics';
3
- import * as path from 'path';
4
-
5
- // Path to collection.json
6
- const collectionPath = path.join(__dirname, '..', 'collection.json').replace(/test\/[.][.]/, '..');
7
-
8
- describe('create-host2-widget schematic', () => {
9
- const runner = new SchematicTestRunner('kip-schematics', collectionPath);
10
- let appTree: UnitTestTree;
11
-
12
- beforeEach(() => {
13
- // Minimal host tree with widget.service.ts skeleton to exercise mutations
14
- appTree = new UnitTestTree(Tree.empty());
15
- appTree.create('src/app/core/services/widget.service.ts', `import { Type } from '@angular/core';\nexport interface WidgetDescription { selector: string; componentClassName: string; category: string; name: string; description: string; icon: string; minWidth: number; minHeight: number; defaultWidth: number; defaultHeight: number; requiredPlugins: string[]; }\nexport class WidgetService {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private readonly _componentTypeMap: Record<string, Type<any>> = {\n };\n private readonly _widgetDefinition: readonly WidgetDescription[] = [\n ];\n}`);
16
- });
17
-
18
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
19
- function run(options: Record<string, any>) {
20
- return runner.runSchematic('create-host2-widget', {
21
- name: 'alpha', title: 'Alpha', registerWidget: 'Core',
22
- pathType: 'number', pathDefault: null, ignoreZones: false,
23
- addSpec: false, todoBlock: false, readme: false,
24
- ...options
25
- }, appTree);
26
- }
27
-
28
- it('generates widget files', async () => {
29
- const tree = await run({});
30
- expect(tree.exists('src/app/widgets/widget-alpha/widget-alpha.component.ts')).toBeTrue();
31
- });
32
-
33
- it('updates service: import, map, definition', async () => {
34
- const tree = await run({});
35
- const service = tree.read('src/app/core/services/widget.service.ts')!.toString('utf-8');
36
- expect(service).toContain("import { WidgetAlphaComponent } from '../../widgets/widget-alpha/widget-alpha.component'");
37
- expect(service).toMatch(/_componentTypeMap[\s\S]*WidgetAlphaComponent: WidgetAlphaComponent/);
38
- expect(service).toMatch(/selector: 'widget-alpha'/);
39
- });
40
-
41
- it('inserts second widget in same category after first', async () => {
42
- let tree = await run({});
43
- appTree = tree; // carry over
44
- tree = await run({ name: 'beta', title: 'Beta' });
45
- const service = tree.read('src/app/core/services/widget.service.ts')!.toString('utf-8');
46
- const alphaIdx = service.indexOf("selector: 'widget-alpha'");
47
- const betaIdx = service.indexOf("selector: 'widget-beta'");
48
- expect(alphaIdx).toBeGreaterThan(-1);
49
- expect(betaIdx).toBeGreaterThan(-1);
50
- expect(betaIdx).toBeGreaterThan(alphaIdx); // inserted after
51
- });
52
-
53
- it('is idempotent (running with same name does not duplicate)', async () => {
54
- let tree = await run({});
55
- appTree = tree;
56
- tree = await run({});
57
- const service = tree.read('src/app/core/services/widget.service.ts')!.toString('utf-8');
58
- const occurrences = (service.match(/selector: 'widget-alpha'/g) || []).length;
59
- expect(occurrences).toBe(1);
60
- });
61
-
62
- it('skips registration when registerWidget = no', async () => {
63
- const tree = await run({ name: 'gamma', title: 'Gamma', registerWidget: 'no' });
64
- const service = tree.read('src/app/core/services/widget.service.ts')!.toString('utf-8');
65
- expect(service).not.toContain('WidgetGammaComponent');
66
- expect(service).not.toContain("selector: 'widget-gamma'");
67
- // component file still generated
68
- expect(tree.exists('src/app/widgets/widget-gamma/widget-gamma.component.ts')).toBeTrue();
69
- });
70
- });
@@ -1,119 +0,0 @@
1
- // JavaScript utility helpers for widget.service.ts mutation formatting & insertion logic
2
- // Converted from TypeScript version.
3
-
4
- function escapeSingle(str) {
5
- return str.replace(/'/g, "\\'");
6
- }
7
-
8
- function buildWidgetDefinitionObject(selector, className, opts) {
9
- return `{
10
- name: '${opts.title}',
11
- description: '${escapeSingle(opts.description)}',
12
- icon: '${opts.icon}', // TODO replace placeholder icon
13
- minWidth: ${opts.minWidth},
14
- minHeight: ${opts.minHeight},
15
- defaultWidth: ${opts.defaultWidth},
16
- defaultHeight: ${opts.defaultHeight},
17
- category: '${opts.category}',
18
- requiredPlugins: [],
19
- selector: '${selector}',
20
- componentClassName: '${className}'
21
- },`;
22
- }
23
-
24
- function appendImport(src, importStatement) {
25
- if (src.includes(importStatement)) return src;
26
- const importBlockRegex = /^(?:import[^;]+;\s*)+/m;
27
- if (importBlockRegex.test(src)) {
28
- return src.replace(importBlockRegex, (block) => {
29
- const normalized = block.replace(/\n*$/, '');
30
- return normalized + '\n' + importStatement + '\n\n';
31
- });
32
- }
33
- return importStatement + '\n\n' + src;
34
- }
35
-
36
- function updateComponentMap(src, className) {
37
- const mapPattern = /_componentTypeMap: Record<string, Type<any>> = {([\s\S]*?)};/m;
38
- return src.replace(mapPattern, (m, inner) => {
39
- if (inner.includes(className + ':')) return m;
40
- const lines = inner.split(/\n/);
41
- while (lines.length && lines[lines.length - 1].trim() === '') lines.pop();
42
- for (let i = lines.length - 1; i >= 0; i--) {
43
- const trimmed = lines[i].trim();
44
- if (!trimmed) continue;
45
- if (!trimmed.includes(':')) break;
46
- if (!trimmed.endsWith(',')) lines[i] = lines[i] + ',';
47
- break;
48
- }
49
- lines.push(` ${className}: ${className}`);
50
- // Replace inner content, then normalize closing brace indentation to two spaces
51
- let replaced = m.replace(inner, lines.join('\n') + '\n');
52
- replaced = replaced.replace(/\n *};/, '\n };');
53
- return replaced;
54
- });
55
- }
56
-
57
- function normalizeDefinitionFormatting(content, baseIndent) {
58
- let rebuilt = content;
59
- // Remove any blank line(s) between objects: ensure pattern `},\n{` with exactly one newline
60
- rebuilt = rebuilt.replace(/},\n\n+(\s*{)/g, '},\n$1');
61
- // Remove blank line before closing array
62
- rebuilt = rebuilt.replace(/,\n\n(\s*])/g, ',\n$1');
63
- // Remove stray duplicate blank lines inside objects
64
- rebuilt = rebuilt.replace(/({\n)([ \t]*\n)+/g, '$1');
65
- rebuilt = rebuilt.replace(/\n\s*\n(\s+\w+:)/g, '\n$1');
66
- // Normalize opening brace indentation
67
- rebuilt = rebuilt.replace(/^(\s*){(?=\n)/gm, baseIndent + '{');
68
- // Collapse any 2+ blank lines to single newline
69
- rebuilt = rebuilt.replace(/\n{2,}/g, '\n');
70
- // Remove any trailing blank lines; do NOT force an extra newline because the array pattern supplies one before the closing ];
71
- return rebuilt.replace(/\n\s*$/,'');
72
- }
73
-
74
- function insertDefinitionObject(src, selector, className, opts) {
75
- const defArrayPattern = /private readonly _widgetDefinition: readonly WidgetDescription\[] = \[(\s*[\s\S]*?)\n\s*];/m;
76
- return src.replace(defArrayPattern, (m, inner) => {
77
- if (inner.includes(`selector: '${selector}'`)) return m;
78
- let defObj = buildWidgetDefinitionObject(selector, className, opts).trim();
79
- defObj = defObj.startsWith('{') ? defObj : '{' + defObj;
80
- defObj = defObj.replace(/\n{2,}/g, '\n');
81
- const linesDef = defObj.split(/\n/).map(l => l.trimEnd());
82
- const openIdx = 0; const closeIdx = linesDef.length - 1;
83
- const indentMatch = inner.match(/^(\s*){/m);
84
- const baseIndent = indentMatch ? indentMatch[1] : ' ';
85
- const firstLine = baseIndent + '{';
86
- const lastLine = baseIndent + linesDef[closeIdx].trim();
87
- const middle = linesDef.slice(openIdx + 1, closeIdx).filter(l => l.trim().length > 0).map(l => baseIndent + ' ' + l.trim());
88
- defObj = [firstLine, ...middle, lastLine].join('\n');
89
- const objectRegex = /{[\s\S]*?},\n?/g;
90
- const objects = inner.match(objectRegex) || [];
91
- if (objects.length === 0) {
92
- return m.replace(inner, defObj + '\n');
93
- }
94
- const metas = objects.map(o => ({ text: o, category: (o.match(/category: '([^']+)'/) || [])[1] }));
95
- let insertAfter = -1;
96
- for (let i = 0; i < metas.length; i++) {
97
- if (metas[i].category === opts.category) insertAfter = i;
98
- }
99
- const formattedNew = defObj + '\n';
100
- let rebuilt = '';
101
- metas.forEach((meta, idx) => {
102
- const normalized = meta.text.endsWith('\n') ? meta.text : meta.text + '\n';
103
- rebuilt += normalized;
104
- if (idx === insertAfter) rebuilt += formattedNew; // inserted immediately, no extra blank line expected
105
- });
106
- if (insertAfter === -1) rebuilt += formattedNew; // appended at end
107
- rebuilt = normalizeDefinitionFormatting(rebuilt, baseIndent);
108
- return m.replace(inner, rebuilt);
109
- });
110
- }
111
-
112
- module.exports = {
113
- escapeSingle,
114
- buildWidgetDefinitionObject,
115
- appendImport,
116
- updateComponentMap,
117
- insertDefinitionObject,
118
- normalizeDefinitionFormatting
119
- };