@pilotiq/pilotiq 0.1.0 → 0.3.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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +14 -0
- package/CLAUDE.md +6 -5
- package/dist/Pilotiq.d.ts +20 -1
- package/dist/Pilotiq.d.ts.map +1 -1
- package/dist/Pilotiq.js.map +1 -1
- package/dist/actions/Action.d.ts +25 -0
- package/dist/actions/Action.d.ts.map +1 -1
- package/dist/actions/Action.js +25 -0
- package/dist/actions/Action.js.map +1 -1
- package/dist/elements/dispatchForm.d.ts +0 -14
- package/dist/elements/dispatchForm.d.ts.map +1 -1
- package/dist/elements/dispatchForm.js +28 -0
- package/dist/elements/dispatchForm.js.map +1 -1
- package/dist/fields/BuilderField.d.ts +27 -1
- package/dist/fields/BuilderField.d.ts.map +1 -1
- package/dist/fields/BuilderField.js +36 -1
- package/dist/fields/BuilderField.js.map +1 -1
- package/dist/fields/FileUploadField.d.ts +65 -0
- package/dist/fields/FileUploadField.d.ts.map +1 -1
- package/dist/fields/FileUploadField.js +72 -0
- package/dist/fields/FileUploadField.js.map +1 -1
- package/dist/fields/RepeaterField.d.ts +34 -1
- package/dist/fields/RepeaterField.d.ts.map +1 -1
- package/dist/fields/RepeaterField.js +43 -1
- package/dist/fields/RepeaterField.js.map +1 -1
- package/dist/fields/RowButton.d.ts +9 -2
- package/dist/fields/RowButton.d.ts.map +1 -1
- package/dist/fields/TextField.d.ts +106 -0
- package/dist/fields/TextField.d.ts.map +1 -1
- package/dist/fields/TextField.js +115 -0
- package/dist/fields/TextField.js.map +1 -1
- package/dist/filters/queryBuilder/Constraint.d.ts +1 -1
- package/dist/filters/queryBuilder/Constraint.d.ts.map +1 -1
- package/dist/filters/queryBuilder/TextConstraint.d.ts.map +1 -1
- package/dist/filters/queryBuilder/TextConstraint.js +2 -3
- package/dist/filters/queryBuilder/TextConstraint.js.map +1 -1
- package/dist/orm/modelDefaults.d.ts +1 -1
- package/dist/orm/modelDefaults.d.ts.map +1 -1
- package/dist/react/SchemaRenderer.d.ts.map +1 -1
- package/dist/react/SchemaRenderer.js +108 -7
- package/dist/react/SchemaRenderer.js.map +1 -1
- package/dist/react/fields/BuilderInput.d.ts.map +1 -1
- package/dist/react/fields/BuilderInput.js +32 -3
- package/dist/react/fields/BuilderInput.js.map +1 -1
- package/dist/react/fields/FieldShell.d.ts +9 -1
- package/dist/react/fields/FieldShell.d.ts.map +1 -1
- package/dist/react/fields/FieldShell.js +4 -3
- package/dist/react/fields/FieldShell.js.map +1 -1
- package/dist/react/fields/FileUploadInput.d.ts +17 -4
- package/dist/react/fields/FileUploadInput.d.ts.map +1 -1
- package/dist/react/fields/FileUploadInput.js +204 -25
- package/dist/react/fields/FileUploadInput.js.map +1 -1
- package/dist/react/fields/RepeaterInput.d.ts.map +1 -1
- package/dist/react/fields/RepeaterInput.js +33 -2
- package/dist/react/fields/RepeaterInput.js.map +1 -1
- package/dist/react/fields/TextLikeInput.d.ts +5 -1
- package/dist/react/fields/TextLikeInput.d.ts.map +1 -1
- package/dist/react/fields/TextLikeInput.js +17 -2
- package/dist/react/fields/TextLikeInput.js.map +1 -1
- package/dist/react/fields/rowChromeButton.d.ts +24 -5
- package/dist/react/fields/rowChromeButton.d.ts.map +1 -1
- package/dist/react/fields/rowChromeButton.js +51 -8
- package/dist/react/fields/rowChromeButton.js.map +1 -1
- package/dist/react/fields/textInputControls.d.ts +47 -0
- package/dist/react/fields/textInputControls.d.ts.map +1 -0
- package/dist/react/fields/textInputControls.js +134 -0
- package/dist/react/fields/textInputControls.js.map +1 -0
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +32 -1
- package/dist/routes.js.map +1 -1
- package/dist/schema/Alert.d.ts +58 -0
- package/dist/schema/Alert.d.ts.map +1 -1
- package/dist/schema/Alert.js +68 -1
- package/dist/schema/Alert.js.map +1 -1
- package/dist/schema/resolveSchema.d.ts.map +1 -1
- package/dist/schema/resolveSchema.js +32 -0
- package/dist/schema/resolveSchema.js.map +1 -1
- package/package.json +12 -11
- package/src/Pilotiq.test.ts +78 -0
- package/src/Pilotiq.ts +20 -1
- package/src/actions/Action.test.ts +47 -0
- package/src/actions/Action.ts +35 -0
- package/src/elements/dispatchForm.ts +28 -0
- package/src/fields/BuilderField.ts +38 -1
- package/src/fields/FileUploadField.test.ts +46 -0
- package/src/fields/FileUploadField.ts +90 -2
- package/src/fields/RepeaterField.ts +45 -1
- package/src/fields/RowButton.test.ts +70 -0
- package/src/fields/RowButton.ts +11 -1
- package/src/fields/TextField.test.ts +168 -0
- package/src/fields/TextField.ts +141 -1
- package/src/filters/QueryBuilderFilter.test.ts +18 -0
- package/src/filters/queryBuilder/Constraint.ts +1 -1
- package/src/filters/queryBuilder/TextConstraint.ts +5 -6
- package/src/orm/modelDefaults.ts +1 -1
- package/src/react/SchemaRenderer.tsx +222 -14
- package/src/react/fields/BuilderInput.tsx +37 -0
- package/src/react/fields/FieldShell.tsx +13 -2
- package/src/react/fields/FileUploadInput.tsx +516 -85
- package/src/react/fields/RepeaterInput.tsx +39 -0
- package/src/react/fields/TextLikeInput.tsx +22 -2
- package/src/react/fields/rowChromeButton.tsx +102 -6
- package/src/react/fields/textInputControls.tsx +238 -0
- package/src/routes.ts +33 -1
- package/src/schema/Alert.test.ts +46 -0
- package/src/schema/Alert.ts +90 -8
- package/src/schema/resolveSchema.ts +32 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useCallback } from 'react';
|
|
3
|
+
import { useToast } from '../Toaster.js';
|
|
4
|
+
/** `renderAction(meta)` is supplied by the caller (SchemaRenderer's
|
|
5
|
+
* `renderElement`) to avoid an import cycle between the controls
|
|
6
|
+
* module and the main schema renderer. */
|
|
7
|
+
export function useTextInputControls(el, name, renderAction) {
|
|
8
|
+
const isPassword = el['password'] === true;
|
|
9
|
+
const isRevealable = el['revealable'] === true;
|
|
10
|
+
const isCopyable = el['copyable'] === true;
|
|
11
|
+
const copyMessage = el['copyMessage'] ?? 'Copied!';
|
|
12
|
+
const mask = el['mask'];
|
|
13
|
+
const prefixAct = el['prefixAction'];
|
|
14
|
+
const suffixAct = el['suffixAction'];
|
|
15
|
+
const [revealed, setRevealed] = useState(false);
|
|
16
|
+
const inputId = name;
|
|
17
|
+
const onCopy = useCopyHandler(inputId, copyMessage);
|
|
18
|
+
const type = isPassword && !revealed ? 'password' : 'text';
|
|
19
|
+
const beforeNodes = [];
|
|
20
|
+
if (prefixAct)
|
|
21
|
+
beforeNodes.push(_jsx("div", { className: "shrink-0", children: renderAction(prefixAct) }, "pre-act"));
|
|
22
|
+
const afterNodes = [];
|
|
23
|
+
if (isCopyable)
|
|
24
|
+
afterNodes.push(_jsx(CopyButton, { onCopy: onCopy }, "copy"));
|
|
25
|
+
if (isRevealable && isPassword) {
|
|
26
|
+
afterNodes.push(_jsx(RevealToggle, { revealed: revealed, onToggle: () => setRevealed(v => !v) }, "reveal"));
|
|
27
|
+
}
|
|
28
|
+
if (suffixAct)
|
|
29
|
+
afterNodes.push(_jsx("div", { className: "shrink-0", children: renderAction(suffixAct) }, "suf-act"));
|
|
30
|
+
const applyMask = useCallback((value) => {
|
|
31
|
+
if (!mask)
|
|
32
|
+
return value;
|
|
33
|
+
return formatWithMask(value, mask);
|
|
34
|
+
}, [mask]);
|
|
35
|
+
return {
|
|
36
|
+
before: beforeNodes.length > 0 ? _jsx(_Fragment, { children: beforeNodes }) : null,
|
|
37
|
+
after: afterNodes.length > 0 ? _jsx(_Fragment, { children: afterNodes }) : null,
|
|
38
|
+
type,
|
|
39
|
+
applyMask,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Format `raw` against `mask` using the documented alphabet. Literals
|
|
44
|
+
* in the mask render verbatim and consume no source character; pattern
|
|
45
|
+
* tokens consume the next matching source character (skipping
|
|
46
|
+
* mismatches so the user can paste an already-formatted value and have
|
|
47
|
+
* it re-format cleanly).
|
|
48
|
+
*/
|
|
49
|
+
export function formatWithMask(raw, mask) {
|
|
50
|
+
let out = '';
|
|
51
|
+
let r = 0;
|
|
52
|
+
for (let m = 0; m < mask.length; m++) {
|
|
53
|
+
const token = mask[m];
|
|
54
|
+
const isPattern = token === '9' || token === 'a' || token === '*';
|
|
55
|
+
if (isPattern) {
|
|
56
|
+
if (r >= raw.length)
|
|
57
|
+
break;
|
|
58
|
+
// Advance through `raw` until we find a matching character.
|
|
59
|
+
while (r < raw.length) {
|
|
60
|
+
const ch = raw[r];
|
|
61
|
+
const ok = token === '9'
|
|
62
|
+
? /[0-9]/.test(ch)
|
|
63
|
+
: token === 'a'
|
|
64
|
+
? /[A-Za-z]/.test(ch)
|
|
65
|
+
: true;
|
|
66
|
+
r++;
|
|
67
|
+
if (ok) {
|
|
68
|
+
out += ch;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
// Literal character — emit even when raw is exhausted, so a
|
|
75
|
+
// partially-typed value still shows the upcoming chrome
|
|
76
|
+
// (e.g. `(415) ` after the user types three digits). Consume the
|
|
77
|
+
// matching raw char if present so a paste of the already-formatted
|
|
78
|
+
// value doesn't double up.
|
|
79
|
+
out += token;
|
|
80
|
+
if (raw[r] === token)
|
|
81
|
+
r++;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
function useCopyHandler(inputId, message) {
|
|
87
|
+
const { notify } = useToast();
|
|
88
|
+
return () => {
|
|
89
|
+
if (typeof document === 'undefined')
|
|
90
|
+
return;
|
|
91
|
+
const el = document.getElementById(inputId);
|
|
92
|
+
if (!el)
|
|
93
|
+
return;
|
|
94
|
+
const value = el.value;
|
|
95
|
+
const writeText = navigator?.clipboard?.writeText?.bind(navigator.clipboard);
|
|
96
|
+
if (writeText) {
|
|
97
|
+
writeText(value).then(() => notify({ type: 'success', title: message, duration: 2000 }), () => notify({ type: 'error', title: 'Copy failed' }));
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
// Fallback: select + execCommand. Modern browsers all expose
|
|
101
|
+
// navigator.clipboard, so this is rare-path.
|
|
102
|
+
el.select();
|
|
103
|
+
try {
|
|
104
|
+
document.execCommand('copy');
|
|
105
|
+
notify({ type: 'success', title: message, duration: 2000 });
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
notify({ type: 'error', title: 'Copy failed' });
|
|
109
|
+
}
|
|
110
|
+
el.setSelectionRange?.(0, 0);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function ChromeButton({ onClick, ariaLabel, children, autoFocus }) {
|
|
115
|
+
return (_jsx("button", { type: "button", tabIndex: -1, onClick: (e) => { e.preventDefault(); onClick(e); }, "aria-label": ariaLabel, className: "inline-flex items-center justify-center rounded-md size-8 text-muted-foreground hover:bg-accent hover:text-accent-foreground shrink-0", autoFocus: autoFocus, children: children }));
|
|
116
|
+
}
|
|
117
|
+
function CopyButton({ onCopy }) {
|
|
118
|
+
return (_jsx(ChromeButton, { onClick: onCopy, ariaLabel: "Copy", children: _jsx(CopyIcon, { className: "size-4" }) }));
|
|
119
|
+
}
|
|
120
|
+
function RevealToggle({ revealed, onToggle }) {
|
|
121
|
+
return (_jsx(ChromeButton, { onClick: onToggle, ariaLabel: revealed ? 'Hide value' : 'Show value', children: revealed ? _jsx(EyeOffIcon, { className: "size-4" }) : _jsx(EyeIcon, { className: "size-4" }) }));
|
|
122
|
+
}
|
|
123
|
+
// ─── Inline icon SVGs (avoids pulling lucide-react import into this file
|
|
124
|
+
// without checking it's already a dep — keeps the bundle stable). ────
|
|
125
|
+
function CopyIcon(props) {
|
|
126
|
+
return (_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [_jsx("rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2" }), _jsx("path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" })] }));
|
|
127
|
+
}
|
|
128
|
+
function EyeIcon(props) {
|
|
129
|
+
return (_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [_jsx("path", { d: "M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z" }), _jsx("circle", { cx: "12", cy: "12", r: "3" })] }));
|
|
130
|
+
}
|
|
131
|
+
function EyeOffIcon(props) {
|
|
132
|
+
return (_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [_jsx("path", { d: "M9.88 9.88a3 3 0 1 0 4.24 4.24" }), _jsx("path", { d: "M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68" }), _jsx("path", { d: "M6.61 6.61A13.526 13.526 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61" }), _jsx("line", { x1: "2", x2: "22", y1: "2", y2: "22" })] }));
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=textInputControls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"textInputControls.js","sourceRoot":"","sources":["../../../src/react/fields/textInputControls.tsx"],"names":[],"mappings":"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"}
|
package/dist/routes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAG9C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AAEzC,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAG9C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AAEzC,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AAgkBtF,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,GACf,IAAI,CA+oFN;AAGD,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,UAAU,EAAE,CAAA;AACpD,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAA;AAC3F,YAAY,EAAE,IAAI,EAAE,CAAA"}
|
package/dist/routes.js
CHANGED
|
@@ -376,9 +376,29 @@ async function handleUploadRequest(req, res, pilotiq) {
|
|
|
376
376
|
return res.json({ ok: false, error: `File exceeds ${maxSize} bytes` });
|
|
377
377
|
}
|
|
378
378
|
}
|
|
379
|
+
// Server-side resize via @rudderjs/image (optional peer dep)
|
|
380
|
+
const resizeWidthStr = typeof body['resize_width'] === 'string' ? body['resize_width'] : '';
|
|
381
|
+
const resizeHeightStr = typeof body['resize_height'] === 'string' ? body['resize_height'] : '';
|
|
382
|
+
let uploadFile = file;
|
|
383
|
+
if (resizeWidthStr && resizeHeightStr) {
|
|
384
|
+
const w = Number(resizeWidthStr);
|
|
385
|
+
const h = Number(resizeHeightStr);
|
|
386
|
+
if (Number.isFinite(w) && w > 0 && Number.isFinite(h) && h > 0) {
|
|
387
|
+
try {
|
|
388
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
389
|
+
const pkg = await import('@rudderjs/image');
|
|
390
|
+
const buf = await pkg.image(file).resize(w, h).format('webp').toBuffer();
|
|
391
|
+
const baseName = file.name.replace(/\.[^.]+$/, '');
|
|
392
|
+
uploadFile = new File([buf.buffer], `${baseName}.webp`, { type: 'image/webp' });
|
|
393
|
+
}
|
|
394
|
+
catch {
|
|
395
|
+
// @rudderjs/image not installed or resize failed — fall through with original file
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
379
399
|
try {
|
|
380
400
|
const result = await cfg.uploads.adapter.put({
|
|
381
|
-
file,
|
|
401
|
+
file: uploadFile,
|
|
382
402
|
...(directory ? { directory } : {}),
|
|
383
403
|
fieldName,
|
|
384
404
|
});
|
|
@@ -3109,6 +3129,17 @@ export function registerPilotiqRoutes(router, pilotiq) {
|
|
|
3109
3129
|
return res.json({ ok: true });
|
|
3110
3130
|
});
|
|
3111
3131
|
}
|
|
3132
|
+
// Plugin route hook — runs AFTER all core routes register so plugins
|
|
3133
|
+
// can mount their own HTTP surface alongside the panel's. Order
|
|
3134
|
+
// matches the registration order on `.use()` / `.plugins([…])`. Each
|
|
3135
|
+
// plugin owns its own URL convention; pilotiq's underscore-prefixed
|
|
3136
|
+
// sibling-route precedent (`_search`, `_uploads`, `_widget`,
|
|
3137
|
+
// `_notifications`) is the recommended shape. Failures inside a
|
|
3138
|
+
// plugin's hook propagate — boot order is "register all core, then
|
|
3139
|
+
// each plugin in order"; a throw on hook N stops hooks N+1..N+M.
|
|
3140
|
+
for (const plugin of pilotiq.getPlugins()) {
|
|
3141
|
+
plugin.registerRoutes?.(router, pilotiq);
|
|
3142
|
+
}
|
|
3112
3143
|
}
|
|
3113
3144
|
// ─── Lifecycle helpers exported for tests ────────────────
|
|
3114
3145
|
export { dispatchFormSubmit, findForms, selectForm };
|