@weppy/roblox-mcp 2.17.8 → 2.17.10
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/CHANGELOG.md +27 -0
- package/README.md +14 -5
- package/dashboard/dist/assets/{AiPromptExamples-FjV57hJp.js → AiPromptExamples-BSFrFYar.js} +1 -1
- package/dashboard/dist/assets/AssetsPage-Bt9gZnJ_.js +61 -0
- package/dashboard/dist/assets/ChangelogPage-C4tBBoXT.js +1 -0
- package/dashboard/dist/assets/{ConfirmModal-Ddk0UX_P.js → ConfirmModal-BbqpSaVw.js} +1 -1
- package/dashboard/dist/assets/ConnectionPage-BStKoHK8.css +1 -0
- package/dashboard/dist/assets/ConnectionPage-Sy7xUWtJ.js +6 -0
- package/dashboard/dist/assets/{ControlsPage-Cl_mQpzx.js → ControlsPage-ECpr55X_.js} +1 -1
- package/dashboard/dist/assets/{GameChangeDetail-br9EgICc.js → GameChangeDetail-DJ0xywJq.js} +1 -1
- package/dashboard/dist/assets/InfoLabel-DAd1I756.js +1 -0
- package/dashboard/dist/assets/OverviewPage-C2xJb1Wf.js +1 -0
- package/dashboard/dist/assets/{PageHeader-Dc41DgFB.js → PageHeader-_z4Dtkbg.js} +1 -1
- package/dashboard/dist/assets/PlaceSelectOptions-Dd_m61bQ.js +1 -0
- package/dashboard/dist/assets/{PlaytestAiPromptExamples-CkR6t6Na.js → PlaytestAiPromptExamples-CNe0qWb1.js} +1 -1
- package/dashboard/dist/assets/{PlaytestPage-ShadLIAO.js → PlaytestPage-DZa14JH0.js} +18 -23
- package/dashboard/dist/assets/{SettingsPage-CGGHBxbL.js → SettingsPage-BiDPnuz8.js} +1 -1
- package/dashboard/dist/assets/SyncPage-BIm9tW0s.css +1 -0
- package/dashboard/dist/assets/SyncPage-EcDvwdB8.js +1 -0
- package/dashboard/dist/assets/Tabs-BoD1I6c5.js +1 -0
- package/dashboard/dist/assets/{CurrentPlaceScope-B6NllTmu.css → Tabs-Ci4-OJm-.css} +1 -1
- package/dashboard/dist/assets/{TierPromoPanel-B0BctivD.js → TierPromoPanel-CQQdO5mK.js} +1 -1
- package/dashboard/dist/assets/ToolsPage-D7ovZ3QM.js +1 -0
- package/dashboard/dist/assets/TooltipText-NA7u0bu6.js +1 -0
- package/dashboard/dist/assets/{UiStudioPage-DzG_JVxv.js → UiStudioPage-wYZQClUu.js} +2 -2
- package/dashboard/dist/assets/{WhatsNewPage-BpSGOLxW.js → WhatsNewPage-D3cvOOAD.js} +1 -1
- package/dashboard/dist/assets/{bot-BCKWpJd_.js → bot-D89pfHg8.js} +1 -1
- package/dashboard/dist/assets/{check-DvBWmDvn.js → check-GVlTbKVy.js} +1 -1
- package/dashboard/dist/assets/{copy-vqzBh0XB.js → copy-DVGVC27v.js} +1 -1
- package/dashboard/dist/assets/index-uP4eoQi-.js +746 -0
- package/dashboard/dist/assets/rotate-ccw-Dxk8CuFi.js +6 -0
- package/dashboard/dist/assets/sample-requests-CQy_WSFJ.js +1 -0
- package/dashboard/dist/assets/{trash-2-zj182u9_.js → trash-2-CEfHj47n.js} +1 -1
- package/dashboard/dist/assets/useLiveUptime-BGDr-4gk.js +1 -0
- package/dashboard/dist/assets/{useSettings-Cme-nLG9.js → useSettings-kOu_k9zT.js} +1 -1
- package/dashboard/dist/index.html +1 -1
- package/dist/index.js +170 -170
- package/package.json +1 -1
- package/roblox-plugin/WeppyRobloxMCP.rbxm +0 -0
- package/dashboard/dist/assets/AssetsPage-DvCSWpoy.js +0 -61
- package/dashboard/dist/assets/ChangelogPage-BrNOX2vc.js +0 -1
- package/dashboard/dist/assets/ConnectionPage-B3fGIK2X.css +0 -1
- package/dashboard/dist/assets/ConnectionPage-B62B5vSh.js +0 -6
- package/dashboard/dist/assets/CurrentPlaceScope-Y25KxsHT.js +0 -1
- package/dashboard/dist/assets/InfoLabel-CAGC3efT.js +0 -1
- package/dashboard/dist/assets/OverviewPage-DxRlbjwz.js +0 -1
- package/dashboard/dist/assets/PlaceSelectOptions-Gd2pK9DL.js +0 -1
- package/dashboard/dist/assets/StatusBadge-Cdfb5vyE.js +0 -1
- package/dashboard/dist/assets/SyncPage-BgbrC3SP.css +0 -1
- package/dashboard/dist/assets/SyncPage-CT2ECSYt.js +0 -1
- package/dashboard/dist/assets/Tabs-CPTkUoYi.css +0 -1
- package/dashboard/dist/assets/Tabs-Dl0dNd8V.js +0 -1
- package/dashboard/dist/assets/ToolsPage-CsFjwKOz.js +0 -1
- package/dashboard/dist/assets/TooltipText-C0DmdntK.js +0 -1
- package/dashboard/dist/assets/index-CG4GxcAc.js +0 -714
- package/dashboard/dist/assets/sample-requests-BqgMpTlQ.js +0 -1
- package/dashboard/dist/assets/useLiveUptime-yZ9iKJ1B.js +0 -1
- /package/dashboard/dist/assets/{StatusBadge-C2zYt5iE.css → useLiveUptime-C2zYt5iE.css} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -54,6 +54,33 @@ All notable changes to this project will be documented in this file.
|
|
|
54
54
|
|
|
55
55
|
|
|
56
56
|
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
## [2.17.10] - 2026-09-26
|
|
61
|
+
|
|
62
|
+
### Features
|
|
63
|
+
|
|
64
|
+
- **See Sync status for each connected Studio** — The Dashboard shows each Studio's Place and Sync state separately. Selecting a Studio to inspect its policy or logs does not change where AI commands are sent.
|
|
65
|
+
- **Review local changes and conflicts in Studio** — The Plugin gives pending changes a clearer review screen and lists bidirectional conflicts with Local and Studio previews before you choose which version to keep.
|
|
66
|
+
- **Restart an unresponsive Bridge from the Dashboard** — When an AI agent is connected, the Connection page can request a Bridge restart and show when Dashboard and Studio reconnect. Active Playtest controls are cleaned up during the restart.
|
|
67
|
+
- **Optional game feel guidance for AI agents** — The WEPPY agent plugin includes guidance for choosing feedback on hits, rewards, movement, and interactions to fit the game being built.
|
|
68
|
+
|
|
69
|
+
### Bug Fixes
|
|
70
|
+
|
|
71
|
+
- **Avoid duplicate Studio objects during reverse Sync** — Local script and properties files arriving together now create one Studio instance. Conflict resolution confirms a local change only after Studio applies it, so a failed apply remains available for review.
|
|
72
|
+
- **Show agent connection times accurately** — The Connection page separates the last confirmed contact from the most recent command instead of presenting one time as both.
|
|
73
|
+
- **Identify occupied Bridge ports correctly** — When a listener stops responding while holding the Bridge port, WEPPY reports a port ownership conflict instead of a generic startup timeout.
|
|
74
|
+
|
|
75
|
+
### Documentation
|
|
76
|
+
|
|
77
|
+
- **Clarify setup and current features** — Public setup guidance now covers Dola's manual MCP configuration, the Node.js 22 requirement, and current Playtest and Place shortcuts.
|
|
78
|
+
|
|
79
|
+
## [2.17.9] - 2026-09-21
|
|
80
|
+
|
|
81
|
+
### Bug Fixes
|
|
82
|
+
|
|
83
|
+
- **Show confirmed Place names in Dashboard selectors** — Tools, Changelog, Playtest, and Assets now keep the connected or last-active Place name visible when multiple folders share the same Place ID and the representative folder is not yet confirmed. The Dashboard still shows the representative-folder warning and folder details without replacing the known Place name with a generic ID label. No manual cleanup is required.
|
|
57
84
|
|
|
58
85
|
## [2.17.8] - 2026-09-21
|
|
59
86
|
|
package/README.md
CHANGED
|
@@ -61,10 +61,12 @@ Use this server command:
|
|
|
61
61
|
npx -y @weppy/roblox-mcp@latest
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
Automatic registration supports Claude Code, Claude Desktop, Cursor, Codex CLI, Codex App, Gemini CLI, and Antigravity / Antigravity IDE / Antigravity CLI.
|
|
65
65
|
|
|
66
66
|
> Any MCP-compatible AI client works. The server command is `npx -y @weppy/roblox-mcp@latest`.
|
|
67
67
|
|
|
68
|
+
**Dola Desktop** connects through a local STDIO Custom Connector. It requires Dola's Pro mode and Local computer. Follow the [Dola manual setup guide](https://weppyai.com/en/docs/agents/dola/); the one-line installer and GitHub marketplace plugin do not configure Dola.
|
|
69
|
+
|
|
68
70
|
### Optional WEPPY AI Agent Plugin
|
|
69
71
|
|
|
70
72
|
The **WEPPY Roblox AI Toolkit** connects to every supported AI app through the **WEPPY MCP Server**. Claude Code, Codex, and Antigravity can additionally install the **WEPPY AI Agent Plugin** for client-native setup and workflow guidance for Studio control, sync, and assets.
|
|
@@ -94,9 +96,9 @@ On Windows Antigravity, CLI installation has been verified to expose skills and
|
|
|
94
96
|
|
|
95
97
|
## Compatibility
|
|
96
98
|
|
|
97
|
-
| Claude Code | Claude Desktop | Cursor | Codex CLI | Gemini CLI | Antigravity / Antigravity IDE / Antigravity CLI |
|
|
98
|
-
|
|
99
|
-
| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
99
|
+
| Claude Code | Claude Desktop | Cursor | Codex CLI | Gemini CLI | Antigravity / Antigravity IDE / Antigravity CLI | Dola Desktop |
|
|
100
|
+
|:-----------:|:--------------:|:------:|:---------:|:----------:|:-----------------------------:|:------------:|
|
|
101
|
+
| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | [Manual setup](https://weppyai.com/en/docs/agents/dola/) |
|
|
100
102
|
|
|
101
103
|
**Requirements:** Node.js 22+, Roblox Studio, Windows 10+ or macOS 12+
|
|
102
104
|
|
|
@@ -125,6 +127,8 @@ Many Roblox experiences are not a single Place. WEPPY lets you keep up to five S
|
|
|
125
127
|
|
|
126
128
|
### 3) Assets: Generate, upload, and apply images in Studio
|
|
127
129
|
|
|
130
|
+
If your AI app can create PNG or JPG files, it can make a new image for this workflow. Otherwise, start with an image you already have and register it in Asset Library before uploading it.
|
|
131
|
+
|
|
128
132
|
WEPPY Assets turns a natural-language asset request into a Studio-ready result.
|
|
129
133
|
|
|
130
134
|
- "Create a gem icon for the shop button, upload it to Roblox, then apply it to the ShopButton image in the Lobby Place."
|
|
@@ -136,11 +140,12 @@ WEPPY Assets turns a natural-language asset request into a Studio-ready result.
|
|
|
136
140
|
|
|
137
141
|
### 4) Sync: Keep full project context stable for AI
|
|
138
142
|
|
|
139
|
-
AI
|
|
143
|
+
AI reads a local mirror of your Studio project. Review pending local changes before applying them to Studio.
|
|
140
144
|
|
|
141
145
|
- Sync starts Off on first use. Start on connection is also Off. Saved settings always take precedence, including a saved Off value. The first-use workflow is Studio First, so the first synchronization treats Studio as the source.
|
|
142
146
|
- Choose Studio First, Bidirectional Review, Local Code, Studio World, or Custom. Custom groups changes into four semantic scopes: Script Source, Properties, Structure, and Service Properties.
|
|
143
147
|
- Content Changes and Structure Changes application modes are shown separately from scope direction. Local file deletion does not delete a Studio instance by default; applying a deletion to Studio requires an additional opt-in and is separate from UI Studio history cleanup.
|
|
148
|
+
- **Review Changes** lists local edits waiting for manual application. **Review Conflicts** lists files changed differently in Studio and locally; compare both versions before choosing one.
|
|
144
149
|
- Basic uses Studio-to-local Sync. Pro adds the richer workflow directions, history, and support for up to five Places.
|
|
145
150
|
- The WEPPY MCP Server and WEPPY Roblox Studio Plugin must come from the same release. Update both together, then restart Roblox Studio before reconnecting if their versions do not match.
|
|
146
151
|
|
|
@@ -164,6 +169,8 @@ Ordinary runtime checks use a structured Play session. AI can wait for game UI,
|
|
|
164
169
|
|
|
165
170
|
The same Playtest page also includes a **Test Values** workspace for development-only values. Create multiple Place-scoped profiles for different test setups; the Dashboard remembers the last profile selected for each Place. While Play or Run remains active, you can switch, create, edit, or delete profiles without restarting the game. Switching keeps the current game values and changes the controls, Watch Values, and Actions shown for the same session. Controls and read-only observations appear in one searchable, paginated list, so large profiles remain easy to scan. Use **Manage values** to add entries discovered from Project Test Adapters, or use a runtime path and the current Studio selection for direct values. A stale or disconnected observation is shown as the last observed value instead of being presented as current.
|
|
166
171
|
|
|
172
|
+
On Pro, profile **Actions** can run a prepared game operation during Play, such as changing a value or calling a reviewed Test Adapter. Actions report their result separately from value changes. **Reset all** restores reversible value changes; it cannot undo saved game data, deaths, rewards, or external requests caused by an Action.
|
|
173
|
+
|
|
167
174
|
Basic includes profile creation and live runtime observation. Pro adds typed value changes during Play, rollback, **Reset all**, and actual saved **Automated Test Results**. The Playtest page explains the Pro additions and links directly to available plans and purchase options.
|
|
168
175
|
|
|
169
176
|
Studio Stop discards Play/Run Instance changes. While the runtime remains active, **Reset all** restores every reversible value changed through any profile in that session, and a partially failed transaction rolls back. Games that cache values at startup or need domain operations can expose reviewed Project Test Adapter methods through optional Dashboard metadata. The Dashboard validates the metadata, shows the registration source, and links a read-only observer to each adapter control. Removing a profile reference leaves the adapter source intact.
|
|
@@ -196,6 +203,8 @@ The MCP server provides a web dashboard where you can check connection status, t
|
|
|
196
203
|
|
|
197
204
|
- Connection topology for AI agents, the MCP server, and connected Roblox Studio windows
|
|
198
205
|
- Studio Targets with copyable Studio IDs, Priority/Pinned badges, and a link to routing controls
|
|
206
|
+
- Published Place names and quick links to Place settings, Experience management, and the Roblox page
|
|
207
|
+
- Place folders available in Tools, Playtest, Changelog, and Assets before the first Sync; duplicate folders are identified for review
|
|
199
208
|
- Multi-agent and multi-Studio workflows: keep several agents and up to five Studio windows visible, then tell the agent which Studio ID to use
|
|
200
209
|
- Assets page for local library items, shared assets, and Roblox upload status
|
|
201
210
|
- Controls page for enforcing post-write Luau syntax validation, including clear On and Off behavior
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as i,j as t}from"./index-
|
|
1
|
+
import{r as i,j as t}from"./index-uP4eoQi-.js";import{C as d}from"./copy-DVGVC27v.js";const _="_examples_1sykl_1",m="_example_1sykl_1",h="_request_1sykl_15",j="_nextStep_1sykl_16",b="_actionRow_1sykl_40",f="_copyButton_1sykl_47",k="_success_1sykl_79",w="_error_1sykl_80",c={examples:_,example:m,request:h,nextStep:j,actionRow:b,copyButton:f,success:k,error:w};function N(s){const[p,a]=i.useState({}),n=i.useRef(0),x=s.examples.map(e=>e.id).join("|");i.useEffect(()=>(n.current+=1,a({}),()=>{n.current+=1}),[x,s.resetKey]);const y=async(e,r)=>{var u;const l=++n.current;a(o=>({...o,[e]:"copying"}));try{if(!((u=navigator.clipboard)!=null&&u.writeText))throw new Error("clipboard_unavailable");if(await navigator.clipboard.writeText(r),l!==n.current)return;a(o=>({...o,[e]:"copied"}))}catch{if(l!==n.current)return;a(o=>({...o,[e]:"error"}))}};return t.jsxs("div",{className:c.examples,children:[s.examples.map(e=>{const r=p[e.id]??"idle";return t.jsxs("section",{className:c.example,children:[t.jsx("h4",{children:e.title}),t.jsx("p",{className:c.request,children:e.request}),t.jsxs("div",{className:c.actionRow,children:[t.jsxs("button",{type:"button",className:c.copyButton,disabled:r==="copying",onClick:()=>void y(e.id,e.request),children:[t.jsx(d,{size:14,"aria-hidden":"true"}),r==="copying"?s.labels.copying:s.labels.copy]}),r==="copied"&&t.jsx("span",{className:c.success,role:"status",children:s.labels.copied})]}),r==="error"&&t.jsx("p",{className:c.error,role:"alert",children:s.labels.copyFailed})]},e.id)}),s.nextStep&&t.jsx("p",{className:c.nextStep,children:s.nextStep})]})}export{N as A};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import{f as le,b as F,l as we,u as ce,j as s,P as ws,I as Rs,r as c,F as $s,m as Ls,R as fs,X as Xe,E as Us,n as bs,g as Ts,o as Ve,p as be,q as Ae,t as Bs,v as Es,a as Gs,e as Ms}from"./index-uP4eoQi-.js";import{C as ys}from"./ConfirmModal-BbqpSaVw.js";import{B as me,C as Ds,D as Qe,b as Fs,P as Os}from"./PageHeader-_z4Dtkbg.js";import{P as Hs,a as zs}from"./PlaceSelectOptions-Dd_m61bQ.js";import{T as se}from"./TooltipText-NA7u0bu6.js";import{A as Ks}from"./AiPromptExamples-BSFrFYar.js";import{B as Ws}from"./bot-D89pfHg8.js";import{T as Vs}from"./trash-2-CEfHj47n.js";import{C as js}from"./copy-DVGVC27v.js";import"./ConfirmModal.module-DJksQHBd.js";/**
|
|
2
|
+
* @license lucide-react v1.8.0 - ISC
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the ISC license.
|
|
5
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/const Ys=[["path",{d:"m12 19-7-7 7-7",key:"1l729n"}],["path",{d:"M19 12H5",key:"x3x0zl"}]],qs=le("arrow-left",Ys);/**
|
|
7
|
+
* @license lucide-react v1.8.0 - ISC
|
|
8
|
+
*
|
|
9
|
+
* This source code is licensed under the ISC license.
|
|
10
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
11
|
+
*/const Xs=[["path",{d:"M2 10v3",key:"1fnikh"}],["path",{d:"M6 6v11",key:"11sgs0"}],["path",{d:"M10 3v18",key:"yhl04a"}],["path",{d:"M14 8v7",key:"3a1oy3"}],["path",{d:"M18 5v13",key:"123xd1"}],["path",{d:"M22 10v3",key:"154ddg"}]],Js=le("audio-lines",Xs);/**
|
|
12
|
+
* @license lucide-react v1.8.0 - ISC
|
|
13
|
+
*
|
|
14
|
+
* This source code is licensed under the ISC license.
|
|
15
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
16
|
+
*/const Zs=[["path",{d:"M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z",key:"3c2336"}]],Qs=le("badge",Zs);/**
|
|
17
|
+
* @license lucide-react v1.8.0 - ISC
|
|
18
|
+
*
|
|
19
|
+
* This source code is licensed under the ISC license.
|
|
20
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
21
|
+
*/const et=[["path",{d:"M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z",key:"hh9hay"}],["path",{d:"m3.3 7 8.7 5 8.7-5",key:"g66t2b"}],["path",{d:"M12 22V12",key:"d0xqtd"}]],st=le("box",et);/**
|
|
22
|
+
* @license lucide-react v1.8.0 - ISC
|
|
23
|
+
*
|
|
24
|
+
* This source code is licensed under the ISC license.
|
|
25
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
26
|
+
*/const tt=[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]],He=le("chevron-right",tt);/**
|
|
27
|
+
* @license lucide-react v1.8.0 - ISC
|
|
28
|
+
*
|
|
29
|
+
* This source code is licensed under the ISC license.
|
|
30
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
31
|
+
*/const at=[["path",{d:"m12.296 3.464 3.02 3.956",key:"qash78"}],["path",{d:"M20.2 6 3 11l-.9-2.4c-.3-1.1.3-2.2 1.3-2.5l13.5-4c1.1-.3 2.2.3 2.5 1.3z",key:"1h7j8b"}],["path",{d:"M3 11h18v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z",key:"4lm6w1"}],["path",{d:"m6.18 5.276 3.1 3.899",key:"zjj9t3"}]],lt=le("clapperboard",at);/**
|
|
32
|
+
* @license lucide-react v1.8.0 - ISC
|
|
33
|
+
*
|
|
34
|
+
* This source code is licensed under the ISC license.
|
|
35
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
36
|
+
*/const nt=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}],["path",{d:"M7 3v18",key:"bbkbws"}],["path",{d:"M3 7.5h4",key:"zfgn84"}],["path",{d:"M3 12h18",key:"1i2n21"}],["path",{d:"M3 16.5h4",key:"1230mu"}],["path",{d:"M17 3v18",key:"in4fa5"}],["path",{d:"M17 7.5h4",key:"myr1c1"}],["path",{d:"M17 16.5h4",key:"go4c1d"}]],ot=le("film",nt);/**
|
|
37
|
+
* @license lucide-react v1.8.0 - ISC
|
|
38
|
+
*
|
|
39
|
+
* This source code is licensed under the ISC license.
|
|
40
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
41
|
+
*/const rt=[["path",{d:"M2 9V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H20a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2v-1",key:"fm4g5t"}],["path",{d:"M2 13h10",key:"pgb2dq"}],["path",{d:"m9 16 3-3-3-3",key:"6m91ic"}]],it=le("folder-input",rt);/**
|
|
42
|
+
* @license lucide-react v1.8.0 - ISC
|
|
43
|
+
*
|
|
44
|
+
* This source code is licensed under the ISC license.
|
|
45
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
46
|
+
*/const dt=[["path",{d:"M12 3v18",key:"108xh3"}],["path",{d:"M3 12h18",key:"1i2n21"}],["rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",key:"h1oib"}]],ct=le("grid-2x2",dt);/**
|
|
47
|
+
* @license lucide-react v1.8.0 - ISC
|
|
48
|
+
*
|
|
49
|
+
* This source code is licensed under the ISC license.
|
|
50
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
51
|
+
*/const ut=[["path",{d:"M3 5h.01",key:"18ugdj"}],["path",{d:"M3 12h.01",key:"nlz23k"}],["path",{d:"M3 19h.01",key:"noohij"}],["path",{d:"M8 5h13",key:"1pao27"}],["path",{d:"M8 12h13",key:"1za7za"}],["path",{d:"M8 19h13",key:"m83p4d"}]],pt=le("list",ut);/**
|
|
52
|
+
* @license lucide-react v1.8.0 - ISC
|
|
53
|
+
*
|
|
54
|
+
* This source code is licensed under the ISC license.
|
|
55
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
56
|
+
*/const ht=[["path",{d:"m21 21-4.34-4.34",key:"14j7rj"}],["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}]],mt=le("search",ht);/**
|
|
57
|
+
* @license lucide-react v1.8.0 - ISC
|
|
58
|
+
*
|
|
59
|
+
* This source code is licensed under the ISC license.
|
|
60
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
61
|
+
*/const xt=[["path",{d:"M12 3v12",key:"1x0j5s"}],["path",{d:"m17 8-5-5-5 5",key:"7q97r8"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}]],gt=le("upload",xt);function vs(e){if(e.scope==="place"&&typeof e.placeId=="number")return{placeId:String(e.placeId)}}function ne(e){const t=vs(e);return t?`?placeId=${encodeURIComponent(t.placeId)}`:""}function $e(e){return`/api/assets/${encodeURIComponent(e.scope)}/${encodeURIComponent(e.category)}`}function ue(e,t){return`${$e(e)}/${encodeURIComponent(t)}`}async function ft(e){return F.get($e(e),vs(e))}async function bt(e){return F.post(`${$e(e)}/rescan${ne(e)}`,{})}async function yt(e,t,n){return(await F.patch(`${ue(e,t)}${ne(e)}`,n)).asset}async function jt(e,t){return F.delete(`${ue(e,t)}${ne(e)}`)}async function vt(e,t,n){return(await F.post(`${ue(e,t)}/upload${ne(e)}`,n)).asset}async function es(e,t){return(await F.post(`${ue(e,t)}/status-refresh${ne(e)}`,{})).asset}async function Ct(e,t,n){const l={...e,placeId:n??e.placeId};return F.post(`${ue(e,t)}/usage-scan${ne(l)}`,{})}async function _t(e,t){return F.post(`${$e(e)}/export-selection-rbxm${ne(e)}`,t)}async function St(e,t,n){return F.post(`${ue(e,t)}/import-rbxm${ne(e)}`,n)}async function Nt(e,t){return(await F.post(`${ue(e,t)}/thumbnail-generate${ne(e)}`,{})).asset}function Cs(e){return e.fileUrl?`${we}${e.fileUrl}`:`${we}/api/assets/${e.scope.kind}/${e.category}/${encodeURIComponent(e.id)}/file${ne({scope:e.scope.kind,placeId:e.scope.kind==="place"?e.scope.placeId:void 0})}`}function Ye(e){return e.previewUrl?`${we}${e.previewUrl}`:`${we}/api/assets/${e.scope.kind}/${e.category}/${encodeURIComponent(e.id)}/preview${ne({scope:e.scope.kind,placeId:e.scope.kind==="place"?e.scope.placeId:void 0})}`}const _s=["all","image","decal","rbxm"],Pt=new Set(_s),ss=["model","animation"];function Ie(e){return/\.(rbxm|rbxmx)$/i.test(e.file.original)}function At(e){return Pt.has(e)}function qe(e,t){return e==="all"?t("assets.category.all","All"):t(`assets.category.${e}`,e==="rbxm"?"RBXM":e)}function ie(e,t){return qe(Ie(e)?"rbxm":e.category,t)}function It(e){return e==="all"?["image","decal",...ss]:e==="rbxm"?ss:[e]}function kt(e,t){return t==="all"?e.category==="image"||e.category==="decal"||Ie(e):t==="rbxm"?Ie(e):(t==="model"||t==="animation")&&Ie(e)?!1:e.category===t}function wt(e){return[...e].sort((t,n)=>n.createdAt.localeCompare(t.createdAt)||n.id.localeCompare(t.id))}function Le(e){return e?e.split("/").filter(Boolean):[]}function Je(e,t){return t.every((n,l)=>e[l]===n)}function Ss(e,t){return t.createdAt.localeCompare(e.createdAt)||t.id.localeCompare(e.id)}function te(e){const t=e.scope.kind==="place"?e.scope.placeId:"-";return`${e.scope.kind}:${t}:${e.category}:${e.id}`}function Ze(e){return Le(e.folderPath)}function Rt(e,t){const n=Le(t),l=new Map;for(const o of e){const f=Ze(o);if(f.length<=n.length||!Je(f,n))continue;const g=f[n.length],x=[...n,g].join("/"),p=l.get(x);p?p.descendantCount+=1:l.set(x,{name:g,path:x,descendantCount:1})}return[...l.values()].sort((o,f)=>o.name.localeCompare(f.name))}function $t(e,t){const n=Le(t);return e.filter(l=>{const o=Ze(l);return o.length===n.length&&Je(o,n)}).sort(Ss)}function Lt(e){return[...e].sort(Ss)}function Ut(e,t){const n=Le(t);for(;n.length>0;){if(e.some(o=>{const f=Ze(o);return f.length>=n.length&&Je(f,n)}))return n.join("/");n.pop()}return""}const Tt="_page_leed4_1",Bt="_experimentalBadge_leed4_9",Et="_toolbarShell_leed4_23",Gt="_toolbar_leed4_23",Mt="_segmented_leed4_41",Dt="_placeContextSlot_leed4_45",Ft="_listContextSummary_leed4_50",Ot="_toolbarActions_leed4_54",Ht="_toolbarExpandedSummary_leed4_59",zt="_placeFolderDetails_leed4_67",Kt="_categoryControl_leed4_72",Wt="_placeStatusGroup_leed4_94",Vt="_contextTextSummary_leed4_95",Yt="_contextDivider_leed4_116",qt="_categoryControlLabel_leed4_120",Xt="_categoryRail_leed4_126",Jt="_categoryButton_leed4_134",Zt="_categoryButtonActive_leed4_163",Qt="_copyRow_leed4_176",ea="_buttonRow_leed4_177",sa="_segmentedActive_leed4_219",ta="_placeSelectorLabel_leed4_224",aa="_placeSelect_leed4_224",la="_sharedPlaceContext_leed4_251",na="_commandButton_leed4_277",oa="_primaryButton_leed4_278",ra="_iconButton_leed4_279",ia="_dangerButton_leed4_319",da="_iconButtonActive_leed4_340",ca="_grid_leed4_353",ua="_folderGrid_leed4_361",pa="_explorer_leed4_370",ha="_explorerToolbar_leed4_377",ma="_explorerLocation_leed4_387",xa="_breadcrumb_leed4_413",ga="_breadcrumbSegment_leed4_414",fa="_viewOptions_leed4_457",ba="_organizationModeControl_leed4_465",ya="_viewModeControl_leed4_466",ja="_gridSizeControl_leed4_467",va="_explorerSection_leed4_520",Ca="_folderTile_leed4_543",_a="_folderListRow_leed4_568",Sa="_assetListRow_leed4_569",Na="_assetCard_leed4_570",Pa="_folderIcon_leed4_575",Aa="_folderName_leed4_587",Ia="_folderCount_leed4_599",ka="_assetList_leed4_569",wa="_folderList_leed4_568",Ra="_assetListHeader_leed4_613",$a="_listPreviewWrap_leed4_650",La="_listPreview_leed4_650",Ua="_listPreviewFallback_leed4_652",Ta="_listAssetName_leed4_681",Ba="_listAssetCategory_leed4_693",Ea="_listAssetScope_leed4_694",Ga="_listAssetUpdated_leed4_695",Ma="_folderType_leed4_696",Da="_folderScope_leed4_697",Fa="_folderStatus_leed4_698",Oa="_folderUpdated_leed4_699",Ha="_assetCardSelected_leed4_728",za="_thumbnailWrap_leed4_733",Ka="_thumbnail_leed4_733",Wa="_thumbnailFallback_leed4_749",Va="_assetCardBody_leed4_760",Ya="_assetName_leed4_767",qa="_assetMeta_leed4_775",Xa="_statusChip_leed4_782",Ja="_categoryPill_leed4_783",Za="_assetId_leed4_788",Qa="_scopeText_leed4_789",el="_muted_leed4_790",sl="_emptyState_leed4_795",tl="_notice_leed4_796",al="_errorState_leed4_797",ll="_messageState_leed4_798",nl="_emptyGuide_leed4_822",ol="_emptyGuideHeader_leed4_832",rl="_emptyGuideMethod_leed4_833",il="_emptyGuideSteps_leed4_855",dl="_emptyGuideMethods_leed4_861",cl="_emptyGuideMethodTitle_leed4_875",ul="_emptyGuideTierNote_leed4_893",pl="_emptyGuideMethodHelp_leed4_898",hl="_emptyGuideCapabilityDescription_leed4_899",ml="_emptyGuideChoices_leed4_905",xl="_emptyGuideChoice_leed4_905",gl="_emptyGuideChoiceSelected_leed4_933",fl="_emptyGuideChoiceLabel_leed4_943",bl="_emptyGuideCapability_leed4_899",yl="_emptyGuideAction_leed4_959",jl="_proNotice_leed4_989",vl="_rbxmGuide_leed4_1007",Cl="_settingsInlinePanel_leed4_1047",_l="_settingsDrawer_leed4_1067",Sl="_detailPopupLayer_leed4_1083",Nl="_detailDialog_leed4_1099",Pl="_detailDialogHeader_leed4_1116",Al="_detailTitleBlock_leed4_1127",Il="_detailEyebrow_leed4_1149",kl="_detailHeaderActions_leed4_1158",wl="_detailDialogBody_leed4_1166",Rl="_detailPreviewPane_leed4_1175",$l="_detailPreview_leed4_1175",Ll="_detailPreviewFallback_leed4_1187",Ul="_detailContentPane_leed4_1223",Tl="_formStack_leed4_1229",Bl="_drawerHeader_leed4_1233",El="_detailSection_leed4_1284",Gl="_noticeList_leed4_1285",Ml="_settingsPanel_leed4_1286",Dl="_setupNotice_leed4_1303",Fl="_field_leed4_1328",Ol="_fieldLabelRow_leed4_1336",Hl="_fieldHelp_leed4_1360",zl="_twoColumn_leed4_1365",Kl="_technicalDetails_leed4_1376",Wl="_detailGrid_leed4_1393",Vl="_metadataList_leed4_1394",Yl="_compactMeta_leed4_1405",ql="_copyableValue_leed4_1432",Xl="_inlineCopyButton_leed4_1443",Jl="_hashText_leed4_1464",Zl="_usageList_leed4_1468",Ql="_usageItem_leed4_1474",en="_metadataItem_leed4_1475",sn="_settingsSubsection_leed4_1523",tn="_settingsSectionHeader_leed4_1528",an="_settingsDefinitionList_leed4_1541",ln="_toggleRow_leed4_1563",nn="_inlineHelp_leed4_1577",a={page:Tt,experimentalBadge:Bt,toolbarShell:Et,toolbar:Gt,segmented:Mt,placeContextSlot:Dt,listContextSummary:Ft,toolbarActions:Ot,toolbarExpandedSummary:Ht,placeFolderDetails:zt,categoryControl:Kt,placeStatusGroup:Wt,contextTextSummary:Vt,contextDivider:Yt,categoryControlLabel:qt,categoryRail:Xt,categoryButton:Jt,categoryButtonActive:Zt,copyRow:Qt,buttonRow:ea,segmentedActive:sa,placeSelectorLabel:ta,placeSelect:aa,sharedPlaceContext:la,commandButton:na,primaryButton:oa,iconButton:ra,dangerButton:ia,iconButtonActive:da,grid:ca,folderGrid:ua,explorer:pa,explorerToolbar:ha,explorerLocation:ma,breadcrumb:xa,breadcrumbSegment:ga,viewOptions:fa,organizationModeControl:ba,viewModeControl:ya,gridSizeControl:ja,explorerSection:va,folderTile:Ca,folderListRow:_a,assetListRow:Sa,assetCard:Na,folderIcon:Pa,folderName:Aa,folderCount:Ia,assetList:ka,folderList:wa,assetListHeader:Ra,listPreviewWrap:$a,listPreview:La,listPreviewFallback:Ua,listAssetName:Ta,listAssetCategory:Ba,listAssetScope:Ea,listAssetUpdated:Ga,folderType:Ma,folderScope:Da,folderStatus:Fa,folderUpdated:Oa,assetCardSelected:Ha,thumbnailWrap:za,thumbnail:Ka,thumbnailFallback:Wa,assetCardBody:Va,assetName:Ya,assetMeta:qa,statusChip:Xa,categoryPill:Ja,assetId:Za,scopeText:Qa,muted:el,emptyState:sl,notice:tl,errorState:al,messageState:ll,emptyGuide:nl,emptyGuideHeader:ol,emptyGuideMethod:rl,emptyGuideSteps:il,emptyGuideMethods:dl,emptyGuideMethodTitle:cl,emptyGuideTierNote:ul,emptyGuideMethodHelp:pl,emptyGuideCapabilityDescription:hl,emptyGuideChoices:ml,emptyGuideChoice:xl,emptyGuideChoiceSelected:gl,emptyGuideChoiceLabel:fl,emptyGuideCapability:bl,emptyGuideAction:yl,proNotice:jl,rbxmGuide:vl,settingsInlinePanel:Cl,settingsDrawer:_l,detailPopupLayer:Sl,detailDialog:Nl,detailDialogHeader:Pl,detailTitleBlock:Al,detailEyebrow:Il,detailHeaderActions:kl,detailDialogBody:wl,detailPreviewPane:Rl,detailPreview:$l,detailPreviewFallback:Ll,detailContentPane:Ul,formStack:Tl,drawerHeader:Bl,detailSection:El,noticeList:Gl,settingsPanel:Ml,setupNotice:Dl,field:Fl,fieldLabelRow:Ol,fieldHelp:Hl,twoColumn:zl,technicalDetails:Kl,detailGrid:Wl,metadataList:Vl,compactMeta:Yl,copyableValue:ql,inlineCopyButton:Xl,hashText:Jl,usageList:Zl,usageItem:Ql,metadataItem:en,settingsSubsection:sn,settingsSectionHeader:tn,settingsDefinitionList:an,toggleRow:ln,inlineHelp:nn},on={image:Rs,decal:Qs,audio:Js,mesh:st,model:ws,video:ot,animation:lt};function Re(e,t){return t(`assets.status.${e}`,e)}function ts(e){switch(e){case"uploaded":return"success";case"failed":return"error";case"processing":case"uploading":return"warning";case"localOnly":case"superseded":default:return"neutral"}}function as(e){return e.category==="image"||e.category==="decal"||!!e.file.preview}function rn(e){return e.category==="decal"?e.roblox.creatorAssetId??e.roblox.assetId:e.roblox.assetId}function Ns(e,t){var g;const n=((g=e.rbxm)==null?void 0:g.studioUploads)??[];if(n.length===0)return null;const l=n.filter(x=>x.status==="uploaded").length,o=n.filter(x=>x.status==="failed").length,f=[l>0?`${l} ${t("assets.detail.rbxmStudioUploadsUploaded","uploaded")}`:null,o>0?`${o} ${t("assets.detail.rbxmStudioUploadsFailed","failed")}`:null].filter(Boolean);return`${t("assets.detail.rbxmStudioUploadsLabel","Studio uploads")}: ${f.join(", ")}`}function dn({assets:e,selectedAssetId:t,selectedAssetKey:n=null,viewMode:l="grid",gridSize:o="medium",onSelect:f}){const{t:g}=ce();return e.length===0?s.jsxs("div",{className:a.emptyState,children:[s.jsx("p",{children:g("assets.empty.title","No assets yet")}),s.jsx("span",{children:g("assets.empty.body","Choose a scope and category, then rescan that inbox folder.")})]}):s.jsx("div",{className:l==="list"?a.assetList:a.grid,"data-view-mode":l,"data-grid-size":o,children:e.map(x=>{const p=on[x.category],L=rn(x),K=Ns(x,g),E=te(x),R=n?n===E:t===x.id,r=x.scope.kind==="shared"?g("assets.scope.shared","Shared"):g("assets.scope.place","Current Place");return l==="list"?s.jsxs("button",{type:"button",className:[a.assetListRow,R?a.assetCardSelected:""].filter(Boolean).join(" "),onClick:()=>f(E),children:[s.jsx("span",{className:a.listPreviewWrap,children:as(x)?s.jsx("img",{className:a.listPreview,src:Ye(x),alt:"",loading:"lazy"}):s.jsx("span",{className:a.listPreviewFallback,"aria-hidden":"true",children:s.jsx(p,{size:18})})}),s.jsx("span",{className:a.listAssetName,children:x.displayName}),s.jsx("span",{className:a.listAssetCategory,children:ie(x,g)}),s.jsx("span",{className:a.listAssetScope,children:r}),s.jsx(me,{variant:ts(x.status),className:a.statusChip,children:Re(x.status,g)}),s.jsx("time",{className:a.listAssetUpdated,dateTime:x.updatedAt,children:new Date(x.updatedAt).toLocaleDateString()})]},E):s.jsxs("button",{type:"button",className:[a.assetCard,R?a.assetCardSelected:""].filter(Boolean).join(" "),onClick:()=>f(E),children:[s.jsx("span",{className:a.thumbnailWrap,children:as(x)?s.jsx("img",{className:a.thumbnail,src:Ye(x),alt:x.displayName,loading:"lazy"}):s.jsx("span",{className:a.thumbnailFallback,"aria-hidden":"true",children:s.jsx(p,{size:30})})}),s.jsxs("span",{className:a.assetCardBody,children:[s.jsx("span",{className:a.assetName,children:x.displayName}),s.jsxs("span",{className:a.assetMeta,children:[s.jsx(me,{variant:"neutral",className:a.categoryPill,children:ie(x,g)}),s.jsx(me,{variant:ts(x.status),className:a.statusChip,children:Re(x.status,g)})]}),s.jsxs("span",{className:a.assetMeta,children:[s.jsx("span",{className:a.scopeText,children:r}),s.jsx("span",{className:a.assetId,children:L?`#${L}`:K??g("assets.status.localOnly","Local only")})]})]})]},E)})})}function ls(e){return{scope:e==="all"?null:e,folderPath:""}}function ze(e,t,n){return t==="shared"?e.scope.kind==="shared":e.scope.kind==="place"&&(n===null||e.scope.placeId===n)}function cn(e,t){var n;return t?e.folderPath===t||((n=e.folderPath)==null?void 0:n.startsWith(`${t}/`))===!0:!0}function un({displayScope:e,assets:t,place:n,categoryFilter:l,organizationMode:o,viewMode:f,gridSize:g,selectedAssetKey:x,onSelectAsset:p,onClearSelection:L,onOrganizationModeChange:K,onViewModeChange:E,onGridSizeChange:R,emptyContent:r}){const{t:b}=ce(),[N,T]=c.useState(()=>ls(e)),W=c.useRef(`${e}:${n.placeId??"-"}`),V=c.useRef(!1),M=c.useRef(null),B=m=>m==="shared"?b("assets.scope.shared","Shared"):n.placeName??b("assets.scope.place","Current Place"),G=m=>{V.current=!0,T(m),L()};c.useEffect(()=>{const m=`${e}:${n.placeId??"-"}`;W.current!==m&&(W.current=m,V.current=!0,T(ls(e)),L())},[e,L,n.placeId]),c.useEffect(()=>{var m;V.current&&(V.current=!1,(m=M.current)==null||m.focus())},[N]);const H=c.useMemo(()=>N.scope===null?[]:t.filter(m=>ze(m,N.scope,n.placeId)),[t,N.scope,n.placeId]);c.useEffect(()=>{if(N.scope===null)return;const m=Ut(H,N.folderPath);m!==N.folderPath&&(V.current=!0,T(U=>({...U,folderPath:m})),L())},[l,N.folderPath,N.scope,L,H]);const D=c.useMemo(()=>o==="folders"?Rt(H,N.folderPath):[],[N.folderPath,o,H]),Q=c.useMemo(()=>e==="all"?t:t.filter(m=>ze(m,e,n.placeId)),[t,e,n.placeId]),P=c.useMemo(()=>o==="all-assets"?Lt(Q):$t(H,N.folderPath),[Q,N.folderPath,o,H]);c.useEffect(()=>{x&&(P.some(m=>te(m)===x)||L())},[L,x,P]);const A=N.folderPath?N.folderPath.split("/"):[],q=o==="all-assets"?b("assets.organization.all","All assets"):A[A.length-1]??(N.scope?B(N.scope):b("assets.scope.all","All scopes")),$=N.scope===null?t.length:H.filter(m=>cn(m,N.folderPath)).length,k=Math.max(0,$-P.length),i=o==="all-assets"?b("assets.organization.summary","{count} assets").replace("{count}",String(P.length)):b("assets.explorer.summary","{direct} in this folder · {descendant} in subfolders").replace("{direct}",String(P.length)).replace("{descendant}",String(k)),y=m=>m===1?b("assets.folder.count.one","1 asset"):b("assets.folder.count.many","{count} assets").replace("{count}",String(m)),X=(m,U,h,z,_)=>s.jsxs("button",{type:"button",className:f==="list"?a.folderListRow:a.folderTile,"aria-label":`${U}, ${y(h)}`,onClick:_,children:[s.jsx("span",{className:a.folderIcon,"aria-hidden":"true",children:s.jsx($s,{size:f==="list"?22:28})}),s.jsx("span",{className:a.folderName,children:U}),f==="list"?s.jsxs(s.Fragment,{children:[s.jsx("span",{className:a.folderType,children:b("assets.folder.type","Folder")}),s.jsx("span",{className:a.folderScope,children:B(z)}),s.jsx("span",{className:a.folderStatus,children:y(h)}),s.jsx("span",{className:a.folderUpdated,children:"—"})]}):s.jsx("span",{className:a.folderCount,children:y(h)})]},m),w=o==="folders"&&e==="all"&&N.scope===null?[{scope:"place",name:B("place")},{scope:"shared",name:B("shared")}].map(({scope:m,name:U})=>({scope:m,name:U,count:t.filter(h=>ze(h,m,n.placeId)).length})):[];return s.jsxs("section",{className:a.explorer,"aria-label":b("assets.explorer.label","Asset explorer"),children:[s.jsxs("div",{className:a.explorerToolbar,children:[s.jsxs("div",{className:a.explorerLocation,children:[s.jsxs("nav",{className:a.breadcrumb,"aria-label":b("assets.breadcrumb.label","Asset path"),children:[o==="all-assets"?s.jsxs(s.Fragment,{children:[s.jsx("span",{children:e==="all"?b("assets.scope.all","All scopes"):B(e)}),s.jsx(He,{size:14,"aria-hidden":"true"}),s.jsx("span",{"aria-current":"page",children:b("assets.organization.all","All assets")})]}):e==="all"?N.scope===null?s.jsx("span",{"aria-current":"page",children:b("assets.scope.all","All scopes")}):s.jsx("button",{type:"button",onClick:()=>G({scope:null,folderPath:""}),children:b("assets.scope.all","All scopes")}):null,o==="folders"&&N.scope?s.jsxs(s.Fragment,{children:[e==="all"?s.jsx(He,{size:14,"aria-hidden":"true"}):null,A.length>0?s.jsx("button",{type:"button",onClick:()=>G({scope:N.scope,folderPath:""}),children:B(N.scope)}):s.jsx("span",{"aria-current":"page",children:B(N.scope)})]}):null,o==="folders"&&A.map((m,U)=>{const h=A.slice(0,U+1).join("/"),z=U===A.length-1;return s.jsxs("span",{className:a.breadcrumbSegment,children:[s.jsx(He,{size:14,"aria-hidden":"true"}),z?s.jsx("span",{"aria-current":"page",children:m}):s.jsx("button",{type:"button",onClick:()=>G({scope:N.scope,folderPath:h}),children:m})]},h)})]}),s.jsx("h2",{ref:M,tabIndex:-1,children:q}),s.jsx("p",{children:i})]}),s.jsxs("div",{className:a.viewOptions,"aria-label":b("assets.view.options","View options"),children:[s.jsxs("div",{className:a.organizationModeControl,role:"group","aria-label":b("assets.organization.label","Browse"),children:[s.jsx("button",{type:"button","aria-pressed":o==="folders",onClick:()=>K("folders"),children:b("assets.organization.folders","Folders")}),s.jsx("button",{type:"button","aria-pressed":o==="all-assets",onClick:()=>K("all-assets"),children:b("assets.organization.all","All assets")})]}),s.jsxs("div",{className:a.viewModeControl,role:"group","aria-label":b("assets.view.mode","View mode"),children:[s.jsxs("button",{type:"button","aria-pressed":f==="grid",onClick:()=>E("grid"),children:[s.jsx(ct,{size:14}),b("assets.view.grid","Grid")]}),s.jsxs("button",{type:"button","aria-pressed":f==="list",onClick:()=>E("list"),children:[s.jsx(pt,{size:14}),b("assets.view.list","List")]})]}),s.jsx("div",{className:a.gridSizeControl,role:"group","aria-label":b("assets.view.thumbnailSize","Thumbnail size"),title:f==="list"?b("assets.view.thumbnailSize.listReason","Thumbnail size is available in Grid view."):void 0,children:["small","medium","large"].map(m=>s.jsx("button",{type:"button","aria-pressed":g===m,disabled:f==="list",onClick:()=>R(m),children:b(`assets.view.size.${m}`,m[0].toUpperCase()+m.slice(1))},m))})]})]}),f==="list"&&(w.length>0||D.length>0||P.length>0)?s.jsxs("div",{className:a.assetListHeader,"aria-hidden":"true",children:[s.jsx("span",{}),s.jsx("span",{children:b("assets.list.name","Name")}),s.jsx("span",{children:b("assets.list.type","Type")}),s.jsx("span",{children:b("assets.list.scope","Scope")}),s.jsx("span",{children:b("assets.list.status","Status")}),s.jsx("span",{children:b("assets.list.updated","Updated")})]}):null,w.length>0?s.jsxs("section",{className:a.explorerSection,children:[s.jsx("h3",{children:b("assets.folders.title","Folders")}),s.jsx("div",{className:f==="list"?a.folderList:a.folderGrid,"data-grid-size":g,children:w.map(m=>X(`scope:${m.scope}`,m.name,m.count,m.scope,()=>G({scope:m.scope,folderPath:""})))})]}):null,D.length>0?s.jsxs("section",{className:a.explorerSection,children:[s.jsx("h3",{children:b("assets.folders.title","Folders")}),s.jsx("div",{className:f==="list"?a.folderList:a.folderGrid,"data-grid-size":g,children:D.map(m=>X(m.path,m.name,m.descendantCount,N.scope,()=>G({scope:N.scope,folderPath:m.path})))})]}):null,P.length>0?s.jsxs("section",{className:a.explorerSection,"aria-label":o==="all-assets"?b("assets.organization.all","All assets"):void 0,children:[o==="folders"?s.jsx("h3",{children:b("assets.folder.assetsTitle","Assets in this folder")}):null,s.jsx(dn,{assets:P,selectedAssetId:null,selectedAssetKey:x,viewMode:f,gridSize:g,onSelect:p})]}):null,D.length===0&&P.length===0&&(w.length===0||t.length===0)?l==="all"&&t.length===0&&r?r:s.jsxs("div",{className:a.emptyState,children:[s.jsx("p",{children:t.length===0?l==="all"?b("assets.empty.title","No assets yet"):b("assets.empty.filteredTitle","No assets match this filter"):b("assets.empty.folderTitle","No matching assets in this folder")}),s.jsx("span",{children:t.length===0?l==="all"?b("assets.empty.body","Choose a scope and category, then rescan that inbox folder."):b("assets.empty.filteredBody","Choose another category or rescan the matching inbox folders."):b("assets.empty.folderBody","Try another folder or category filter.")})]}):null]})}function pn(e){return{generate:{id:"generate-image",title:e("assets.emptyGuide.ai.generateTitle","Generate and register a new image"),request:e("assets.emptyGuide.ai.generateRequest","Create an image asset for this project. If your current tools can generate image files, first confirm its intended use, size, style, transparent-background needs, and whether to save it for the current Place or Shared. Generate the file, avoid duplicating an existing asset, register it in the WEPPY Asset Library, and make the result available on the Assets page. If you cannot generate image files, tell me and ask for an existing file location instead. Do not upload it to Roblox unless I ask.")},register:{id:"register-image",title:e("assets.emptyGuide.ai.imageTitle","Register an image file you already have"),request:e("assets.emptyGuide.ai.imageRequest","Register an image file for this project in the WEPPY Asset Library. First confirm the file location and whether to save it for the current Place or Shared. Avoid creating a duplicate of an existing asset, do not upload it to Roblox, and make the result available on the Assets page.")}}}function hn(e){const{locale:t,t:n}=ce(),[l,o]=c.useState("register"),f=pn(n),g=e.scope==="all"?n("assets.emptyGuide.scope.all","Choose Current Place or Shared before adding files."):e.scope==="shared"?n("assets.emptyGuide.scope.shared","New files will be registered in the Shared library."):n("assets.emptyGuide.scope.place","New files will be registered for the selected Place.");return s.jsxs("section",{className:a.emptyGuide,children:[s.jsxs("header",{className:a.emptyGuideHeader,children:[s.jsx("h3",{children:n("assets.emptyGuide.title","Collect assets for your game")}),s.jsx("p",{children:n("assets.emptyGuide.description","Register image files or save a selected Studio model, then manage them here.")})]}),s.jsxs("div",{className:a.emptyGuideMethods,children:[s.jsxs("section",{className:a.emptyGuideMethod,children:[s.jsxs("div",{className:a.emptyGuideMethodTitle,children:[s.jsx(Ws,{size:16,"aria-hidden":"true"}),s.jsx("h4",{children:n("assets.emptyGuide.ai.title","Ask AI")})]}),s.jsx("p",{className:a.emptyGuideMethodHelp,children:n("assets.emptyGuide.ai.methodHelp","Choose a method that matches your AI. If you are unsure, register an existing image.")}),s.jsxs("div",{className:a.emptyGuideChoices,role:"radiogroup","aria-label":n("assets.emptyGuide.ai.methodLabel","Image preparation method"),children:[s.jsxs("button",{type:"button",role:"radio","aria-checked":l==="register",className:`${a.emptyGuideChoice} ${l==="register"?a.emptyGuideChoiceSelected:""}`,onClick:()=>o("register"),children:[s.jsx("span",{className:a.emptyGuideChoiceLabel,children:n("assets.emptyGuide.ai.registerOption","Register an existing image")}),s.jsx("span",{className:a.emptyGuideCapability,children:n("assets.emptyGuide.ai.registerCapability","Image generation not required")})]}),s.jsxs("button",{type:"button",role:"radio","aria-checked":l==="generate",className:`${a.emptyGuideChoice} ${l==="generate"?a.emptyGuideChoiceSelected:""}`,onClick:()=>o("generate"),children:[s.jsx("span",{className:a.emptyGuideChoiceLabel,children:n("assets.emptyGuide.ai.generateOption","Generate a new image")}),s.jsx("span",{className:a.emptyGuideCapability,children:n("assets.emptyGuide.ai.generateCapability","Image generation required")})]})]}),s.jsx("p",{className:a.emptyGuideCapabilityDescription,children:l==="register"?n("assets.emptyGuide.ai.registerDescription","Use this when you already have an image file or are unsure whether your AI can generate images."):n("assets.emptyGuide.ai.generateDescription","Use this only when your AI can create PNG or JPG files or has an image generation tool.")}),s.jsx(Ks,{examples:[f[l]],resetKey:`${t}|assets-${l}`,labels:{copy:n("guidance.ai.copy","Copy request"),copying:n("guidance.ai.copying","Copying…"),copied:n("guidance.ai.copied","Copied"),copyFailed:n("guidance.ai.copyFailed","Could not copy. Select the request text and copy it manually.")},nextStep:n("guidance.ai.nextStep","Paste this request into an AI chat connected to WEPPY.")})]}),s.jsxs("section",{className:a.emptyGuideMethod,children:[s.jsxs("div",{className:a.emptyGuideMethodTitle,children:[s.jsx(it,{size:16,"aria-hidden":"true"}),s.jsx("h4",{children:n("assets.emptyGuide.direct.title","Add files yourself")})]}),s.jsx("p",{children:g}),s.jsxs("ol",{className:a.emptyGuideSteps,children:[s.jsx("li",{children:n("assets.emptyGuide.direct.image","Put image or decal files in the inbox for the selected scope, then rescan.")}),s.jsx("li",{children:n("assets.emptyGuide.direct.model","For models, select objects in Studio and save them from WEPPY Plugin > Assets.")}),s.jsx("li",{children:n("assets.emptyGuide.direct.upload","Upload registered assets to Roblox from the asset details with Roblox Open Cloud (Pro).")})]}),!e.isPro&&s.jsx("p",{className:a.emptyGuideTierNote,children:n("assets.emptyGuide.direct.pro","Saving Studio models as RBXM and uploading assets to Roblox are available with Pro. Local image and decal registration is available on Basic.")}),s.jsx("button",{type:"button",className:a.emptyGuideAction,disabled:e.busy,onClick:e.onRescan,children:n("assets.emptyGuide.direct.rescan","Rescan inbox")})]})]})]})}const mn="https://create.roblox.com/dashboard/creations/store",xn=/^https:\/\/create\.roblox\.com\/store\/asset\/\d+(?:\/.*)?$/;function gn(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/1024/1024).toFixed(1)} MB`}function ke(e){const t=new Date(e);if(Number.isNaN(t.getTime()))return e;const n=t.getFullYear(),l=String(t.getMonth()+1).padStart(2,"0"),o=String(t.getDate()).padStart(2,"0"),f=String(t.getHours()).padStart(2,"0"),g=String(t.getMinutes()).padStart(2,"0");return`${n}-${l}-${o} ${f}:${g}`}function fn(e){return e.category==="image"||e.category==="decal"||!!e.file.preview}function bn(e){return e.file.preview?Ye(e):Cs(e)}function yn(e){var n;const t=Object.entries(((n=e.rbxm)==null?void 0:n.classCounts)??{}).sort((l,o)=>o[1]-l[1]).slice(0,8);return t.length===0?"-":t.map(([l,o])=>`${l} ${o}`).join(", ")}function ns(e){var o;const t=(o=e.rbxm)==null?void 0:o.thumbnail;if(!t)return"-";const n=t.source?` via ${t.source}`:"",l=t.message?` · ${t.message}`:"";return`${t.status}${n}${l}`}function jn(e){var o,f;const t=(f=(o=e.rbxm)==null?void 0:o.review)==null?void 0:f.summary;if(!t)return"-";const n=[["roots",t.rootCount],["parts",t.partCount],["mesh parts",t.meshPartCount],["scripts",t.scriptCount],["unanchored",t.unanchoredPartCount]].flatMap(([g,x])=>typeof x=="number"?[`${g} ${x}`]:[]),l=t.bounds;if(l&&typeof l=="object"&&"size"in l){const g=l.size;if(g&&typeof g=="object"){const{x,y:p,z:L}=g;typeof x=="number"&&typeof p=="number"&&typeof L=="number"&&n.push(`bounds ${x} x ${p} x ${L}`)}}return n.length>0?n.join(", "):"-"}function vn(e){var n,l;const t=(n=e.rbxm)==null?void 0:n.generation;return t?t.schemaMode==="custom"&&((l=t.schemaGroups)!=null&&l.length)?`custom · ${t.schemaGroups.join(", ")}`:t.predefinedSchema?`${t.schemaMode??"predefined"} · ${t.predefinedSchema}`:t.schemaMode??"-":"-"}function os(e){const{width:t,height:n}=e.file;return t===null||n===null?null:`${t} x ${n}px`}function rs(e){const{durationMs:t}=e.file;return t===null?null:t<1e3?`${t} ms`:`${(t/1e3).toFixed(1)} s`}function Cn(e){return`${mn}/${e}/configure`}function _n(e){return e.category==="decal"?e.roblox.creatorAssetId??e.roblox.assetId??null:e.roblox.assetId??null}function Sn(e){const t=_n(e),n=t?Cn(t):null,l=e.category==="decal"?e.roblox.creatorAssetWebUrl??e.roblox.assetWebUrl:e.roblox.assetWebUrl;return!l||n&&xn.test(l)?n:l}function Nn(e){return`${ke(e.startedAt)} -> ${e.status}`}function is(e){return!e.creatorType||!e.creatorId?null:`${e.creatorType} ${e.creatorId}`}function ds(e){return e.assetRole?`Asset role: ${e.assetRole}`:null}function Pn(e){const t=e.sourceProperty?` · ${e.sourceProperty}`:"";return`${e.path} · ${e.assetType} · ${e.status}${t}`}function An(e){return e.assetUri&&e.assetId?`${e.assetUri} (#${e.assetId})`:e.assetUri?e.assetUri:e.assetId?`#${e.assetId}`:e.message??"-"}function Ne({label:e,value:t}){return t?s.jsx("button",{type:"button",className:a.inlineCopyButton,"aria-label":e,title:e,onClick:()=>{var n;return void((n=navigator.clipboard)==null?void 0:n.writeText(t))},children:s.jsx(js,{size:13})}):null}function In({asset:e,busyAction:t,canUpload:n,canImportRbxm:l,importRbxmTooltip:o,importRbxmTargetParent:f,onClose:g,onSave:x,onUpload:p,onDelete:L,onImportRbxm:K,onRefreshStatus:E,onScanUsage:R}){var $,k;const{t:r}=ce(),b=c.useRef(null),[N,T]=c.useState(""),[W,V]=c.useState("");if(c.useEffect(()=>{T((e==null?void 0:e.displayName)??""),V((e==null?void 0:e.description)??"")},[e==null?void 0:e.description,e==null?void 0:e.displayName,e==null?void 0:e.id]),c.useEffect(()=>{var y;if(!e)return;(y=b.current)==null||y.focus();const i=X=>{X.key==="Escape"&&g()};return document.addEventListener("keydown",i),()=>document.removeEventListener("keydown",i)},[e,g]),!e)return null;const M=e.status==="processing"&&!!(e.roblox.operationId??e.roblox.operationPath),B=!!e.roblox.assetUri,G=Sn(e),H=e.roblox.uploadAttempts??[],D=e.category==="decal"&&!!(e.roblox.creatorAssetId||e.roblox.backingImageAssetId||e.roblox.assetId),Q=e.roblox.creatorAssetId??e.roblox.assetId,P=e.roblox.backingImageAssetId??e.roblox.assetId,A=Ns(e,r),q=e.roblox.assetId?e.usage.lastScannedAt?r("assets.detail.noUsageAfterScan","No references were found in local Sync files during the last check."):r("assets.detail.noUsageUnscanned","Run Scan usage to search local Sync files for this Roblox Asset ID."):r("assets.detail.noUsageNoRobloxId","This asset does not have a Roblox Asset ID yet, so usage cannot be checked. Upload it before scanning usage.");return s.jsx("div",{className:a.detailPopupLayer,onClick:g,role:"presentation",children:s.jsxs("section",{ref:b,className:a.detailDialog,role:"dialog","aria-modal":"true","aria-label":r("assets.detail.title","Asset details"),tabIndex:-1,onClick:i=>i.stopPropagation(),children:[s.jsxs("div",{className:a.detailDialogHeader,children:[s.jsxs("div",{className:a.detailTitleBlock,children:[s.jsxs("span",{className:a.detailEyebrow,children:[ie(e,r)," · ",Re(e.status,r)]}),s.jsx("h2",{children:e.displayName}),s.jsx("span",{children:e.id})]}),s.jsxs("div",{className:a.detailHeaderActions,children:[s.jsx(se,{text:n?r("assets.upload.open.tooltip","Upload this local file to Roblox through Open Cloud."):r("assets.proOnly.tooltip","Roblox upload is available on Pro."),children:s.jsxs("button",{type:"button",className:a.commandButton,disabled:!n,onClick:p,children:[s.jsx(gt,{size:15}),r("assets.upload.open","Upload")]})}),l&&s.jsx(se,{text:o,children:s.jsxs("button",{type:"button",className:a.commandButton,disabled:t==="import-rbxm",onClick:()=>void K(),children:[s.jsx(Ls,{size:15}),r("assets.detail.importRbxm","Insert into Studio")]})}),s.jsxs("button",{type:"button",className:a.commandButton,disabled:!M||t==="status-refresh",onClick:()=>void E(),children:[s.jsx(fs,{size:15}),r("assets.detail.refreshStatus","Refresh")]}),s.jsxs("button",{type:"button",className:a.commandButton,disabled:!e.roblox.assetId||t==="usage-scan",onClick:()=>void R(),children:[s.jsx(mt,{size:15}),r("assets.detail.scanUsage","Scan usage")]}),s.jsx(se,{text:r("assets.delete.tooltip","Delete this local Asset Library item."),children:s.jsxs("button",{type:"button",className:`${a.commandButton} ${a.dangerButton}`,disabled:t==="delete",onClick:L,children:[s.jsx(Vs,{size:15}),r("common.delete","Delete")]})}),s.jsx(se,{text:r("common.close","Close"),children:s.jsx("button",{type:"button",className:a.iconButton,onClick:g,"aria-label":r("common.close","Close"),children:s.jsx(Xe,{size:16})})})]})]}),s.jsxs("div",{className:a.detailDialogBody,children:[s.jsx("div",{className:a.detailPreviewPane,children:fn(e)?s.jsx("img",{className:a.detailPreview,src:bn(e),alt:e.displayName}):s.jsxs("div",{className:a.detailPreviewFallback,children:[s.jsx("span",{children:ie(e,r)}),s.jsx("code",{children:e.file.original}),(($=e.rbxm)==null?void 0:$.thumbnail)&&s.jsx("small",{children:ns(e)})]})}),s.jsxs("div",{className:a.detailContentPane,children:[s.jsxs("div",{className:a.formStack,children:[s.jsxs("label",{className:a.field,children:[s.jsx("span",{children:r("assets.detail.displayName","Display name")}),s.jsx("input",{value:N,onChange:i=>T(i.target.value)})]}),s.jsxs("label",{className:a.field,children:[s.jsx("span",{children:r("assets.detail.description","Description")}),s.jsx("textarea",{value:W,rows:3,onChange:i=>V(i.target.value)})]}),s.jsx("button",{type:"button",className:a.primaryButton,disabled:t==="update",onClick:()=>void x(N,W),children:r("assets.detail.save","Save metadata")})]}),s.jsxs("section",{className:a.detailSection,children:[s.jsx("h3",{children:r("assets.detail.localFile","Local file")}),s.jsxs("dl",{className:a.detailGrid,children:[s.jsx("dt",{children:r("assets.detail.fileName","File")}),s.jsx("dd",{children:e.file.original}),s.jsx("dt",{children:r("assets.detail.source","Source path")}),s.jsx("dd",{children:e.source.originalPath}),s.jsx("dt",{children:r("assets.detail.category","Category")}),s.jsx("dd",{children:ie(e,r)}),s.jsx("dt",{children:r("assets.detail.scope","Scope")}),s.jsx("dd",{children:e.scope.kind==="shared"?r("assets.scope.shared","Shared"):r("assets.scope.place","Current Place")}),s.jsx("dt",{children:r("assets.detail.mimeType","Type")}),s.jsx("dd",{children:e.file.mimeType}),s.jsx("dt",{children:r("assets.detail.size","Size")}),s.jsx("dd",{children:gn(e.file.sizeBytes)}),os(e)&&s.jsxs(s.Fragment,{children:[s.jsx("dt",{children:r("assets.detail.dimensions","Dimensions")}),s.jsx("dd",{children:os(e)})]}),rs(e)&&s.jsxs(s.Fragment,{children:[s.jsx("dt",{children:r("assets.detail.duration","Duration")}),s.jsx("dd",{children:rs(e)})]})]})]}),e.rbxm&&s.jsxs("section",{className:a.detailSection,children:[s.jsx("h3",{children:r("assets.detail.rbxm","RBXM contents")}),s.jsxs("dl",{className:a.detailGrid,children:[s.jsx("dt",{children:r("assets.detail.rbxmExportedCount","Exported roots")}),s.jsx("dd",{children:e.rbxm.exportedCount}),s.jsx("dt",{children:r("assets.detail.rbxmClasses","Classes")}),s.jsx("dd",{children:yn(e)}),s.jsx("dt",{children:r("assets.detail.rbxmThumbnail","Thumbnail")}),s.jsx("dd",{children:ns(e)}),A&&s.jsxs(s.Fragment,{children:[s.jsx("dt",{children:r("assets.detail.rbxmStudioUploadsLabel","Studio uploads")}),s.jsx("dd",{children:A})]}),l&&s.jsxs(s.Fragment,{children:[s.jsx("dt",{children:r("assets.detail.studioInsertTarget","Studio insert target")}),s.jsx("dd",{children:f})]})]}),e.rbxm.roots.length>0&&s.jsxs("div",{className:a.metadataList,children:[s.jsx("strong",{children:r("assets.detail.rbxmRoots","Root tree")}),e.rbxm.roots.map(i=>s.jsxs("div",{className:a.metadataItem,children:[s.jsxs("span",{children:[i.name," (",i.className,")"]}),s.jsx("code",{children:i.path})]},`${i.path}-${i.className}`))]}),e.rbxm.resourceReferences.length>0&&s.jsxs("div",{className:a.metadataList,children:[s.jsx("strong",{children:r("assets.detail.rbxmReferences","Asset references")}),e.rbxm.resourceReferences.map((i,y)=>s.jsxs("div",{className:a.metadataItem,children:[s.jsxs("span",{children:[i.path," · ",i.property]}),s.jsx("code",{children:i.assetId?`${i.value} (#${i.assetId})`:i.value})]},`${i.path}-${i.property}-${y}`))]}),e.rbxm.studioUploads&&e.rbxm.studioUploads.length>0&&s.jsxs("div",{className:a.metadataList,children:[s.jsx("strong",{children:r("assets.detail.rbxmStudioUploads","Embedded Studio uploads")}),e.rbxm.studioUploads.map((i,y)=>s.jsxs("div",{className:a.metadataItem,children:[s.jsx("span",{children:Pn(i)}),s.jsx("code",{children:An(i)})]},`${i.path}-${i.assetType}-${i.sourceProperty??""}-${y}`))]}),e.rbxm.generation&&s.jsxs("div",{className:a.metadataList,children:[s.jsx("strong",{children:r("assets.detail.rbxmGeneration","Generated model")}),s.jsxs("div",{className:a.metadataItem,children:[s.jsx("span",{children:r("assets.detail.rbxmGenerationProvider","Provider")}),s.jsx("code",{children:e.rbxm.generation.provider})]}),e.rbxm.generation.prompt&&s.jsxs("div",{className:a.metadataItem,children:[s.jsx("span",{children:r("assets.detail.rbxmGenerationPrompt","Prompt")}),s.jsx("code",{children:e.rbxm.generation.prompt})]}),s.jsxs("div",{className:a.metadataItem,children:[s.jsx("span",{children:r("assets.detail.rbxmGenerationSchema","Schema")}),s.jsx("code",{children:vn(e)})]}),e.rbxm.generation.path&&s.jsxs("div",{className:a.metadataItem,children:[s.jsx("span",{children:r("assets.detail.rbxmGenerationPath","Studio path")}),s.jsx("code",{children:e.rbxm.generation.path})]})]}),e.rbxm.review&&s.jsxs("div",{className:a.metadataList,children:[s.jsx("strong",{children:r("assets.detail.rbxmReview","Model review")}),s.jsxs("div",{className:a.metadataItem,children:[s.jsx("span",{children:r("assets.detail.rbxmReviewReadiness","Readiness")}),s.jsx("code",{children:e.rbxm.review.readiness})]}),s.jsxs("div",{className:a.metadataItem,children:[s.jsx("span",{children:r("assets.detail.rbxmReviewSummary","Summary")}),s.jsx("code",{children:jn(e)})]}),e.rbxm.review.findings.slice(0,8).map((i,y)=>s.jsxs("div",{className:a.metadataItem,children:[s.jsxs("span",{children:[i.severity," · ",i.category," · ",i.code]}),s.jsx("code",{children:i.path?`${i.path}: ${i.message}`:i.message})]},`${i.code}-${i.path}-${y}`))]})]}),s.jsxs("section",{className:a.detailSection,children:[s.jsx("h3",{children:r("assets.detail.roblox","Roblox upload status")}),s.jsxs("dl",{className:a.detailGrid,children:[s.jsx("dt",{children:r("assets.detail.status","Status")}),s.jsx("dd",{children:Re(e.status,r)}),D?s.jsxs(s.Fragment,{children:[s.jsx("dt",{children:r("assets.detail.decalAssetId","Roblox Decal ID")}),s.jsxs("dd",{className:a.copyableValue,children:[s.jsx("span",{children:Q??r("assets.status.localOnly","Local only")}),s.jsx(Ne,{label:r("assets.detail.copyDecalAssetId","Copy Roblox Decal ID"),value:Q})]}),s.jsx("dt",{children:r("assets.detail.studioTextureImageId","Studio Texture Image ID")}),s.jsxs("dd",{className:a.copyableValue,children:[s.jsx("span",{children:P??"-"}),s.jsx(Ne,{label:r("assets.detail.copyStudioTextureImageId","Copy Studio Texture Image ID"),value:P})]})]}):s.jsxs(s.Fragment,{children:[s.jsx("dt",{children:r("assets.detail.assetId","Asset ID")}),s.jsxs("dd",{className:a.copyableValue,children:[s.jsx("span",{children:e.roblox.assetId??r("assets.status.localOnly","Local only")}),s.jsx(Ne,{label:r("assets.detail.copyAssetId","Copy Asset ID"),value:e.roblox.assetId})]})]}),s.jsx("dt",{children:r("assets.detail.studioUri","Studio URI")}),s.jsx("dd",{children:e.roblox.assetUri??"-"}),s.jsx("dt",{children:r("assets.detail.robloxWebUrl","Creator Dashboard URL")}),s.jsxs("dd",{className:a.copyableValue,children:[s.jsx("span",{children:G??"-"}),s.jsx(Ne,{label:r("assets.detail.copyWebUrl","Copy configure URL"),value:G})]}),e.roblox.errorMessage&&s.jsxs(s.Fragment,{children:[s.jsx("dt",{children:r("assets.detail.error","Error")}),s.jsx("dd",{children:e.roblox.errorMessage})]})]}),s.jsxs("div",{className:a.copyRow,children:[s.jsxs("button",{type:"button",className:a.commandButton,disabled:!B,onClick:()=>{var i;return e.roblox.assetUri&&void((i=navigator.clipboard)==null?void 0:i.writeText(e.roblox.assetUri))},children:[s.jsx(js,{size:15}),r("assets.detail.copyStudioUri","Copy Studio URI")]}),G&&s.jsxs("a",{className:a.commandButton,href:G,target:"_blank",rel:"noreferrer",children:[s.jsx(Us,{size:15}),r("assets.detail.openRobloxPage","Open configure page")]})]}),e.roblox.assetId&&s.jsx("p",{className:a.muted,children:r("assets.detail.robloxWebUrlNotice","Opening this page requires the Roblox account that owns or can manage the uploaded asset.")}),H.length>0&&s.jsxs("div",{className:a.metadataList,children:[s.jsx("strong",{children:r("assets.detail.uploadHistory","Upload history")}),H.slice().reverse().map((i,y)=>s.jsxs("div",{className:a.metadataItem,children:[s.jsx("span",{children:Nn(i)}),is(i)&&s.jsx("code",{children:is(i)}),ds(i)&&s.jsx("code",{children:ds(i)}),i.operationPath&&s.jsx("code",{children:i.operationPath}),i.assetId&&s.jsxs("code",{children:[r("assets.detail.assetId","Asset ID"),": ",i.assetId]}),i.remotePath&&s.jsx("code",{children:i.remotePath}),i.message&&s.jsx("code",{children:i.message}),i.errorMessage&&s.jsx("code",{children:i.errorMessage})]},`${i.startedAt}-${i.operationPath??y}`))]})]}),s.jsxs("section",{className:a.detailSection,children:[s.jsx("h3",{children:r("assets.detail.usedInPlace","Where this asset is used in this Place")}),s.jsxs("dl",{className:a.detailGrid,children:[s.jsx("dt",{children:r("assets.detail.usageSource","Checked against")}),s.jsx("dd",{children:e.usage.scanSource==="localSync"?r("assets.detail.usageSource.localSync","Local Sync files"):r("assets.detail.usageSource.notScanned","Not checked yet")}),s.jsx("dt",{children:r("assets.detail.lastScanned","Last checked")}),s.jsx("dd",{children:e.usage.lastScannedAt?r("assets.detail.lastScannedAt","Last checked: {time}").replace("{time}",ke(e.usage.lastScannedAt)):r("assets.detail.lastScanned.never","No check yet")})]}),e.usage.references.length===0?s.jsx("p",{className:a.muted,children:q}):s.jsx("div",{className:a.usageList,children:e.usage.references.map((i,y)=>s.jsxs("div",{className:a.usageItem,children:[s.jsx("strong",{children:i.kind==="property"?i.instancePath:i.filePath}),s.jsx("span",{children:i.property??r("assets.detail.line","line {line}").replace("{line}",String(i.line??"-"))}),s.jsx("code",{children:i.value})]},`${i.kind}-${y}`))})]}),s.jsxs("details",{className:a.technicalDetails,children:[s.jsx("summary",{children:r("assets.detail.technicalDetails","Technical details")}),s.jsxs("dl",{className:a.detailGrid,children:[s.jsx("dt",{children:r("assets.detail.stableId","Stable ID")}),s.jsx("dd",{className:a.hashText,children:e.id}),s.jsx("dt",{children:r("assets.detail.sourceKind","Source kind")}),s.jsx("dd",{children:e.source.kind}),s.jsx("dt",{children:r("assets.detail.sha256","SHA-256")}),s.jsx("dd",{className:a.hashText,children:e.file.sha256}),s.jsx("dt",{children:r("assets.detail.createdAt","Created")}),s.jsx("dd",{children:ke(e.createdAt)}),s.jsx("dt",{children:r("assets.detail.updatedAt","Updated")}),s.jsx("dd",{children:ke(e.updatedAt)}),e.roblox.operationId&&s.jsxs(s.Fragment,{children:[s.jsx("dt",{children:r("assets.detail.operationId","Operation ID")}),s.jsx("dd",{className:a.hashText,children:e.roblox.operationId})]}),e.roblox.operationPath&&s.jsxs(s.Fragment,{children:[s.jsx("dt",{children:r("assets.detail.operationPath","Operation path")}),s.jsx("dd",{className:a.hashText,children:e.roblox.operationPath})]}),e.roblox.versionId&&s.jsxs(s.Fragment,{children:[s.jsx("dt",{children:r("assets.detail.versionId","Version ID")}),s.jsx("dd",{className:a.hashText,children:e.roblox.versionId})]}),e.roblox.remotePath&&s.jsxs(s.Fragment,{children:[s.jsx("dt",{children:r("assets.detail.remotePath","Remote path")}),s.jsx("dd",{className:a.hashText,children:e.roblox.remotePath})]}),e.roblox.moderationState&&s.jsxs(s.Fragment,{children:[s.jsx("dt",{children:r("assets.detail.moderationState","Moderation")}),s.jsx("dd",{children:e.roblox.moderationState})]})]}),((k=e.rbxm)==null?void 0:k.thumbnail.attempts)&&e.rbxm.thumbnail.attempts.length>0&&s.jsxs("div",{className:a.metadataList,children:[s.jsx("strong",{children:r("assets.detail.rbxmThumbnailAttempts","Thumbnail attempts")}),e.rbxm.thumbnail.attempts.map((i,y)=>s.jsxs("div",{className:a.metadataItem,children:[s.jsxs("span",{children:[i.method," · ",i.status]}),i.message&&s.jsx("code",{children:i.message})]},`${i.method}-${y}`))]})]})]})]})]})})}function Ps(e){return{assetUploadByOpenCloudEnabled:e.hot.ENABLE_ASSET_UPLOAD_BY_OPEN_CLOUD===!0}}function kn(e){const t={};return typeof e.assetUploadByOpenCloudEnabled=="boolean"&&(t.ENABLE_ASSET_UPLOAD_BY_OPEN_CLOUD=e.assetUploadByOpenCloudEnabled),t}async function As(){const e=await F.get("/api/dashboard/settings");return Ps(e)}async function wn(e){const t=await F.patch("/api/dashboard/settings",kn(e));return Ps(t)}async function Is(){return F.get("/api/dashboard/open-cloud/credential-profiles")}async function Rn(e){return F.post("/api/dashboard/open-cloud/credential-profiles",e)}async function $n(e){return F.patch("/api/dashboard/open-cloud/credential-profiles/active",{profileId:e})}async function Ln(e,t){return F.put(`/api/dashboard/open-cloud/credential-profiles/${encodeURIComponent(e)}/api-key`,t)}async function Un(e){return F.delete(`/api/dashboard/open-cloud/credential-profiles/${encodeURIComponent(e)}`)}async function Tn(e,t){return F.post(`/api/dashboard/open-cloud/credential-profiles/${encodeURIComponent(e)}/creators`,t)}async function Bn(e,t){return F.patch(`/api/dashboard/open-cloud/credential-profiles/${encodeURIComponent(e)}/creators/${encodeURIComponent(t)}/default`,{})}async function En(e,t){return F.delete(`/api/dashboard/open-cloud/credential-profiles/${encodeURIComponent(e)}/creators/${encodeURIComponent(t)}`)}async function Gn(e,t){return F.post(`/api/dashboard/open-cloud/credential-profiles/${encodeURIComponent(e)}/test`,t?{creatorPresetId:t}:{})}async function Mn(e){return F.post("/api/dashboard/open-cloud/credential/test",e?{apiKey:e}:{})}function Dn(e){return e.category==="image"||e.category==="decal"}function Fn(e,t){return e==="group"?t("assets.creator.group","Group"):t("assets.creator.user","User")}function On(e,t){return`${e.label} · ${Fn(e.creatorType,t)} ${e.creatorId}`}function cs(e){if(!e)return null;if(e.defaultCreatorId){const t=e.creators.find(n=>n.id===e.defaultCreatorId);if(t)return t}return e.creators[0]??null}function Hn({asset:e,open:t,canUpload:n,busyAction:l,onClose:o,onBack:f,onOpenSettings:g,onUpload:x}){const{t:p}=ce(),L=c.useRef(null),[K,E]=c.useState(null),[R,r]=c.useState(null),[b,N]=c.useState(!1),[T,W]=c.useState(null),[V,M]=c.useState(""),[B,G]=c.useState(""),[H,D]=c.useState(""),[Q,P]=c.useState("user"),[A,q]=c.useState("");if(c.useEffect(()=>{M((e==null?void 0:e.displayName)??""),G((e==null?void 0:e.description)??"")},[e==null?void 0:e.description,e==null?void 0:e.displayName,e==null?void 0:e.id]),c.useEffect(()=>{if(!t)return;let _=!1;return N(!0),W(null),(async()=>{try{const[S,J]=await Promise.all([As(),Is()]);if(_)return;E(S);const ee=J.profiles.find(pe=>pe.id===J.activeProfileId)??J.profiles[0]??null;r(ee);const Z=cs(ee);D((Z==null?void 0:Z.id)??""),P((Z==null?void 0:Z.creatorType)??"user"),q((Z==null?void 0:Z.creatorId)??"")}catch(S){if(_)return;W(S instanceof Error?S.message:p("assets.upload.settingsLoadFailed","Failed to load upload settings.")),E(null),r(null)}finally{_||N(!1)}})(),()=>{_=!0}},[t,p]),c.useEffect(()=>{var S;if(!t||!e)return;(S=L.current)==null||S.focus();const _=J=>{J.key==="Escape"&&o()};return document.addEventListener("keydown",_),()=>document.removeEventListener("keydown",_)},[e,o,t]),!t||!e)return null;const $=(K==null?void 0:K.assetUploadByOpenCloudEnabled)===!0,k=!!R,i=cs(R),y=(R==null?void 0:R.creators.find(_=>_.id===H))??null,X=!!i,m=(R==null?void 0:R.storageProvider)==="env"&&k&&!X,U=m&&A.trim().length>0,h=n&&!b&&!T&&(!$||!k||!X&&!m),z=n&&!b&&!T&&$&&k&&(X||U)&&l!=="upload";return s.jsx("div",{className:a.detailPopupLayer,onClick:o,role:"presentation",children:s.jsxs("section",{ref:L,className:a.detailDialog,role:"dialog","aria-modal":"true","aria-label":p("assets.upload.title","Upload asset"),tabIndex:-1,onClick:_=>_.stopPropagation(),children:[s.jsxs("div",{className:a.detailDialogHeader,children:[s.jsxs("div",{className:a.detailTitleBlock,children:[s.jsxs("span",{className:a.detailEyebrow,children:[ie(e,p)," · ",p("assets.upload.intent","Upload to Roblox")]}),s.jsx("h2",{children:p("assets.upload.title","Upload asset")}),s.jsx("span",{children:e.displayName})]}),s.jsxs("div",{className:a.detailHeaderActions,children:[s.jsxs("button",{type:"button",className:a.commandButton,onClick:f,children:[s.jsx(qs,{size:15}),p("assets.upload.backToDetails","Back to details")]}),s.jsx(se,{text:p("common.close","Close"),children:s.jsx("button",{type:"button",className:a.iconButton,onClick:o,"aria-label":p("common.close","Close"),children:s.jsx(Xe,{size:16})})})]})]}),s.jsxs("div",{className:a.detailDialogBody,children:[s.jsx("div",{className:a.detailPreviewPane,children:Dn(e)?s.jsx("img",{className:a.detailPreview,src:Cs(e),alt:e.displayName}):s.jsxs("div",{className:a.detailPreviewFallback,children:[s.jsx("span",{children:ie(e,p)}),s.jsx("code",{children:e.file.original})]})}),s.jsxs("div",{className:a.detailContentPane,children:[!n&&s.jsx("div",{className:a.notice,children:p("assets.proOnly.upload","Roblox upload is available on Pro.")}),b&&s.jsx("div",{className:a.notice,children:p("assets.upload.checkingSettings","Checking upload settings...")}),T&&s.jsx("div",{className:a.errorState,children:T}),s.jsxs("dl",{className:a.compactMeta,children:[s.jsx("dt",{children:p("assets.detail.category","Category")}),s.jsx("dd",{children:ie(e,p)}),s.jsx("dt",{children:p("assets.detail.source","Source")}),s.jsx("dd",{children:e.source.originalPath})]}),h&&s.jsxs("div",{className:a.setupNotice,children:[s.jsx("strong",{children:p("assets.upload.settingsRequired","Upload settings required")}),s.jsx("p",{children:k?$?p("assets.upload.settingsRequired.creator","Save a default Creator before uploading."):p("assets.upload.settingsRequired.toggle","Enable Open Cloud upload before uploading."):p("assets.upload.settingsRequired.apiKey","Save an Open Cloud API key before uploading.")}),s.jsxs("button",{type:"button",className:a.commandButton,onClick:g,children:[s.jsx(bs,{size:15}),p("assets.upload.openSettings","Open Asset Library settings")]})]}),s.jsxs("div",{className:a.formStack,children:[s.jsxs("label",{className:a.field,children:[s.jsx("span",{children:p("assets.detail.displayName","Display name")}),s.jsx("input",{value:V,disabled:!n,onChange:_=>M(_.target.value)}),s.jsx("small",{className:a.fieldHelp,children:p("assets.upload.displayNameHelp","Saved to Roblox as the asset display name.")})]}),s.jsxs("label",{className:a.field,children:[s.jsx("span",{children:p("assets.detail.description","Description")}),s.jsx("textarea",{value:B,rows:3,disabled:!n,onChange:_=>G(_.target.value)}),s.jsx("small",{className:a.fieldHelp,children:p("assets.upload.descriptionHelp","Saved to Roblox as the asset description.")})]}),X&&s.jsxs("label",{className:a.field,children:[s.jsx("span",{children:p("assets.upload.creator","Creator")}),s.jsx("select",{"aria-label":p("assets.upload.creator","Creator"),value:H,disabled:!n||b,onChange:_=>D(_.target.value),children:R==null?void 0:R.creators.map(_=>s.jsx("option",{value:_.id,children:On(_,p)},_.id))}),s.jsx("small",{className:a.fieldHelp,children:p("assets.upload.creatorHelp","Used by Open Cloud as the owner of the uploaded asset.")})]}),m&&s.jsxs(s.Fragment,{children:[s.jsx("p",{className:a.inlineHelp,children:p("assets.upload.envCreatorHelp","Environment API keys cannot save a default Creator here. Enter the Creator for this upload.")}),s.jsxs("div",{className:a.twoColumn,children:[s.jsxs("label",{className:a.field,children:[s.jsx("span",{children:p("assets.upload.creatorType","Creator type")}),s.jsxs("select",{value:Q,disabled:!n,onChange:_=>P(_.target.value),children:[s.jsx("option",{value:"user",children:p("assets.creator.user","User")}),s.jsx("option",{value:"group",children:p("assets.creator.group","Group")})]}),s.jsx("small",{className:a.fieldHelp,children:p("assets.upload.creatorTypeHelp","Sent to Open Cloud as the Creator type.")})]}),s.jsxs("label",{className:a.field,children:[s.jsx("span",{children:p("assets.upload.creatorId","Creator ID")}),s.jsx("input",{value:A,disabled:!n,onChange:_=>q(_.target.value)}),s.jsx("small",{className:a.fieldHelp,children:p("assets.upload.creatorIdHelp","Sent to Open Cloud as the User or Group ID that owns the uploaded asset.")})]})]})]}),s.jsx("button",{type:"button",className:a.primaryButton,disabled:!z,onClick:()=>{const _=A.trim(),S=m&&_?{creatorType:Q,creatorId:_}:{},J=!m&&y&&i&&y.id!==i.id?{creatorType:y.creatorType,creatorId:y.creatorId}:{};x({displayName:V,description:B,...S,...J})},children:l==="upload"?p("assets.upload.uploading","Uploading..."):p("assets.upload.submit","Upload with Roblox Open Cloud")})]}),s.jsxs("div",{className:a.noticeList,children:[s.jsx("p",{children:p("assets.upload.noDelete","WEPPY does not provide Roblox asset deletion.")}),s.jsx("p",{children:p("assets.upload.delay","Roblox processing and moderation can delay visibility in Studio or Creator Dashboard.")})]})]})]})]})})}function us(e,t){return e==="env"?t("assets.settings.credential.env","Environment variable"):t("assets.settings.credential.local","Local encrypted file")}function Ke(e,t){return e==="valid"?t("assets.settings.validation.valid","Connected"):e==="invalid"?t("assets.settings.validation.invalid","Needs attention"):t("assets.settings.validation.unknown","Not tested")}function zn(e,t){return(e==null?void 0:e.status)==="valid"?t("assets.settings.apiKeyTested","Open Cloud API key connection tested."):(e==null?void 0:e.message)??t("assets.settings.tested","Connection tested.")}function Kn(e,t){return(e==null?void 0:e.status)==="valid"?t("assets.settings.apiKeyTested","Open Cloud API key connection tested."):(e==null?void 0:e.message)??t("assets.settings.tested","Connection tested.")}function Wn(e,t){return e==="group"?t("assets.creator.group","Group"):t("assets.creator.user","User")}function Vn(e,t){return`${Wn(e.creatorType,t)} ${e.creatorId}`}function Yn({open:e,tier:t,onClose:n}){const{t:l}=ce(),[o,f]=c.useState(null),[g,x]=c.useState(null),[p,L]=c.useState(""),[K,E]=c.useState(!1),[R,r]=c.useState(""),[b,N]=c.useState(""),[T,W]=c.useState("user"),[V,M]=c.useState(""),[B,G]=c.useState(""),[H,D]=c.useState(!0),[Q,P]=c.useState(null),[A,q]=c.useState(null),[$,k]=c.useState(!1),i=t==="basic",y=c.useCallback(async()=>{k(!0),P(null);try{const[d,j]=await Promise.all([As(),Is()]);f(d),x(j);const I=j.profiles.find(O=>O.id===j.activeProfileId)??j.profiles[0]??null;L((I==null?void 0:I.id)??""),E(!I),D(!I||I.creators.length===0),W("user"),M(""),G("")}catch(d){P(d instanceof Error?d.message:l("assets.settings.loadFailed","Failed to load upload settings."))}finally{k(!1)}},[l]);if(c.useEffect(()=>{e&&y()},[y,e]),!e)return null;const X=(o==null?void 0:o.assetUploadByOpenCloudEnabled)===!0,w=b.trim(),m=V.trim(),U=(g==null?void 0:g.profiles)??[],h=U.find(d=>d.id===p)??U[0]??null,z=!!h,_=z&&(h==null?void 0:h.storageProvider)==="localFile",S=z&&(h==null?void 0:h.storageProvider)==="env",J=h!=null&&h.defaultCreatorId?h.creators.find(d=>d.id===h.defaultCreatorId):h==null?void 0:h.creators[0],ee=!!(h!=null&&h.creators.length),Z=!ee||H,pe=U.length>1,oe=i?l("assets.settings.action.proRequired","Asset upload settings are available on Pro."):$?l("assets.settings.action.busy","Wait for the current settings action to finish."):null,ve=i||$||!w,xe=oe??(w?l("assets.settings.saveApiKey.tooltip.ready","Save this API key to local encrypted storage."):l("assets.settings.saveApiKey.tooltip.enter","Enter an Open Cloud API key to save it locally.")),ae=i||$||!w&&!z,Ce=oe??(w?l("assets.settings.testConnection.tooltip.entered","Test the entered API key before saving it."):z?l("assets.settings.testConnection.tooltip.saved","Test the saved Open Cloud API key."):l("assets.settings.testConnection.tooltip.enterOrSaved","Enter an API key or save one before testing the connection.")),_e=i||$||!_,Se=oe??(_?l("assets.settings.removeApiKey.tooltip.ready","Remove the locally saved Open Cloud API key."):S?l("assets.settings.removeApiKey.tooltip.env","Environment API keys cannot be removed from Dashboard. Remove ROBLOX_OPEN_CLOUD_API_KEY outside WEPPY."):l("assets.settings.removeApiKey.tooltip.none","No local Open Cloud API key is saved.")),Ue=i||$||!_||!m,Te=oe??(S?l("assets.settings.saveCreator.tooltip.env","Environment API keys cannot save a default Creator here. Enter Creator details in the upload dialog."):_?m?l("assets.settings.saveCreator.tooltip.ready","Save this Creator as the default owner for uploads."):l("assets.settings.saveCreator.tooltip.enterId","Enter a user or group ID before saving the default Creator."):l("assets.settings.saveCreator.tooltip.noLocal","Save a local Open Cloud API key before saving a default Creator.")),Be=oe??(_?l("assets.settings.addCreator.tooltip.ready","Add another User or Group Creator preset to this profile."):l("assets.settings.saveCreator.tooltip.noLocal","Save a local Open Cloud API key before saving a default Creator.")),Ee=i||$||S||!_,Ge=oe??(_?l("assets.settings.unregisterCreator.tooltip.ready","Unregister this Creator from the selected profile."):S?l("assets.settings.saveCreator.tooltip.env","Environment API keys cannot save a default Creator here. Enter Creator details in the upload dialog."):l("assets.settings.saveCreator.tooltip.noLocal","Save a local Open Cloud API key before saving a default Creator.")),Me=J?l("assets.settings.saveCreatorPreset","Save Creator"):l("assets.settings.saveCreator","Save default Creator"),De=(h==null?void 0:h.label)??l("assets.settings.credential.none","No API key saved"),ge=d=>{const j=d.profiles.find(I=>I.id===d.activeProfileId)??d.profiles[0]??null;x(d),L((j==null?void 0:j.id)??""),D(!j||j.creators.length===0),E(d.profiles.length===0)},Fe=async()=>{if(h){k(!0);try{const d=await Gn(h.id,J==null?void 0:J.id);ge(d),P(Kn(d.validation,l))}catch(d){P(d instanceof Error?d.message:l("assets.settings.testFailed","Connection test failed."))}finally{k(!1)}}},Oe=async()=>{if(A){k(!0);try{if(A.kind==="apiKey"){const d=await Un(A.profileId);ge(d),P(l("assets.settings.apiKeyRemoved","Open Cloud API key unregistered from local storage."))}else{const d=await En(A.profileId,A.creatorPresetId);ge(d),P(l("assets.settings.creatorUnregistered","Creator unregistered from this profile."))}q(null)}catch(d){P(d instanceof Error?d.message:A.kind==="apiKey"?l("assets.settings.removeFailed","Failed to unregister API key."):l("assets.settings.creatorUnregisterFailed","Failed to unregister Creator."))}finally{k(!1)}}},u=(A==null?void 0:A.kind)==="apiKey"?l("assets.settings.unregisterApiKey.title","Unregister API Key?"):l("assets.settings.unregisterCreator.title","Unregister Creator?"),v=(A==null?void 0:A.kind)==="apiKey"?l("assets.settings.unregisterApiKey.message","Roblox API key is not revoked. WEPPY only removes the local Credential Profile registration on this device."):l("assets.settings.unregisterCreator.message","Roblox user or group is not deleted. WEPPY only removes this Creator from the selected API Key profile."),C=(A==null?void 0:A.kind)==="apiKey"?l("assets.settings.removeApiKey","Unregister API Key"):l("assets.settings.unregisterCreator","Unregister Creator");return s.jsxs("section",{id:"asset-library-settings-panel",className:`${a.settingsInlinePanel} ${a.settingsDrawer}`,role:"region","aria-label":l("assets.settings.title","Asset Library settings"),"data-panel-placement":"toolbar-popover",children:[s.jsxs("div",{className:a.drawerHeader,children:[s.jsxs("div",{children:[s.jsx("h2",{children:l("assets.settings.title","Asset Library settings")}),s.jsx("span",{children:De})]}),s.jsx(se,{text:l("common.close","Close"),children:s.jsx("button",{type:"button",className:a.iconButton,onClick:n,"aria-label":l("common.close","Close"),children:s.jsx(Xe,{size:16})})})]}),i&&s.jsx("div",{className:`${a.notice} ${a.proNotice}`,children:l("assets.settings.proOnly","Roblox upload settings and Open Cloud credential controls are available on Pro.")}),s.jsxs("section",{className:a.settingsPanel,children:[s.jsxs("label",{className:a.toggleRow,children:[s.jsxs("span",{children:[s.jsx("strong",{children:l("assets.settings.openCloudToggle","Open Cloud upload")}),s.jsx("small",{children:l("assets.settings.openCloudToggle.help","Controls whether server-side Open Cloud upload mutations can run.")})]}),s.jsx(Ds,{checked:X,disabled:i||$,onChange:d=>{(async()=>{k(!0);try{const j=await wn({assetUploadByOpenCloudEnabled:d.target.checked});f(j),P(l("assets.settings.saved","Upload settings saved."))}catch(j){P(j instanceof Error?j.message:l("assets.settings.saveFailed","Failed to save upload settings."))}finally{k(!1)}})()}})]}),pe&&s.jsx("div",{className:a.metadataList,children:U.map(d=>{const j=d.id===(h==null?void 0:h.id);return s.jsxs("div",{className:a.metadataItem,children:[s.jsx("strong",{children:d.label}),s.jsxs("span",{children:[l("assets.settings.field.storage","Storage"),": ",us(d.storageProvider,l)]}),s.jsxs("span",{children:[l("assets.settings.field.validationStatus","Validation status"),": ",Ke(d.validationStatus,l)]}),j&&s.jsx("code",{children:l("assets.settings.activeProfileBadge","Active")}),!j&&d.storageProvider==="localFile"&&s.jsx("button",{type:"button",className:a.commandButton,disabled:i||$,onClick:()=>{(async()=>{k(!0);try{const I=await $n(d.id),O=I.profiles.find(de=>de.id===(I.activeProfileId??d.id))??d;x(I),L(O.id),D(O.creators.length===0),W("user"),M(""),G(""),P(l("assets.settings.profileSelected","Open Cloud credential profile selected."))}catch(I){P(I instanceof Error?I.message:l("assets.settings.saveFailed","Failed to save upload settings."))}finally{k(!1)}})()},children:l("assets.settings.useProfile","Use profile")})]},d.id)})}),h&&s.jsxs("div",{className:a.settingsSubsection,children:[s.jsx("div",{className:a.settingsSectionHeader,children:s.jsx("h3",{children:l("assets.settings.credentialProfile","Credential Profile")})}),s.jsxs("div",{className:a.metadataItem,children:[s.jsxs("dl",{className:a.settingsDefinitionList,children:[s.jsxs("div",{children:[s.jsx("dt",{children:l("assets.settings.field.profile","Profile")}),s.jsx("dd",{children:h.label})]}),h.maskedKey&&s.jsxs("div",{children:[s.jsx("dt",{children:l("assets.settings.field.apiKey","API Key")}),s.jsx("dd",{children:h.maskedKey})]}),s.jsxs("div",{children:[s.jsx("dt",{children:l("assets.settings.field.storage","Storage")}),s.jsx("dd",{children:us(h.storageProvider,l)})]}),s.jsxs("div",{children:[s.jsx("dt",{children:l("assets.settings.field.validationStatus","Validation status")}),s.jsx("dd",{children:Ke(h.validationStatus,l)})]}),s.jsxs("div",{children:[s.jsx("dt",{children:l("assets.settings.field.creators","Creators")}),s.jsx("dd",{children:h.creators.length})]})]}),!K&&s.jsxs("div",{className:a.buttonRow,children:[s.jsx(se,{text:Ce,children:s.jsx("button",{type:"button",className:a.commandButton,disabled:ae,onClick:()=>{Fe()},children:l("assets.settings.testConnection","Test Connection")})}),_&&s.jsx("button",{type:"button",className:a.commandButton,disabled:i||$,onClick:()=>E(!0),children:l("assets.settings.replaceApiKey","Replace API Key")}),s.jsx(se,{text:Se,children:s.jsx("button",{type:"button",className:`${a.commandButton} ${a.dangerButton}`,disabled:_e,onClick:()=>q({kind:"apiKey",profileId:h.id}),children:l("assets.settings.removeApiKey","Unregister API Key")})})]})]})]}),K&&s.jsxs("div",{className:a.formStack,children:[s.jsxs("div",{className:a.field,children:[s.jsx("div",{className:a.fieldLabelRow,children:s.jsx("label",{htmlFor:"asset-settings-open-cloud-profile-label",children:l("assets.settings.profileLabel","Profile name")})}),s.jsx("input",{id:"asset-settings-open-cloud-profile-label",value:R,disabled:i||$,onChange:d=>r(d.target.value),placeholder:l("assets.settings.profileLabel.placeholder","Studio automation key")}),s.jsx("p",{className:a.inlineHelp,children:l("assets.settings.profileLabel.help","Optional. If left blank, WEPPY saves this profile as Open Cloud key automatically.")})]}),s.jsxs("div",{className:a.field,children:[s.jsxs("div",{className:a.fieldLabelRow,children:[s.jsx("label",{htmlFor:"asset-settings-open-cloud-api-key",children:l("assets.settings.apiKey","Open Cloud API Key")}),s.jsx(Qe,{topicId:"openCloudApiKey",variant:"field",state:{hasOpenCloudCredential:z}})]}),s.jsx("input",{id:"asset-settings-open-cloud-api-key",value:b,type:"password",disabled:i||$,onChange:d=>N(d.target.value)}),s.jsx("p",{className:a.inlineHelp,children:l("assets.settings.apiKey.inlineHelp","WEPPY uses this key only for Roblox Open Cloud requests. The key is encrypted on this device and is not sent to WEPPY servers or stored in any other external storage.")})]}),!z&&s.jsx("p",{className:a.inlineHelp,children:s.jsx("a",{href:Fs["open_cloud.api_key"].docsUrl,target:"_blank",rel:"noreferrer",children:l("assets.settings.apiKeyGuide","Create a Roblox API key with Assets Read and Write permissions.")})}),s.jsxs("div",{className:a.buttonRow,children:[s.jsx(se,{text:xe,children:s.jsx("button",{type:"button",className:a.commandButton,disabled:ve,onClick:()=>{(async()=>{var d;k(!0);try{const j={apiKey:w,...R.trim()?{label:R.trim()}:{}},I=(h==null?void 0:h.storageProvider)==="localFile"?await Ln(h.id,j):await Rn(j),O=I.profiles.find(de=>{var Y;return de.id===(I.activeProfileId??((Y=I.profile)==null?void 0:Y.id))});x(I),L(I.activeProfileId??((d=I.profile)==null?void 0:d.id)??""),D(!O||O.creators.length===0),E(!1),N(""),r(""),P(l("assets.settings.apiKeySaved","Open Cloud API key saved locally."))}catch(j){P(j instanceof Error?j.message:l("assets.settings.saveFailed","Failed to save upload settings."))}finally{k(!1)}})()},children:l("assets.settings.saveApiKey","Save API Key")})}),s.jsx(se,{text:Ce,children:s.jsx("button",{type:"button",className:a.commandButton,disabled:ae,onClick:()=>{(async()=>{k(!0);try{const d=await Mn(w||void 0);P(zn(d.validation,l))}catch(d){P(d instanceof Error?d.message:l("assets.settings.testFailed","Connection test failed."))}finally{k(!1)}})()},children:l("assets.settings.testConnection","Test Connection")})}),s.jsx(se,{text:Se,children:s.jsx("button",{type:"button",className:`${a.commandButton} ${a.dangerButton}`,disabled:_e,onClick:()=>{h&&q({kind:"apiKey",profileId:h.id})},children:l("assets.settings.removeApiKey","Unregister API Key")})})]})]}),s.jsx("div",{className:a.metadataList,children:h==null?void 0:h.creators.map(d=>s.jsxs("div",{className:a.metadataItem,children:[s.jsx("strong",{children:d.label}),s.jsx("span",{children:Vn(d,l)}),d.id===h.defaultCreatorId&&s.jsx("code",{children:l("assets.settings.defaultCreatorBadge","Default")}),s.jsxs("span",{children:[l("assets.settings.field.validationStatus","Validation status"),": ",Ke(d.validationStatus,l)]}),s.jsxs("div",{className:a.buttonRow,children:[d.id!==h.defaultCreatorId&&h.storageProvider==="localFile"&&s.jsx("button",{type:"button",className:a.commandButton,disabled:i||$,onClick:()=>{(async()=>{if(h){k(!0);try{const j=await Bn(h.id,d.id);x(j),P(l("assets.settings.defaultCreatorSaved","Open Cloud default Creator saved locally."))}catch(j){P(j instanceof Error?j.message:l("assets.settings.saveFailed","Failed to save upload settings."))}finally{k(!1)}}})()},children:l("assets.settings.makeDefaultCreator","Make default")}),s.jsx(se,{text:Ge,children:s.jsx("button",{type:"button",className:`${a.commandButton} ${a.dangerButton}`,disabled:Ee,onClick:()=>q({kind:"creator",profileId:h.id,creatorPresetId:d.id}),children:l("assets.settings.unregisterCreator","Unregister Creator")})})]})]},d.id))}),ee&&!H&&s.jsx(se,{text:Be,children:s.jsx("button",{type:"button",className:a.commandButton,disabled:i||$||S||!_,onClick:()=>{W("user"),M(""),G(""),D(!0)},children:l("assets.settings.addCreator","Add Creator")})}),Z&&s.jsxs(s.Fragment,{children:[s.jsxs("div",{className:a.twoColumn,children:[s.jsxs("div",{className:a.field,children:[s.jsx("div",{className:a.fieldLabelRow,children:s.jsx("label",{htmlFor:"asset-settings-creator-type",children:l("assets.upload.creatorType","Creator type")})}),s.jsxs("select",{id:"asset-settings-creator-type",value:T,disabled:i||$||S||!_,onChange:d=>W(d.target.value),children:[s.jsx("option",{value:"user",children:l("assets.creator.user","User")}),s.jsx("option",{value:"group",children:l("assets.creator.group","Group")})]})]}),s.jsxs("div",{className:a.field,children:[s.jsxs("div",{className:a.fieldLabelRow,children:[s.jsx("label",{htmlFor:"asset-settings-creator-id",children:l("assets.upload.creatorId","Creator ID")}),s.jsx(Qe,{topicId:"openCloudCreatorId",variant:"field",state:{hasDefaultCreator:!!J}})]}),s.jsx("input",{id:"asset-settings-creator-id",value:V,disabled:i||$||S||!_,onChange:d=>M(d.target.value)}),s.jsx("p",{className:a.inlineHelp,children:l("assets.settings.creatorId.inlineHelp","Default owner for new Roblox assets: your User ID or a Group ID.")})]})]}),s.jsxs("div",{className:a.field,children:[s.jsx("div",{className:a.fieldLabelRow,children:s.jsx("label",{htmlFor:"asset-settings-creator-label",children:l("assets.settings.creatorLabel","Creator label")})}),s.jsx("input",{id:"asset-settings-creator-label",value:B,disabled:i||$||S||!_,onChange:d=>G(d.target.value),placeholder:l("assets.settings.creatorLabel.placeholder","Main studio group")}),s.jsx("p",{className:a.inlineHelp,children:l("assets.settings.creatorLabel.help","Optional. If left blank, WEPPY automatically saves a label like User 123 or Group 456.")})]}),!J&&s.jsx("p",{className:a.inlineHelp,children:l("assets.settings.creatorHelp","Use the numeric user ID from a profile URL or group ID from a group URL.")}),s.jsxs("div",{className:a.buttonRow,children:[s.jsx(se,{text:Te,children:s.jsx("button",{type:"button",className:a.primaryButton,disabled:Ue,onClick:()=>{(async()=>{if(h){k(!0);try{const d=await Tn(h.id,{creatorType:T,creatorId:m,makeDefault:!J,...B.trim()?{label:B.trim()}:{}});x(d),M(""),G(""),D(!1),P(l("assets.settings.defaultCreatorSaved","Open Cloud default Creator saved locally."))}catch(d){P(d instanceof Error?d.message:l("assets.settings.saveFailed","Failed to save upload settings."))}finally{k(!1)}}})()},children:Me})}),ee&&s.jsx("button",{type:"button",className:a.commandButton,disabled:i||$,onClick:()=>{W("user"),M(""),G(""),D(!1)},children:l("assets.settings.cancelCreator","Cancel")})]})]})]}),Q&&s.jsx("div",{className:a.messageState,children:Q}),s.jsx(ys,{open:A!==null,title:u,message:v,cancelLabel:l("common.cancel","Cancel"),confirmLabel:C,loading:$,onCancel:()=>q(null),onConfirm:()=>{Oe()}})]})}const qn=12,Xn=5e3;function re(e,t){return e instanceof Error&&e.message.trim().length>0?e.message:t}function ps(e,t){return e.some(l=>je(l,t))?e.map(l=>je(l,t)?t:l):[t,...e]}function je(e,t){return e.id!==t.id||e.category!==t.category||e.scope.kind!==t.scope.kind?!1:e.scope.kind==="shared"||t.scope.kind==="place"&&e.scope.placeId===t.scope.placeId}function Jn(e,t){return e.some(n=>je(n,t))?e.map(n=>je(n,t)?t:n):e}function We(e,t){return wt(e.filter(n=>kt(n,t)))}function ye(e,t){return e?`${e.displayName} (${e.id})`:t??"unknown asset"}function Zn(e){return e.length===0?"none":e.map(t=>ye(t)).join(", ")}function hs(e){const t=`status ${e.status}`;return e.roblox.assetId?`Roblox asset ${e.roblox.assetId}; ${t}`:t}function Qn(e,t){const n=ye(t);return e==="update"?`Updated metadata for asset: ${n}.`:e==="upload"?`Uploaded asset: ${n} -> ${hs(t)}.`:e==="thumbnail-generate"?`Generated thumbnail for asset: ${n}.`:e==="status-refresh"?`Refreshed Roblox status for asset: ${n} -> ${hs(t)}.`:e==="usage-scan"?`Scanned usage for asset: ${n} -> ${t.usage.references.length} reference(s).`:`Updated asset: ${n}.`}function eo(e){return e!=="upload"&&e!=="status-refresh"}function ms(e){return e.status==="processing"&&!!(e.roblox.operationId??e.roblox.operationPath)}function Pe(e){return{scope:e.scope.kind,placeId:e.scope.kind==="place"?e.scope.placeId:void 0,category:e.category}}function so(e,t){return e==="shared"?[{scope:"shared"}]:e==="place"?t===null?[]:[{scope:"place",placeId:t}]:[...t===null?[]:[{scope:"place",placeId:t}],{scope:"shared"}]}function xs(e,t,n){return so(e,t).flatMap(l=>It(n).map(o=>({request:{...l,category:o},label:`${l.scope}/${o}`})))}function gs(e,t){if(t.length===0)return null;const n=t.map(({label:l,reason:o})=>`${l}: ${re(o,"request failed")}`);return`${e}: ${n.join("; ")}`}function to(e){if(e.pluginConnected&&e.activePlaceId!==null){const n=Ve(e.places,e.activePlaceId),l=n?be(e.places,n.placeId):!1;return{placeId:e.activePlaceId,placeName:e.activePlaceName??(l?null:(n==null?void 0:n.placeName)??null),studioConnected:!0,folderUnresolved:l,hasSyncMetadata:n?Ae(e.places,n):void 0}}if(e.lastActivePlaceId!==null){const n=Ve(e.places,e.lastActivePlaceId),l=n?be(e.places,n.placeId):!1;return{placeId:e.lastActivePlaceId,placeName:e.lastActivePlaceName??(l?null:(n==null?void 0:n.placeName)??null),studioConnected:!1,folderUnresolved:l,hasSyncMetadata:n?Ae(e.places,n):void 0}}const t=Es(e.places);return{placeId:(t==null?void 0:t.placeId)??null,placeName:t&&!be(e.places,t.placeId)?t.placeName:null,studioConnected:!1,folderUnresolved:t?be(e.places,t.placeId):!1,hasSyncMetadata:t?Ae(e.places,t):void 0}}function ao(e,t){if(typeof t=="number"){const n=Ve(e.places,t);if(n){const l=be(e.places,n.placeId);return{placeId:n.placeId,placeName:Bs(e,n.placeId)??(l?null:n.placeName),studioConnected:n.isConnected,folderUnresolved:l,hasSyncMetadata:Ae(e.places,n),overrideStillValid:!0}}}return{...to(e),overrideStillValid:t===null}}function lo(){const[e,t]=c.useState([]),[n,l]=c.useState(0),[o,f]=c.useState(null),[g,x]=c.useState("place"),[p,L]=c.useState("all"),[K,E]=c.useState([]),[R,r]=c.useState(null),[b,N]=c.useState(null),[T,W]=c.useState(null),[V,M]=c.useState(null),[B,G]=c.useState(!1),[H,D]=c.useState(!1),[Q,P]=c.useState(void 0),[A,q]=c.useState(!1),[$,k]=c.useState(!0),[i,y]=c.useState(null),[X,w]=c.useState(null),[m,U]=c.useState(null),h=c.useRef(!0),z=c.useRef(new Map),_=c.useRef(new Set),S=c.useMemo(()=>e.find(u=>te(u)===o)??null,[e,o]),J=(S==null?void 0:S.id)??null;c.useEffect(()=>{o&&(e.some(u=>te(u)===o)||f(null))},[e,o]);const ee=c.useCallback(u=>{const v=z.current.get(u);v!==void 0&&(clearTimeout(v),z.current.delete(u))},[]),Z=c.useCallback((u,v=qn)=>{const C=te(u);if(!ms(u)||v<=0){ee(C);return}_.current.has(C)||(ee(C),_.current.add(C),(async()=>{try{const d=await es(Pe(u),u.id);if(!h.current)return;if(t(j=>Jn(j,d)),ms(d)&&v>1){const j=te(d),I=setTimeout(()=>{z.current.delete(j),Z(d,v-1)},Xn);z.current.set(j,I);return}ee(te(d))}catch(d){if(!h.current)return;ee(C),w(re(d,"Asset Library status refresh failed."))}finally{_.current.delete(C)}})())},[ee]);c.useEffect(()=>()=>{h.current=!1;for(const u of z.current.values())clearTimeout(u);z.current.clear(),_.current.clear()},[]);const pe=c.useCallback(()=>g==="shared"?{scope:"shared"}:{scope:"place",placeId:T??void 0},[T,g]),oe=c.useCallback(u=>({...pe(),category:u}),[pe]),ve=c.useCallback(async()=>{try{const u=await Ts(),v=ao(u,R);return E(u.places),v.overrideStillValid||r(null),N(v.placeId),W(v.placeId),M(v.placeName),G(v.studioConnected),D(v.folderUnresolved),P(v.hasSyncMetadata),q(v.studioConnected),v.placeId}catch{return E([]),N(null),W(null),M(null),G(!1),D(!1),P(void 0),q(!1),null}},[R]),xe=c.useCallback(async()=>{w(null);try{const u=await ve();if(g==="place"&&u===null){t([]),l(0),k(!1),w("No active place is connected for place-scoped assets.");return}const v=xs(g,u,p),C=await Promise.allSettled(v.map(({request:O})=>ft(O))),d=C.flatMap(O=>O.status==="fulfilled"?[O.value]:[]),j=C.flatMap((O,de)=>O.status==="rejected"?[{label:v[de].label,reason:O.reason}]:[]);g==="all"&&u===null&&j.unshift({label:"place",reason:new Error("No active place is available")});const I=We(d.flatMap(O=>O.assets),p);t(I),l(I.length);for(const O of I)Z(O);w(gs("Some Asset Library requests failed",j))}catch(u){w(re(u,"Failed to load Asset Library."))}finally{k(!1)}},[p,ve,g,Z]);c.useEffect(()=>{xe()},[xe]);const ae=c.useCallback(async(u,v,C)=>{const d=(S==null?void 0:S.id)===v?S:e.find(j=>j.id===v)??null;if(!d)return w("Asset context is unavailable."),null;y(u),w(null),U(null);try{const j=await C(Pe(d));return t(I=>ps(I,j)),f(te(j)),eo(u)&&U(Qn(u,j)),j}catch(j){return w(re(j,"Asset Library action failed.")),null}finally{y(null)}},[e,S]),Ce=c.useCallback(async()=>{y("rescan"),w(null),U(null);try{const u=xs(g,T,p);if(g==="place"&&T===null){w("No active place is connected for place-scoped assets.");return}const v=await Promise.allSettled(u.map(({request:Y})=>bt(Y))),C=v.flatMap(Y=>Y.status==="fulfilled"?[Y.value]:[]),d=v.flatMap((Y,fe)=>Y.status==="rejected"?[{label:u[fe].label,reason:Y.reason}]:[]);g==="all"&&T===null&&d.unshift({label:"place",reason:new Error("No active place is available")});const j=We(C.flatMap(Y=>Y.assets),p),I=C.reduce((Y,fe)=>Y+fe.adoptedCount,0),O=C.reduce((Y,fe)=>Y+fe.skippedCount,0),de=We(C.flatMap(Y=>Y.adopted),p);t(j),l(j.length),U(`Rescan complete for ${p}: ${I} asset(s) added, ${O} skipped. Added: ${Zn(de)}.`),w(gs("Some Asset Library rescans failed",d))}catch(u){w(re(u,"Asset Library rescan failed."))}finally{y(null)}},[T,p,g]),_e=c.useCallback(async(u,v)=>{y("export-selection-rbxm"),w(null),U(null);try{const C=await _t(oe(u),v);return t(d=>ps(d,C.asset)),f(te(C.asset)),U(`Exported Studio selection as RBXM asset: ${ye(C.asset)}${C.deduplicated?" (reused existing local asset)":""}.`),C}catch(C){return w(re(C,"Asset Library .rbxm export failed.")),null}finally{y(null)}},[oe]),Se=c.useCallback((u,v)=>ae("update",u,C=>yt(C,u,v)),[ae]),Ue=c.useCallback(async(u,v)=>{const C=await ae("upload",u,d=>vt(d,u,v));return C&&Z(C),C},[ae,Z]),Te=c.useCallback(async u=>{const v=(S==null?void 0:S.id)===u?S:e.find(d=>d.id===u)??null;if(!v)return w("Asset context is unavailable."),!1;const C=te(v);ee(C),y("delete"),w(null),U(null);try{return await jt(Pe(v),u),t(d=>{const j=d.filter(I=>!je(I,v));return l(j.length),j}),f(d=>d===C?null:d),U(`Deleted asset: ${ye(v,u)}. Local files removed; uploaded Roblox assets were not deleted.`),!0}catch(d){return w(re(d,"Asset Library delete failed.")),!1}finally{y(null)}},[e,ee,S]),Be=c.useCallback(async(u,v)=>{const C=(S==null?void 0:S.id)===u?S:e.find(d=>d.id===u)??null;if(!C)return w("Asset context is unavailable."),null;y("import-rbxm"),w(null),U(null);try{const d=await St(Pe(C),u,v);return f(te(C)),U(`Imported RBXM asset: ${ye(C,u)} -> ${d.importedCount} instance(s) to ${d.targetParent}.`),d}catch(d){return w(re(d,"Asset Library .rbxm import failed.")),null}finally{y(null)}},[e,S]),Ee=c.useCallback(u=>ae("thumbnail-generate",u,v=>Nt(v,u)),[ae]),Ge=c.useCallback(u=>{const v=(S==null?void 0:S.id)===u?S:e.find(C=>C.id===u)??null;return v&&ee(te(v)),ae("status-refresh",u,C=>es(C,u))},[e,ee,ae,S]),Me=c.useCallback((u,v)=>ae("usage-scan",u,async C=>(await Ct(C,u,v)).asset),[ae]),De=c.useCallback(u=>{x(u),f(null)},[]),ge=c.useCallback(u=>{r(u),f(null)},[]),Fe=c.useCallback(u=>{At(u)&&L(u)},[]),Oe=c.useCallback(u=>{if(u===null){f(null);return}const C=e.find(d=>te(d)===u)??e.find(d=>d.id===u);f(C?te(C):u)},[e]);return{assets:e,totalCount:n,selectedAsset:S,selectedAssetId:J,selectedAssetKey:o,scope:g,categoryFilter:p,availablePlaces:K,selectedPlaceId:b,activePlaceId:T,activePlaceName:V,selectedPlaceIsConnected:B,selectedPlaceFolderUnresolved:H,selectedPlaceHasSyncMetadata:Q,studioConnected:A,loading:$,busyAction:i,error:X,lastMessage:m,setScope:De,setSelectedPlaceId:ge,setCategoryFilter:Fe,selectAsset:Oe,refresh:xe,rescan:Ce,exportSelectionRbxm:_e,updateMetadata:Se,uploadAsset:Ue,deleteAsset:Te,importRbxm:Be,generateThumbnail:Ee,refreshStatus:Ge,scanUsage:Me}}const ks="weppy-assets-view-preferences-v1",he={organizationMode:"folders",viewMode:"grid",gridSize:"medium"};function no(e){return e==="folders"||e==="all-assets"}function oo(e){return e==="grid"||e==="list"}function ro(e){return e==="small"||e==="medium"||e==="large"}function io(){if(typeof window>"u")return he;try{const e=window.localStorage.getItem(ks);if(!e)return he;const t=JSON.parse(e);return{organizationMode:no(t.organizationMode)?t.organizationMode:he.organizationMode,viewMode:oo(t.viewMode)?t.viewMode:he.viewMode,gridSize:ro(t.gridSize)?t.gridSize:he.gridSize}}catch{return he}}function co(){const[e,t]=c.useState(io);return c.useEffect(()=>{try{window.localStorage.setItem(ks,JSON.stringify(e))}catch{}},[e]),{...e,setOrganizationMode:n=>{t(l=>({...l,organizationMode:n}))},setViewMode:n=>{t(l=>({...l,viewMode:n}))},setGridSize:n=>{t(l=>({...l,gridSize:n}))}}}function uo(e,t){return t("assets.count.shown","Shown assets: {count}").replace("{count}",String(e))}function po(e,t){return e===null?null:t("assets.place.id","Place ID {placeId}").replace("{placeId}",String(e))}function _o(){const{t:e}=ce(),{trackEvent:t}=Gs(),{tier:n,loading:l}=Ms(),o=lo(),f=co(),[g,x]=c.useState(!1),[p,L]=c.useState(!1),[K,E]=c.useState(!1),R=!l&&n==="pro",r=o.selectedAsset,b=(r==null?void 0:r.file.original.toLowerCase().endsWith(".rbxm"))??!1,N=(r==null?void 0:r.category)==="model"||(r==null?void 0:r.category)==="animation",T="game.Workspace",V=!!(R&&o.studioConnected&&r&&b&&N),M=o.availablePlaces??[],B=o.selectedPlaceId??o.activePlaceId,G=c.useMemo(()=>{var y;const i=new Map;return typeof B=="number"&&((y=o.activePlaceName)!=null&&y.trim())&&i.set(B,o.activePlaceName.trim()),i},[o.activePlaceName,B]),H=o.selectedAssetKey??(r?te(r):null),D=c.useCallback(()=>{o.selectAsset(null)},[o.selectAsset]),Q=c.useMemo(()=>{const i=typeof o.activePlaceId=="number"?e("placeScope.folder.unresolvedPlace","Place {placeId}").replace("{placeId}",String(o.activePlaceId)):e("assets.scope.place","Current Place"),y=o.activePlaceName??i;return o.scope==="shared"?[e("assets.scope.shared","Shared")]:o.scope==="all"?[e("assets.scope.all","All scopes"),y,e("assets.scope.shared","Shared")]:[y,o.selectedPlaceFolderUnresolved?null:po(o.activePlaceId,e)].filter(X=>!!X)},[o.activePlaceId,o.activePlaceName,o.scope,o.selectedPlaceFolderUnresolved,e]),P=o.scope==="place"&&typeof B=="number"?o.selectedPlaceIsConnected?e("placeScope.connected","Studio connected"):e("placeScope.stored","Stored data"):null,A=c.useMemo(()=>qe(o.categoryFilter,e),[o.categoryFilter,e]),q=uo(o.totalCount,e),$=o.scope==="place"&&(o.selectedPlaceFolderUnresolved||o.selectedPlaceHasSyncMetadata===!1),k=e("assets.detail.importRbxm.tooltip","Insert this local RBXM asset into {target} in the connected Studio place.").replace("{target}",T);return s.jsxs("div",{className:a.page,children:[s.jsx(Os,{title:e("assets.title","Assets"),description:e("assets.subtitle","Browse local originals, upload to Roblox, and inspect synced usage by place."),badge:s.jsx("span",{className:a.experimentalBadge,children:e("assets.experimental","Experimental")}),helpTopicId:"assets",helpState:{tier:n}}),s.jsxs("div",{className:a.toolbarShell,children:[s.jsxs("div",{className:[a.toolbar,$?a.toolbarExpandedSummary:""].filter(Boolean).join(" "),children:[s.jsxs("div",{className:a.segmented,role:"group","aria-label":e("assets.scope.label","Asset scope"),children:[s.jsx("button",{type:"button","aria-pressed":o.scope==="all",className:o.scope==="all"?a.segmentedActive:"",onClick:()=>o.setScope("all"),children:e("assets.scope.all","All scopes")}),s.jsx("button",{type:"button","aria-pressed":o.scope==="place",className:o.scope==="place"?a.segmentedActive:"",onClick:()=>o.setScope("place"),children:e("assets.scope.place","Current Place")}),s.jsx("button",{type:"button","aria-pressed":o.scope==="shared",className:o.scope==="shared"?a.segmentedActive:"",onClick:()=>o.setScope("shared"),children:e("assets.scope.shared","Shared")})]}),s.jsx("div",{className:a.placeContextSlot,role:"group","aria-label":e("assets.place.context","Asset place context"),children:o.scope==="shared"?s.jsx("span",{className:a.sharedPlaceContext,children:e("assets.place.sharedLibrary","Shared library")}):M.length>0?s.jsxs("label",{className:a.placeSelectorLabel,children:[s.jsx("span",{children:e("assets.place.selector","Asset place")}),s.jsxs("select",{className:a.placeSelect,value:typeof B=="number"?String(B):"",onChange:i=>{const y=Number.parseInt(i.currentTarget.value,10);Number.isInteger(y)&&o.setSelectedPlaceId(y)},children:[typeof B!="number"?s.jsx("option",{value:"",disabled:!0,children:e("placeScope.selector.noneSelectable","No selectable Place folder")}):null,s.jsx(Hs,{places:M,confirmedNames:G,t:e})]})]}):s.jsx("span",{className:a.sharedPlaceContext,children:o.activePlaceName??e("assets.scope.place","Current Place")})}),s.jsxs("div",{className:a.listContextSummary,children:[P||o.scope==="place"&&(o.selectedPlaceFolderUnresolved||o.selectedPlaceHasSyncMetadata===!1)?s.jsxs("div",{className:a.placeStatusGroup,children:[P?s.jsx(me,{variant:o.selectedPlaceIsConnected?"success":"neutral",shape:"pill",children:P}):null,o.scope==="place"&&o.selectedPlaceFolderUnresolved?s.jsx(me,{variant:"neutral",shape:"pill",children:e("placeScope.folder.unresolved","Representative folder unconfirmed")}):null,o.scope==="place"&&o.selectedPlaceHasSyncMetadata===!1?s.jsx(me,{variant:"neutral",shape:"pill",children:e("placeScope.folder.noSyncHistory","No sync history")}):null]}):null,s.jsxs("div",{className:a.contextTextSummary,children:[Q.map((i,y)=>s.jsxs("span",{children:[y>0?s.jsx("span",{className:a.contextDivider,children:" · "}):null,i]},`${i}-${y}`)),Q.length>0?s.jsx("span",{className:a.contextDivider,children:" · "}):null,s.jsx("span",{children:A}),s.jsx("span",{className:a.contextDivider,children:" · "}),s.jsx("strong",{children:q})]})]}),s.jsxs("div",{className:a.toolbarActions,children:[s.jsx(se,{text:e("assets.rescan.tooltip","Scan inbox folders for the current filter."),children:s.jsxs("button",{type:"button",className:a.commandButton,disabled:o.busyAction==="rescan",onClick:()=>{t("dashboard_click_event",{click_target:"assets_rescan",page:"assets"}),o.rescan()},children:[s.jsx(fs,{size:15}),e("assets.rescan","Rescan")]})}),s.jsx(se,{text:p?"":e("assets.settings.open.tooltip","Open Roblox upload settings."),children:s.jsx("button",{type:"button",className:[a.iconButton,p?a.iconButtonActive:""].filter(Boolean).join(" "),onClick:()=>{t("dashboard_click_event",{click_target:"assets_open_settings",page:"assets"}),L(i=>!i)},"aria-label":e("assets.settings.open","Open settings"),"aria-controls":"asset-library-settings-panel","aria-expanded":p,children:s.jsx(bs,{size:16})})})]}),s.jsxs("div",{className:a.categoryControl,children:[s.jsx("span",{id:"assets-category-filter-label",className:a.categoryControlLabel,children:e("assets.category.filter","Category")}),s.jsx("div",{className:a.categoryRail,role:"radiogroup","aria-labelledby":"assets-category-filter-label",children:_s.map(i=>{const y=o.categoryFilter===i,X=qe(i,e);return s.jsx("button",{type:"button",role:"radio","aria-checked":y,className:[a.categoryButton,y?a.categoryButtonActive:""].filter(Boolean).join(" "),onClick:()=>{o.setCategoryFilter(i)},children:X},i)})})]})]}),M.some(i=>i.folderStatus==="duplicate"||i.folderStatus==="unresolved")?s.jsx("div",{className:a.placeFolderDetails,children:s.jsx(zs,{places:M,t:e})}):null,s.jsx(Yn,{open:p,tier:n,onClose:()=>L(!1)})]}),o.error&&s.jsxs("div",{className:a.errorState,children:[o.scope==="all"?s.jsx("strong",{children:e("assets.partial.title","Some locations could not be loaded")}):null,s.jsx("span",{children:o.error})]}),o.lastMessage&&s.jsx("div",{className:a.messageState,children:o.lastMessage}),o.categoryFilter==="rbxm"&&s.jsxs("section",{className:a.rbxmGuide,"aria-label":e("assets.rbxmGuide.title","Save RBXM from Studio"),children:[s.jsx("h2",{children:e("assets.rbxmGuide.title","Save RBXM from Studio")}),s.jsx("p",{children:e("assets.rbxmGuide.body","Select objects in Roblox Studio, then use WEPPY Plugin > Assets to save the selection as a local RBXM asset.")}),s.jsx("p",{children:e("assets.rbxmGuide.thumbnail","The plugin save flow includes a thumbnail option, and saved RBXM assets appear here for management, upload, and insertion.")})]}),!R&&!l&&s.jsx("div",{className:`${a.notice} ${a.proNotice}`,children:e("assets.basic.notice","Browse, preview, edit metadata, and scan usage on Basic. Roblox upload controls are available on Pro.")}),o.loading?s.jsx("div",{className:a.emptyState,children:e("assets.loading.scope","Loading {scope} assets...").replace("{scope}",o.scope==="all"?e("assets.scope.all","All scopes"):o.scope==="shared"?e("assets.scope.shared","Shared"):e("assets.scope.place","Current Place"))}):s.jsx(un,{displayScope:o.scope,assets:o.assets,place:{placeId:o.activePlaceId,placeName:o.activePlaceName},categoryFilter:o.categoryFilter,organizationMode:f.organizationMode,viewMode:f.viewMode,gridSize:f.gridSize,selectedAssetKey:H,onSelectAsset:o.selectAsset,onClearSelection:D,onOrganizationModeChange:f.setOrganizationMode,onViewModeChange:f.setViewMode,onGridSizeChange:f.setGridSize,emptyContent:o.error?void 0:s.jsx(hn,{scope:o.scope,isPro:R,busy:o.busyAction==="rescan",onRescan:()=>{t("dashboard_click_event",{click_target:"assets_empty_rescan",page:"assets"}),o.rescan()}})}),s.jsx(In,{asset:g||p||K?null:r,busyAction:o.busyAction,canUpload:R,canImportRbxm:V,importRbxmTooltip:k,importRbxmTargetParent:T,onClose:()=>o.selectAsset(null),onSave:async(i,y)=>{r&&await o.updateMetadata(r.id,{displayName:i,description:y})},onUpload:()=>x(!0),onDelete:()=>E(!0),onImportRbxm:async()=>{r&&(t("dashboard_click_event",{click_target:"assets_import_rbxm",page:"assets"}),await o.importRbxm(r.id,{targetParent:T}))},onRefreshStatus:async()=>{r&&await o.refreshStatus(r.id)},onScanUsage:async()=>{r&&(t("dashboard_click_event",{click_target:"assets_usage_scan",page:"assets"}),await o.scanUsage(r.id,o.activePlaceId??void 0))}}),s.jsx(ys,{open:K&&!!r,title:e("assets.delete.title","Delete asset"),message:e("assets.delete.message","This removes the local Asset Library files only. Uploaded Roblox assets are not deleted."),cancelLabel:e("common.cancel","Cancel"),confirmLabel:e("common.delete","Delete"),loading:o.busyAction==="delete",onCancel:()=>E(!1),onConfirm:()=>{r&&(t("dashboard_click_event",{click_target:"assets_delete",page:"assets"}),o.deleteAsset(r.id).then(i=>{i&&E(!1)}))}}),s.jsx(Hn,{asset:r,open:g,canUpload:R,busyAction:o.busyAction,onClose:()=>{x(!1),o.selectAsset(null)},onBack:()=>x(!1),onOpenSettings:()=>{x(!1),L(!0)},onUpload:async i=>{if(!r)return;t("dashboard_click_event",{click_target:"assets_upload_submit",page:"assets"}),await o.uploadAsset(r.id,i)&&x(!1)}})]})}export{_o as Component};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as o,b as P,D as Q,u as q,j as e,X as W,a as X,w as Y,c as J,e as ee,k as te,T as ae}from"./index-uP4eoQi-.js";import{B as ne,P as se}from"./PageHeader-_z4Dtkbg.js";import{C as ie}from"./ConfirmModal-BbqpSaVw.js";import{C as ce,a as oe,T as re}from"./Tabs-BoD1I6c5.js";import{T as O}from"./TooltipText-NA7u0bu6.js";import{I as le}from"./InfoLabel-DAd1I756.js";import{G as de}from"./GameChangeDetail-DJ0xywJq.js";import"./ConfirmModal.module-DJksQHBd.js";import"./PlaceSelectOptions-Dd_m61bQ.js";const ge=10;function me(t,i){return typeof i!="number"?t:`${t}?placeId=${encodeURIComponent(String(i))}`}function he(t){const i=(t==null?void 0:t.placeId)??null,[m,c]=o.useState([]),[n,s]=o.useState(0),[u,p]=o.useState(!1),[r,T]=o.useState(!0),[C,E]=o.useState(0),[f,z]=o.useState("all"),B=o.useRef(null),S=o.useCallback(async(y,v)=>{T(!0);try{const k={limit:String(ge),offset:String(y)};v!=="all"&&(k.status=v),typeof i=="number"&&(k.placeId=String(i));const w=await P.get("/api/dashboard/changelog",k);c(w.entries),s(w.total),p(w.hasMore)}catch{c([]),s(0),p(!1)}finally{T(!1)}},[i]),I=o.useCallback(()=>{S(C,f)},[S,C,f]),$=o.useCallback(async()=>{await P.post(me("/api/dashboard/changelog/clear",i)),c([]),s(0),p(!1)},[i]);return o.useEffect(()=>{S(C,f)},[S,C,f]),o.useEffect(()=>{const y=new Q;B.current=y,y.connect();const v=y.on("command",()=>{S(C,f)});return()=>{v(),y.disconnect(),B.current=null}},[S,C,f]),{entries:m,total:n,hasMore:u,loading:r,offset:C,statusFilter:f,setOffset:E,setStatusFilter:z,refresh:I,clear:$}}const ue="_card_qniob_2",pe="_header_qniob_27",fe="_statusBadge_qniob_34",ye="_statusDot_qniob_45",xe="_active_qniob_51",_e="_completed_qniob_60",be="_timeRange_qniob_68",Ce="_summaryList_qniob_75",Se="_summaryItem_qniob_81",ve="_summaryIcon_qniob_90",je="_summaryText_qniob_96",Ne="_progressBar_qniob_101",Te="_progressFill_qniob_110",Ie="_emptySummary_qniob_124",ke="_contextBlock_qniob_132",we="_contextLabel_qniob_141",$e="_contextValue_qniob_149",h={card:ue,header:pe,statusBadge:fe,statusDot:ye,active:xe,completed:_e,timeRange:be,summaryList:Ce,summaryItem:Se,summaryIcon:ve,summaryText:je,progressBar:Ne,progressFill:Te,emptySummary:Ie,contextBlock:ke,contextLabel:we,contextValue:$e};function H(t){if(!t)return"--:--";const i=new Date(t);return`${String(i.getHours()).padStart(2,"0")}:${String(i.getMinutes()).padStart(2,"0")}`}function Be({entry:t,onClick:i,buttonRef:m}){var v,k,w,L,A,R,d,_,D,M;const{t:c}=q(),n=t.changeSummary,s=t.status==="active",u=t.isBootstrapOnly===!0,p=[],r=n.scriptsModified+n.scriptsCreated;if(r>0){const g=[];n.scriptsModified>0&&g.push(`${n.scriptsModified} ${c("changelog.card.modified","modified")}`),n.scriptsCreated>0&&g.push(`${n.scriptsCreated} ${c("changelog.card.created","created")}`);const x=`${r} ${c("changelog.card.scripts","scripts")} ${g.join(", ")}`;p.push({icon:"📝",text:x,tooltip:c("changelog.card.scripts.tooltip","Script changes made in this session.")})}const T=n.instancesCreated+n.instancesDeleted+n.instancesMoved;if(T>0){const g=[];n.instancesCreated>0&&g.push(`${n.instancesCreated} ${c("changelog.card.created","created")}`),n.instancesDeleted>0&&g.push(`${n.instancesDeleted} ${c("changelog.card.deleted","deleted")}`),n.instancesMoved>0&&g.push(`${n.instancesMoved} ${c("changelog.card.moved","moved")}`);const x=`${T} ${c("changelog.card.instances","instances")} ${g.join(", ")}`;p.push({icon:"🧱",text:x,tooltip:c("changelog.card.instances.tooltip","Instance create, delete, move, or clone changes in this session.")})}n.propertiesChanged>0&&p.push({icon:"🎨",text:`${n.propertiesChanged} ${c("changelog.card.propertiesChanged","properties changed")}`,tooltip:c("changelog.card.propertiesChanged.tooltip","Property value changes recorded for this session.")}),n.lightingChanged&&p.push({icon:"🌅",text:c("changelog.card.lightingConfigured","Lighting configured"),tooltip:c("changelog.card.lightingConfigured.tooltip","Lighting or atmosphere settings changed in this session.")}),n.terrainChanged&&p.push({icon:"⛰️",text:c("changelog.card.terrainConfigured","Terrain configured"),tooltip:c("changelog.card.terrainConfigured.tooltip","Terrain data or terrain settings changed in this session.")}),n.assetsInserted>0&&p.push({icon:"📦",text:`${n.assetsInserted} ${c("changelog.card.assetsInserted","assets inserted")}`,tooltip:c("changelog.card.assetsInserted.tooltip","Assets inserted into the place during this session.")});const C=H(t.startTime),E=s?c("changelog.card.inProgress","in progress"):t.endTime?H(t.endTime):"--:--",f=u?c("changelog.card.bootstrapStatus","Bootstrap"):s?c("changelog.card.active","Active"):c("changelog.card.completed","Completed"),z=u?c("changelog.card.bootstrapStatus.tooltip","This session only contains the initial sync bootstrap snapshot."):s?c("changelog.card.active.tooltip","This session is still receiving new game changes."):c("changelog.card.completed.tooltip","This session has ended and no more changes are expected."),B=u?c("changelog.card.bootstrapSummary","Initial sync snapshot"):c("changelog.card.noChanges","No changes yet"),S=u?c("changelog.card.bootstrapSummary.tooltip","Initial file sync writes are collapsed into a single bootstrap snapshot row."):c("changelog.card.noChanges.tooltip","No game changes have been extracted for this session yet."),I=(k=(v=t.contextSummary)==null?void 0:v.intent)==null?void 0:k.trim(),$=((R=(A=(L=(w=t.contextSummary)==null?void 0:w.affectedAreas)==null?void 0:L[0])==null?void 0:A.label)==null?void 0:R.trim())||((_=(d=t.contextSummary)==null?void 0:d.testScenario)==null?void 0:_.trim()),y=(M=(D=t.verificationSummary)==null?void 0:D.label)==null?void 0:M.trim();return e.jsxs("button",{ref:m,className:h.card,type:"button",onClick:g=>i(g.currentTarget),children:[e.jsxs("span",{className:h.header,children:[e.jsx(O,{text:z,children:e.jsxs("span",{className:`${h.statusBadge} ${s?h.active:h.completed}`,children:[e.jsx("span",{className:h.statusDot}),f]})}),e.jsxs("span",{className:h.timeRange,children:[C,"~",E]})]}),e.jsx("span",{className:h.summaryList,children:p.length>0?p.map((g,x)=>e.jsxs("span",{className:h.summaryItem,children:[e.jsx("span",{className:h.summaryIcon,children:g.icon}),e.jsx(O,{text:g.tooltip,children:e.jsx("span",{className:h.summaryText,children:g.text})})]},x)):e.jsx(O,{text:S,children:e.jsx("span",{className:h.emptySummary,style:{display:"block"},children:B})})}),I&&e.jsxs("span",{className:h.contextBlock,children:[e.jsx("span",{className:h.contextLabel,children:c("changelog.card.sessionIntent","Session intent")}),e.jsx("span",{className:h.contextValue,children:I})]}),!I&&$&&e.jsxs("span",{className:h.contextBlock,children:[e.jsx("span",{className:h.contextLabel,children:c("changelog.card.representativeArea","Representative area")}),e.jsx("span",{className:h.contextValue,children:$})]}),y&&e.jsxs("span",{className:h.contextBlock,children:[e.jsx("span",{className:h.contextLabel,children:c("changelog.card.verification","Verification")}),e.jsx("span",{className:h.contextValue,children:y})]}),s&&e.jsx("span",{className:h.progressBar,children:e.jsx("span",{className:h.progressFill})})]})}function ze(t){const i={scriptsModified:0,scriptsCreated:0,instancesCreated:0,instancesDeleted:0,instancesMoved:0,propertiesChanged:0,lightingChanged:!1,terrainChanged:!1,assetsInserted:0};for(const m of t)switch(m.category){case"script":m.changeType==="create"?i.scriptsCreated++:i.scriptsModified++;break;case"instance":m.changeType==="create"?i.instancesCreated++:m.changeType==="delete"?i.instancesDeleted++:m.changeType==="move"&&i.instancesMoved++;break;case"property":i.propertiesChanged++;break;case"lighting":i.lightingChanged=!0;break;case"terrain":i.terrainChanged=!0;break;case"asset":i.assetsInserted++;break}return i}function Ee(t){if(typeof t=="number")return{placeId:String(t)}}function Le(t,i){const[m,c]=o.useState(""),[n,s]=o.useState(""),[u,p]=o.useState(),[r,T]=o.useState("completed"),[C,E]=o.useState([]),[f,z]=o.useState([]),[B,S]=o.useState([]),[I,$]=o.useState(),[y,v]=o.useState(),[k,w]=o.useState(),[L,A]=o.useState({scriptsModified:0,scriptsCreated:0,instancesCreated:0,instancesDeleted:0,instancesMoved:0,propertiesChanged:0,lightingChanged:!1,terrainChanged:!1,assetsInserted:0}),[R,d]=o.useState(!0),[_,D]=o.useState(null),M=o.useCallback(async()=>{if(t){d(!0),D(null);try{const g=Ee(i),[x,G]=await Promise.all([g?P.get(`/api/dashboard/changelog/${t}`,g):P.get(`/api/dashboard/changelog/${t}`),g?P.get(`/api/dashboard/changelog/${t}/changes`,g):P.get(`/api/dashboard/changelog/${t}/changes`)]);c(x.entryId),s(x.startTime),p(x.endTime),T(x.status),E(x.entries),z(x.failures),$(x.contextSummary),v(x.replayMetadata),w(x.verificationSummary),S(G.changes),A(ze(G.changes))}catch(g){D(g instanceof Error?g.message:"Failed to load changelog detail")}finally{d(!1)}}},[t,i]);return o.useEffect(()=>{M()},[M]),{entryId:m,startTime:n,endTime:u,status:r,entries:C,failures:f,changes:B,changeSummary:L,contextSummary:I,replayMetadata:y,verificationSummary:k,loading:R,error:_,refresh:M}}const Ae={script:"📝",instance:"🧱",property:"🎨",lighting:"🌅",terrain:"⛰️",asset:"📦"};function Re(t){return Ae[t]??"❓"}const Me="_dialogContent_197zf_2",Oe="_dialogHeader_197zf_10",De="_dialogTitleGroup_197zf_20",Fe="_dialogTitle_197zf_20",Pe="_dialogMeta_197zf_36",Ge="_dialogClose_197zf_43",Ke="_dialogBody_197zf_68",Ve="_page_197zf_77",qe="_headerTime_197zf_84",Ue="_dialogActions_197zf_90",He="_retryButton_197zf_96",Ze="_statusActive_197zf_129",Qe="_statusCompleted_197zf_134",We="_section_197zf_139",Xe="_sectionTitle_197zf_146",Ye="_summaryGrid_197zf_159",Je="_summaryCard_197zf_165",et="_summaryCardActive_197zf_188",tt="_summaryIcon_197zf_193",at="_summaryCount_197zf_199",nt="_summaryLabel_197zf_207",st="_contextGrid_197zf_217",it="_contextRow_197zf_223",ct="_contextKey_197zf_229",ot="_contextValue_197zf_237",rt="_timelineFilter_197zf_245",lt="_filterLabel_197zf_253",dt="_filterSelect_197zf_259",gt="_ownershipToggle_197zf_269",mt="_timeline_197zf_245",ht="_timelineEntry_197zf_297",ut="_timelineTime_197zf_326",pt="_timelineIcon_197zf_334",ft="_timelineBody_197zf_339",yt="_timelineSummary_197zf_345",xt="_timelineTarget_197zf_353",_t="_timelineConfidence_197zf_361",bt="_ownershipBadge_197zf_370",Ct="_confidenceExact_197zf_378",St="_confidencePartial_197zf_383",vt="_confidenceAfterOnly_197zf_388",jt="_confidenceIntentOnly_197zf_393",Nt="_confidenceUnknown_197zf_398",Tt="_timelineExpanded_197zf_404",It="_empty_197zf_413",kt="_loading_197zf_422",wt="_error_197zf_431",a={dialogContent:Me,dialogHeader:Oe,dialogTitleGroup:De,dialogTitle:Fe,dialogMeta:Pe,dialogClose:Ge,dialogBody:Ke,page:Ve,headerTime:qe,dialogActions:Ue,retryButton:He,statusActive:Ze,statusCompleted:Qe,section:We,sectionTitle:Xe,summaryGrid:Ye,summaryCard:Je,summaryCardActive:et,summaryIcon:tt,summaryCount:at,summaryLabel:nt,contextGrid:st,contextRow:it,contextKey:ct,contextValue:ot,timelineFilter:rt,filterLabel:lt,filterSelect:dt,ownershipToggle:gt,timeline:mt,timelineEntry:ht,timelineTime:ut,timelineIcon:pt,timelineBody:ft,timelineSummary:yt,timelineTarget:xt,timelineConfidence:_t,ownershipBadge:bt,confidenceExact:Ct,confidencePartial:St,confidenceAfterOnly:vt,confidenceIntentOnly:jt,confidenceUnknown:Nt,timelineExpanded:Tt,empty:It,loading:kt,error:wt},Z=[{key:"script",icon:"📝",labelKey:"changelog.category.script"},{key:"instance",icon:"🧱",labelKey:"changelog.category.instance"},{key:"property",icon:"🎨",labelKey:"changelog.category.property"},{key:"lighting",icon:"🌅",labelKey:"changelog.category.lighting"},{key:"terrain",icon:"⛰️",labelKey:"changelog.category.terrain"},{key:"asset",icon:"📦",labelKey:"changelog.category.asset"}];function V(t){if(!t)return"--:--";const i=new Date(t);return`${String(i.getHours()).padStart(2,"0")}:${String(i.getMinutes()).padStart(2,"0")}`}function $t(t){if(!t)return"--:--:--";const i=new Date(t);return`${String(i.getHours()).padStart(2,"0")}:${String(i.getMinutes()).padStart(2,"0")}:${String(i.getSeconds()).padStart(2,"0")}`}function Bt(t,i){if(!t||!i)return"";const m=new Date(i).getTime()-new Date(t).getTime();return m<0?"":`${Math.round(m/6e4)}min`}function zt(t){switch(t){case"exact":return a.confidenceExact;case"partial":return a.confidencePartial;case"after-only":return a.confidenceAfterOnly;case"intent-only":return a.confidenceIntentOnly;default:return a.confidenceUnknown}}function Et(t,i){switch(i){case"exact":return t("changelog.detail.confidence.exact","Exact");case"partial":return t("changelog.detail.confidence.partial","Partial");case"after-only":return t("changelog.detail.confidence.afterOnly","After only");case"intent-only":return t("changelog.detail.confidence.intentOnly","Intent only");default:return t("changelog.detail.confidence.unknown","Unknown")}}function Lt(t,i){switch(i){case"exact":return t("changelog.detail.confidence.exact.tooltip","Both the before and after state were confirmed for this change.");case"partial":return t("changelog.detail.confidence.partial.tooltip","Only part of the before and after state could be confirmed for this change.");case"after-only":return t("changelog.detail.confidence.afterOnly.tooltip","Only the resulting state after the change could be confirmed.");case"intent-only":return t("changelog.detail.confidence.intentOnly.tooltip","Only the requested action was recorded, not the resulting state.");default:return t("changelog.detail.confidence.unknown.tooltip","This change could not be confidently classified from the available data.")}}function At(t,i){switch(i){case"user_source":return t("changelog.ownership.userSource","User source");case"canonical_mirror":return t("changelog.ownership.canonicalMirror","Mirror metadata");case"generated":return t("changelog.ownership.generated","Generated");default:return null}}function Rt({entryId:t,placeId:i,onClose:m,returnFocusTo:c=null}){var v,k,w,L,A,R,d,_,D,M,g,x,G,U;const{t:n}=q(),s=Le(t,i),[u,p]=o.useState("all"),[r,T]=o.useState(!0),[C,E]=o.useState(null),f=o.useMemo(()=>{const l=r?s.changes:s.changes.filter(b=>b.artifactOwnership!=="generated");return[...u==="all"?l:l.filter(b=>b.category===u)].reverse()},[s.changes,u,r]),z=s.changes.some(l=>l.artifactOwnership==="generated"),B=Bt(s.startTime,s.endTime),S=s.endTime?`${V(s.startTime)} → ${V(s.endTime)} (${B})`:`${V(s.startTime)} → ${n("changelog.card.inProgress","in progress")}`,I=!!((v=s.contextSummary)!=null&&v.intent||(k=s.contextSummary)!=null&&k.testScenario||(w=s.contextSummary)!=null&&w.expectedBehavior||(L=s.contextSummary)!=null&&L.observedBehavior),$=!!((A=s.verificationSummary)!=null&&A.label||(R=s.verificationSummary)!=null&&R.status||(d=s.verificationSummary)!=null&&d.testTimestamp),y=n("changelog.detail.dialogLabel","Changelog detail");return e.jsx(ce,{open:!0,ariaLabel:y,onClose:m,returnFocusTo:c,testId:"changelog-detail-backdrop",children:e.jsxs("div",{className:a.dialogContent,children:[e.jsxs("div",{className:a.dialogHeader,children:[e.jsxs("div",{className:a.dialogTitleGroup,children:[e.jsx("h2",{className:a.dialogTitle,children:y}),!s.loading&&!s.error&&e.jsxs("div",{className:a.dialogMeta,children:[e.jsx("span",{className:a.headerTime,children:S}),e.jsx(O,{text:s.status==="active"?n("changelog.card.active.tooltip","This session is still receiving new game changes."):n("changelog.card.completed.tooltip","This session has ended and no more changes are expected."),children:e.jsx("span",{className:s.status==="active"?a.statusActive:a.statusCompleted,children:s.status==="active"?n("changelog.card.active","Active"):n("changelog.card.completed","Completed")})})]})]}),e.jsx("button",{className:a.dialogClose,type:"button","aria-label":n("common.close","Close"),onClick:m,children:e.jsx(W,{size:18,"aria-hidden":"true"})})]}),e.jsxs("div",{className:a.dialogBody,children:[s.loading&&e.jsx("div",{className:a.loading,children:n("common.loading","Loading...")}),s.error&&e.jsxs("div",{className:a.error,children:[e.jsx("span",{children:s.error}),e.jsxs("div",{className:a.dialogActions,children:[e.jsx("button",{className:a.retryButton,type:"button",onClick:s.refresh,children:n("common.retry","Retry")}),e.jsx("button",{className:a.retryButton,type:"button",onClick:m,children:n("common.close","Close")})]})]}),!s.loading&&!s.error&&e.jsxs("div",{className:a.page,children:[e.jsxs("div",{className:a.section,children:[e.jsx("div",{className:a.sectionTitle,children:e.jsx(O,{text:n("changelog.detail.changeSummary.tooltip","Counts of extracted game changes grouped by category for this session."),children:e.jsx("span",{children:n("changelog.detail.changeSummary","Change Summary")})})}),e.jsx("div",{className:a.summaryGrid,children:Z.map(l=>{const j=s.changeSummary;let b;switch(l.key){case"script":b=j.scriptsModified+j.scriptsCreated;break;case"instance":b=j.instancesCreated+j.instancesDeleted+j.instancesMoved;break;case"property":b=j.propertiesChanged;break;case"lighting":b=j.lightingChanged?1:0;break;case"terrain":b=j.terrainChanged?1:0;break;case"asset":b=j.assetsInserted;break;default:b=0}const F=u===l.key;return e.jsxs("button",{type:"button",className:`${a.summaryCard} ${F?a.summaryCardActive:""}`,"aria-label":`${n(l.labelKey,l.key)}: ${b}`,"aria-pressed":F,onClick:()=>p(F?"all":l.key),children:[e.jsx("span",{className:a.summaryIcon,children:l.icon}),e.jsx("span",{className:a.summaryCount,children:b}),e.jsx("span",{className:a.summaryLabel,children:n(l.labelKey,l.key)})]},l.key)})})]}),I&&e.jsxs("div",{className:a.section,children:[e.jsx("div",{className:a.sectionTitle,children:e.jsx(O,{text:n("changelog.detail.context.tooltip","Structured execution context captured for this changelog session."),children:e.jsx("span",{children:n("changelog.detail.context.title","Context Summary")})})}),e.jsxs("div",{className:a.contextGrid,children:[((_=s.contextSummary)==null?void 0:_.intent)&&e.jsxs("div",{className:a.contextRow,children:[e.jsx("span",{className:a.contextKey,children:n("changelog.card.sessionIntent","Session intent")}),e.jsx("span",{className:a.contextValue,children:s.contextSummary.intent})]}),((D=s.contextSummary)==null?void 0:D.testScenario)&&e.jsxs("div",{className:a.contextRow,children:[e.jsx("span",{className:a.contextKey,children:n("playtest.context.why","Why this test ran")}),e.jsx("span",{className:a.contextValue,children:s.contextSummary.testScenario})]}),((M=s.contextSummary)==null?void 0:M.expectedBehavior)&&e.jsxs("div",{className:a.contextRow,children:[e.jsx("span",{className:a.contextKey,children:n("playtest.context.expected","Expected")}),e.jsx("span",{className:a.contextValue,children:s.contextSummary.expectedBehavior})]}),((g=s.contextSummary)==null?void 0:g.observedBehavior)&&e.jsxs("div",{className:a.contextRow,children:[e.jsx("span",{className:a.contextKey,children:n("playtest.context.observed","Observed")}),e.jsx("span",{className:a.contextValue,children:s.contextSummary.observedBehavior})]})]})]}),$&&e.jsxs("div",{className:a.section,children:[e.jsx("div",{className:a.sectionTitle,children:e.jsx(O,{text:n("changelog.detail.verification.tooltip","Verification signals linked to this changelog session."),children:e.jsx("span",{children:n("changelog.detail.verification.title","Verification")})})}),e.jsxs("div",{className:a.contextGrid,children:[((x=s.verificationSummary)==null?void 0:x.label)&&e.jsxs("div",{className:a.contextRow,children:[e.jsx("span",{className:a.contextKey,children:n("changelog.detail.verification.label","Result")}),e.jsx("span",{className:a.contextValue,children:s.verificationSummary.label})]}),((G=s.verificationSummary)==null?void 0:G.status)&&e.jsxs("div",{className:a.contextRow,children:[e.jsx("span",{className:a.contextKey,children:n("changelog.detail.verification.status","Status")}),e.jsx("span",{className:a.contextValue,children:s.verificationSummary.status})]}),((U=s.verificationSummary)==null?void 0:U.testTimestamp)&&e.jsxs("div",{className:a.contextRow,children:[e.jsx("span",{className:a.contextKey,children:n("changelog.detail.verification.timestamp","Recorded at")}),e.jsx("span",{className:a.contextValue,children:s.verificationSummary.testTimestamp})]})]})]}),e.jsxs("div",{className:a.section,children:[e.jsx("div",{className:a.sectionTitle,children:e.jsx(O,{text:n("changelog.detail.changeTimeline.tooltip","Chronological list of extracted game changes for this session."),children:e.jsx("span",{children:n("changelog.detail.changeTimeline","Change Timeline")})})}),e.jsxs("div",{className:a.timelineFilter,children:[e.jsx("span",{className:a.filterLabel,children:e.jsx(le,{label:`${n("changelog.detail.filterCategory","Category")}:`,tooltip:n("changelog.detail.filterCategory.tooltip","Filter the timeline to a single change category.")})}),e.jsxs("select",{className:a.filterSelect,value:u,onChange:l=>p(l.target.value),children:[e.jsx("option",{value:"all",children:n("tools.filter.all","All")}),Z.map(l=>e.jsxs("option",{value:l.key,children:[l.icon," ",n(l.labelKey,l.key)]},l.key))]}),z&&e.jsxs("label",{className:a.ownershipToggle,children:[e.jsx("input",{type:"checkbox",checked:r,onChange:l=>T(l.target.checked)}),n("changelog.ownership.showGenerated","Show generated metadata")]})]}),f.length===0?e.jsx("div",{className:a.empty,children:n("changelog.detail.noChanges","No changes in this category")}):e.jsx("div",{className:a.timeline,children:f.map((l,j)=>{const b=C===j,F=At(n,l.artifactOwnership);return e.jsxs("div",{children:[e.jsxs("button",{type:"button",className:a.timelineEntry,"aria-expanded":b,onClick:()=>E(b?null:j),children:[e.jsx("span",{className:a.timelineTime,children:$t(l.timestamp)}),e.jsx("span",{className:a.timelineIcon,children:Re(l.category)}),e.jsxs("span",{className:a.timelineBody,children:[e.jsxs("span",{className:a.timelineSummary,children:[l.summary,F&&e.jsx(ne,{variant:l.artifactOwnership==="generated"?"neutral":"accent",className:a.ownershipBadge,children:F}),e.jsx(O,{text:Lt(n,l.confidence),children:e.jsx("span",{className:`${a.timelineConfidence} ${zt(l.confidence)}`,children:Et(n,l.confidence)})})]}),e.jsx("span",{className:a.timelineTarget,children:l.target})]})]}),b&&e.jsx("div",{className:a.timelineExpanded,children:e.jsx(de,{change:l})})]},j)})})]})]})]})]})})}const Mt="_page_1tggr_2",Ot="_limitNotice_1tggr_9",Dt="_limitNoticeContent_1tggr_23",Ft="_limitNoticeTitle_1tggr_28",Pt="_limitNoticeText_1tggr_35",Gt="_primaryAction_1tggr_41",Kt="_clearButton_1tggr_67",Vt="_list_1tggr_88",qt="_empty_1tggr_95",Ut="_loading_1tggr_104",Ht="_pagination_1tggr_113",Zt="_pageInfo_1tggr_121",Qt="_btn_1tggr_127",N={page:Mt,limitNotice:Ot,limitNoticeContent:Dt,limitNoticeTitle:Ft,limitNoticeText:Pt,primaryAction:Gt,clearButton:Kt,list:Vt,empty:qt,loading:Ut,pagination:Ht,pageInfo:Zt,btn:Qt},K=10;function Wt(t,i){return typeof i!="number"?`/changelog/${t}`:`/changelog/${t}?placeId=${encodeURIComponent(String(i))}`}function Xt(t){const i=/^\/changelog\/([^/]+)$/.exec(t);if(!i)return null;try{return decodeURIComponent(i[1])}catch{return i[1]}}function Yt(t){const i=new URLSearchParams(t).get("placeId");if(!i)return null;const m=Number.parseInt(i,10);return Number.isInteger(m)&&m>=0?m:null}const Jt=[{key:"all",labelKey:"changelog.filter.all"},{key:"active",labelKey:"changelog.filter.active"},{key:"completed",labelKey:"changelog.filter.completed"}];function la(){const{t}=q(),{trackEvent:i,trackPageView:m}=X(),c=Y(),n=J(),s=Xt(n.pathname),[u,p]=o.useState(()=>Yt(n.search)),r=he({placeId:u}),T=ee(),{show:C}=te(),[E,f]=o.useState(!1),[z,B]=o.useState(!1),[S,I]=o.useState(null),$=o.useRef(null),y=s??S,v=!T.loading&&T.tier==="basic",k=v?r.entries.slice(0,3):r.entries,w=!v&&r.total>K;o.useEffect(()=>{s&&s===S&&I(null)},[S,s]);const L=async()=>{B(!0);try{await r.clear(),C(t("toast.clearSuccess","Cleared successfully"),"success"),f(!1)}catch{C(t("toast.clearFailed","Failed to clear data"),"error")}finally{B(!1)}},A=(d,_)=>{$.current=_,I(d),c(Wt(d,u))},R=()=>{I(null),c("/changelog",{replace:!0})};return e.jsxs("div",{className:N.page,children:[e.jsx(se,{title:t("page.changelog.title","Changelog"),description:t("page.changelog.description","Review game-change sessions captured from AI actions and sync events."),helpTopicId:"changelog",helpState:{tier:T.tier}}),e.jsx(oe,{surface:"changelog",selectable:!0,selectedPlaceId:u,onSelectedPlaceIdChange:d=>{p(d),r.setOffset(0)}}),e.jsx(re,{items:Jt.map(d=>({key:d.key,label:t(d.labelKey,d.key.charAt(0).toUpperCase()+d.key.slice(1))})),value:r.statusFilter,onChange:d=>{const _=`changelog_${d}`;i("dashboard_click_event",{click_target:`changelog_tab_${d}`,page:"changelog",tab:_}),m({page:"changelog",tab:_}),r.setStatusFilter(d),r.setOffset(0)},rightActions:e.jsx("button",{className:N.clearButton,onClick:()=>{i("dashboard_click_event",{click_target:"changelog_clear",page:"changelog",tab:`changelog_${r.statusFilter}`}),f(!0)},children:t("common.clear","Clear")})}),r.loading&&r.entries.length===0&&e.jsx("div",{className:N.loading,children:t("common.loading","Loading...")}),!r.loading&&r.entries.length===0?e.jsx("div",{className:N.empty,children:t("changelog.empty","No changelog entries for the current place yet")}):e.jsx("div",{className:N.list,children:k.map(d=>e.jsx(Be,{entry:d,onClick:_=>A(d.entryId,_),buttonRef:_=>{d.entryId===y&&_&&($.current=_)}},d.entryId))}),w&&e.jsxs("div",{className:N.pagination,children:[e.jsx("button",{className:N.btn,disabled:r.offset===0,onClick:()=>r.setOffset(Math.max(0,r.offset-K)),children:t("tools.page.prev","Prev")}),e.jsxs("span",{className:N.pageInfo,children:[r.offset+1,"–",Math.min(r.offset+K,r.total)," / ",r.total]}),e.jsx("button",{className:N.btn,disabled:!r.hasMore,onClick:()=>r.setOffset(r.offset+K),children:t("tools.page.next","Next")})]}),v&&e.jsx(e.Fragment,{children:e.jsxs("div",{className:N.limitNotice,children:[e.jsxs("div",{className:N.limitNoticeContent,children:[e.jsx("div",{className:N.limitNoticeTitle,children:t("changelog.basic.limit.title","Basic preview shows the latest 3 sessions")}),e.jsx("div",{className:N.limitNoticeText,children:t("changelog.basic.limit.body","Full changelog timeline browsing is available with Pro.")})]}),e.jsx("a",{className:N.primaryAction,href:ae.changelog,target:"_blank",rel:"noreferrer",onClick:()=>i("dashboard_click_event",{click_target:"upgrade_cta",placement:"changelog_limit_notice",page:"changelog",tab:`changelog_${r.statusFilter}`}),children:t("tier.upgrade","View Pro")})]})}),e.jsx(ie,{open:E,title:t("changelog.clear.title","Clear changelog?"),message:t("changelog.clear.message","This permanently removes the stored changelog for the current place."),cancelLabel:t("common.cancel","Cancel"),confirmLabel:t("common.clear","Clear"),loading:z,onCancel:()=>!z&&f(!1),onConfirm:L}),y&&e.jsx(Rt,{entryId:y,placeId:u,onClose:R,returnFocusTo:$.current})]})}export{la as Component};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as t,j as s}from"./index-
|
|
1
|
+
import{r as t,j as s}from"./index-uP4eoQi-.js";import{s as r}from"./ConfirmModal.module-DJksQHBd.js";function D({open:a,title:y,message:E,cancelLabel:R,confirmLabel:j,loading:n=!1,onCancel:c,onConfirm:k}){const i=t.useId(),o=t.useRef(null),f=t.useRef(null),d=t.useRef(null),m=t.useRef(c),h=t.useRef(n);return m.current=c,h.current=n,t.useEffect(()=>{var b;if(!a)return;d.current=document.activeElement instanceof HTMLElement?document.activeElement:null,(b=f.current)==null||b.focus();const l=e=>{if(e.key==="Escape"){e.preventDefault(),h.current||m.current();return}if(e.key!=="Tab"||!o.current)return;const u=Array.from(o.current.querySelectorAll("button:not([disabled])"));if(u.length===0){e.preventDefault(),o.current.focus();return}const p=u[0],x=u[u.length-1];e.shiftKey&&document.activeElement===p?(e.preventDefault(),x.focus()):!e.shiftKey&&document.activeElement===x&&(e.preventDefault(),p.focus())};return document.addEventListener("keydown",l),()=>{document.removeEventListener("keydown",l);const e=d.current;e&&document.contains(e)&&e.focus()}},[a]),a?s.jsx("div",{className:r.backdrop,onClick:n?void 0:c,children:s.jsxs("div",{ref:o,className:r.modal,role:"dialog","aria-modal":"true","aria-labelledby":i,tabIndex:-1,onClick:l=>l.stopPropagation(),children:[s.jsx("h2",{id:i,className:r.title,children:y}),s.jsx("p",{className:r.message,children:E}),s.jsxs("div",{className:r.actions,children:[s.jsx("button",{ref:f,className:r.cancelButton,onClick:c,disabled:n,children:R}),s.jsx("button",{className:r.confirmButton,onClick:k,disabled:n,children:n?"...":j})]})]})}):null}export{D as C};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
._container_1h084_2{max-height:200px;overflow-y:auto;font-family:var(--font-code);font-size:12px;line-height:1.6;padding:8px 12px;background:var(--bg-secondary);border-radius:4px}._entry_1h084_14{display:flex;gap:8px;white-space:nowrap}._timestamp_1h084_21{color:var(--text-muted);flex-shrink:0}._message_1h084_27{color:var(--text-primary);overflow:hidden;text-overflow:ellipsis}._warn_1h084_34 ._message_1h084_27{color:var(--warning)}._error_1h084_39 ._message_1h084_27{color:var(--error)}._empty_1h084_44{color:var(--text-muted);font-style:italic;padding:8px 0}._page_6dxry_2{display:flex;flex-direction:column;gap:var(--space-page);width:100%;max-width:1180px}._card_6dxry_11{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:var(--card-padding-block) var(--card-padding-inline)}._topologyCard_6dxry_19{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:18px 20px 20px}._topologyDisconnected_6dxry_26{border-color:var(--error-border)}._topologyHeader_6dxry_30{display:flex;justify-content:space-between;gap:16px;align-items:flex-start;margin-bottom:18px}._topologyIntro_6dxry_38{margin:-6px 0 0;color:var(--text-secondary);font-size:13px;line-height:1.5}._topologyNetwork_6dxry_45{position:relative}._topologyLinks_6dxry_49{position:absolute;top:0;right:0;bottom:0;left:0;z-index:0;width:100%;height:100%;pointer-events:none;overflow:visible}._topologyLink_6dxry_49{stroke:color-mix(in srgb,var(--accent) 62%,var(--border));stroke-linecap:round;stroke-width:1.5;opacity:.82}._topologyLink_agent_6dxry_66{stroke:color-mix(in srgb,var(--accent) 58%,var(--border))}._topologyLink_studio_6dxry_70{stroke:color-mix(in srgb,var(--accent) 66%,var(--border))}._topologyGrid_6dxry_74{position:relative;z-index:1;display:grid;grid-template-columns:minmax(220px,1fr) minmax(220px,.82fr) minmax(240px,1.18fr);align-items:start;gap:52px}._topologyColumn_6dxry_83{min-width:0;display:flex;flex-direction:column;gap:10px}._topologyColumnHeader_6dxry_90{display:flex;align-items:center;gap:8px;min-height:28px;color:var(--text-primary);font-family:var(--font-label);font-size:12px;font-weight:700}._topologyColumnHeaderSpacer_6dxry_101{min-height:28px}._topologyCount_6dxry_105{display:inline-flex;align-items:center;justify-content:center;min-width:22px;height:20px;padding:0 6px;border-radius:var(--radius-pill);background:var(--bg-secondary);border:1px solid var(--border);color:var(--text-secondary);font-family:var(--font-code);font-size:11px}._topologyList_6dxry_120{display:flex;flex-direction:column;gap:8px;justify-content:flex-start;min-height:178px}._topologyListCentered_6dxry_128{justify-content:center}._topologyNode_6dxry_132{min-width:0;border:1px solid var(--border);border-radius:8px;background:var(--bg-secondary);padding:10px 12px}._topologyNodeTitle_6dxry_140{display:flex;align-items:center;min-width:0;gap:8px;color:var(--text-primary);font-family:var(--font-label);font-size:13px;font-weight:600}._topologyNodeTitle_6dxry_140 strong,._topologyNodeTitle_6dxry_140 span{min-width:0}._topologyNodeMeta_6dxry_156,._topologyNodeSubtle_6dxry_157{margin-top:6px;color:var(--text-secondary);font-family:var(--font-code);font-size:11px;line-height:1.4;overflow-wrap:anywhere}._topologyNodeSubtle_6dxry_157{color:var(--text-muted)}._topologyState_6dxry_170{margin-left:auto;flex:0 0 auto;border:1px solid var(--border);border-radius:var(--radius-pill);padding:2px 7px;background:color-mix(in srgb,var(--bg-card) 76%,transparent);color:var(--text-secondary);font-family:var(--font-label);font-size:10px;font-weight:600}._topologyEmpty_6dxry_183{min-height:82px;display:flex;align-items:center;justify-content:center;border:1px dashed var(--border);border-radius:8px;color:var(--text-muted);background:color-mix(in srgb,var(--bg-secondary) 58%,transparent);padding:12px;text-align:center;font-size:12px;line-height:1.45}._topologyOverflow_6dxry_198{display:flex;align-items:center;justify-content:space-between;gap:10px;min-height:34px;padding:6px 8px 6px 12px;border:1px solid var(--border);border-radius:7px;background:color-mix(in srgb,var(--bg-card) 72%,transparent);color:var(--text-secondary);font-family:var(--font-label);font-size:12px}._topologyOverflowButton_6dxry_213{flex:0 0 auto;border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--bg-secondary);color:var(--text-primary);cursor:pointer;font-family:var(--font-label);font-size:11px;font-weight:600;padding:4px 8px;transition:background var(--transition),border-color var(--transition),color var(--transition)}._topologyOverflowButton_6dxry_213:hover{border-color:var(--border-highlight);background:var(--accent-dim);color:var(--accent)}._topologyServerColumn_6dxry_236{min-width:0;display:flex;flex-direction:column;gap:10px}._topologyServer_6dxry_236{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;min-height:178px;border-color:color-mix(in srgb,var(--accent) 42%,var(--border));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--accent) 16%,transparent)}._topologyServerIcon_6dxry_254{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;border:1px solid var(--border-highlight);border-radius:50%;background:var(--accent-dim);color:var(--accent);margin-bottom:10px}._topologyServerBody_6dxry_267{display:flex;flex-direction:column;align-items:center;gap:8px;min-width:0;width:100%}._topologyServerTitle_6dxry_276{color:var(--text-primary);font-family:var(--font-label);font-size:15px;font-weight:700}._topologyServerMeta_6dxry_283{color:var(--text-secondary);font-family:var(--font-code);font-size:11px;overflow-wrap:anywhere}._routingSummaryCompact_6dxry_290{display:flex;justify-content:center;width:100%;min-width:0}._disabled_6dxry_298{opacity:.4;pointer-events:none}._cardHeader_6dxry_304{font-family:var(--font-label);font-weight:600;font-size:var(--type-card-title-size);text-transform:uppercase;letter-spacing:.05em;color:var(--text-primary);margin-bottom:var(--space-section);display:flex;align-items:center;justify-content:space-between}._restartButton_6dxry_317{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:32px;padding:0 10px;border:1px solid var(--border);border-radius:var(--radius-control);background:var(--bg-secondary);color:var(--text-primary);cursor:pointer;font-family:var(--font-label);font-size:11px;font-weight:600;letter-spacing:0;text-transform:none;transition:background var(--transition),border-color var(--transition),color var(--transition)}._restartButton_6dxry_317:hover:not(:disabled){border-color:var(--border-highlight);background:var(--accent-dim);color:var(--accent)}._restartButton_6dxry_317:focus-visible{outline:none;box-shadow:var(--focus-ring)}._restartButton_6dxry_317:disabled{cursor:not-allowed;opacity:.55}._bridgeActionHint_6dxry_356{margin:calc(var(--space-section) * -.55) 0 12px;color:var(--text-muted);font-size:12px;line-height:1.5}._restartProgress_6dxry_363,._restartFailure_6dxry_364{display:flex;align-items:center;gap:12px;min-height:68px;border:1px solid var(--border-highlight);border-radius:var(--radius-control);padding:12px 14px;background:var(--accent-dim);color:var(--text-primary)}._restartProgress_6dxry_363 strong{font-family:var(--font-label);font-size:13px;font-weight:600}._restartProgress_6dxry_363 p,._restartFailure_6dxry_364 p{margin:4px 0 0;color:var(--text-secondary);font-size:12px;line-height:1.5}._restartFailure_6dxry_364{justify-content:space-between;border-color:var(--error-border);background:var(--error-bg)}._restartFailure_6dxry_364 p{margin:0;color:var(--error-text)}._restartIconSpinning_6dxry_401{animation:_restart-spin_6dxry_1 .9s linear infinite}@keyframes _restart-spin_6dxry_1{to{transform:rotate(360deg)}}@media(prefers-reduced-motion:reduce){._restartIconSpinning_6dxry_401{animation:none}}._cardHint_6dxry_417{margin:-4px 0 12px;color:var(--text-muted);font-size:12px;line-height:1.5}._clearButton_6dxry_424{border:1px solid var(--danger-border);background:var(--danger-bg);color:var(--danger-text);border-radius:var(--radius-control);padding:6px 12px;font-family:var(--font-label);font-size:12px;font-weight:600;cursor:pointer;transition:background var(--transition),border-color var(--transition),color var(--transition)}._clearButton_6dxry_424:hover{background:var(--danger-hover-bg);border-color:var(--danger)}._clearButton_6dxry_424:focus-visible{outline:none;box-shadow:var(--focus-ring)}._serverGrid_6dxry_448{display:grid;grid-template-columns:auto 1fr;gap:4px 16px;font-family:var(--font-code);font-size:13px}._serverGrid_6dxry_448 dt{color:var(--text-muted)}._serverGrid_6dxry_448 dd{color:var(--text-primary);margin:0}._statusRow_6dxry_466{display:flex;align-items:center;gap:16px;margin-bottom:12px}._metaItem_6dxry_473{font-family:var(--font-code);font-size:12px;color:var(--text-secondary)}._table_6dxry_480{width:100%;border-collapse:collapse;font-family:var(--font-code);font-size:12px}._table_6dxry_480 th{text-align:left;color:var(--text-muted);font-weight:400;padding:4px 8px 4px 0;border-bottom:1px solid var(--border)}._table_6dxry_480 td{padding:6px 8px 6px 0;color:var(--text-primary)}._tableWrap_6dxry_500{overflow-x:auto}._table_6dxry_480 tr:hover td{background:var(--accent-dim)}._routingSummary_6dxry_290{display:inline-flex;align-items:center;gap:10px;margin-bottom:12px;flex-wrap:wrap}._manageLink_6dxry_516{display:inline-flex;align-items:center;height:24px;padding:0 8px;border:1px solid var(--border);border-radius:var(--radius-control);background:var(--bg-secondary);color:var(--text-primary);font-family:var(--font-label);font-size:11px;font-weight:600;text-decoration:none;transition:border-color var(--transition),background var(--transition),color var(--transition)}._manageLink_6dxry_516:hover{border-color:var(--border-highlight);background:var(--accent-dim);color:var(--accent);text-decoration:none}._segment_6dxry_542,._segmentActive_6dxry_543{height:28px;padding:0 10px;border:none;border-right:1px solid var(--border);background:transparent;color:var(--text-secondary);font-family:var(--font-label);font-size:12px;cursor:pointer}._segment_6dxry_542:last-child,._segmentActive_6dxry_543:last-child{border-right:none}._segment_6dxry_542:hover:not(:disabled){background:var(--accent-dim);color:var(--accent)}._segmentActive_6dxry_543{background:var(--accent-dim);color:var(--text-primary);font-weight:600}._segment_6dxry_542:disabled,._segmentActive_6dxry_543:disabled{cursor:default;opacity:.55}._targetPrimary_6dxry_577{white-space:nowrap}._monoMuted_6dxry_581{color:var(--text-secondary)}._copyIconButton_6dxry_585{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;margin-left:6px;border:1px solid var(--border);border-radius:var(--radius-control);background:var(--bg-secondary);color:var(--text-secondary);cursor:pointer;vertical-align:middle;transition:border-color var(--transition),background var(--transition),color var(--transition)}._copyIconButton_6dxry_585:hover{color:var(--accent);border-color:var(--border-highlight);background:var(--accent-dim)}._routingBadge_6dxry_610{display:inline-flex;align-items:center;min-height:22px;padding:0 8px;border:1px solid var(--border-highlight);border-radius:var(--radius-control);background:var(--accent-dim);color:var(--text-primary);font-family:var(--font-label);font-size:11px;font-weight:600}._studioStateBadge_6dxry_624{display:inline-flex;align-items:center;min-height:22px;padding:0 8px;border:1px solid var(--border);border-radius:var(--radius-control);background:var(--bg-secondary);color:var(--text-secondary);font-family:var(--font-label);font-size:11px;font-weight:600;white-space:nowrap}._studioState_running_6dxry_639{border-color:color-mix(in srgb,var(--success) 42%,var(--border));background:color-mix(in srgb,var(--success) 12%,var(--bg-secondary));color:var(--success)}._studioState_paused_6dxry_645{border-color:color-mix(in srgb,var(--warning) 42%,var(--border));background:color-mix(in srgb,var(--warning) 12%,var(--bg-secondary));color:var(--warning)}._studioState_edit_6dxry_651{border-color:var(--border-highlight);background:color-mix(in srgb,var(--accent) 9%,var(--bg-secondary));color:var(--text-primary)}._studioState_unknown_6dxry_657{border-color:var(--border);background:var(--bg-secondary);color:var(--text-muted)}._toggleBtn_6dxry_664{background:none;border:none;color:var(--text-secondary);cursor:pointer;font-size:12px;padding:0 4px;transition:color var(--transition)}._toggleBtn_6dxry_664:hover{color:var(--accent)}._disconnected_6dxry_679{text-align:center;padding:32px 16px}._disconnected_6dxry_679 h3{color:var(--error);font-size:16px;margin:0 0 8px}._disconnected_6dxry_679 p{color:var(--text-secondary);font-size:13px;margin:0 0 4px}._disconnectedActions_6dxry_696{display:flex;gap:8px;justify-content:center;margin-top:16px}._btn_6dxry_703{font-family:var(--font-label);font-size:12px;padding:6px 14px;border-radius:var(--radius-control);border:1px solid var(--border);background:var(--bg-secondary);color:var(--text-primary);cursor:pointer;transition:background var(--transition),border-color var(--transition)}._btn_6dxry_703:hover{border-color:var(--accent);background:var(--accent-dim)}._activity_active_6dxry_721,._activity_stale_6dxry_722,._activity_unknown_6dxry_723{display:inline-block;width:7px;height:7px;border-radius:50%;margin-right:6px;vertical-align:middle}._activity_active_6dxry_721{background:var(--success);box-shadow:0 0 4px var(--success)}._activity_stale_6dxry_722{background:var(--text-muted)}._activity_unknown_6dxry_723{background:var(--text-muted);opacity:.4}._killBtn_6dxry_747{font-family:var(--font-label);font-size:11px;padding:3px 10px;border-radius:var(--radius-control);border:1px solid var(--danger-border);background:var(--danger-bg);color:var(--danger-text);cursor:pointer;transition:background var(--transition),border-color var(--transition)}._killBtn_6dxry_747:hover{background:var(--danger-hover-bg);border-color:var(--danger);color:var(--danger-text)}._killBtn_6dxry_747:focus-visible{outline:none;box-shadow:var(--focus-ring)}._emptyRow_6dxry_771{color:var(--text-muted);font-style:italic}@media(max-width:980px){._topologyHeader_6dxry_30{flex-direction:column;align-items:stretch}._topologyGrid_6dxry_74{grid-template-columns:1fr;gap:10px}._topologyColumnHeaderSpacer_6dxry_101{display:none}._topologyServer_6dxry_236{min-height:150px}}@media(max-width:640px){._card_6dxry_11,._topologyCard_6dxry_19{padding:14px}._topologyNodeTitle_6dxry_140{flex-wrap:wrap}._topologyState_6dxry_170{margin-left:0}}
|