@forge-kit/plugin-source-map-prase 0.0.2 → 0.0.3
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/app.js +3 -5
- package/dist/node.js +2556 -0
- package/package.json +5 -3
- package/src/App.less +35 -26
- package/src/App.tsx +72 -23
- package/src/components/map-input-panel/index.less +71 -78
- package/src/components/map-input-panel/index.tsx +19 -20
- package/src/components/panel-card/index.less +16 -13
- package/src/components/panel-card/index.tsx +2 -2
- package/src/components/trace-chain/index.less +119 -120
- package/src/components/trace-chain/index.tsx +9 -7
- package/src/main.tsx +1 -1
- package/src/node/index.ts +6 -0
- package/src/{utils/source-map → node/trace/core}/base/registry.ts +14 -11
- package/src/{utils/source-map → node/trace/core}/base/types.ts +1 -0
- package/src/node/trace/core/domain/chain-slots.ts +33 -0
- package/src/{utils/source-map → node/trace/core}/domain/source-content.ts +15 -2
- package/src/node/trace/core/domain/trace-resolver.ts +179 -0
- package/src/node/trace/core/domain/view-model.ts +57 -0
- package/src/node/trace/resolve/context.ts +59 -0
- package/src/node/trace/resolve/index.ts +97 -0
- package/src/node/trace/resolve/input.ts +35 -0
- package/src/node/trace/resolve/snippet-limit.ts +35 -0
- package/src/node/trace/resolve/types.ts +37 -0
- package/src/node/trace/runner.ts +149 -0
- package/src/shared/trace-common.ts +104 -0
- package/src/shared/trace-contract.ts +29 -0
- package/src/types.ts +19 -0
- package/src/utils/trace-ui/index.ts +12 -0
- package/src/utils/trace-ui/state.ts +81 -0
- package/src/utils/source-map/domain/chain-slots.ts +0 -59
- package/src/utils/source-map/domain/trace-resolver.ts +0 -165
- package/src/utils/source-map/domain/view-model.ts +0 -20
- package/src/utils/source-map/facade/source-map-utils.ts +0 -212
- package/src/utils/source-map/index.ts +0 -18
- /package/src/{utils/source-map → node/trace/core}/base/constants.ts +0 -0
- /package/src/{utils/source-map → node/trace/core}/base/path.ts +0 -0
package/package.json
CHANGED
|
@@ -6,11 +6,12 @@
|
|
|
6
6
|
},
|
|
7
7
|
"files": [
|
|
8
8
|
"dist",
|
|
9
|
-
"src"
|
|
9
|
+
"src",
|
|
10
|
+
"manifest.json"
|
|
10
11
|
],
|
|
11
12
|
"author": "yu.pan <panyupy@vip.qq.com>",
|
|
12
13
|
"license": "MIT",
|
|
13
|
-
"version": "0.0.
|
|
14
|
+
"version": "0.0.3",
|
|
14
15
|
"type": "module",
|
|
15
16
|
"scripts": {
|
|
16
17
|
"dev": "vite",
|
|
@@ -24,7 +25,8 @@
|
|
|
24
25
|
"@dnd-kit/utilities": "^3.2.2",
|
|
25
26
|
"@forge-kit/component": "workspace:*",
|
|
26
27
|
"@forge-kit/icons": "workspace:*",
|
|
27
|
-
"@forge-kit/
|
|
28
|
+
"@forge-kit/helper": "workspace:*",
|
|
29
|
+
"@forge-kit/node-sdk": "workspace:*",
|
|
28
30
|
"classnames": "^2.5.1",
|
|
29
31
|
"react": "^19.2.0",
|
|
30
32
|
"react-dom": "^19.2.0",
|
package/src/App.less
CHANGED
|
@@ -16,46 +16,55 @@ html, body, #root {
|
|
|
16
16
|
overflow: hidden;
|
|
17
17
|
min-height: 0;
|
|
18
18
|
|
|
19
|
-
|
|
20
19
|
.top-cards {
|
|
21
20
|
flex: 1;
|
|
22
21
|
min-height: 0;
|
|
22
|
+
|
|
23
|
+
.top-trace-card {
|
|
24
|
+
flex: 1;
|
|
25
|
+
min-height: 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.top-input-card {
|
|
29
|
+
flex: 1;
|
|
30
|
+
min-height: 0;
|
|
31
|
+
}
|
|
23
32
|
}
|
|
24
33
|
|
|
25
34
|
.result-panel-card {
|
|
26
35
|
flex: 1;
|
|
27
36
|
min-height: 0;
|
|
28
37
|
display: flex;
|
|
29
|
-
}
|
|
30
38
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
39
|
+
.result-panel-content {
|
|
40
|
+
flex: 1;
|
|
41
|
+
min-height: 0;
|
|
42
|
+
width: 100%;
|
|
43
|
+
overflow-y: auto;
|
|
44
|
+
overflow-x: hidden;
|
|
38
45
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
.output-meta {
|
|
47
|
+
margin-bottom: var(--space-2);
|
|
48
|
+
color: var(--gray-11);
|
|
49
|
+
font-size: 12px;
|
|
50
|
+
border: 1px solid var(--gray-6);
|
|
51
|
+
border-radius: 999px;
|
|
52
|
+
padding: 2px 10px;
|
|
53
|
+
}
|
|
47
54
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
overflow-y: hidden;
|
|
55
|
+
.code-scroll-wrap {
|
|
56
|
+
width: 100%;
|
|
57
|
+
max-width: 100%;
|
|
58
|
+
min-width: 0;
|
|
59
|
+
overflow: auto;
|
|
54
60
|
|
|
55
|
-
|
|
56
|
-
|
|
61
|
+
.code-highlight-view {
|
|
62
|
+
width: max-content;
|
|
63
|
+
min-width: 100%;
|
|
64
|
+
box-sizing: border-box;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
57
67
|
}
|
|
58
68
|
}
|
|
59
69
|
}
|
|
60
|
-
|
|
61
70
|
}
|
package/src/App.tsx
CHANGED
|
@@ -4,12 +4,18 @@ import {CodeHighlight} from "@/components/code-highlight";
|
|
|
4
4
|
import {MapInputPanel} from "@/components/map-input-panel";
|
|
5
5
|
import {PanelCard} from "@/components/panel-card";
|
|
6
6
|
import {TraceChain} from "@/components/trace-chain";
|
|
7
|
+
import type {
|
|
8
|
+
ForgeKitBridge,
|
|
9
|
+
MapInputConfig,
|
|
10
|
+
ResolveTraceMetaOutput,
|
|
11
|
+
ResolveTraceSnippetOutput,
|
|
12
|
+
} from "@/types";
|
|
7
13
|
import {
|
|
8
14
|
SourceMapUtils,
|
|
9
15
|
type ChainMapSlot,
|
|
10
16
|
type SourceMapChainState,
|
|
11
17
|
type TraceOutputState,
|
|
12
|
-
} from "@/utils/
|
|
18
|
+
} from "@/utils/trace-ui";
|
|
13
19
|
import '@forge-kit/component/style.css'
|
|
14
20
|
import './App.less'
|
|
15
21
|
|
|
@@ -17,20 +23,21 @@ interface AppProps {
|
|
|
17
23
|
themeProps?: React.ComponentProps<typeof Theme>
|
|
18
24
|
}
|
|
19
25
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
const DEFAULT_MAX_SNIPPET_PAYLOAD_BYTES = String(32 * 1024)
|
|
27
|
+
|
|
28
|
+
const stripMapExt = (fileName: string) => fileName.replace(/\.map$/i, "")
|
|
29
|
+
const getMapFileNameFromPath = (filePath: string) => {
|
|
30
|
+
const normalized = filePath.replace(/\\/g, "/")
|
|
31
|
+
const segments = normalized.split("/")
|
|
32
|
+
return segments[segments.length - 1] || filePath
|
|
24
33
|
}
|
|
25
34
|
|
|
26
35
|
const initialChainState: SourceMapChainState = {
|
|
27
|
-
sourceMaps: {},
|
|
28
|
-
sourceMapFileNames: [],
|
|
29
36
|
chainMapSlots: [],
|
|
30
37
|
entryFileName: "",
|
|
31
38
|
}
|
|
32
39
|
|
|
33
|
-
const initialInputState:
|
|
40
|
+
const initialInputState: MapInputConfig = {
|
|
34
41
|
entryLine: "",
|
|
35
42
|
entryColumn: "",
|
|
36
43
|
contextLineRadius: String(SourceMapUtils.DEFAULT_CONTEXT_LINE_RADIUS),
|
|
@@ -39,7 +46,7 @@ const initialInputState: InputState = {
|
|
|
39
46
|
export const App: React.FC<AppProps> = (props) => {
|
|
40
47
|
const {themeProps} = props
|
|
41
48
|
const [chainState, setChainState] = React.useState<SourceMapChainState>(initialChainState)
|
|
42
|
-
const [inputState, setInputState] = React.useState<
|
|
49
|
+
const [inputState, setInputState] = React.useState<MapInputConfig>(initialInputState)
|
|
43
50
|
const [outputState, setOutputState] = React.useState<TraceOutputState>(SourceMapUtils.createInitialOutputState())
|
|
44
51
|
|
|
45
52
|
const traceChainDisplayData = React.useMemo(() => {
|
|
@@ -47,16 +54,23 @@ export const App: React.FC<AppProps> = (props) => {
|
|
|
47
54
|
}, [outputState.traceData])
|
|
48
55
|
|
|
49
56
|
const applyChainSlots = (slots: ChainMapSlot[]) => {
|
|
50
|
-
setChainState(
|
|
57
|
+
setChainState({
|
|
58
|
+
chainMapSlots: slots,
|
|
59
|
+
entryFileName: slots.length ? stripMapExt(slots[0].mapFileName) : "",
|
|
60
|
+
})
|
|
51
61
|
}
|
|
52
62
|
|
|
53
63
|
const setOutputMessage = (message: string) => {
|
|
54
64
|
setOutputState((prev) => SourceMapUtils.patchOutputMessage(prev, message))
|
|
55
65
|
}
|
|
56
66
|
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
|
|
67
|
+
const handleAppendMapFilePath = (filePath: string) => {
|
|
68
|
+
const slot: ChainMapSlot = {
|
|
69
|
+
id: `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
|
|
70
|
+
mapFileName: getMapFileNameFromPath(filePath),
|
|
71
|
+
mapFilePath: filePath,
|
|
72
|
+
}
|
|
73
|
+
applyChainSlots([...chainState.chainMapSlots, slot])
|
|
60
74
|
}
|
|
61
75
|
|
|
62
76
|
const handleRemoveChainSlot = (slotId: string) => {
|
|
@@ -73,18 +87,52 @@ export const App: React.FC<AppProps> = (props) => {
|
|
|
73
87
|
entryLine: inputState.entryLine,
|
|
74
88
|
entryColumn: inputState.entryColumn,
|
|
75
89
|
contextLineRadius: inputState.contextLineRadius,
|
|
76
|
-
mapCount: chainState.
|
|
90
|
+
mapCount: chainState.chainMapSlots.length,
|
|
77
91
|
})
|
|
78
92
|
|
|
79
93
|
if (!validated.ok) return setOutputMessage(validated.message)
|
|
80
94
|
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
95
|
+
const applyNodeMethod = (window as Window & { forgeKit?: ForgeKitBridge }).forgeKit?.applyNodeMethod
|
|
96
|
+
|
|
97
|
+
const mapFilePaths = chainState.chainMapSlots
|
|
98
|
+
.map((slot) => slot.mapFilePath)
|
|
99
|
+
.filter((path): path is string => Boolean(path))
|
|
100
|
+
|
|
101
|
+
if (!applyNodeMethod) return setOutputMessage("Node bridge 不可用,无法执行解析。")
|
|
102
|
+
|
|
103
|
+
if (mapFilePaths.length === 0) return setOutputMessage("未提供 map 文件路径,无法在 Node 侧解析。")
|
|
104
|
+
|
|
105
|
+
const payload = {
|
|
106
|
+
mapFilePaths,
|
|
107
|
+
entryFileName: validated.entry.fileName,
|
|
108
|
+
entryLine: String(validated.entry.lineNumber),
|
|
109
|
+
entryColumn: String(validated.entry.columnNumber),
|
|
110
|
+
contextLineRadius: String(validated.contextLineRadius),
|
|
111
|
+
maxSnippetPayloadBytes: DEFAULT_MAX_SNIPPET_PAYLOAD_BYTES,
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
const nextOutput = await applyNodeMethod('resolveTrace', JSON.stringify(payload)) as ResolveTraceMetaOutput
|
|
116
|
+
setOutputState((prev) => ({
|
|
117
|
+
...prev,
|
|
118
|
+
traceData: nextOutput.traceData || [],
|
|
119
|
+
resolvedSourceMeta: nextOutput.resolvedSourceMeta || null,
|
|
120
|
+
traceCode: nextOutput.message || prev.traceCode,
|
|
121
|
+
traceHighlightLines: [],
|
|
122
|
+
}))
|
|
123
|
+
if (nextOutput?.resolvedSourceMeta) {
|
|
124
|
+
try {
|
|
125
|
+
const snippet = await applyNodeMethod('getSourceSnippet', JSON.stringify(payload)) as ResolveTraceSnippetOutput
|
|
126
|
+
setOutputState((prev) => ({...prev, ...snippet}))
|
|
127
|
+
} catch (error) {
|
|
128
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
129
|
+
setOutputState((prev) => SourceMapUtils.patchOutputMessage(prev, `源码片段加载失败: ${message}`))
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
} catch (error) {
|
|
133
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
134
|
+
setOutputMessage(`Node resolve failed: ${message}`)
|
|
135
|
+
}
|
|
88
136
|
}
|
|
89
137
|
|
|
90
138
|
return (
|
|
@@ -93,6 +141,7 @@ export const App: React.FC<AppProps> = (props) => {
|
|
|
93
141
|
<Flex className="forge-kit-plugin-source-map-prase-content" direction="column" gap="3">
|
|
94
142
|
<Flex className="top-cards" gap="3" align="stretch">
|
|
95
143
|
<TraceChain
|
|
144
|
+
className="top-trace-card"
|
|
96
145
|
slots={chainState.chainMapSlots.map((slot) => ({
|
|
97
146
|
id: slot.id,
|
|
98
147
|
mapFileName: slot.mapFileName,
|
|
@@ -101,16 +150,16 @@ export const App: React.FC<AppProps> = (props) => {
|
|
|
101
150
|
data={traceChainDisplayData}
|
|
102
151
|
onReorder={handleReorderChainSlots}
|
|
103
152
|
onDelete={handleRemoveChainSlot}
|
|
104
|
-
className="trace-chain-root"
|
|
105
153
|
/>
|
|
106
154
|
|
|
107
155
|
<MapInputPanel
|
|
156
|
+
className="top-input-card"
|
|
108
157
|
chainDepth={chainState.chainMapSlots.length}
|
|
109
158
|
entryFileName={chainState.entryFileName}
|
|
110
159
|
inputConfig={inputState}
|
|
111
160
|
onInputConfigChange={setInputState}
|
|
112
161
|
onResolve={handleResolveTrace}
|
|
113
|
-
|
|
162
|
+
onAppendMapFilePath={handleAppendMapFilePath}
|
|
114
163
|
/>
|
|
115
164
|
</Flex>
|
|
116
165
|
|
|
@@ -1,94 +1,87 @@
|
|
|
1
|
-
.
|
|
2
|
-
.input-panel-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
.input-panel-card {
|
|
2
|
+
.input-panel-content {
|
|
3
|
+
overflow: auto;
|
|
4
|
+
gap: 10px;
|
|
5
5
|
|
|
6
|
-
.input-
|
|
7
|
-
flex: 1;
|
|
8
|
-
overflow: auto;
|
|
9
|
-
gap: 10px;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
.input-footer {
|
|
6
|
+
.input-summary-grid {
|
|
13
7
|
display: grid;
|
|
14
|
-
grid-template-
|
|
15
|
-
|
|
16
|
-
border-top: 1px solid var(--gray-5);
|
|
17
|
-
padding-top: 10px;
|
|
18
|
-
flex: 1;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
8
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
9
|
+
gap: 8px;
|
|
21
10
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
11
|
+
.input-summary-item {
|
|
12
|
+
border: 1px solid var(--gray-5);
|
|
13
|
+
border-radius: var(--radius-3);
|
|
14
|
+
padding: 8px 10px;
|
|
15
|
+
background: var(--gray-2);
|
|
27
16
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
17
|
+
.input-summary-label {
|
|
18
|
+
display: block;
|
|
19
|
+
color: var(--gray-10);
|
|
20
|
+
font-size: 12px;
|
|
21
|
+
margin-bottom: 4px;
|
|
22
|
+
}
|
|
34
23
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
24
|
+
.input-summary-value {
|
|
25
|
+
display: block;
|
|
26
|
+
color: var(--gray-12);
|
|
27
|
+
font-size: 13px;
|
|
28
|
+
font-weight: 600;
|
|
29
|
+
word-break: break-all;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
41
33
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
word-break: break-all;
|
|
48
|
-
}
|
|
34
|
+
.input-hints {
|
|
35
|
+
border: 1px dashed var(--gray-6);
|
|
36
|
+
border-radius: var(--radius-3);
|
|
37
|
+
padding: 8px 10px;
|
|
38
|
+
background: color-mix(in srgb, var(--gray-2) 70%, transparent);
|
|
49
39
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
40
|
+
.input-hints-title {
|
|
41
|
+
display: block;
|
|
42
|
+
font-size: 12px;
|
|
43
|
+
font-weight: 600;
|
|
44
|
+
color: var(--gray-11);
|
|
45
|
+
margin-bottom: 6px;
|
|
46
|
+
}
|
|
56
47
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
48
|
+
.input-hints-item {
|
|
49
|
+
display: block;
|
|
50
|
+
font-size: 12px;
|
|
51
|
+
line-height: 1.6;
|
|
52
|
+
color: var(--gray-11);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
64
55
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
56
|
+
.input-footer {
|
|
57
|
+
display: grid;
|
|
58
|
+
grid-template-rows: auto minmax(0, 1fr);
|
|
59
|
+
row-gap: 10px;
|
|
60
|
+
border-top: 1px solid var(--gray-5);
|
|
61
|
+
padding-top: 10px;
|
|
71
62
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
63
|
+
.entry-row {
|
|
64
|
+
.field-row-compact {
|
|
65
|
+
flex: 1;
|
|
75
66
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
67
|
+
.field-label {
|
|
68
|
+
color: var(--gray-11);
|
|
69
|
+
font-size: 12px;
|
|
70
|
+
}
|
|
80
71
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
72
|
+
.rt-TextFieldRoot {
|
|
73
|
+
border-radius: 6px;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
84
77
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
font-size: 12px;
|
|
88
|
-
}
|
|
78
|
+
.entry-actions {
|
|
79
|
+
display: flex;
|
|
89
80
|
|
|
90
|
-
|
|
91
|
-
|
|
81
|
+
.entry-action-row {
|
|
82
|
+
width: auto;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
92
86
|
}
|
|
93
|
-
|
|
94
87
|
}
|
|
@@ -1,22 +1,19 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import {Box, Button, Flex, Text, TextField} from "@forge-kit/component";
|
|
3
3
|
import {PanelCard} from "@/components/panel-card";
|
|
4
|
+
import type {ForgeKitBridge, MapInputConfig} from "@/types";
|
|
4
5
|
import {noop} from "@/utils";
|
|
6
|
+
import classNames from "classnames";
|
|
5
7
|
import "./index.less";
|
|
6
8
|
|
|
7
|
-
interface MapInputConfig {
|
|
8
|
-
entryLine: string
|
|
9
|
-
entryColumn: string
|
|
10
|
-
contextLineRadius: string
|
|
11
|
-
}
|
|
12
|
-
|
|
13
9
|
interface MapInputPanelProps {
|
|
10
|
+
className?: string
|
|
14
11
|
chainDepth: number
|
|
15
12
|
entryFileName: string
|
|
16
13
|
inputConfig: MapInputConfig
|
|
17
14
|
onInputConfigChange: (next: MapInputConfig) => void
|
|
18
15
|
onResolve: () => void
|
|
19
|
-
|
|
16
|
+
onAppendMapFilePath: (filePath: string) => void
|
|
20
17
|
}
|
|
21
18
|
|
|
22
19
|
interface MapInputFieldProps {
|
|
@@ -45,25 +42,27 @@ const MapInputField: React.FC<MapInputFieldProps> = (props) => {
|
|
|
45
42
|
|
|
46
43
|
export const MapInputPanel: React.FC<MapInputPanelProps> = (props) => {
|
|
47
44
|
const {
|
|
45
|
+
className,
|
|
48
46
|
chainDepth,
|
|
49
47
|
entryFileName,
|
|
50
48
|
inputConfig,
|
|
51
49
|
onInputConfigChange,
|
|
52
50
|
onResolve,
|
|
53
|
-
|
|
51
|
+
onAppendMapFilePath,
|
|
54
52
|
} = props
|
|
55
53
|
|
|
56
|
-
const openFilePicker = () => {
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
54
|
+
const openFilePicker = async () => {
|
|
55
|
+
const openFileDialog = (window as Window & {forgeKit?: ForgeKitBridge}).forgeKit?.openFileDialog
|
|
56
|
+
if (!openFileDialog) return
|
|
57
|
+
|
|
58
|
+
const selected = await openFileDialog({
|
|
59
|
+
multiple: true,
|
|
60
|
+
filters: [{name: "Source Map", extensions: ["map", "json"]}],
|
|
61
|
+
})
|
|
62
|
+
const paths = Array.isArray(selected) ? selected : (selected ? [selected] : [])
|
|
63
|
+
paths.forEach((filePath) => {
|
|
64
|
+
if (typeof filePath === "string") onAppendMapFilePath(filePath)
|
|
65
|
+
})
|
|
67
66
|
}
|
|
68
67
|
|
|
69
68
|
const handleInputConfigChange = (field: keyof MapInputConfig, value: string) => {
|
|
@@ -71,7 +70,7 @@ export const MapInputPanel: React.FC<MapInputPanelProps> = (props) => {
|
|
|
71
70
|
}
|
|
72
71
|
|
|
73
72
|
return (
|
|
74
|
-
<PanelCard title="MAP INPUT" className="input-panel-card">
|
|
73
|
+
<PanelCard title="MAP INPUT" className={classNames("input-panel-card", className)}>
|
|
75
74
|
<Flex className="input-panel-content" direction='column' gap="3">
|
|
76
75
|
<Box className="input-summary-grid">
|
|
77
76
|
<Box className="input-summary-item">
|
|
@@ -1,18 +1,21 @@
|
|
|
1
|
+
.panel-card {
|
|
2
|
+
display: flex !important;
|
|
1
3
|
|
|
2
|
-
.panel-shell {
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
.panel-shell {
|
|
5
|
+
overflow: hidden;
|
|
6
|
+
flex: 1;
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
.panel-title {
|
|
9
|
+
display: block;
|
|
10
|
+
padding: 0 0 var(--space-3);
|
|
11
|
+
margin-bottom: var(--space-3);
|
|
12
|
+
border-bottom: solid 1px var(--gray-5);
|
|
13
|
+
font-size: 12px;
|
|
14
|
+
letter-spacing: 0.1em;
|
|
15
|
+
color: var(--gray-11);
|
|
16
|
+
text-transform: uppercase;
|
|
17
|
+
}
|
|
15
18
|
}
|
|
16
|
-
}
|
|
17
19
|
|
|
20
|
+
}
|
|
18
21
|
|
|
@@ -5,7 +5,7 @@ import './index.less'
|
|
|
5
5
|
|
|
6
6
|
interface PanelCardProps {
|
|
7
7
|
title: string
|
|
8
|
-
className
|
|
8
|
+
className?: string
|
|
9
9
|
children?: React.ReactNode
|
|
10
10
|
}
|
|
11
11
|
|
|
@@ -13,7 +13,7 @@ export const PanelCard: React.FC<PanelCardProps> = (props) => {
|
|
|
13
13
|
const {title, className, children} = props
|
|
14
14
|
|
|
15
15
|
return (
|
|
16
|
-
<Card className={classNames('panel-card', className)}>
|
|
16
|
+
<Card className={classNames('panel-card', className)} >
|
|
17
17
|
<Flex className="panel-shell" direction="column">
|
|
18
18
|
<Text className="panel-title">{title}</Text>
|
|
19
19
|
<>{children}</>
|