@huaqiu/component-gen-app 0.3.7 → 0.3.8
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/dist/assets/{index-DTShI_jq.js → index-B83Ehy7Z.js} +5 -5
- package/dist/index.html +1 -1
- package/lib/index.d.ts +27 -0
- package/lib/index.js +69 -4
- package/package.json +1 -1
- package/src/api/component-gen-client.ts +5 -0
- package/src/components/ResultStage.tsx +46 -0
- package/src/copy/en.ts +6 -0
- package/src/copy/zh.ts +6 -0
- package/src/ports.ts +16 -0
package/dist/index.html
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>华秋 Component Gen</title>
|
|
7
|
-
<script type="module" crossorigin src="./assets/index-
|
|
7
|
+
<script type="module" crossorigin src="./assets/index-B83Ehy7Z.js"></script>
|
|
8
8
|
</head>
|
|
9
9
|
<body>
|
|
10
10
|
<div id="root"></div>
|
package/lib/index.d.ts
CHANGED
|
@@ -129,6 +129,23 @@ interface ComponentGenAuthPort {
|
|
|
129
129
|
login(): Promise<void>;
|
|
130
130
|
onAuthStateChanged(listener: (authenticated: boolean) => void): () => void;
|
|
131
131
|
}
|
|
132
|
+
/**
|
|
133
|
+
* Optional Place capability: send a generated artifact into the host EDA
|
|
134
|
+
* editor through HQ Edge (`hqEdge.placeArtifact`, same-origin edge-bridge).
|
|
135
|
+
*
|
|
136
|
+
* Structurally defined — the app stays DSH-agnostic. The host adapter decides
|
|
137
|
+
* availability via `canPlace` (editor compatibility, UX-only: HQ Edge
|
|
138
|
+
* re-enforces the same matrix server-side). Absent in standalone deployments,
|
|
139
|
+
* in which case the app hides the Place action.
|
|
140
|
+
*/
|
|
141
|
+
interface ComponentGenPlacePort {
|
|
142
|
+
canPlace(type: 'symbol' | 'footprint'): boolean;
|
|
143
|
+
placeArtifact(request: {
|
|
144
|
+
type: 'symbol' | 'footprint';
|
|
145
|
+
artifactUri: string;
|
|
146
|
+
filename?: string;
|
|
147
|
+
}): Promise<unknown>;
|
|
148
|
+
}
|
|
132
149
|
/** The whole contract the app needs from its host. */
|
|
133
150
|
interface ComponentGenPorts {
|
|
134
151
|
config(): Promise<ComponentGenConfig>;
|
|
@@ -144,6 +161,8 @@ interface ComponentGenPorts {
|
|
|
144
161
|
/** data URL of a stored input thumbnail. */
|
|
145
162
|
inputImage(imageId: string): Promise<string>;
|
|
146
163
|
auth: ComponentGenAuthPort;
|
|
164
|
+
/** Optional Place-into-editor capability (HQ Edge host only). */
|
|
165
|
+
place?: ComponentGenPlacePort;
|
|
147
166
|
}
|
|
148
167
|
//#endregion
|
|
149
168
|
//#region src/App.d.ts
|
|
@@ -289,6 +308,12 @@ declare const ZH: {
|
|
|
289
308
|
readonly loadMore: "加载更多";
|
|
290
309
|
readonly noMore: "没有更多了";
|
|
291
310
|
};
|
|
311
|
+
readonly result: {
|
|
312
|
+
readonly place: "放置到编辑器";
|
|
313
|
+
readonly placing: "放置中…";
|
|
314
|
+
readonly placeDone: "已放置到编辑器";
|
|
315
|
+
readonly placeFailed: "放置失败:";
|
|
316
|
+
};
|
|
292
317
|
readonly auth: {
|
|
293
318
|
readonly notLoggedIn: "未登录华秋账号";
|
|
294
319
|
readonly login: "登录华秋 EDA";
|
|
@@ -404,6 +429,8 @@ interface HttpPortsOptions {
|
|
|
404
429
|
artifactsBase?: string;
|
|
405
430
|
doFetch?: typeof fetch;
|
|
406
431
|
auth?: ComponentGenAuthPort;
|
|
432
|
+
/** Optional Place-into-editor capability, forwarded verbatim. */
|
|
433
|
+
place?: ComponentGenPlacePort;
|
|
407
434
|
}
|
|
408
435
|
/** The shared fetch client. */
|
|
409
436
|
declare function createHttpPorts(options: HttpPortsOptions): ComponentGenPorts;
|
package/lib/index.js
CHANGED
|
@@ -136,6 +136,12 @@ const ZH = {
|
|
|
136
136
|
loadMore: "加载更多",
|
|
137
137
|
noMore: "没有更多了"
|
|
138
138
|
},
|
|
139
|
+
result: {
|
|
140
|
+
place: "放置到编辑器",
|
|
141
|
+
placing: "放置中…",
|
|
142
|
+
placeDone: "已放置到编辑器",
|
|
143
|
+
placeFailed: "放置失败:"
|
|
144
|
+
},
|
|
139
145
|
auth: {
|
|
140
146
|
notLoggedIn: "未登录华秋账号",
|
|
141
147
|
login: "登录华秋 EDA",
|
|
@@ -278,6 +284,12 @@ const EN = {
|
|
|
278
284
|
loadMore: "Load more",
|
|
279
285
|
noMore: "No more"
|
|
280
286
|
},
|
|
287
|
+
result: {
|
|
288
|
+
place: "Place in editor",
|
|
289
|
+
placing: "Placing…",
|
|
290
|
+
placeDone: "Placed into the editor",
|
|
291
|
+
placeFailed: "Placement failed: "
|
|
292
|
+
},
|
|
281
293
|
auth: {
|
|
282
294
|
notLoggedIn: "Not logged in to Huaqiu EDA",
|
|
283
295
|
login: "Login to Huaqiu EDA",
|
|
@@ -626,6 +638,19 @@ function artifactIdOf(result) {
|
|
|
626
638
|
}
|
|
627
639
|
return null;
|
|
628
640
|
}
|
|
641
|
+
/**
|
|
642
|
+
* HQ Edge-resolvable URI of the generated artifact (`file://`), attached by
|
|
643
|
+
* the node half when the placement channel is available. Place stays hidden
|
|
644
|
+
* when it is missing.
|
|
645
|
+
*/
|
|
646
|
+
function artifactUriOf(result) {
|
|
647
|
+
const art = result.artifact;
|
|
648
|
+
if (art && typeof art === "object") {
|
|
649
|
+
const uri = art.uri;
|
|
650
|
+
if (typeof uri === "string" && uri) return uri;
|
|
651
|
+
}
|
|
652
|
+
return null;
|
|
653
|
+
}
|
|
629
654
|
function filenameOf(result, kind) {
|
|
630
655
|
const f = result.filename;
|
|
631
656
|
if (typeof f === "string" && f) return f;
|
|
@@ -633,9 +658,12 @@ function filenameOf(result, kind) {
|
|
|
633
658
|
}
|
|
634
659
|
function ResultStage({ ports, kind, result, t, srcKey }) {
|
|
635
660
|
const artifactId = artifactIdOf(result);
|
|
661
|
+
const artifactUri = artifactUriOf(result);
|
|
636
662
|
const [content, setContent] = useState(null);
|
|
637
663
|
const [previewErr, setPreviewErr] = useState(null);
|
|
638
664
|
const [downloading, setDownloading] = useState(false);
|
|
665
|
+
const [placing, setPlacing] = useState(false);
|
|
666
|
+
const [placeStatus, setPlaceStatus] = useState(null);
|
|
639
667
|
useEffect(() => {
|
|
640
668
|
if (!artifactId) return;
|
|
641
669
|
let cancelled = false;
|
|
@@ -676,6 +704,32 @@ function ResultStage({ ports, kind, result, t, srcKey }) {
|
|
|
676
704
|
]);
|
|
677
705
|
const autoGenerated = result.autoGenerated === true;
|
|
678
706
|
const note = typeof result.note === "string" ? result.note : null;
|
|
707
|
+
/** Send the generated artifact into the host EDA editor (HQ Edge only). */
|
|
708
|
+
const place = useCallback(async () => {
|
|
709
|
+
if (placing || !ports.place || !artifactUri) return;
|
|
710
|
+
setPlacing(true);
|
|
711
|
+
setPlaceStatus(null);
|
|
712
|
+
try {
|
|
713
|
+
await ports.place.placeArtifact({
|
|
714
|
+
type: kind,
|
|
715
|
+
artifactUri,
|
|
716
|
+
...result.filename && typeof result.filename === "string" ? { filename: result.filename } : {}
|
|
717
|
+
});
|
|
718
|
+
setPlaceStatus(t("result.placeDone"));
|
|
719
|
+
} catch (e) {
|
|
720
|
+
setPlaceStatus(t("result.placeFailed") + String(e?.message || e));
|
|
721
|
+
} finally {
|
|
722
|
+
setPlacing(false);
|
|
723
|
+
}
|
|
724
|
+
}, [
|
|
725
|
+
placing,
|
|
726
|
+
ports,
|
|
727
|
+
artifactUri,
|
|
728
|
+
kind,
|
|
729
|
+
result,
|
|
730
|
+
t
|
|
731
|
+
]);
|
|
732
|
+
const canPlace = !!ports.place?.canPlace(kind) && !!artifactUri;
|
|
679
733
|
return /* @__PURE__ */ jsx("div", {
|
|
680
734
|
className: "cga-panel",
|
|
681
735
|
children: /* @__PURE__ */ jsxs("div", {
|
|
@@ -698,16 +752,26 @@ function ResultStage({ ports, kind, result, t, srcKey }) {
|
|
|
698
752
|
className: "cga-banner cga-banner--info",
|
|
699
753
|
children: note
|
|
700
754
|
}) : null,
|
|
701
|
-
/* @__PURE__ */
|
|
755
|
+
/* @__PURE__ */ jsxs("div", {
|
|
702
756
|
className: "cga-actions",
|
|
703
|
-
children: /* @__PURE__ */ jsx("button", {
|
|
757
|
+
children: [/* @__PURE__ */ jsx("button", {
|
|
704
758
|
type: "button",
|
|
705
759
|
className: "cga-btn cga-btn--primary",
|
|
706
760
|
onClick: () => void download(),
|
|
707
761
|
disabled: downloading,
|
|
708
762
|
children: kind === "symbol" ? t("symbol.download") : t("footprint.download")
|
|
709
|
-
})
|
|
710
|
-
|
|
763
|
+
}), canPlace ? /* @__PURE__ */ jsx("button", {
|
|
764
|
+
type: "button",
|
|
765
|
+
className: "cga-btn",
|
|
766
|
+
onClick: () => void place(),
|
|
767
|
+
disabled: placing,
|
|
768
|
+
children: placing ? t("result.placing") : t("result.place")
|
|
769
|
+
}) : null]
|
|
770
|
+
}),
|
|
771
|
+
placeStatus ? /* @__PURE__ */ jsx("div", {
|
|
772
|
+
className: "cga-banner cga-banner--info",
|
|
773
|
+
children: placeStatus
|
|
774
|
+
}) : null
|
|
711
775
|
]
|
|
712
776
|
})
|
|
713
777
|
});
|
|
@@ -2265,6 +2329,7 @@ function createHttpPorts(options) {
|
|
|
2265
2329
|
const url = (p) => `${base}${p}`;
|
|
2266
2330
|
const artifactUrl = (p) => `${artifactsBase}${p}`;
|
|
2267
2331
|
return {
|
|
2332
|
+
...options.place ? { place: options.place } : {},
|
|
2268
2333
|
async config() {
|
|
2269
2334
|
const cfg = await readJson(await doFetch(url("/config"), { headers: { accept: "application/json" } }));
|
|
2270
2335
|
return {
|
package/package.json
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import type {
|
|
11
11
|
ComponentGenAuthPort,
|
|
12
12
|
ComponentGenConfig,
|
|
13
|
+
ComponentGenPlacePort,
|
|
13
14
|
ComponentGenPorts,
|
|
14
15
|
HistoryEntry,
|
|
15
16
|
HistoryPage,
|
|
@@ -44,6 +45,8 @@ export interface HttpPortsOptions {
|
|
|
44
45
|
artifactsBase?: string
|
|
45
46
|
doFetch?: typeof fetch
|
|
46
47
|
auth?: ComponentGenAuthPort
|
|
48
|
+
/** Optional Place-into-editor capability, forwarded verbatim. */
|
|
49
|
+
place?: ComponentGenPlacePort
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
/** The shared fetch client. */
|
|
@@ -58,6 +61,8 @@ export function createHttpPorts(options: HttpPortsOptions): ComponentGenPorts {
|
|
|
58
61
|
const artifactUrl = (p: string): string => `${artifactsBase}${p}`
|
|
59
62
|
|
|
60
63
|
return {
|
|
64
|
+
// Optional Place capability, forwarded from the host adapter verbatim.
|
|
65
|
+
...(options.place ? { place: options.place } : {}),
|
|
61
66
|
async config(): Promise<ComponentGenConfig> {
|
|
62
67
|
const res = await doFetch(url('/config'), { headers: { accept: 'application/json' } })
|
|
63
68
|
const cfg = await readJson<Partial<ComponentGenConfig>>(res)
|
|
@@ -28,6 +28,20 @@ function artifactIdOf(result: Record<string, unknown>): string | null {
|
|
|
28
28
|
return null
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* HQ Edge-resolvable URI of the generated artifact (`file://`), attached by
|
|
33
|
+
* the node half when the placement channel is available. Place stays hidden
|
|
34
|
+
* when it is missing.
|
|
35
|
+
*/
|
|
36
|
+
function artifactUriOf(result: Record<string, unknown>): string | null {
|
|
37
|
+
const art = result.artifact
|
|
38
|
+
if (art && typeof art === 'object') {
|
|
39
|
+
const uri = (art as { uri?: unknown }).uri
|
|
40
|
+
if (typeof uri === 'string' && uri) return uri
|
|
41
|
+
}
|
|
42
|
+
return null
|
|
43
|
+
}
|
|
44
|
+
|
|
31
45
|
function filenameOf(result: Record<string, unknown>, kind: string): string {
|
|
32
46
|
const f = result.filename
|
|
33
47
|
if (typeof f === 'string' && f) return f
|
|
@@ -36,9 +50,12 @@ function filenameOf(result: Record<string, unknown>, kind: string): string {
|
|
|
36
50
|
|
|
37
51
|
export function ResultStage({ ports, kind, result, t, srcKey }: ResultStageProps): ReactElement {
|
|
38
52
|
const artifactId = artifactIdOf(result)
|
|
53
|
+
const artifactUri = artifactUriOf(result)
|
|
39
54
|
const [content, setContent] = useState<string | null>(null)
|
|
40
55
|
const [previewErr, setPreviewErr] = useState<string | null>(null)
|
|
41
56
|
const [downloading, setDownloading] = useState(false)
|
|
57
|
+
const [placing, setPlacing] = useState(false)
|
|
58
|
+
const [placeStatus, setPlaceStatus] = useState<string | null>(null)
|
|
42
59
|
|
|
43
60
|
useEffect(() => {
|
|
44
61
|
if (!artifactId) return
|
|
@@ -71,6 +88,27 @@ export function ResultStage({ ports, kind, result, t, srcKey }: ResultStageProps
|
|
|
71
88
|
const autoGenerated = result.autoGenerated === true
|
|
72
89
|
const note = typeof result.note === 'string' ? result.note : null
|
|
73
90
|
|
|
91
|
+
/** Send the generated artifact into the host EDA editor (HQ Edge only). */
|
|
92
|
+
const place = useCallback(async (): Promise<void> => {
|
|
93
|
+
if (placing || !ports.place || !artifactUri) return
|
|
94
|
+
setPlacing(true)
|
|
95
|
+
setPlaceStatus(null)
|
|
96
|
+
try {
|
|
97
|
+
await ports.place.placeArtifact({
|
|
98
|
+
type: kind,
|
|
99
|
+
artifactUri,
|
|
100
|
+
...(result.filename && typeof result.filename === 'string' ? { filename: result.filename } : {}),
|
|
101
|
+
})
|
|
102
|
+
setPlaceStatus(t('result.placeDone'))
|
|
103
|
+
} catch (e) {
|
|
104
|
+
setPlaceStatus(t('result.placeFailed') + String((e as Error)?.message || e))
|
|
105
|
+
} finally {
|
|
106
|
+
setPlacing(false)
|
|
107
|
+
}
|
|
108
|
+
}, [placing, ports, artifactUri, kind, result, t])
|
|
109
|
+
|
|
110
|
+
const canPlace = !!ports.place?.canPlace(kind) && !!artifactUri
|
|
111
|
+
|
|
74
112
|
return (
|
|
75
113
|
<div className="cga-panel">
|
|
76
114
|
<div className="cga-panel__body">
|
|
@@ -85,7 +123,15 @@ export function ResultStage({ ports, kind, result, t, srcKey }: ResultStageProps
|
|
|
85
123
|
<button type="button" className="cga-btn cga-btn--primary" onClick={() => void download()} disabled={downloading}>
|
|
86
124
|
{kind === 'symbol' ? t('symbol.download') : t('footprint.download')}
|
|
87
125
|
</button>
|
|
126
|
+
{canPlace
|
|
127
|
+
? (
|
|
128
|
+
<button type="button" className="cga-btn" onClick={() => void place()} disabled={placing}>
|
|
129
|
+
{placing ? t('result.placing') : t('result.place')}
|
|
130
|
+
</button>
|
|
131
|
+
)
|
|
132
|
+
: null}
|
|
88
133
|
</div>
|
|
134
|
+
{placeStatus ? <div className="cga-banner cga-banner--info">{placeStatus}</div> : null}
|
|
89
135
|
</div>
|
|
90
136
|
</div>
|
|
91
137
|
)
|
package/src/copy/en.ts
CHANGED
|
@@ -133,6 +133,12 @@ export const EN: DeepStrings<typeof ZH> = {
|
|
|
133
133
|
loadMore: 'Load more',
|
|
134
134
|
noMore: 'No more',
|
|
135
135
|
},
|
|
136
|
+
result: {
|
|
137
|
+
place: 'Place in editor',
|
|
138
|
+
placing: 'Placing…',
|
|
139
|
+
placeDone: 'Placed into the editor',
|
|
140
|
+
placeFailed: 'Placement failed: ',
|
|
141
|
+
},
|
|
136
142
|
auth: {
|
|
137
143
|
notLoggedIn: 'Not logged in to Huaqiu EDA',
|
|
138
144
|
login: 'Login to Huaqiu EDA',
|
package/src/copy/zh.ts
CHANGED
|
@@ -130,6 +130,12 @@ export const ZH = {
|
|
|
130
130
|
loadMore: '加载更多',
|
|
131
131
|
noMore: '没有更多了',
|
|
132
132
|
},
|
|
133
|
+
result: {
|
|
134
|
+
place: '放置到编辑器',
|
|
135
|
+
placing: '放置中…',
|
|
136
|
+
placeDone: '已放置到编辑器',
|
|
137
|
+
placeFailed: '放置失败:',
|
|
138
|
+
},
|
|
133
139
|
auth: {
|
|
134
140
|
notLoggedIn: '未登录华秋账号',
|
|
135
141
|
login: '登录华秋 EDA',
|
package/src/ports.ts
CHANGED
|
@@ -131,6 +131,20 @@ export interface ComponentGenAuthPort {
|
|
|
131
131
|
onAuthStateChanged(listener: (authenticated: boolean) => void): () => void
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Optional Place capability: send a generated artifact into the host EDA
|
|
136
|
+
* editor through HQ Edge (`hqEdge.placeArtifact`, same-origin edge-bridge).
|
|
137
|
+
*
|
|
138
|
+
* Structurally defined — the app stays DSH-agnostic. The host adapter decides
|
|
139
|
+
* availability via `canPlace` (editor compatibility, UX-only: HQ Edge
|
|
140
|
+
* re-enforces the same matrix server-side). Absent in standalone deployments,
|
|
141
|
+
* in which case the app hides the Place action.
|
|
142
|
+
*/
|
|
143
|
+
export interface ComponentGenPlacePort {
|
|
144
|
+
canPlace(type: 'symbol' | 'footprint'): boolean
|
|
145
|
+
placeArtifact(request: { type: 'symbol' | 'footprint'; artifactUri: string; filename?: string }): Promise<unknown>
|
|
146
|
+
}
|
|
147
|
+
|
|
134
148
|
/** The whole contract the app needs from its host. */
|
|
135
149
|
export interface ComponentGenPorts {
|
|
136
150
|
config(): Promise<ComponentGenConfig>
|
|
@@ -146,4 +160,6 @@ export interface ComponentGenPorts {
|
|
|
146
160
|
/** data URL of a stored input thumbnail. */
|
|
147
161
|
inputImage(imageId: string): Promise<string>
|
|
148
162
|
auth: ComponentGenAuthPort
|
|
163
|
+
/** Optional Place-into-editor capability (HQ Edge host only). */
|
|
164
|
+
place?: ComponentGenPlacePort
|
|
149
165
|
}
|