@rainbow-robotics/plugin-ui 1.1.5 → 1.2.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.
@@ -39,6 +39,19 @@ export interface PluginAction {
39
39
  /** Optional payload schema hint (field → type name). */
40
40
  schema?: Record<string, string>;
41
41
  }
42
+ /** Allowed variable value types exposed to pyfm. */
43
+ export declare const VARIABLE_TYPES: readonly ["number", "string", "array"];
44
+ export type PluginVariableType = (typeof VARIABLE_TYPES)[number];
45
+ /** A variable the plugin pre-declares for use in pyfm programs. */
46
+ export interface PluginVariable {
47
+ /** Identifier, must start with "RBP_" (then letters, digits, underscore). Unique per plugin. */
48
+ name: `RBP_${string}`;
49
+ type: PluginVariableType;
50
+ /** Initial value — must match `type`. */
51
+ init: number | string | any[];
52
+ /** Optional. Without it the UI cannot explain what the variable is for. */
53
+ description?: string | Record<string, string>;
54
+ }
42
55
  export type PluginRuntime = {
43
56
  type: "none";
44
57
  } | {
@@ -69,6 +82,8 @@ export interface PluginManifest {
69
82
  contributes?: PluginContribution[];
70
83
  /** Host actions the plugin can invoke. */
71
84
  actions?: PluginAction[];
85
+ /** Variables pre-declared for pyfm; the variable picker UI lists these. */
86
+ variables?: PluginVariable[];
72
87
  /** Back-end runtime declaration. */
73
88
  runtime?: PluginRuntime;
74
89
  }
@@ -1 +1 @@
1
- {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AACA;;;;;GAKG;AAEH,sDAAsD;AACtD,eAAO,MAAM,mBAAmB,4DAKtB,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAErE,4DAA4D;AAC5D,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;AAE7D,MAAM,WAAW,kBAAkB;IACjC,sCAAsC;IACtC,KAAK,EAAE,iBAAiB,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IACzC,gFAAgF;IAChF,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,sEAAsE;IACtE,IAAI,CAAC,EACD,MAAM,GACN;QACE,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACN,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,yDAAyD;IACzD,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B,WAAW,CAAC,EAAE;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KAC5B,CAAC;CACH;AAED,MAAM,WAAW,YAAY;IAC3B,wDAAwD;IACxD,EAAE,EAAE,MAAM,CAAC;IACX,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjC;IACE,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC/B,CAAC;AAEN,MAAM,WAAW,cAAc;IAC7B,8DAA8D;IAC9D,EAAE,EAAE,MAAM,CAAC;IACX,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yCAAyC;IACzC,KAAK,EACD,MAAM,GACN;QACE,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACN,iCAAiC;IACjC,WAAW,CAAC,EAAE,kBAAkB,EAAE,CAAC;IACnC,0CAA0C;IAC1C,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,oCAAoC;IACpC,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,CAiBzD"}
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"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"}
package/dist/manifest.js CHANGED
@@ -4,6 +4,7 @@ const CONTRIBUTION_POINTS = [
4
4
  "move.panel",
5
5
  "program.panel"
6
6
  ];
7
+ const VARIABLE_TYPES = ["number", "string", "array"];
7
8
  function validateManifest(value) {
8
9
  const errors = [];
9
10
  if (typeof value !== "object" || value === null) {
@@ -20,10 +21,13 @@ function validateManifest(value) {
20
21
  errors.push("manifest.contributes must be an array");
21
22
  if (m.actions !== void 0 && !Array.isArray(m.actions))
22
23
  errors.push("manifest.actions must be an array");
24
+ if (m.variables !== void 0 && !Array.isArray(m.variables))
25
+ errors.push("manifest.variables must be an array");
23
26
  return errors;
24
27
  }
25
28
  export {
26
29
  CONTRIBUTION_POINTS,
30
+ VARIABLE_TYPES,
27
31
  validateManifest
28
32
  };
29
33
  //# sourceMappingURL=manifest.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/manifest.ts"],
4
- "sourcesContent": ["/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * Plugin manifest schema \u2014 the single source of truth shared by the front end\n * (nexus reads it) and the back end (rby2 mirrors it for validation).\n *\n * Evolve additively only.\n */\n\n/** Known contribution points the host understands. */\nexport const CONTRIBUTION_POINTS = [\n \"toolbar\",\n \"lnb\",\n \"move.panel\",\n \"program.panel\",\n] as const;\n\nexport type ContributionPoint = (typeof CONTRIBUTION_POINTS)[number];\n\n/** How a header.toolbar contribution opens when clicked. */\nexport type ContributionOpens = \"popover\" | \"panel\" | \"page\";\n\nexport interface PluginContribution {\n /** Where this contribution mounts. */\n point: ContributionPoint | (string & {});\n /** UI entry name relative to ui/ (without extension). Defaults to \"content\". */\n ui?: string;\n /** Icon path relative to the plugin root (e.g. \"assets/icon.svg\"). */\n icon?:\n | string\n | {\n \"16\"?: string;\n \"48\"?: string;\n \"126\"?: string;\n };\n /** Display label. */\n label?: string | Record<string, string>;\n /** For header.toolbar: how the contribution surfaces. */\n opens?: ContributionOpens;\n commandInfo?: {\n name: string;\n icon: string;\n funcName: string;\n args?: Record<string, any>;\n };\n}\n\nexport interface PluginAction {\n /** Action id referenced by `rb.action(id, payload)`. */\n id: string;\n /** Transport topic (Zenoh / ROS2) the back end routes to. */\n topic: string;\n /** Optional payload schema hint (field \u2192 type name). */\n schema?: Record<string, string>;\n}\n\nexport type PluginRuntime =\n | { type: \"none\" }\n | { type: \"python\"; entry: string }\n | {\n type: \"ros2\";\n package: string;\n launch: string;\n rosClient: \"rclpy\" | \"rclcpp\";\n };\n\nexport interface PluginManifest {\n /** Reverse-DNS unique id, e.g. \"com.rainbow.gripper-tool\". */\n id: string;\n /** Human-readable name. */\n name: string;\n /** Plugin version (semver). */\n version: string;\n /** Minimum host (Muscat) version this plugin supports. */\n minAppVersion?: string;\n /** Icon path relative to plugin root. */\n icons:\n | string\n | {\n \"16\"?: string;\n \"48\"?: string;\n \"128\"?: string;\n };\n /** UI / chrome contributions. */\n contributes?: PluginContribution[];\n /** Host actions the plugin can invoke. */\n actions?: PluginAction[];\n /** Back-end runtime declaration. */\n runtime?: PluginRuntime;\n}\n\n/**\n * Lightweight structural check. Returns the list of problems (empty = valid).\n * Kept dependency-free so both front and back ends can reuse it; richer\n * validation (zod) can layer on top later without breaking this contract.\n */\nexport function validateManifest(value: unknown): string[] {\n const errors: string[] = [];\n if (typeof value !== \"object\" || value === null) {\n return [\"manifest must be an object\"];\n }\n const m = value as Record<string, unknown>;\n if (typeof m.id !== \"string\" || m.id.length === 0)\n errors.push(\"manifest.id is required (string)\");\n if (typeof m.name !== \"string\" || m.name.length === 0)\n errors.push(\"manifest.name is required (string)\");\n if (typeof m.version !== \"string\" || m.version.length === 0)\n errors.push(\"manifest.version is required (string)\");\n if (m.contributes !== undefined && !Array.isArray(m.contributes))\n errors.push(\"manifest.contributes must be an array\");\n if (m.actions !== undefined && !Array.isArray(m.actions))\n errors.push(\"manifest.actions must be an array\");\n return errors;\n}\n"],
5
- "mappings": "AASO,MAAM,sBAAsB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAiFO,SAAS,iBAAiB,OAA0B;AACzD,QAAM,SAAmB,CAAC;AAC1B,MAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC/C,WAAO,CAAC,4BAA4B;AAAA,EACtC;AACA,QAAM,IAAI;AACV,MAAI,OAAO,EAAE,OAAO,YAAY,EAAE,GAAG,WAAW;AAC9C,WAAO,KAAK,kCAAkC;AAChD,MAAI,OAAO,EAAE,SAAS,YAAY,EAAE,KAAK,WAAW;AAClD,WAAO,KAAK,oCAAoC;AAClD,MAAI,OAAO,EAAE,YAAY,YAAY,EAAE,QAAQ,WAAW;AACxD,WAAO,KAAK,uCAAuC;AACrD,MAAI,EAAE,gBAAgB,UAAa,CAAC,MAAM,QAAQ,EAAE,WAAW;AAC7D,WAAO,KAAK,uCAAuC;AACrD,MAAI,EAAE,YAAY,UAAa,CAAC,MAAM,QAAQ,EAAE,OAAO;AACrD,WAAO,KAAK,mCAAmC;AACjD,SAAO;AACT;",
4
+ "sourcesContent": ["/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * Plugin manifest schema \u2014 the single source of truth shared by the front end\n * (nexus reads it) and the back end (rby2 mirrors it for validation).\n *\n * Evolve additively only.\n */\n\n/** Known contribution points the host understands. */\nexport const CONTRIBUTION_POINTS = [\n \"toolbar\",\n \"lnb\",\n \"move.panel\",\n \"program.panel\",\n] as const;\n\nexport type ContributionPoint = (typeof CONTRIBUTION_POINTS)[number];\n\n/** How a header.toolbar contribution opens when clicked. */\nexport type ContributionOpens = \"popover\" | \"panel\" | \"page\";\n\nexport interface PluginContribution {\n /** Where this contribution mounts. */\n point: ContributionPoint | (string & {});\n /** UI entry name relative to ui/ (without extension). Defaults to \"content\". */\n ui?: string;\n /** Icon path relative to the plugin root (e.g. \"assets/icon.svg\"). */\n icon?:\n | string\n | {\n \"16\"?: string;\n \"48\"?: string;\n \"126\"?: string;\n };\n /** Display label. */\n label?: string | Record<string, string>;\n /** For header.toolbar: how the contribution surfaces. */\n opens?: ContributionOpens;\n commandInfo?: {\n name: string;\n icon: string;\n funcName: string;\n args?: Record<string, any>;\n };\n}\n\nexport interface PluginAction {\n /** Action id referenced by `rb.action(id, payload)`. */\n id: string;\n /** Transport topic (Zenoh / ROS2) the back end routes to. */\n topic: string;\n /** Optional payload schema hint (field \u2192 type name). */\n schema?: Record<string, string>;\n}\n\n/** Allowed variable value types exposed to pyfm. */\nexport const VARIABLE_TYPES = [\"number\", \"string\", \"array\"] as const;\n\nexport type PluginVariableType = (typeof VARIABLE_TYPES)[number];\n\n/** A variable the plugin pre-declares for use in pyfm programs. */\nexport interface PluginVariable {\n /** Identifier, must start with \"RBP_\" (then letters, digits, underscore). Unique per plugin. */\n name: `RBP_${string}`;\n type: PluginVariableType;\n /** Initial value \u2014 must match `type`. */\n init: number | string | any[];\n /** Optional. Without it the UI cannot explain what the variable is for. */\n description?: string | Record<string, string>;\n}\n\nexport type PluginRuntime =\n | { type: \"none\" }\n | { type: \"python\"; entry: string }\n | {\n type: \"ros2\";\n package: string;\n launch: string;\n rosClient: \"rclpy\" | \"rclcpp\";\n };\n\nexport interface PluginManifest {\n /** Reverse-DNS unique id, e.g. \"com.rainbow.gripper-tool\". */\n id: string;\n /** Human-readable name. */\n name: string;\n /** Plugin version (semver). */\n version: string;\n /** Minimum host (Muscat) version this plugin supports. */\n minAppVersion?: string;\n /** Icon path relative to plugin root. */\n icons:\n | string\n | {\n \"16\"?: string;\n \"48\"?: string;\n \"128\"?: string;\n };\n /** UI / chrome contributions. */\n contributes?: PluginContribution[];\n /** Host actions the plugin can invoke. */\n actions?: PluginAction[];\n /** Variables pre-declared for pyfm; the variable picker UI lists these. */\n variables?: PluginVariable[];\n /** Back-end runtime declaration. */\n runtime?: PluginRuntime;\n}\n\n/**\n * Lightweight structural check. Returns the list of problems (empty = valid).\n * Kept dependency-free so both front and back ends can reuse it; richer\n * validation (zod) can layer on top later without breaking this contract.\n */\nexport function validateManifest(value: unknown): string[] {\n const errors: string[] = [];\n if (typeof value !== \"object\" || value === null) {\n return [\"manifest must be an object\"];\n }\n const m = value as Record<string, unknown>;\n if (typeof m.id !== \"string\" || m.id.length === 0)\n errors.push(\"manifest.id is required (string)\");\n if (typeof m.name !== \"string\" || m.name.length === 0)\n errors.push(\"manifest.name is required (string)\");\n if (typeof m.version !== \"string\" || m.version.length === 0)\n errors.push(\"manifest.version is required (string)\");\n if (m.contributes !== undefined && !Array.isArray(m.contributes))\n errors.push(\"manifest.contributes must be an array\");\n if (m.actions !== undefined && !Array.isArray(m.actions))\n errors.push(\"manifest.actions must be an array\");\n if (m.variables !== undefined && !Array.isArray(m.variables))\n errors.push(\"manifest.variables must be an array\");\n return errors;\n}\n"],
5
+ "mappings": "AASO,MAAM,sBAAsB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AA0CO,MAAM,iBAAiB,CAAC,UAAU,UAAU,OAAO;AAyDnD,SAAS,iBAAiB,OAA0B;AACzD,QAAM,SAAmB,CAAC;AAC1B,MAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC/C,WAAO,CAAC,4BAA4B;AAAA,EACtC;AACA,QAAM,IAAI;AACV,MAAI,OAAO,EAAE,OAAO,YAAY,EAAE,GAAG,WAAW;AAC9C,WAAO,KAAK,kCAAkC;AAChD,MAAI,OAAO,EAAE,SAAS,YAAY,EAAE,KAAK,WAAW;AAClD,WAAO,KAAK,oCAAoC;AAClD,MAAI,OAAO,EAAE,YAAY,YAAY,EAAE,QAAQ,WAAW;AACxD,WAAO,KAAK,uCAAuC;AACrD,MAAI,EAAE,gBAAgB,UAAa,CAAC,MAAM,QAAQ,EAAE,WAAW;AAC7D,WAAO,KAAK,uCAAuC;AACrD,MAAI,EAAE,YAAY,UAAa,CAAC,MAAM,QAAQ,EAAE,OAAO;AACrD,WAAO,KAAK,mCAAmC;AACjD,MAAI,EAAE,cAAc,UAAa,CAAC,MAAM,QAAQ,EAAE,SAAS;AACzD,WAAO,KAAK,qCAAqC;AACnD,SAAO;AACT;",
6
6
  "names": []
7
7
  }
package/dist/react.d.ts CHANGED
@@ -3762,8 +3762,17 @@ type FactoryMapProps = {
3762
3762
  imageTransformControl?: MapImageTransformGeometry | null;
3763
3763
  /** 지도 위 이미지형 요소의 편집 결과 */
3764
3764
  onImageTransformControlChange?: (geometry: MapImageTransformGeometry) => void;
3765
+ /** DeckGL WebGL context 생성·소실·복구·정리 진단 이벤트 */
3766
+ onWebGLContextEvent?: (event: FactoryMapWebGLContextEvent) => void;
3765
3767
  };
3766
- declare const FactoryMap: ({ tileUrlTemplate, backgroundImageUrl, backgroundImageBounds, minZoom, maxZoom, mapTopoData, targetPosition, trackingAmrId, focusPosition, highlightedNodeId, onGoalNodeClick, moveStatusDataMap, focusAmrId, onFocusAmrApplied, useInterpolation, exiting, keymapContent, showKeymapPointCloudLayer, safetyZones, trafficZoneData, showSafetyZones, showTrafficZones, lidarCloudPoints, enableLidarFlashEffect, onAmrSelectionChange, onAmrSelectionStart, onAmrToggleClick, selectedAmrIdsFromMap, focusedAmrIdForIcon, showAmrMovementTrail, conveyorBeltTransform, dockingStationTransform, conveyorBeltIconAtlasUrl, dockingStationIconAtlasUrl, showConveyorBelt, showDockingStation, mapMode, amrIconPngDataUrl, amrRobotModelById, amrModelIconVariants, layerColors, viewBearingDeg, amrGlobalPaths, amrLocalPaths, zoomControlsStyle, initialMainViewState, onMainViewStateChange, showMiniMap, tooltipLabels, imageTransformControl, onImageTransformControlChange, }: FactoryMapProps) => react_jsx_runtime.JSX.Element;
3768
+ type FactoryMapWebGLContextEvent = {
3769
+ phase: "created" | "lost" | "restored" | "finalized";
3770
+ activeContexts: number;
3771
+ vendor?: string;
3772
+ renderer?: string;
3773
+ version?: string;
3774
+ };
3775
+ declare const FactoryMap: ({ tileUrlTemplate, backgroundImageUrl, backgroundImageBounds, minZoom, maxZoom, mapTopoData, targetPosition, trackingAmrId, focusPosition, highlightedNodeId, onGoalNodeClick, moveStatusDataMap, focusAmrId, onFocusAmrApplied, useInterpolation, exiting, keymapContent, showKeymapPointCloudLayer, safetyZones, trafficZoneData, showSafetyZones, showTrafficZones, lidarCloudPoints, enableLidarFlashEffect, onAmrSelectionChange, onAmrSelectionStart, onAmrToggleClick, selectedAmrIdsFromMap, focusedAmrIdForIcon, showAmrMovementTrail, conveyorBeltTransform, dockingStationTransform, conveyorBeltIconAtlasUrl, dockingStationIconAtlasUrl, showConveyorBelt, showDockingStation, mapMode, amrIconPngDataUrl, amrRobotModelById, amrModelIconVariants, layerColors, viewBearingDeg, amrGlobalPaths, amrLocalPaths, zoomControlsStyle, initialMainViewState, onMainViewStateChange, showMiniMap, tooltipLabels, imageTransformControl, onImageTransformControlChange, onWebGLContextEvent, }: FactoryMapProps) => react_jsx_runtime.JSX.Element;
3767
3776
 
3768
3777
  type TopoNode$3 = {
3769
3778
  id: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rainbow-robotics/plugin-ui",
3
- "version": "1.1.5",
3
+ "version": "1.2.0",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=20"
package/src/manifest.ts CHANGED
@@ -53,6 +53,22 @@ export interface PluginAction {
53
53
  schema?: Record<string, string>;
54
54
  }
55
55
 
56
+ /** Allowed variable value types exposed to pyfm. */
57
+ export const VARIABLE_TYPES = ["number", "string", "array"] as const;
58
+
59
+ export type PluginVariableType = (typeof VARIABLE_TYPES)[number];
60
+
61
+ /** A variable the plugin pre-declares for use in pyfm programs. */
62
+ export interface PluginVariable {
63
+ /** Identifier, must start with "RBP_" (then letters, digits, underscore). Unique per plugin. */
64
+ name: `RBP_${string}`;
65
+ type: PluginVariableType;
66
+ /** Initial value — must match `type`. */
67
+ init: number | string | any[];
68
+ /** Optional. Without it the UI cannot explain what the variable is for. */
69
+ description?: string | Record<string, string>;
70
+ }
71
+
56
72
  export type PluginRuntime =
57
73
  | { type: "none" }
58
74
  | { type: "python"; entry: string }
@@ -84,6 +100,8 @@ export interface PluginManifest {
84
100
  contributes?: PluginContribution[];
85
101
  /** Host actions the plugin can invoke. */
86
102
  actions?: PluginAction[];
103
+ /** Variables pre-declared for pyfm; the variable picker UI lists these. */
104
+ variables?: PluginVariable[];
87
105
  /** Back-end runtime declaration. */
88
106
  runtime?: PluginRuntime;
89
107
  }
@@ -109,5 +127,7 @@ export function validateManifest(value: unknown): string[] {
109
127
  errors.push("manifest.contributes must be an array");
110
128
  if (m.actions !== undefined && !Array.isArray(m.actions))
111
129
  errors.push("manifest.actions must be an array");
130
+ if (m.variables !== undefined && !Array.isArray(m.variables))
131
+ errors.push("manifest.variables must be an array");
112
132
  return errors;
113
133
  }