@weppy/roblox-mcp 2.8.1 → 2.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +46 -14
  3. package/dashboard/dist/assets/AssetsPage-Be5aZDhj.css +1 -0
  4. package/dashboard/dist/assets/AssetsPage-Bg2-L4ZA.js +46 -0
  5. package/dashboard/dist/assets/ChangelogDetailPage-BfKpoGXf.js +1 -0
  6. package/dashboard/dist/assets/ChangelogPage-CJgsI7aS.js +1 -0
  7. package/dashboard/dist/assets/ConfirmModal-C9EhZCHZ.js +1 -0
  8. package/dashboard/dist/assets/ConfirmModal-D1kfK31C.css +1 -0
  9. package/dashboard/dist/assets/ConfirmModal.module-NrFlfTWy.js +1 -0
  10. package/dashboard/dist/assets/ConnectionPage-D1GWlHZP.css +1 -0
  11. package/dashboard/dist/assets/ConnectionPage-DGUYptQR.js +11 -0
  12. package/dashboard/dist/assets/ControlsPage-rqArYVq2.js +1 -0
  13. package/dashboard/dist/assets/CurrentPlaceScope-BMyP2w7Z.js +1 -0
  14. package/dashboard/dist/assets/CurrentPlaceScope-v3pl1mLI.css +1 -0
  15. package/dashboard/dist/assets/{GameChangeDetail-CghOvUm8.js → GameChangeDetail-DKAKmyGF.js} +1 -1
  16. package/dashboard/dist/assets/{InfoLabel-Cyz7d4Kc.js → InfoLabel-ZfsTcz5c.js} +1 -1
  17. package/dashboard/dist/assets/{OverviewPage-B6ZL_JXU.js → OverviewPage-C9OL33DV.js} +1 -1
  18. package/dashboard/dist/assets/PageHeader-Cqg4GMtU.js +6 -0
  19. package/dashboard/dist/assets/PlaytestPage-CczAQ-A8.js +11 -0
  20. package/dashboard/dist/assets/SettingsPage-DNp4oJDT.js +1 -0
  21. package/dashboard/dist/assets/SettingsPage-DSipzuEo.css +1 -0
  22. package/dashboard/dist/assets/{StatusBadge-CkLieULy.js → StatusBadge-BSFzbkXM.js} +1 -1
  23. package/dashboard/dist/assets/SyncPage-DzOONMOM.js +4 -0
  24. package/dashboard/dist/assets/{Tabs-BhkhdCvF.js → Tabs-B8mbzhmZ.js} +1 -1
  25. package/dashboard/dist/assets/ToolsPage-DFh7yyab.js +1 -0
  26. package/dashboard/dist/assets/TooltipText-ZamrETeK.js +1 -0
  27. package/dashboard/dist/assets/UiStudioPage-D7awEU2z.js +11 -0
  28. package/dashboard/dist/assets/{WhatsNewPage-CBUk7WTn.js → WhatsNewPage-CTZEuf65.js} +1 -1
  29. package/dashboard/dist/assets/copy-Cey6jv67.js +6 -0
  30. package/dashboard/dist/assets/index-B9LVK3-K.js +606 -0
  31. package/dashboard/dist/assets/index-Dd1aCYFM.css +1 -0
  32. package/dashboard/dist/assets/{sample-requests-D1b5Z8FU.js → sample-requests-CS0o0F7H.js} +1 -1
  33. package/dashboard/dist/assets/{useLiveUptime-BHqJirBV.js → useLiveUptime-BGlwL1Q-.js} +1 -1
  34. package/dashboard/dist/assets/useSettings-Bsfu70PT.css +1 -0
  35. package/dashboard/dist/assets/useSettings-mbARvRgI.js +1 -0
  36. package/dashboard/dist/index.html +2 -2
  37. package/dist/index.js +93 -93
  38. package/package.json +1 -1
  39. package/roblox-plugin/WeppyRobloxMCP.rbxm +0 -0
  40. package/dashboard/dist/assets/AssetsPage-BQGliX7Q.css +0 -1
  41. package/dashboard/dist/assets/AssetsPage-yddSUaZg.js +0 -51
  42. package/dashboard/dist/assets/ChangelogDetailPage-BiiG5ZpO.js +0 -1
  43. package/dashboard/dist/assets/ChangelogPage-oIxW8_VE.js +0 -1
  44. package/dashboard/dist/assets/ConfirmModal-CpImpY9c.js +0 -1
  45. package/dashboard/dist/assets/ConnectionPage-CNtjimlm.css +0 -1
  46. package/dashboard/dist/assets/ConnectionPage-zGBwRnwi.js +0 -1
  47. package/dashboard/dist/assets/PageHeader-CThGgsAt.js +0 -6
  48. package/dashboard/dist/assets/PlaytestPage-CQqE8m04.js +0 -11
  49. package/dashboard/dist/assets/SettingsPage-DX6vgUTw.js +0 -1
  50. package/dashboard/dist/assets/SettingsPage-d0wOFs8U.css +0 -1
  51. package/dashboard/dist/assets/SyncPage-cfQ-4IDk.js +0 -4
  52. package/dashboard/dist/assets/ToolsPage-B004HHzX.js +0 -1
  53. package/dashboard/dist/assets/TooltipText-H3YSCbob.js +0 -1
  54. package/dashboard/dist/assets/UiStudioPage-CwURRVO9.js +0 -11
  55. package/dashboard/dist/assets/index-CjzKb5lS.css +0 -1
  56. package/dashboard/dist/assets/index-DG2RrKOl.js +0 -532
package/CHANGELOG.md CHANGED
@@ -9,6 +9,28 @@ All notable changes to this project will be documented in this file.
9
9
 
10
10
 
11
11
 
12
+
13
+
14
+ ## [2.9.0] - 2026-06-18
15
+
16
+ ### Features
17
+
18
+ - **Multiple Roblox Studio windows from one MCP server** — WEPPY can now keep several Roblox Studio windows connected as separate Studio targets. This helps lobby games and multi-place experiences: open each place in its own Studio window, then tell the AI which `Studio ID` or `placeId` to use. Requests without a named target follow the Dashboard Studio Routing setting.
19
+ - **New Dashboard Controls tab** — MCP behavior settings now have a dedicated Controls page. Use **Controls > Studio Routing** to switch between automatic recent priority and a pinned Studio window, set the priority target, and copy Studio IDs. Project Root and General Settings also live in Controls, while Settings stays focused on license, data, environment, and language.
20
+ - **Clearer connection view for Studio targets** — The Connection page now shows Studio targets instead of a generic plugin list, with Studio ID, place, connection, routing, and in-flight request details. This makes it easier to see which Studio window will receive AI requests.
21
+ - **Place-aware Dashboard data** — Dashboard areas that read saved data now keep the selected place clearer, so tool history, reports, assets, and current-place context stay tied to the Studio target or place you are working with.
22
+
23
+ ### Stability
24
+
25
+ - **More reliable multi-place routing** — WEPPY now preserves selected Studio targets across routed requests, handles disconnected pinned targets by returning to automatic routing, and keeps asset and Playtest work scoped to the intended place.
26
+ - **Larger multi-place sync cache** — Project Sync can keep up to five place contexts in memory at once. Existing `place_*` folders are preserved on disk, and no manual migration is required.
27
+
28
+ ## [2.8.2] - 2026-06-15
29
+
30
+ ### Bug Fixes
31
+
32
+ - **More complete Dashboard bug reports** — Bug reports opened from WEPPY Dashboard now keep the Roblox Studio version when Studio reconnects or refreshes its plugin metadata. If the Plugin cannot report the Studio version, WEPPY also checks the installed Roblox Studio app or executable and marks that value as an installed-app fallback in the GitHub issue prefill. This gives support reports the Studio version more consistently without requiring any setup change.
33
+
12
34
  ## [2.8.1] - 2026-06-15
13
35
 
14
36
  ### Features
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **WEPPY** is an MCP server that lets AI coding agents control a live Roblox Studio session - create and edit scripts, instances, terrain, lighting, assets, audio, and animations through natural language.
4
4
 
5
- **Action-based tool surface · Bidirectional sync · Automated playtest · UI Studio · Multi-place support**
5
+ **Multi-Place Studio work · Generated assets to Roblox · Bidirectional sync · Automated playtest · UI Studio**
6
6
 
7
7
  **English** | [한국어](https://weppyai.com/ko) | [日本語](https://weppyai.com/ja) | [Español](https://weppyai.com/es) | [Português](https://weppyai.com/pt-br) | [Bahasa Indonesia](https://weppyai.com/id) | [Deutsch](https://weppyai.com/de)
8
8
 
@@ -14,7 +14,11 @@ AI coding agents like Claude, Codex, and Gemini are powerful, but they cannot se
14
14
 
15
15
  **WEPPY** bridges AI agents and Roblox Studio. AI directly creates and modifies instances, scripts, properties, terrain, and more inside Studio, and the changes are reflected immediately in Studio and the dashboard so you can see exactly what changed.
16
16
 
17
- No copy-pasting code. AI does the work, you review the results.
17
+ WEPPY is also built for Roblox experiences that are split across several Places. Open up to five Studio windows for Lobby, Game, Shop, Tutorial, or other Places, then tell the agent which Studio ID to use. One request can update several Places without re-explaining context or copying changes by hand.
18
+
19
+ For assets, an agent can create or prepare an image, save it to the Asset Library, upload it through Roblox Open Cloud, and apply the returned asset URI to a Place. The result is a shorter path from "make this icon/decal" to "it is visible in Studio."
20
+
21
+ No copy-pasting code or asset IDs. AI does the work, you review the results.
18
22
 
19
23
  ## Quick Install
20
24
 
@@ -100,16 +104,38 @@ AI can directly handle scripts, instances, properties, terrain, lighting, assets
100
104
  - "Generate terrain with mountains and rivers, then place spawn points on flat areas."
101
105
  - "Search the Creator Store for a sword model and insert it into StarterPack."
102
106
 
103
- ### 2) Sync: Keep full project context stable for AI
107
+ ### 2) Multi-Place work: Split one request across several Studio windows
108
+
109
+ Many Roblox experiences are not a single Place. WEPPY lets you keep up to five Studio windows connected to one MCP server, then route work by Studio ID.
110
+
111
+ - Open up to five Roblox Studio windows, such as Lobby, Game, Shop, or Tutorial
112
+ - Ask once: "In studio-1, add the event portal to Lobby. In studio-2, add the arrival point and guide UI to Game."
113
+ - Use Dashboard Connection to see every AI agent, Studio Target, copyable Studio ID, and routing state
114
+ - Work with the multi-Studio flow also documented by [Roblox's official Studio MCP guide](https://create.roblox.com/docs/studio/mcp), with WEPPY's dashboard visibility on top
115
+
116
+ ![WEPPY Dashboard Connection - multiple AI agents and Studio Targets connected to one MCP server](https://raw.githubusercontent.com/hope1026/weppy-roblox-mcp/main/docs/assets/screenshots/dashboard/dashboard_connection.png)
117
+
118
+ ### 3) Assets: Generate, upload, and apply images in Studio
119
+
120
+ WEPPY Assets turns a natural-language asset request into a Studio-ready result.
121
+
122
+ - "Create a gem icon for the shop button, upload it to Roblox, then apply it to the ShopButton image in the Lobby Place."
123
+ - Save generated images, Decals, and RBXM files to the local Asset Library
124
+ - Upload images through Roblox Open Cloud and reuse place-specific or shared assets
125
+ - Apply the returned asset URI to ImageLabel, Decal, Texture, or other Studio properties
126
+
127
+ ![WEPPY Dashboard Assets - local Asset Library items and Roblox upload status](https://raw.githubusercontent.com/hope1026/weppy-roblox-mcp/main/docs/assets/screenshots/dashboard/dashboard_assets.png)
128
+
129
+ ### 4) Sync: Keep full project context stable for AI
104
130
 
105
131
  AI works from a synchronized local mirror, so multi-file updates stay consistent.
106
132
 
107
133
  - Basic: one-way sync (Studio -> Local)
108
- - Pro: bidirectional sync + per-type Direction/Apply Mode + history + multi-place
134
+ - Pro: bidirectional sync + per-type Direction/Apply Mode + history + up to five Places
109
135
 
110
136
  ![Sync workflow - Studio and local files synchronized in real time](https://raw.githubusercontent.com/hope1026/weppy-roblox-mcp/main/docs/assets/screenshots/plugin/sync/sync-overview.png)
111
137
 
112
- ### 3) Playtest: Let AI run and verify tests automatically
138
+ ### 5) Playtest: Let AI run and verify tests automatically
113
139
 
114
140
  AI can control Roblox Studio playtests directly. It can start and stop Play (F5) or Run (F8), inject test scripts, collect logs, and generate local reports automatically.
115
141
 
@@ -119,7 +145,7 @@ AI can control Roblox Studio playtests directly. It can start and stop Play (F5)
119
145
 
120
146
  ![WEPPY Playtest Dashboard - Test history and detailed report](https://raw.githubusercontent.com/hope1026/weppy-roblox-mcp/main/docs/assets/screenshots/dashboard/dashboard_playtest.png)
121
147
 
122
- ### 4) UI Studio: Build and inspect in-game UI
148
+ ### 6) UI Studio: Build and inspect in-game UI
123
149
 
124
150
  UI Studio lets AI agents create in-game UI that matches your game's style, or analyze the UI you already have and suggest improvements.
125
151
 
@@ -129,17 +155,20 @@ UI Studio lets AI agents create in-game UI that matches your game's style, or an
129
155
 
130
156
  ![WEPPY UI Studio - Roblox Studio showing AI-generated in-game UI](https://raw.githubusercontent.com/hope1026/weppy-roblox-mcp/main/docs/assets/screenshots/dashboard/dashboard_ui_roblox_studio.png)
131
157
 
132
- ### 5) WEPPY Dashboard: Monitor AI work in real time
158
+ ### 7) WEPPY Dashboard: Monitor AI work in real time
133
159
 
134
160
  The MCP server provides a web dashboard where you can check connection status, tool execution history, sync state, UI Studio history, and game change logs in real time.
135
161
 
136
- - Server/Plugin/Agent connection status at a glance
162
+ - Connection topology for AI agents, the MCP server, and connected Roblox Studio windows
163
+ - Studio Targets with copyable Studio IDs, Priority/Pinned badges, and a link to routing controls
164
+ - 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
165
+ - Assets page for local library items, shared assets, and Roblox upload status
137
166
  - Compare every change the AI made via Before & After in Changelog
138
167
  - Analyze workflow with tool execution history, UI Studio captures, and statistics
139
168
 
140
169
  ![WEPPY Dashboard Overview - Server status, recent changes, and session summary](https://raw.githubusercontent.com/hope1026/weppy-roblox-mcp/main/docs/assets/screenshots/dashboard/dashboard_overview.png)
141
170
 
142
- ### 6) WEPPY Roblox Explorer: Browse Studio hierarchy in VSCode
171
+ ### 8) WEPPY Roblox Explorer: Browse Studio hierarchy in VSCode
143
172
 
144
173
  View the full instance tree of your Roblox Studio place directly inside VSCode. Navigate services, open synced scripts and property files, and track sync status - all without switching to Studio.
145
174
  WEPPY Roblox Explorer is a companion VSCode extension for sync data generated by WEPPY. Tree browsing works from synced files, and live sync state or direction indicators are enhanced when the local MCP server is running.
@@ -147,22 +176,25 @@ Install from [VS Code Marketplace](https://marketplace.visualstudio.com/items?it
147
176
 
148
177
  - Class icons matching Studio for instant recognition
149
178
  - Click to open synced scripts and property files
150
- - Multi-place support with sync status indicators
179
+ - Multi-place support with sync status indicators for up to five Places
151
180
 
152
181
  ![WEPPY Roblox Explorer - Studio instance tree displayed in VSCode sidebar](https://raw.githubusercontent.com/hope1026/weppy-roblox-mcp/main/docs/assets/screenshots/roblox-explorer/roblox-explorer-screen.png)
153
182
 
154
183
  ## Use Cases
155
184
 
156
185
  - **Rapid prototyping**: Describe a game mechanic in natural language and watch AI build it in Studio
186
+ - **Multi-Place production**: Keep Lobby and Game open in separate Studio windows and update both from one request
157
187
  - **Bulk refactoring**: Rename a module interface and update every dependent script in one request
158
188
  - **Terrain & environment**: Generate procedural terrain, set lighting/atmosphere, place assets - all from a single prompt
159
189
  - **UI design**: Generate in-game UI, capture previews, and iterate on Design Check suggestions
160
190
  - **Multi-file consistency**: AI reads the full project via Sync and applies changes across related scripts together
161
- - **Asset integration**: Search the Creator Store, insert models, and configure properties without leaving your editor
191
+ - **Generated asset integration**: Create an icon or decal, upload it to Roblox, apply it to a UI or Decal property, and keep the asset for reuse
162
192
 
163
193
  ## Why It Matters
164
194
 
165
195
  - Compress repetitive work: turn many manual edits into one request
196
+ - Work across up to five Places without re-explaining context or copying changes between Studio windows
197
+ - Turn generated images into applied Roblox assets without manually moving files and asset IDs
166
198
  - Change related files together: not just one target file
167
199
  - Lower risk: rely on sync state and history before applying changes
168
200
  - Better token efficiency (Pro): reduce round trips with bulk actions
@@ -200,17 +232,17 @@ Yes. Any MCP-compatible AI client works.
200
232
  Yes. AI can create instances, write scripts, generate terrain, set up lighting, insert assets, configure physics, and more - all inside a live Roblox Studio session. It goes beyond code generation to executable actions.
201
233
 
202
234
  ### What is the difference between Basic and Pro?
203
- Basic (Free) includes MCP tool execution and one-way sync (Studio -> Local). Pro adds bidirectional sync, UI Studio, bulk operations, terrain generation, spatial analysis, audio/animation control, and multi-place support. See the Pro upgrade page.
235
+ Basic (Free) includes MCP tool execution and one-way sync (Studio -> Local). Pro adds multi-place work across up to five Places, Asset Library with Roblox upload, bidirectional sync, UI Studio, bulk operations, terrain generation, spatial analysis, and audio/animation control. See the Pro upgrade page.
204
236
 
205
237
  ### How is Weppy different from other Roblox MCP servers?
206
- Weppy uses action-based dispatching instead of separate tools for each function. This reduces AI token consumption significantly. It also provides bidirectional project sync and multi-place support, which most alternatives lack.
238
+ Weppy uses action-based dispatching instead of separate tools for each function. This reduces AI token consumption significantly. It also combines Studio ID based multi-place work, generated asset upload/apply, bidirectional project sync, and Playtest control.
207
239
 
208
240
  ### Is it safe? Can AI break my game?
209
241
  The server runs on localhost only (127.0.0.1:3002). Forbidden paths (CoreGui, CorePackages) are blocked. Rate limiting (450 req/min) and 30-second timeouts prevent runaway operations. All changes are trackable via sync history.
210
242
 
211
243
  ## Pro Upgrade
212
244
 
213
- Bidirectional Sync, UI Studio, advanced build capabilities, and AI token efficiency - all in one upgrade.
245
+ Multi-Place work, generated assets to Roblox, bidirectional Sync, UI Studio, Playtest control, and AI token efficiency - all in one upgrade.
214
246
 
215
247
  [Pro Upgrade Guide](https://weppyai.com/plans/)
216
248
 
@@ -0,0 +1 @@
1
+ ._page_188au_1{display:flex;flex-direction:column;gap:14px;min-height:100%;max-width:var(--content-max)}._experimentalBadge_188au_9{display:inline-flex;align-items:center;min-height:20px;border:1px solid color-mix(in srgb,var(--accent) 45%,var(--border));border-radius:4px;background:color-mix(in srgb,var(--accent) 14%,var(--bg-card));color:var(--accent);padding:0 7px;font-family:var(--font-label);font-size:11px;line-height:1}._toolbarShell_188au_23{position:relative;z-index:30;border-top:1px solid var(--border);border-bottom:1px solid var(--border);padding:12px 0}._toolbar_188au_23{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}._toolbar_188au_23>._segmented_188au_39{order:1}._toolbar_188au_23>._placeSelectorLabel_188au_43{order:2}._toolbar_188au_23>._listContextSummary_188au_47{order:3;flex:1 1 auto;min-width:220px}._toolbar_188au_23>._toolbarActions_188au_53{order:4;margin-left:auto}._categoryControl_188au_58{order:5;display:inline-flex;align-items:center;gap:8px;width:100%;min-width:0;flex:1 0 100%}._listContextSummary_188au_47{color:var(--text-secondary);font-size:12px;line-height:1.4}._listContextSummary_188au_47 strong{color:var(--text-primary);font-family:var(--font-label);font-weight:600}._contextDivider_188au_80{color:var(--text-muted)}._categoryControlLabel_188au_84{flex:0 0 auto;color:var(--text-secondary);font-size:12px}._categoryRail_188au_90{display:flex;align-items:center;gap:4px;flex-wrap:wrap;min-width:0}._categoryButton_188au_98{min-height:32px;border:1px solid var(--border);border-radius:6px;background:var(--bg-card);color:var(--text-secondary);padding:0 10px;font-family:var(--font-label);font-size:12px;line-height:1;cursor:pointer;transition:border-color var(--transition),color var(--transition),background var(--transition)}._categoryButton_188au_98:hover{border-color:var(--accent);color:var(--text-primary)}._categoryButton_188au_98:disabled{cursor:not-allowed;opacity:.48}._categoryButton_188au_98:disabled:hover{border-color:var(--border);color:var(--text-secondary)}._categoryButtonActive_188au_127{border-color:color-mix(in srgb,var(--accent) 76%,var(--border));background:var(--accent-dim);color:var(--accent)}._toolbarActions_188au_53,._actionRow_188au_134,._copyRow_188au_135,._buttonRow_188au_136{display:flex;align-items:center;gap:8px;flex-wrap:wrap}._segmented_188au_39{display:inline-flex;min-height:32px;border:1px solid var(--border);border-radius:6px;overflow:hidden;background:var(--bg-card)}._segmented_188au_39 button{border:0;border-right:1px solid var(--border);background:transparent;color:var(--text-secondary);padding:0 10px;font-family:var(--font-label);font-size:12px;cursor:pointer}._segmented_188au_39 button:last-child{border-right:0}._segmented_188au_39 ._segmentedActive_188au_167{background:var(--accent-dim);color:var(--accent)}._placeSelectorLabel_188au_43{display:inline-flex;align-items:center;gap:8px;min-width:0;color:var(--text-secondary);font-size:12px}._placeSelectorLabel_188au_43 span{flex:0 0 auto}._placeSelect_188au_43{min-width:190px;max-width:min(320px,100%);min-height:32px;border:1px solid var(--border);border-radius:4px;background:var(--bg-card);color:var(--text-primary);padding:0 8px;font:inherit}._filterLabel_188au_197{display:inline-flex;align-items:center;gap:8px;color:var(--text-secondary);font-size:12px}._filterLabel_188au_197 select{min-height:32px;border:1px solid var(--border);border-radius:4px;background:var(--bg-card);color:var(--text-primary);padding:0 8px;font:inherit}._commandButton_188au_215,._primaryButton_188au_216,._iconButton_188au_217{display:inline-flex;align-items:center;justify-content:center;gap:6px;border:1px solid var(--border);border-radius:4px;background:var(--bg-card);color:var(--text-primary);font-family:var(--font-label);font-size:12px;cursor:pointer;transition:border-color var(--transition),color var(--transition),background var(--transition),opacity var(--transition)}._commandButton_188au_215{min-height:32px;padding:6px 10px;text-decoration:none}._primaryButton_188au_216{min-height:34px;padding:7px 12px;border-color:var(--accent);color:var(--accent)}._iconButton_188au_217{width:32px;height:32px;padding:0}._commandButton_188au_215:hover,._primaryButton_188au_216:hover,._iconButton_188au_217:hover{border-color:var(--accent)}._dangerButton_188au_257{color:var(--error-text)}._dangerButton_188au_257:hover{border-color:var(--error-border);background:var(--error-bg);color:var(--error-text)}._iconButtonActive_188au_267{border-color:var(--accent);background:var(--accent-dim);color:var(--accent)}._commandButton_188au_215:disabled,._primaryButton_188au_216:disabled,._iconButton_188au_217:disabled{cursor:not-allowed;opacity:.5}._grid_188au_280{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:12px}._assetCard_188au_286{display:flex;flex-direction:column;gap:8px;min-width:0;border:1px solid var(--border);border-radius:var(--radius);background:var(--bg-card);padding:8px;color:var(--text-primary);text-align:left;cursor:pointer}._assetCardSelected_188au_300{border-color:var(--accent);box-shadow:0 0 0 1px color-mix(in srgb,var(--accent) 40%,transparent)}._thumbnailWrap_188au_305{display:grid;place-items:center;width:100%;aspect-ratio:1;overflow:hidden;border-radius:6px;background:var(--bg-secondary)}._thumbnail_188au_305{width:100%;height:100%;object-fit:contain}._thumbnailFallback_188au_321{display:grid;place-items:center;width:48px;height:48px;border:1px solid var(--border);border-radius:8px;color:var(--text-secondary);background:var(--bg-card)}._assetCardBody_188au_332{display:flex;flex-direction:column;gap:6px;min-width:0}._assetName_188au_339{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--font-label);font-size:13px}._assetMeta_188au_347{display:flex;align-items:center;justify-content:space-between;gap:8px}._statusChip_188au_354,._categoryPill_188au_355{border:1px solid var(--border);border-radius:4px;padding:2px 6px;font-size:11px;color:var(--text-secondary)}._categoryPill_188au_355{color:var(--text-primary);background:var(--bg-secondary)}._status_uploaded_188au_368{color:var(--success);border-color:var(--success)}._status_failed_188au_373{color:var(--error);border-color:var(--error)}._status_processing_188au_378,._status_uploading_188au_379{color:var(--warning);border-color:var(--warning)}._assetId_188au_384,._scopeText_188au_385,._muted_188au_386{color:var(--text-muted);font-size:12px}._emptyState_188au_391,._notice_188au_392,._errorState_188au_393,._messageState_188au_394{border:1px solid var(--border);border-radius:var(--radius);background:var(--bg-card);padding:14px;color:var(--text-secondary)}._emptyState_188au_391{min-height:160px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;text-align:center}._emptyState_188au_391 p{margin:0;color:var(--text-primary);font-family:var(--font-label)}._notice_188au_392{color:var(--warning-text);border-color:var(--warning-border);background:var(--warning-bg)}._proNotice_188au_424{color:var(--pro-text);border-color:var(--pro-border);background:var(--pro-bg-soft)}._errorState_188au_393{color:var(--error);border-color:var(--error)}._messageState_188au_394{color:var(--success);border-color:var(--success)}._rbxmGuide_188au_440{display:flex;flex-direction:column;gap:6px;border:1px solid color-mix(in srgb,var(--accent) 35%,var(--border));border-radius:var(--radius);background:color-mix(in srgb,var(--accent) 8%,var(--bg-card));padding:14px}._rbxmGuide_188au_440 h2{margin:0;color:var(--text-primary);font-family:var(--font-label);font-size:14px;letter-spacing:0}._rbxmGuide_188au_440 p{margin:0;max-width:760px;color:var(--text-secondary);font-size:12px;line-height:1.5}._drawer_188au_466{position:fixed;top:0;right:0;z-index:40;width:min(460px,100vw);height:100vh;overflow-y:auto;border-left:1px solid var(--border);background:var(--bg-primary);padding:18px;box-shadow:-12px 0 24px #00000047}._settingsInlinePanel_188au_480{position:absolute;top:calc(100% + 8px);right:0;z-index:35;display:flex;flex-direction:column;gap:12px;width:min(560px,100%);max-height:min(680px,calc(100vh - var(--header-height) - 112px));overflow-y:auto;border:1px solid var(--border);border-radius:8px;background:var(--bg-card);padding:14px;box-shadow:0 18px 44px #00000057;animation:_settingsPopoverIn_188au_1 .12s ease-out;transform-origin:top right}._settingsDrawer_188au_500{width:min(560px,100%)}@keyframes _settingsPopoverIn_188au_1{0%{opacity:0;transform:translateY(-4px) scale(.99)}to{opacity:1;transform:translateY(0) scale(1)}}._detailPopupLayer_188au_516{position:fixed;top:calc(var(--header-height) + 16px);right:24px;bottom:24px;left:calc(var(--sidebar-width) + 24px);z-index:900;display:flex;align-items:stretch;justify-content:center;padding:clamp(12px,2vw,24px);background:#03071294;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);box-sizing:border-box}._detailDialog_188au_532{width:min(1120px,100%);min-height:0;display:flex;flex-direction:column;overflow:hidden;border:1px solid var(--border);border-radius:var(--radius);background:var(--bg-card);color:var(--text-primary);box-shadow:0 24px 60px #0000006b}._detailDialog_188au_532:focus{outline:none}._detailDialogHeader_188au_549{flex:0 0 auto;display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:16px;padding:14px 16px;border-bottom:1px solid var(--border);background:color-mix(in srgb,var(--bg-card) 92%,var(--bg-secondary))}._detailTitleBlock_188au_560{min-width:0;display:flex;flex-direction:column;gap:3px}._detailTitleBlock_188au_560 h2{margin:0;font-size:18px;letter-spacing:0}._detailTitleBlock_188au_560 span:last-child{overflow:hidden;color:var(--text-muted);font-family:var(--font-code);font-size:12px;text-overflow:ellipsis;white-space:nowrap}._detailEyebrow_188au_582{color:var(--text-muted);font-family:var(--font-label);font-size:11px;font-weight:600;letter-spacing:0;text-transform:uppercase}._detailHeaderActions_188au_591{display:flex;align-items:center;justify-content:flex-end;gap:8px;min-width:0}._detailDialogBody_188au_599{flex:1 1 auto;min-height:0;display:grid;grid-template-columns:minmax(260px,.9fr) minmax(360px,1.1fr);gap:0;overflow:hidden}._detailPreviewPane_188au_608{min-width:0;min-height:0;display:flex;align-items:center;justify-content:center;padding:24px;border-right:1px solid var(--border);background:var(--bg-secondary)}._detailPreview_188au_608,._detailPreviewFallback_188au_620{width:100%;max-width:520px;aspect-ratio:1;border:1px solid var(--border);border-radius:var(--radius);background:var(--bg-card)}._detailPreview_188au_608{display:block;object-fit:contain}._detailPreviewFallback_188au_620{display:grid;place-items:center;gap:8px;color:var(--text-secondary)}._detailPreviewFallback_188au_620 code{color:var(--text-muted);font-family:var(--font-code);font-size:12px}._detailPreviewFallback_188au_620 small{max-width:88%;color:var(--text-muted);font-size:12px;line-height:1.35;overflow-wrap:anywhere;text-align:center}._detailContentPane_188au_656{min-width:0;overflow-y:auto;padding:18px 22px 24px}._detailContentPane_188au_656 ._formStack_188au_662{margin-top:0}._drawerHeader_188au_666{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:14px}._settingsInlinePanel_188au_480 ._drawerHeader_188au_666{margin-bottom:0}._drawerHeader_188au_666 h2{margin:0;font-size:18px;letter-spacing:0}._drawerHeader_188au_666 span{color:var(--text-muted);font-size:12px}._preview_188au_689,._previewFallback_188au_690{width:100%;aspect-ratio:1;border:1px solid var(--border);border-radius:var(--radius);background:var(--bg-secondary);margin-bottom:14px}._preview_188au_689{object-fit:contain}._previewFallback_188au_690{display:grid;place-items:center;gap:8px;color:var(--text-secondary)}._previewFallback_188au_690 code{color:var(--text-muted);font-family:var(--font-code);font-size:12px}._formStack_188au_662,._detailSection_188au_717,._noticeList_188au_718,._settingsPanel_188au_719{display:flex;flex-direction:column;gap:10px;margin-top:14px}._noticeList_188au_718{color:var(--text-muted);font-size:12px;line-height:1.45}._noticeList_188au_718 p{margin:0}._setupNotice_188au_736{display:grid;gap:8px;margin-top:14px;border:1px solid var(--warning-border);border-radius:6px;background:var(--warning-bg);color:var(--warning-text);padding:12px;font-size:12px}._setupNotice_188au_736 strong{color:var(--text-primary);font-size:13px}._setupNotice_188au_736 p{margin:0}._setupNotice_188au_736 ._commandButton_188au_215{justify-self:start}._field_188au_761{display:flex;flex-direction:column;gap:6px;font-size:12px;color:var(--text-secondary)}._fieldLabelRow_188au_769{display:flex;align-items:center;gap:4px;min-height:24px}._fieldLabelRow_188au_769 label,._fieldLabelRow_188au_769 span{min-width:0}._field_188au_761 input,._field_188au_761 textarea,._field_188au_761 select{width:100%;border:1px solid var(--border);border-radius:4px;background:var(--bg-secondary);color:var(--text-primary);padding:8px;font:inherit}._fieldHelp_188au_793{color:var(--text-muted);line-height:1.35}._twoColumn_188au_798{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:10px}._detailSection_188au_717{padding-top:12px;border-top:1px solid var(--border)}._technicalDetails_188au_809{margin-top:14px;padding-top:12px;border-top:1px solid var(--border)}._technicalDetails_188au_809 summary{cursor:pointer;color:var(--text-secondary);font-size:13px;font-weight:600}._technicalDetails_188au_809 summary:hover{color:var(--text-primary)}._technicalDetails_188au_809 ._detailGrid_188au_826,._technicalDetails_188au_809 ._metadataList_188au_827{margin-top:10px}._detailSection_188au_717 h3{margin:0;font-size:13px;letter-spacing:0}._detailGrid_188au_826,._compactMeta_188au_838{display:grid;grid-template-columns:90px minmax(0,1fr);gap:6px 10px;margin:0;font-size:12px}._compactMeta_188au_838{border:1px solid var(--border);border-radius:6px;padding:10px;background:var(--bg-card)}._detailGrid_188au_826 dt,._compactMeta_188au_838 dt{color:var(--text-muted)}._detailGrid_188au_826 dd,._compactMeta_188au_838 dd{margin:0;min-width:0;overflow-wrap:anywhere}._copyableValue_188au_865{display:inline-flex;align-items:center;gap:6px}._copyableValue_188au_865 span{min-width:0;overflow-wrap:anywhere}._inlineCopyButton_188au_876{display:inline-flex;flex:0 0 auto;align-items:center;justify-content:center;width:24px;height:24px;border:1px solid var(--border);border-radius:4px;background:transparent;color:var(--text-muted);cursor:pointer;transition:border-color var(--transition),color var(--transition),background var(--transition)}._inlineCopyButton_188au_876:hover{border-color:var(--accent);color:var(--accent);background:var(--accent-dim)}._hashText_188au_897{font-family:var(--font-code)}._usageList_188au_901{display:flex;flex-direction:column;gap:8px}._usageItem_188au_907,._metadataItem_188au_908{display:grid;gap:4px;border:1px solid var(--border);border-radius:6px;padding:8px;background:var(--bg-card);font-size:12px}._metadataList_188au_827{display:flex;flex-direction:column;gap:8px}._metadataList_188au_827 strong,._usageItem_188au_907 strong{color:var(--text-primary);overflow-wrap:anywhere}._metadataItem_188au_908 span{color:var(--text-secondary);overflow-wrap:anywhere}._metadataItem_188au_908 code,._usageItem_188au_907 code{color:var(--accent);overflow-wrap:anywhere}._settingsPanel_188au_719{border:1px solid var(--border);border-radius:8px;padding:12px;background:var(--bg-card)}._settingsInlinePanel_188au_480 ._settingsPanel_188au_719{border:0;border-radius:0;background:transparent;padding:0;margin-top:0}._settingsSubsection_188au_956{display:grid;gap:8px}._settingsSectionHeader_188au_961{display:flex;align-items:center;justify-content:space-between;gap:10px}._settingsSectionHeader_188au_961 h3{margin:0;color:var(--text-primary);font-size:13px}._settingsDefinitionList_188au_974{display:grid;gap:6px;margin:0}._settingsDefinitionList_188au_974 div{display:grid;grid-template-columns:minmax(96px,max-content) minmax(0,1fr);gap:10px}._settingsDefinitionList_188au_974 dt{color:var(--text-muted)}._settingsDefinitionList_188au_974 dd{margin:0;color:var(--text-primary);overflow-wrap:anywhere}._toggleRow_188au_996{display:flex;align-items:center;justify-content:space-between;gap:16px;font-size:13px}._toggleRow_188au_996 span{display:grid;gap:3px}._toggleRow_188au_996 small,._inlineHelp_188au_1010{color:var(--text-muted);font-size:12px}._toggleRow_188au_996 input{width:18px;height:18px}._inlineHelp_188au_1010{margin:0}._inlineHelp_188au_1010 a{color:var(--accent)}@media(max-width:1120px){._detailPopupLayer_188au_516{right:16px;bottom:16px;left:calc(var(--sidebar-width) + 16px);padding:12px}._detailDialogBody_188au_599{grid-template-columns:minmax(240px,.8fr) minmax(320px,1.2fr)}}@media(max-width:820px){._detailPopupLayer_188au_516{top:calc(var(--header-height) + 10px);right:10px;bottom:10px;left:calc(var(--sidebar-collapsed) + 10px);padding:8px}._detailDialogHeader_188au_549{grid-template-columns:minmax(0,1fr);align-items:stretch;gap:10px;padding:12px}._detailHeaderActions_188au_591{justify-content:flex-start;overflow-x:auto;padding-bottom:2px}._detailDialogBody_188au_599{grid-template-columns:minmax(0,1fr);overflow-y:auto}._detailPreviewPane_188au_608{min-height:auto;padding:14px;border-right:0;border-bottom:1px solid var(--border)}._detailPreview_188au_608,._detailPreviewFallback_188au_620{max-width:340px}._detailContentPane_188au_656{overflow:visible;padding:14px}}@media(max-width:720px){._headerRow_188au_1087,._toolbar_188au_23{align-items:stretch;flex-direction:column}._headerMeta_188au_1093{justify-items:start}._toolbarActions_188au_53{justify-content:flex-start}._placeSelectorLabel_188au_43,._placeSelect_188au_43{width:100%}._settingsInlinePanel_188au_480{right:auto;left:0;width:100%;transform-origin:top left}._twoColumn_188au_798{grid-template-columns:1fr}}
@@ -0,0 +1,46 @@
1
+ import{i as ne,a as R,n as ve,u as he,j as t,P as dt,I as ut,r as i,o as pt,R as qe,X as De,E as ht,p as Ze,g as mt,e as gt,h as xt}from"./index-B9LVK3-K.js";import{C as Je}from"./ConfirmModal-C9EhZCHZ.js";import{D as Ue,P as bt}from"./PageHeader-Cqg4GMtU.js";import{T as K}from"./TooltipText-ZamrETeK.js";import{C as Qe}from"./copy-Cey6jv67.js";import"./ConfirmModal.module-NrFlfTWy.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 ft=[["path",{d:"m12 19-7-7 7-7",key:"1l729n"}],["path",{d:"M19 12H5",key:"x3x0zl"}]],yt=ne("arrow-left",ft);/**
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 jt=[["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"}]],vt=ne("audio-lines",jt);/**
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 Ct=[["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"}]],_t=ne("badge",Ct);/**
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 St=[["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"}]],At=ne("box",St);/**
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 It=[["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"}]],Nt=ne("clapperboard",It);/**
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 kt=[["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"}]],Pt=ne("film",kt);/**
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 Rt=[["path",{d:"m21 21-4.34-4.34",key:"14j7rj"}],["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}]],wt=ne("search",Rt);/**
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 Lt=[["path",{d:"M10 11v6",key:"nco0om"}],["path",{d:"M14 11v6",key:"outv1u"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",key:"miytrc"}],["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",key:"e791ji"}]],$t=ne("trash-2",Lt);/**
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 Bt=[["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"}]],Dt=ne("upload",Bt);function et(e){if(e.scope==="place"&&typeof e.placeId=="number")return{placeId:String(e.placeId)}}function se(e){const a=et(e);return a?`?placeId=${encodeURIComponent(a.placeId)}`:""}function Ce(e){return`/api/assets/${encodeURIComponent(e.scope)}/${encodeURIComponent(e.category)}`}function ce(e,a){return`${Ce(e)}/${encodeURIComponent(a)}`}async function Et(e){return R.get(Ce(e),et(e))}async function Ut(e){return R.post(`${Ce(e)}/rescan${se(e)}`,{})}async function Tt(e,a,d){return(await R.patch(`${ce(e,a)}${se(e)}`,d)).asset}async function Ot(e,a){return R.delete(`${ce(e,a)}${se(e)}`)}async function Ft(e,a,d){return(await R.post(`${ce(e,a)}/upload${se(e)}`,d)).asset}async function Te(e,a){return(await R.post(`${ce(e,a)}/status-refresh${se(e)}`,{})).asset}async function Mt(e,a,d){const n={...e,placeId:d??e.placeId};return R.post(`${ce(e,a)}/usage-scan${se(n)}`,{})}async function Ht(e,a){return R.post(`${Ce(e)}/export-selection-rbxm${se(e)}`,a)}async function Kt(e,a,d){return R.post(`${ce(e,a)}/import-rbxm${se(e)}`,d)}async function Gt(e,a){return(await R.post(`${ce(e,a)}/thumbnail-generate${se(e)}`,{})).asset}function tt(e){return e.fileUrl?`${ve}${e.fileUrl}`:`${ve}/api/assets/${e.scope.kind}/${e.category}/${encodeURIComponent(e.id)}/file${se({scope:e.scope.kind,placeId:e.scope.kind==="place"?e.scope.placeId:void 0})}`}function st(e){return e.previewUrl?`${ve}${e.previewUrl}`:`${ve}/api/assets/${e.scope.kind}/${e.category}/${encodeURIComponent(e.id)}/preview${se({scope:e.scope.kind,placeId:e.scope.kind==="place"?e.scope.placeId:void 0})}`}const at=["all","image","decal","rbxm"],Wt=new Set(at),Oe=["model","animation"];function ye(e){return/\.(rbxm|rbxmx)$/i.test(e.file.original)}function zt(e){return Wt.has(e)}function $e(e,a){return e==="all"?a("assets.category.all","All"):a(`assets.category.${e}`,e==="rbxm"?"RBXM":e)}function ie(e,a){return $e(ye(e)?"rbxm":e.category,a)}function Fe(e){return e==="all"?["image","decal",...Oe]:e==="rbxm"?Oe:[e]}function Vt(e,a){return a==="all"?e.category==="image"||e.category==="decal"||ye(e):a==="rbxm"?ye(e):(a==="model"||a==="animation")&&ye(e)?!1:e.category===a}function Yt(e){return[...e].sort((a,d)=>d.createdAt.localeCompare(a.createdAt)||d.id.localeCompare(a.id))}const Xt="_page_188au_1",qt="_experimentalBadge_188au_9",Zt="_toolbarShell_188au_23",Jt="_toolbar_188au_23",Qt="_segmented_188au_39",es="_placeSelectorLabel_188au_43",ts="_listContextSummary_188au_47",ss="_toolbarActions_188au_53",as="_categoryControl_188au_58",ns="_contextDivider_188au_80",os="_categoryControlLabel_188au_84",ls="_categoryRail_188au_90",rs="_categoryButton_188au_98",is="_categoryButtonActive_188au_127",cs="_actionRow_188au_134",ds="_copyRow_188au_135",us="_buttonRow_188au_136",ps="_segmentedActive_188au_167",hs="_placeSelect_188au_43",ms="_filterLabel_188au_197",gs="_commandButton_188au_215",xs="_primaryButton_188au_216",bs="_iconButton_188au_217",fs="_dangerButton_188au_257",ys="_iconButtonActive_188au_267",js="_grid_188au_280",vs="_assetCard_188au_286",Cs="_assetCardSelected_188au_300",_s="_thumbnailWrap_188au_305",Ss="_thumbnail_188au_305",As="_thumbnailFallback_188au_321",Is="_assetCardBody_188au_332",Ns="_assetName_188au_339",ks="_assetMeta_188au_347",Ps="_statusChip_188au_354",Rs="_categoryPill_188au_355",ws="_status_uploaded_188au_368",Ls="_status_failed_188au_373",$s="_status_processing_188au_378",Bs="_status_uploading_188au_379",Ds="_assetId_188au_384",Es="_scopeText_188au_385",Us="_muted_188au_386",Ts="_emptyState_188au_391",Os="_notice_188au_392",Fs="_errorState_188au_393",Ms="_messageState_188au_394",Hs="_proNotice_188au_424",Ks="_rbxmGuide_188au_440",Gs="_drawer_188au_466",Ws="_settingsInlinePanel_188au_480",zs="_settingsPopoverIn_188au_1",Vs="_settingsDrawer_188au_500",Ys="_detailPopupLayer_188au_516",Xs="_detailDialog_188au_532",qs="_detailDialogHeader_188au_549",Zs="_detailTitleBlock_188au_560",Js="_detailEyebrow_188au_582",Qs="_detailHeaderActions_188au_591",ea="_detailDialogBody_188au_599",ta="_detailPreviewPane_188au_608",sa="_detailPreview_188au_608",aa="_detailPreviewFallback_188au_620",na="_detailContentPane_188au_656",oa="_formStack_188au_662",la="_drawerHeader_188au_666",ra="_preview_188au_689",ia="_previewFallback_188au_690",ca="_detailSection_188au_717",da="_noticeList_188au_718",ua="_settingsPanel_188au_719",pa="_setupNotice_188au_736",ha="_field_188au_761",ma="_fieldLabelRow_188au_769",ga="_fieldHelp_188au_793",xa="_twoColumn_188au_798",ba="_technicalDetails_188au_809",fa="_detailGrid_188au_826",ya="_metadataList_188au_827",ja="_compactMeta_188au_838",va="_copyableValue_188au_865",Ca="_inlineCopyButton_188au_876",_a="_hashText_188au_897",Sa="_usageList_188au_901",Aa="_usageItem_188au_907",Ia="_metadataItem_188au_908",Na="_settingsSubsection_188au_956",ka="_settingsSectionHeader_188au_961",Pa="_settingsDefinitionList_188au_974",Ra="_toggleRow_188au_996",wa="_inlineHelp_188au_1010",La="_headerRow_188au_1087",$a="_headerMeta_188au_1093",s={page:Xt,experimentalBadge:qt,toolbarShell:Zt,toolbar:Jt,segmented:Qt,placeSelectorLabel:es,listContextSummary:ts,toolbarActions:ss,categoryControl:as,contextDivider:ns,categoryControlLabel:os,categoryRail:ls,categoryButton:rs,categoryButtonActive:is,actionRow:cs,copyRow:ds,buttonRow:us,segmentedActive:ps,placeSelect:hs,filterLabel:ms,commandButton:gs,primaryButton:xs,iconButton:bs,dangerButton:fs,iconButtonActive:ys,grid:js,assetCard:vs,assetCardSelected:Cs,thumbnailWrap:_s,thumbnail:Ss,thumbnailFallback:As,assetCardBody:Is,assetName:Ns,assetMeta:ks,statusChip:Ps,categoryPill:Rs,status_uploaded:ws,status_failed:Ls,status_processing:$s,status_uploading:Bs,assetId:Ds,scopeText:Es,muted:Us,emptyState:Ts,notice:Os,errorState:Fs,messageState:Ms,proNotice:Hs,rbxmGuide:Ks,drawer:Gs,settingsInlinePanel:Ws,settingsPopoverIn:zs,settingsDrawer:Vs,detailPopupLayer:Ys,detailDialog:Xs,detailDialogHeader:qs,detailTitleBlock:Zs,detailEyebrow:Js,detailHeaderActions:Qs,detailDialogBody:ea,detailPreviewPane:ta,detailPreview:sa,detailPreviewFallback:aa,detailContentPane:na,formStack:oa,drawerHeader:la,preview:ra,previewFallback:ia,detailSection:ca,noticeList:da,settingsPanel:ua,setupNotice:pa,field:ha,fieldLabelRow:ma,fieldHelp:ga,twoColumn:xa,technicalDetails:ba,detailGrid:fa,metadataList:ya,compactMeta:ja,copyableValue:va,inlineCopyButton:Ca,hashText:_a,usageList:Sa,usageItem:Aa,metadataItem:Ia,settingsSubsection:Na,settingsSectionHeader:ka,settingsDefinitionList:Pa,toggleRow:Ra,inlineHelp:wa,headerRow:La,headerMeta:$a},Ba={image:ut,decal:_t,audio:vt,mesh:At,model:dt,video:Pt,animation:Nt};function Be(e,a){return a(`assets.status.${e}`,e)}function Da(e){return e.category==="image"||e.category==="decal"||!!e.file.preview}function Ea(e){return e.category==="decal"?e.roblox.creatorAssetId??e.roblox.assetId:e.roblox.assetId}function Ua({assets:e,selectedAssetId:a,onSelect:d}){const{t:n}=he();return e.length===0?t.jsxs("div",{className:s.emptyState,children:[t.jsx("p",{children:n("assets.empty.title","No assets yet")}),t.jsx("span",{children:n("assets.empty.body","Choose a scope and category, then rescan that inbox folder.")})]}):t.jsx("div",{className:s.grid,children:e.map(r=>{const N=Ba[r.category],v=Ea(r);return t.jsxs("button",{type:"button",className:[s.assetCard,a===r.id?s.assetCardSelected:""].filter(Boolean).join(" "),onClick:()=>d(r.id),children:[t.jsx("span",{className:s.thumbnailWrap,children:Da(r)?t.jsx("img",{className:s.thumbnail,src:st(r),alt:r.displayName,loading:"lazy"}):t.jsx("span",{className:s.thumbnailFallback,"aria-hidden":"true",children:t.jsx(N,{size:30})})}),t.jsxs("span",{className:s.assetCardBody,children:[t.jsx("span",{className:s.assetName,children:r.displayName}),t.jsxs("span",{className:s.assetMeta,children:[t.jsx("span",{className:s.categoryPill,children:ie(r,n)}),t.jsx("span",{className:`${s.statusChip} ${s[`status_${r.status}`]??""}`,children:Be(r.status,n)})]}),t.jsxs("span",{className:s.assetMeta,children:[t.jsx("span",{className:s.scopeText,children:r.scope.kind==="shared"?n("assets.scope.shared","Shared"):n("assets.scope.place","Current Place")}),t.jsx("span",{className:s.assetId,children:v?`#${v}`:n("assets.status.localOnly","Local only")})]})]})]},r.id)})})}const Ta="https://create.roblox.com/dashboard/creations/store",Oa=/^https:\/\/create\.roblox\.com\/store\/asset\/\d+(?:\/.*)?$/;function Fa(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/1024/1024).toFixed(1)} MB`}function je(e){const a=new Date(e);if(Number.isNaN(a.getTime()))return e;const d=a.getFullYear(),n=String(a.getMonth()+1).padStart(2,"0"),r=String(a.getDate()).padStart(2,"0"),N=String(a.getHours()).padStart(2,"0"),v=String(a.getMinutes()).padStart(2,"0");return`${d}-${n}-${r} ${N}:${v}`}function Ma(e){return e.category==="image"||e.category==="decal"||!!e.file.preview}function Ha(e){return e.file.preview?st(e):tt(e)}function Ka(e){var d;const a=Object.entries(((d=e.rbxm)==null?void 0:d.classCounts)??{}).sort((n,r)=>r[1]-n[1]).slice(0,8);return a.length===0?"-":a.map(([n,r])=>`${n} ${r}`).join(", ")}function Me(e){var r;const a=(r=e.rbxm)==null?void 0:r.thumbnail;if(!a)return"-";const d=a.source?` via ${a.source}`:"",n=a.message?` · ${a.message}`:"";return`${a.status}${d}${n}`}function He(e){const{width:a,height:d}=e.file;return a===null||d===null?null:`${a} x ${d}px`}function Ke(e){const{durationMs:a}=e.file;return a===null?null:a<1e3?`${a} ms`:`${(a/1e3).toFixed(1)} s`}function Ga(e){return`${Ta}/${e}/configure`}function Wa(e){return e.category==="decal"?e.roblox.creatorAssetId??e.roblox.assetId??null:e.roblox.assetId??null}function za(e){const a=Wa(e),d=a?Ga(a):null,n=e.category==="decal"?e.roblox.creatorAssetWebUrl??e.roblox.assetWebUrl:e.roblox.assetWebUrl;return!n||d&&Oa.test(n)?d:n}function Va(e){return`${je(e.startedAt)} -> ${e.status}`}function Ge(e){return!e.creatorType||!e.creatorId?null:`${e.creatorType} ${e.creatorId}`}function We(e){return e.assetRole?`Asset role: ${e.assetRole}`:null}function fe({label:e,value:a}){return a?t.jsx("button",{type:"button",className:s.inlineCopyButton,"aria-label":e,title:e,onClick:()=>{var d;return void((d=navigator.clipboard)==null?void 0:d.writeText(a))},children:t.jsx(Qe,{size:13})}):null}function Ya({asset:e,busyAction:a,canUpload:d,canImportRbxm:n,importRbxmTooltip:r,importRbxmTargetParent:N,onClose:v,onSave:E,onUpload:p,onDelete:V,onImportRbxm:Y,onRefreshStatus:U,onScanUsage:g}){var k,S;const{t:l}=he(),X=i.useRef(null),[G,W]=i.useState(""),[M,Z]=i.useState("");if(i.useEffect(()=>{W((e==null?void 0:e.displayName)??""),Z((e==null?void 0:e.description)??"")},[e==null?void 0:e.description,e==null?void 0:e.displayName,e==null?void 0:e.id]),i.useEffect(()=>{var j;if(!e)return;(j=X.current)==null||j.focus();const o=L=>{L.key==="Escape"&&v()};return document.addEventListener("keydown",o),()=>document.removeEventListener("keydown",o)},[e,v]),!e)return null;const T=e.status==="processing"&&!!(e.roblox.operationId??e.roblox.operationPath),Q=!!e.roblox.assetUri,$=za(e),ee=e.roblox.uploadAttempts??[],O=e.category==="decal"&&!!(e.roblox.creatorAssetId||e.roblox.backingImageAssetId||e.roblox.assetId),y=e.roblox.creatorAssetId??e.roblox.assetId,x=e.roblox.backingImageAssetId??e.roblox.assetId,I=e.roblox.assetId?e.usage.lastScannedAt?l("assets.detail.noUsageAfterScan","No references were found in local Sync files during the last check."):l("assets.detail.noUsageUnscanned","Run Scan usage to search local Sync files for this Roblox Asset ID."):l("assets.detail.noUsageNoRobloxId","This asset does not have a Roblox Asset ID yet, so usage cannot be checked. Upload it before scanning usage.");return t.jsx("div",{className:s.detailPopupLayer,onClick:v,role:"presentation",children:t.jsxs("section",{ref:X,className:s.detailDialog,role:"dialog","aria-modal":"true","aria-label":l("assets.detail.title","Asset details"),tabIndex:-1,onClick:o=>o.stopPropagation(),children:[t.jsxs("div",{className:s.detailDialogHeader,children:[t.jsxs("div",{className:s.detailTitleBlock,children:[t.jsxs("span",{className:s.detailEyebrow,children:[ie(e,l)," · ",Be(e.status,l)]}),t.jsx("h2",{children:e.displayName}),t.jsx("span",{children:e.id})]}),t.jsxs("div",{className:s.detailHeaderActions,children:[t.jsx(K,{text:d?l("assets.upload.open.tooltip","Upload this local file to Roblox through Open Cloud."):l("assets.proOnly.tooltip","Roblox upload is available on Pro."),children:t.jsxs("button",{type:"button",className:s.commandButton,disabled:!d,onClick:p,children:[t.jsx(Dt,{size:15}),l("assets.upload.open","Upload")]})}),n&&t.jsx(K,{text:r,children:t.jsxs("button",{type:"button",className:s.commandButton,disabled:a==="import-rbxm",onClick:()=>void Y(),children:[t.jsx(pt,{size:15}),l("assets.detail.importRbxm","Insert into Studio")]})}),t.jsxs("button",{type:"button",className:s.commandButton,disabled:!T||a==="status-refresh",onClick:()=>void U(),children:[t.jsx(qe,{size:15}),l("assets.detail.refreshStatus","Refresh")]}),t.jsxs("button",{type:"button",className:s.commandButton,disabled:!e.roblox.assetId||a==="usage-scan",onClick:()=>void g(),children:[t.jsx(wt,{size:15}),l("assets.detail.scanUsage","Scan usage")]}),t.jsx(K,{text:l("assets.delete.tooltip","Delete this local Asset Library item."),children:t.jsxs("button",{type:"button",className:`${s.commandButton} ${s.dangerButton}`,disabled:a==="delete",onClick:V,children:[t.jsx($t,{size:15}),l("common.delete","Delete")]})}),t.jsx(K,{text:l("common.close","Close"),children:t.jsx("button",{type:"button",className:s.iconButton,onClick:v,"aria-label":l("common.close","Close"),children:t.jsx(De,{size:16})})})]})]}),t.jsxs("div",{className:s.detailDialogBody,children:[t.jsx("div",{className:s.detailPreviewPane,children:Ma(e)?t.jsx("img",{className:s.detailPreview,src:Ha(e),alt:e.displayName}):t.jsxs("div",{className:s.detailPreviewFallback,children:[t.jsx("span",{children:ie(e,l)}),t.jsx("code",{children:e.file.original}),((k=e.rbxm)==null?void 0:k.thumbnail)&&t.jsx("small",{children:Me(e)})]})}),t.jsxs("div",{className:s.detailContentPane,children:[t.jsxs("div",{className:s.formStack,children:[t.jsxs("label",{className:s.field,children:[t.jsx("span",{children:l("assets.detail.displayName","Display name")}),t.jsx("input",{value:G,onChange:o=>W(o.target.value)})]}),t.jsxs("label",{className:s.field,children:[t.jsx("span",{children:l("assets.detail.description","Description")}),t.jsx("textarea",{value:M,rows:3,onChange:o=>Z(o.target.value)})]}),t.jsx("button",{type:"button",className:s.primaryButton,disabled:a==="update",onClick:()=>void E(G,M),children:l("assets.detail.save","Save metadata")})]}),t.jsxs("section",{className:s.detailSection,children:[t.jsx("h3",{children:l("assets.detail.localFile","Local file")}),t.jsxs("dl",{className:s.detailGrid,children:[t.jsx("dt",{children:l("assets.detail.fileName","File")}),t.jsx("dd",{children:e.file.original}),t.jsx("dt",{children:l("assets.detail.source","Source path")}),t.jsx("dd",{children:e.source.originalPath}),t.jsx("dt",{children:l("assets.detail.category","Category")}),t.jsx("dd",{children:ie(e,l)}),t.jsx("dt",{children:l("assets.detail.scope","Scope")}),t.jsx("dd",{children:e.scope.kind==="shared"?l("assets.scope.shared","Shared"):l("assets.scope.place","Current Place")}),t.jsx("dt",{children:l("assets.detail.mimeType","Type")}),t.jsx("dd",{children:e.file.mimeType}),t.jsx("dt",{children:l("assets.detail.size","Size")}),t.jsx("dd",{children:Fa(e.file.sizeBytes)}),He(e)&&t.jsxs(t.Fragment,{children:[t.jsx("dt",{children:l("assets.detail.dimensions","Dimensions")}),t.jsx("dd",{children:He(e)})]}),Ke(e)&&t.jsxs(t.Fragment,{children:[t.jsx("dt",{children:l("assets.detail.duration","Duration")}),t.jsx("dd",{children:Ke(e)})]})]})]}),e.rbxm&&t.jsxs("section",{className:s.detailSection,children:[t.jsx("h3",{children:l("assets.detail.rbxm","RBXM contents")}),t.jsxs("dl",{className:s.detailGrid,children:[t.jsx("dt",{children:l("assets.detail.rbxmExportedCount","Exported roots")}),t.jsx("dd",{children:e.rbxm.exportedCount}),t.jsx("dt",{children:l("assets.detail.rbxmClasses","Classes")}),t.jsx("dd",{children:Ka(e)}),t.jsx("dt",{children:l("assets.detail.rbxmThumbnail","Thumbnail")}),t.jsx("dd",{children:Me(e)}),n&&t.jsxs(t.Fragment,{children:[t.jsx("dt",{children:l("assets.detail.studioInsertTarget","Studio insert target")}),t.jsx("dd",{children:N})]})]}),e.rbxm.roots.length>0&&t.jsxs("div",{className:s.metadataList,children:[t.jsx("strong",{children:l("assets.detail.rbxmRoots","Root tree")}),e.rbxm.roots.map(o=>t.jsxs("div",{className:s.metadataItem,children:[t.jsxs("span",{children:[o.name," (",o.className,")"]}),t.jsx("code",{children:o.path})]},`${o.path}-${o.className}`))]}),e.rbxm.resourceReferences.length>0&&t.jsxs("div",{className:s.metadataList,children:[t.jsx("strong",{children:l("assets.detail.rbxmReferences","Asset references")}),e.rbxm.resourceReferences.map((o,j)=>t.jsxs("div",{className:s.metadataItem,children:[t.jsxs("span",{children:[o.path," · ",o.property]}),t.jsx("code",{children:o.assetId?`${o.value} (#${o.assetId})`:o.value})]},`${o.path}-${o.property}-${j}`))]})]}),t.jsxs("section",{className:s.detailSection,children:[t.jsx("h3",{children:l("assets.detail.roblox","Roblox upload status")}),t.jsxs("dl",{className:s.detailGrid,children:[t.jsx("dt",{children:l("assets.detail.status","Status")}),t.jsx("dd",{children:Be(e.status,l)}),O?t.jsxs(t.Fragment,{children:[t.jsx("dt",{children:l("assets.detail.decalAssetId","Roblox Decal ID")}),t.jsxs("dd",{className:s.copyableValue,children:[t.jsx("span",{children:y??l("assets.status.localOnly","Local only")}),t.jsx(fe,{label:l("assets.detail.copyDecalAssetId","Copy Roblox Decal ID"),value:y})]}),t.jsx("dt",{children:l("assets.detail.studioTextureImageId","Studio Texture Image ID")}),t.jsxs("dd",{className:s.copyableValue,children:[t.jsx("span",{children:x??"-"}),t.jsx(fe,{label:l("assets.detail.copyStudioTextureImageId","Copy Studio Texture Image ID"),value:x})]})]}):t.jsxs(t.Fragment,{children:[t.jsx("dt",{children:l("assets.detail.assetId","Asset ID")}),t.jsxs("dd",{className:s.copyableValue,children:[t.jsx("span",{children:e.roblox.assetId??l("assets.status.localOnly","Local only")}),t.jsx(fe,{label:l("assets.detail.copyAssetId","Copy Asset ID"),value:e.roblox.assetId})]})]}),t.jsx("dt",{children:l("assets.detail.studioUri","Studio URI")}),t.jsx("dd",{children:e.roblox.assetUri??"-"}),t.jsx("dt",{children:l("assets.detail.robloxWebUrl","Creator Dashboard URL")}),t.jsxs("dd",{className:s.copyableValue,children:[t.jsx("span",{children:$??"-"}),t.jsx(fe,{label:l("assets.detail.copyWebUrl","Copy configure URL"),value:$})]}),e.roblox.errorMessage&&t.jsxs(t.Fragment,{children:[t.jsx("dt",{children:l("assets.detail.error","Error")}),t.jsx("dd",{children:e.roblox.errorMessage})]})]}),t.jsxs("div",{className:s.copyRow,children:[t.jsxs("button",{type:"button",className:s.commandButton,disabled:!Q,onClick:()=>{var o;return e.roblox.assetUri&&void((o=navigator.clipboard)==null?void 0:o.writeText(e.roblox.assetUri))},children:[t.jsx(Qe,{size:15}),l("assets.detail.copyStudioUri","Copy Studio URI")]}),$&&t.jsxs("a",{className:s.commandButton,href:$,target:"_blank",rel:"noreferrer",children:[t.jsx(ht,{size:15}),l("assets.detail.openRobloxPage","Open configure page")]})]}),e.roblox.assetId&&t.jsx("p",{className:s.muted,children:l("assets.detail.robloxWebUrlNotice","Opening this page requires the Roblox account that owns or can manage the uploaded asset.")}),ee.length>0&&t.jsxs("div",{className:s.metadataList,children:[t.jsx("strong",{children:l("assets.detail.uploadHistory","Upload history")}),ee.slice().reverse().map((o,j)=>t.jsxs("div",{className:s.metadataItem,children:[t.jsx("span",{children:Va(o)}),Ge(o)&&t.jsx("code",{children:Ge(o)}),We(o)&&t.jsx("code",{children:We(o)}),o.operationPath&&t.jsx("code",{children:o.operationPath}),o.assetId&&t.jsxs("code",{children:[l("assets.detail.assetId","Asset ID"),": ",o.assetId]}),o.remotePath&&t.jsx("code",{children:o.remotePath}),o.message&&t.jsx("code",{children:o.message}),o.errorMessage&&t.jsx("code",{children:o.errorMessage})]},`${o.startedAt}-${o.operationPath??j}`))]})]}),t.jsxs("section",{className:s.detailSection,children:[t.jsx("h3",{children:l("assets.detail.usedInPlace","Where this asset is used in this Place")}),t.jsxs("dl",{className:s.detailGrid,children:[t.jsx("dt",{children:l("assets.detail.usageSource","Checked against")}),t.jsx("dd",{children:e.usage.scanSource==="localSync"?l("assets.detail.usageSource.localSync","Local Sync files"):l("assets.detail.usageSource.notScanned","Not checked yet")}),t.jsx("dt",{children:l("assets.detail.lastScanned","Last checked")}),t.jsx("dd",{children:e.usage.lastScannedAt?l("assets.detail.lastScannedAt","Last checked: {time}").replace("{time}",je(e.usage.lastScannedAt)):l("assets.detail.lastScanned.never","No check yet")})]}),e.usage.references.length===0?t.jsx("p",{className:s.muted,children:I}):t.jsx("div",{className:s.usageList,children:e.usage.references.map((o,j)=>t.jsxs("div",{className:s.usageItem,children:[t.jsx("strong",{children:o.kind==="property"?o.instancePath:o.filePath}),t.jsx("span",{children:o.property??l("assets.detail.line","line {line}").replace("{line}",String(o.line??"-"))}),t.jsx("code",{children:o.value})]},`${o.kind}-${j}`))})]}),t.jsxs("details",{className:s.technicalDetails,children:[t.jsx("summary",{children:l("assets.detail.technicalDetails","Technical details")}),t.jsxs("dl",{className:s.detailGrid,children:[t.jsx("dt",{children:l("assets.detail.stableId","Stable ID")}),t.jsx("dd",{className:s.hashText,children:e.id}),t.jsx("dt",{children:l("assets.detail.sourceKind","Source kind")}),t.jsx("dd",{children:e.source.kind}),t.jsx("dt",{children:l("assets.detail.sha256","SHA-256")}),t.jsx("dd",{className:s.hashText,children:e.file.sha256}),t.jsx("dt",{children:l("assets.detail.createdAt","Created")}),t.jsx("dd",{children:je(e.createdAt)}),t.jsx("dt",{children:l("assets.detail.updatedAt","Updated")}),t.jsx("dd",{children:je(e.updatedAt)}),e.roblox.operationId&&t.jsxs(t.Fragment,{children:[t.jsx("dt",{children:l("assets.detail.operationId","Operation ID")}),t.jsx("dd",{className:s.hashText,children:e.roblox.operationId})]}),e.roblox.operationPath&&t.jsxs(t.Fragment,{children:[t.jsx("dt",{children:l("assets.detail.operationPath","Operation path")}),t.jsx("dd",{className:s.hashText,children:e.roblox.operationPath})]}),e.roblox.versionId&&t.jsxs(t.Fragment,{children:[t.jsx("dt",{children:l("assets.detail.versionId","Version ID")}),t.jsx("dd",{className:s.hashText,children:e.roblox.versionId})]}),e.roblox.remotePath&&t.jsxs(t.Fragment,{children:[t.jsx("dt",{children:l("assets.detail.remotePath","Remote path")}),t.jsx("dd",{className:s.hashText,children:e.roblox.remotePath})]}),e.roblox.moderationState&&t.jsxs(t.Fragment,{children:[t.jsx("dt",{children:l("assets.detail.moderationState","Moderation")}),t.jsx("dd",{children:e.roblox.moderationState})]})]}),((S=e.rbxm)==null?void 0:S.thumbnail.attempts)&&e.rbxm.thumbnail.attempts.length>0&&t.jsxs("div",{className:s.metadataList,children:[t.jsx("strong",{children:l("assets.detail.rbxmThumbnailAttempts","Thumbnail attempts")}),e.rbxm.thumbnail.attempts.map((o,j)=>t.jsxs("div",{className:s.metadataItem,children:[t.jsxs("span",{children:[o.method," · ",o.status]}),o.message&&t.jsx("code",{children:o.message})]},`${o.method}-${j}`))]})]})]})]})]})})}function nt(e){return{assetUploadByOpenCloudEnabled:e.hot.ENABLE_ASSET_UPLOAD_BY_OPEN_CLOUD===!0}}function Xa(e){const a={};return typeof e.assetUploadByOpenCloudEnabled=="boolean"&&(a.ENABLE_ASSET_UPLOAD_BY_OPEN_CLOUD=e.assetUploadByOpenCloudEnabled),a}async function ot(){const e=await R.get("/api/dashboard/settings");return nt(e)}async function qa(e){const a=await R.patch("/api/dashboard/settings",Xa(e));return nt(a)}async function lt(){return R.get("/api/dashboard/open-cloud/credential-profiles")}async function Za(e){return R.post("/api/dashboard/open-cloud/credential-profiles",e)}async function Ja(e){return R.patch("/api/dashboard/open-cloud/credential-profiles/active",{profileId:e})}async function Qa(e,a){return R.put(`/api/dashboard/open-cloud/credential-profiles/${encodeURIComponent(e)}/api-key`,a)}async function en(e){return R.delete(`/api/dashboard/open-cloud/credential-profiles/${encodeURIComponent(e)}`)}async function tn(e,a){return R.post(`/api/dashboard/open-cloud/credential-profiles/${encodeURIComponent(e)}/creators`,a)}async function sn(e,a){return R.patch(`/api/dashboard/open-cloud/credential-profiles/${encodeURIComponent(e)}/creators/${encodeURIComponent(a)}/default`,{})}async function an(e,a){return R.delete(`/api/dashboard/open-cloud/credential-profiles/${encodeURIComponent(e)}/creators/${encodeURIComponent(a)}`)}async function nn(e,a){return R.post(`/api/dashboard/open-cloud/credential-profiles/${encodeURIComponent(e)}/test`,a?{creatorPresetId:a}:{})}async function on(e){return R.post("/api/dashboard/open-cloud/credential/test",e?{apiKey:e}:{})}function ln(e){return e.category==="image"||e.category==="decal"}function rn(e,a){return e==="group"?a("assets.creator.group","Group"):a("assets.creator.user","User")}function cn(e,a){return`${e.label} · ${rn(e.creatorType,a)} ${e.creatorId}`}function ze(e){if(!e)return null;if(e.defaultCreatorId){const a=e.creators.find(d=>d.id===e.defaultCreatorId);if(a)return a}return e.creators[0]??null}function dn({asset:e,open:a,canUpload:d,busyAction:n,onClose:r,onBack:N,onOpenSettings:v,onUpload:E}){const{t:p}=he(),V=i.useRef(null),[Y,U]=i.useState(null),[g,l]=i.useState(null),[X,G]=i.useState(!1),[W,M]=i.useState(null),[Z,T]=i.useState(""),[Q,$]=i.useState(""),[ee,O]=i.useState(""),[y,x]=i.useState("user"),[I,k]=i.useState("");if(i.useEffect(()=>{T((e==null?void 0:e.displayName)??""),$((e==null?void 0:e.description)??"")},[e==null?void 0:e.description,e==null?void 0:e.displayName,e==null?void 0:e.id]),i.useEffect(()=>{if(!a)return;let m=!1;return G(!0),M(null),(async()=>{try{const[w,D]=await Promise.all([ot(),lt()]);if(m)return;U(w);const F=D.profiles.find(de=>de.id===D.activeProfileId)??D.profiles[0]??null;l(F);const J=ze(F);O((J==null?void 0:J.id)??""),x((J==null?void 0:J.creatorType)??"user"),k((J==null?void 0:J.creatorId)??"")}catch(w){if(m)return;M(w instanceof Error?w.message:p("assets.upload.settingsLoadFailed","Failed to load upload settings.")),U(null),l(null)}finally{m||G(!1)}})(),()=>{m=!0}},[a,p]),i.useEffect(()=>{var w;if(!a||!e)return;(w=V.current)==null||w.focus();const m=D=>{D.key==="Escape"&&r()};return document.addEventListener("keydown",m),()=>document.removeEventListener("keydown",m)},[e,r,a]),!a||!e)return null;const S=(Y==null?void 0:Y.assetUploadByOpenCloudEnabled)===!0,o=!!g,j=ze(g),L=(g==null?void 0:g.creators.find(m=>m.id===ee))??null,ae=!!j,B=(g==null?void 0:g.storageProvider)==="env"&&o&&!ae,H=B&&I.trim().length>0,h=d&&!X&&!W&&(!S||!o||!ae&&!B),te=d&&!X&&!W&&S&&o&&(ae||H)&&n!=="upload";return t.jsx("div",{className:s.detailPopupLayer,onClick:r,role:"presentation",children:t.jsxs("section",{ref:V,className:s.detailDialog,role:"dialog","aria-modal":"true","aria-label":p("assets.upload.title","Upload asset"),tabIndex:-1,onClick:m=>m.stopPropagation(),children:[t.jsxs("div",{className:s.detailDialogHeader,children:[t.jsxs("div",{className:s.detailTitleBlock,children:[t.jsxs("span",{className:s.detailEyebrow,children:[ie(e,p)," · ",p("assets.upload.intent","Upload to Roblox")]}),t.jsx("h2",{children:p("assets.upload.title","Upload asset")}),t.jsx("span",{children:e.displayName})]}),t.jsxs("div",{className:s.detailHeaderActions,children:[t.jsxs("button",{type:"button",className:s.commandButton,onClick:N,children:[t.jsx(yt,{size:15}),p("assets.upload.backToDetails","Back to details")]}),t.jsx(K,{text:p("common.close","Close"),children:t.jsx("button",{type:"button",className:s.iconButton,onClick:r,"aria-label":p("common.close","Close"),children:t.jsx(De,{size:16})})})]})]}),t.jsxs("div",{className:s.detailDialogBody,children:[t.jsx("div",{className:s.detailPreviewPane,children:ln(e)?t.jsx("img",{className:s.detailPreview,src:tt(e),alt:e.displayName}):t.jsxs("div",{className:s.detailPreviewFallback,children:[t.jsx("span",{children:ie(e,p)}),t.jsx("code",{children:e.file.original})]})}),t.jsxs("div",{className:s.detailContentPane,children:[!d&&t.jsx("div",{className:s.notice,children:p("assets.proOnly.upload","Roblox upload is available on Pro.")}),X&&t.jsx("div",{className:s.notice,children:p("assets.upload.checkingSettings","Checking upload settings...")}),W&&t.jsx("div",{className:s.errorState,children:W}),t.jsxs("dl",{className:s.compactMeta,children:[t.jsx("dt",{children:p("assets.detail.category","Category")}),t.jsx("dd",{children:ie(e,p)}),t.jsx("dt",{children:p("assets.detail.source","Source")}),t.jsx("dd",{children:e.source.originalPath})]}),h&&t.jsxs("div",{className:s.setupNotice,children:[t.jsx("strong",{children:p("assets.upload.settingsRequired","Upload settings required")}),t.jsx("p",{children:o?S?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.")}),t.jsxs("button",{type:"button",className:s.commandButton,onClick:v,children:[t.jsx(Ze,{size:15}),p("assets.upload.openSettings","Open Asset Library settings")]})]}),t.jsxs("div",{className:s.formStack,children:[t.jsxs("label",{className:s.field,children:[t.jsx("span",{children:p("assets.detail.displayName","Display name")}),t.jsx("input",{value:Z,disabled:!d,onChange:m=>T(m.target.value)}),t.jsx("small",{className:s.fieldHelp,children:p("assets.upload.displayNameHelp","Saved to Roblox as the asset display name.")})]}),t.jsxs("label",{className:s.field,children:[t.jsx("span",{children:p("assets.detail.description","Description")}),t.jsx("textarea",{value:Q,rows:3,disabled:!d,onChange:m=>$(m.target.value)}),t.jsx("small",{className:s.fieldHelp,children:p("assets.upload.descriptionHelp","Saved to Roblox as the asset description.")})]}),ae&&t.jsxs("label",{className:s.field,children:[t.jsx("span",{children:p("assets.upload.creator","Creator")}),t.jsx("select",{"aria-label":p("assets.upload.creator","Creator"),value:ee,disabled:!d||X,onChange:m=>O(m.target.value),children:g==null?void 0:g.creators.map(m=>t.jsx("option",{value:m.id,children:cn(m,p)},m.id))}),t.jsx("small",{className:s.fieldHelp,children:p("assets.upload.creatorHelp","Used by Open Cloud as the owner of the uploaded asset.")})]}),B&&t.jsxs(t.Fragment,{children:[t.jsx("p",{className:s.inlineHelp,children:p("assets.upload.envCreatorHelp","Environment API keys cannot save a default Creator here. Enter the Creator for this upload.")}),t.jsxs("div",{className:s.twoColumn,children:[t.jsxs("label",{className:s.field,children:[t.jsx("span",{children:p("assets.upload.creatorType","Creator type")}),t.jsxs("select",{value:y,disabled:!d,onChange:m=>x(m.target.value),children:[t.jsx("option",{value:"user",children:p("assets.creator.user","User")}),t.jsx("option",{value:"group",children:p("assets.creator.group","Group")})]}),t.jsx("small",{className:s.fieldHelp,children:p("assets.upload.creatorTypeHelp","Sent to Open Cloud as the Creator type.")})]}),t.jsxs("label",{className:s.field,children:[t.jsx("span",{children:p("assets.upload.creatorId","Creator ID")}),t.jsx("input",{value:I,disabled:!d,onChange:m=>k(m.target.value)}),t.jsx("small",{className:s.fieldHelp,children:p("assets.upload.creatorIdHelp","Sent to Open Cloud as the User or Group ID that owns the uploaded asset.")})]})]})]}),t.jsx("button",{type:"button",className:s.primaryButton,disabled:!te,onClick:()=>{const m=I.trim(),w=B&&m?{creatorType:y,creatorId:m}:{},D=!B&&L&&j&&L.id!==j.id?{creatorType:L.creatorType,creatorId:L.creatorId}:{};E({displayName:Z,description:Q,...w,...D})},children:n==="upload"?p("assets.upload.uploading","Uploading..."):p("assets.upload.submit","Upload with Roblox Open Cloud")})]}),t.jsxs("div",{className:s.noticeList,children:[t.jsx("p",{children:p("assets.upload.noDelete","WEPPY does not provide Roblox asset deletion.")}),t.jsx("p",{children:p("assets.upload.delay","Roblox processing and moderation can delay visibility in Studio or Creator Dashboard.")})]})]})]})]})})}function Ve(e,a){return e==="env"?a("assets.settings.credential.env","Environment variable"):a("assets.settings.credential.local","Local encrypted file")}function Pe(e,a){return e==="valid"?a("assets.settings.validation.valid","Connected"):e==="invalid"?a("assets.settings.validation.invalid","Needs attention"):a("assets.settings.validation.unknown","Not tested")}function un(e,a){return(e==null?void 0:e.status)==="valid"?a("assets.settings.apiKeyTested","Open Cloud API key connection tested."):(e==null?void 0:e.message)??a("assets.settings.tested","Connection tested.")}function pn(e,a){return(e==null?void 0:e.status)==="valid"?a("assets.settings.apiKeyTested","Open Cloud API key connection tested."):(e==null?void 0:e.message)??a("assets.settings.tested","Connection tested.")}function hn(e,a){return e==="group"?a("assets.creator.group","Group"):a("assets.creator.user","User")}function mn(e,a){return`${hn(e.creatorType,a)} ${e.creatorId}`}function gn({open:e,tier:a,onClose:d}){const{t:n}=he(),[r,N]=i.useState(null),[v,E]=i.useState(null),[p,V]=i.useState(""),[Y,U]=i.useState(!1),[g,l]=i.useState(""),[X,G]=i.useState(""),[W,M]=i.useState("user"),[Z,T]=i.useState(""),[Q,$]=i.useState(""),[ee,O]=i.useState(!0),[y,x]=i.useState(null),[I,k]=i.useState(null),[S,o]=i.useState(!1),j=a==="basic",L=i.useCallback(async()=>{o(!0),x(null);try{const[u,_]=await Promise.all([ot(),lt()]);N(u),E(_);const P=_.profiles.find(le=>le.id===_.activeProfileId)??_.profiles[0]??null;V((P==null?void 0:P.id)??""),U(!P),O(!P||P.creators.length===0),M("user"),T(""),$("")}catch(u){x(u instanceof Error?u.message:n("assets.settings.loadFailed","Failed to load upload settings."))}finally{o(!1)}},[n]);if(i.useEffect(()=>{e&&L()},[L,e]),!e)return null;const ae=(r==null?void 0:r.assetUploadByOpenCloudEnabled)===!0,q=X.trim(),B=Z.trim(),H=(v==null?void 0:v.profiles)??[],h=H.find(u=>u.id===p)??H[0]??null,te=!!h,m=te&&(h==null?void 0:h.storageProvider)==="localFile",w=te&&(h==null?void 0:h.storageProvider)==="env",D=h!=null&&h.defaultCreatorId?h.creators.find(u=>u.id===h.defaultCreatorId):h==null?void 0:h.creators[0],F=!!(h!=null&&h.creators.length),J=!F||ee,de=H.length>1,oe=j?n("assets.settings.action.proRequired","Asset upload settings are available on Pro."):S?n("assets.settings.action.busy","Wait for the current settings action to finish."):null,_e=j||S||!q,Se=oe??(q?n("assets.settings.saveApiKey.tooltip.ready","Save this API key to local encrypted storage."):n("assets.settings.saveApiKey.tooltip.enter","Enter an Open Cloud API key to save it locally.")),me=j||S||!q&&!te,ge=oe??(q?n("assets.settings.testConnection.tooltip.entered","Test the entered API key before saving it."):te?n("assets.settings.testConnection.tooltip.saved","Test the saved Open Cloud API key."):n("assets.settings.testConnection.tooltip.enterOrSaved","Enter an API key or save one before testing the connection.")),xe=j||S||!m,be=oe??(m?n("assets.settings.removeApiKey.tooltip.ready","Remove the locally saved Open Cloud API key."):w?n("assets.settings.removeApiKey.tooltip.env","Environment API keys cannot be removed from Dashboard. Remove ROBLOX_OPEN_CLOUD_API_KEY outside WEPPY."):n("assets.settings.removeApiKey.tooltip.none","No local Open Cloud API key is saved.")),Ae=j||S||!m||!B,Ie=oe??(w?n("assets.settings.saveCreator.tooltip.env","Environment API keys cannot save a default Creator here. Enter Creator details in the upload dialog."):m?B?n("assets.settings.saveCreator.tooltip.ready","Save this Creator as the default owner for uploads."):n("assets.settings.saveCreator.tooltip.enterId","Enter a user or group ID before saving the default Creator."):n("assets.settings.saveCreator.tooltip.noLocal","Save a local Open Cloud API key before saving a default Creator.")),Ne=oe??(m?n("assets.settings.addCreator.tooltip.ready","Add another User or Group Creator preset to this profile."):n("assets.settings.saveCreator.tooltip.noLocal","Save a local Open Cloud API key before saving a default Creator.")),c=j||S||w||!m,b=oe??(m?n("assets.settings.unregisterCreator.tooltip.ready","Unregister this Creator from the selected profile."):w?n("assets.settings.saveCreator.tooltip.env","Environment API keys cannot save a default Creator here. Enter Creator details in the upload dialog."):n("assets.settings.saveCreator.tooltip.noLocal","Save a local Open Cloud API key before saving a default Creator.")),f=D?n("assets.settings.saveCreatorPreset","Save Creator"):n("assets.settings.saveCreator","Save default Creator"),C=(h==null?void 0:h.label)??n("assets.settings.credential.none","No API key saved"),A=u=>{const _=u.profiles.find(P=>P.id===u.activeProfileId)??u.profiles[0]??null;E(u),V((_==null?void 0:_.id)??""),O(!_||_.creators.length===0),U(u.profiles.length===0)},z=async()=>{if(h){o(!0);try{const u=await nn(h.id,D==null?void 0:D.id);A(u),x(pn(u.validation,n))}catch(u){x(u instanceof Error?u.message:n("assets.settings.testFailed","Connection test failed."))}finally{o(!1)}}},ue=async()=>{if(I){o(!0);try{if(I.kind==="apiKey"){const u=await en(I.profileId);A(u),x(n("assets.settings.apiKeyRemoved","Open Cloud API key unregistered from local storage."))}else{const u=await an(I.profileId,I.creatorPresetId);A(u),x(n("assets.settings.creatorUnregistered","Creator unregistered from this profile."))}k(null)}catch(u){x(u instanceof Error?u.message:I.kind==="apiKey"?n("assets.settings.removeFailed","Failed to unregister API key."):n("assets.settings.creatorUnregisterFailed","Failed to unregister Creator."))}finally{o(!1)}}},rt=(I==null?void 0:I.kind)==="apiKey"?n("assets.settings.unregisterApiKey.title","Unregister API Key?"):n("assets.settings.unregisterCreator.title","Unregister Creator?"),it=(I==null?void 0:I.kind)==="apiKey"?n("assets.settings.unregisterApiKey.message","Roblox API key is not revoked. WEPPY only removes the local Credential Profile registration on this device."):n("assets.settings.unregisterCreator.message","Roblox user or group is not deleted. WEPPY only removes this Creator from the selected API Key profile."),ct=(I==null?void 0:I.kind)==="apiKey"?n("assets.settings.removeApiKey","Unregister API Key"):n("assets.settings.unregisterCreator","Unregister Creator");return t.jsxs("section",{id:"asset-library-settings-panel",className:`${s.settingsInlinePanel} ${s.settingsDrawer}`,role:"region","aria-label":n("assets.settings.title","Asset Library settings"),"data-panel-placement":"toolbar-popover",children:[t.jsxs("div",{className:s.drawerHeader,children:[t.jsxs("div",{children:[t.jsx("h2",{children:n("assets.settings.title","Asset Library settings")}),t.jsx("span",{children:C})]}),t.jsx(K,{text:n("common.close","Close"),children:t.jsx("button",{type:"button",className:s.iconButton,onClick:d,"aria-label":n("common.close","Close"),children:t.jsx(De,{size:16})})})]}),j&&t.jsx("div",{className:`${s.notice} ${s.proNotice}`,children:n("assets.settings.proOnly","Roblox upload settings and Open Cloud credential controls are available on Pro.")}),t.jsxs("section",{className:s.settingsPanel,children:[t.jsxs("label",{className:s.toggleRow,children:[t.jsxs("span",{children:[t.jsx("strong",{children:n("assets.settings.openCloudToggle","Open Cloud upload")}),t.jsx("small",{children:n("assets.settings.openCloudToggle.help","Controls whether server-side Open Cloud upload mutations can run.")})]}),t.jsx("input",{type:"checkbox",checked:ae,disabled:j||S,onChange:u=>{(async()=>{o(!0);try{const _=await qa({assetUploadByOpenCloudEnabled:u.target.checked});N(_),x(n("assets.settings.saved","Upload settings saved."))}catch(_){x(_ instanceof Error?_.message:n("assets.settings.saveFailed","Failed to save upload settings."))}finally{o(!1)}})()}})]}),de&&t.jsx("div",{className:s.metadataList,children:H.map(u=>{const _=u.id===(h==null?void 0:h.id);return t.jsxs("div",{className:s.metadataItem,children:[t.jsx("strong",{children:u.label}),t.jsxs("span",{children:[n("assets.settings.field.storage","Storage"),": ",Ve(u.storageProvider,n)]}),t.jsxs("span",{children:[n("assets.settings.field.validationStatus","Validation status"),": ",Pe(u.validationStatus,n)]}),_&&t.jsx("code",{children:n("assets.settings.activeProfileBadge","Active")}),!_&&u.storageProvider==="localFile"&&t.jsx("button",{type:"button",className:s.commandButton,disabled:j||S,onClick:()=>{(async()=>{o(!0);try{const P=await Ja(u.id),le=P.profiles.find(ke=>ke.id===(P.activeProfileId??u.id))??u;E(P),V(le.id),O(le.creators.length===0),M("user"),T(""),$(""),x(n("assets.settings.profileSelected","Open Cloud credential profile selected."))}catch(P){x(P instanceof Error?P.message:n("assets.settings.saveFailed","Failed to save upload settings."))}finally{o(!1)}})()},children:n("assets.settings.useProfile","Use profile")})]},u.id)})}),h&&t.jsxs("div",{className:s.settingsSubsection,children:[t.jsx("div",{className:s.settingsSectionHeader,children:t.jsx("h3",{children:n("assets.settings.credentialProfile","Credential Profile")})}),t.jsxs("div",{className:s.metadataItem,children:[t.jsxs("dl",{className:s.settingsDefinitionList,children:[t.jsxs("div",{children:[t.jsx("dt",{children:n("assets.settings.field.profile","Profile")}),t.jsx("dd",{children:h.label})]}),h.maskedKey&&t.jsxs("div",{children:[t.jsx("dt",{children:n("assets.settings.field.apiKey","API Key")}),t.jsx("dd",{children:h.maskedKey})]}),t.jsxs("div",{children:[t.jsx("dt",{children:n("assets.settings.field.storage","Storage")}),t.jsx("dd",{children:Ve(h.storageProvider,n)})]}),t.jsxs("div",{children:[t.jsx("dt",{children:n("assets.settings.field.validationStatus","Validation status")}),t.jsx("dd",{children:Pe(h.validationStatus,n)})]}),t.jsxs("div",{children:[t.jsx("dt",{children:n("assets.settings.field.creators","Creators")}),t.jsx("dd",{children:h.creators.length})]})]}),!Y&&t.jsxs("div",{className:s.buttonRow,children:[t.jsx(K,{text:ge,children:t.jsx("button",{type:"button",className:s.commandButton,disabled:me,onClick:()=>{z()},children:n("assets.settings.testConnection","Test Connection")})}),m&&t.jsx("button",{type:"button",className:s.commandButton,disabled:j||S,onClick:()=>U(!0),children:n("assets.settings.replaceApiKey","Replace API Key")}),t.jsx(K,{text:be,children:t.jsx("button",{type:"button",className:`${s.commandButton} ${s.dangerButton}`,disabled:xe,onClick:()=>k({kind:"apiKey",profileId:h.id}),children:n("assets.settings.removeApiKey","Unregister API Key")})})]})]})]}),Y&&t.jsxs("div",{className:s.formStack,children:[t.jsxs("div",{className:s.field,children:[t.jsx("div",{className:s.fieldLabelRow,children:t.jsx("label",{htmlFor:"asset-settings-open-cloud-profile-label",children:n("assets.settings.profileLabel","Profile name")})}),t.jsx("input",{id:"asset-settings-open-cloud-profile-label",value:g,disabled:j||S,onChange:u=>l(u.target.value),placeholder:n("assets.settings.profileLabel.placeholder","Studio automation key")}),t.jsx("p",{className:s.inlineHelp,children:n("assets.settings.profileLabel.help","Optional. If left blank, WEPPY saves this profile as Open Cloud key automatically.")})]}),t.jsxs("div",{className:s.field,children:[t.jsxs("div",{className:s.fieldLabelRow,children:[t.jsx("label",{htmlFor:"asset-settings-open-cloud-api-key",children:n("assets.settings.apiKey","Open Cloud API Key")}),t.jsx(Ue,{topicId:"openCloudApiKey",variant:"field",state:{hasOpenCloudCredential:te}})]}),t.jsx("input",{id:"asset-settings-open-cloud-api-key",value:X,type:"password",disabled:j||S,onChange:u=>G(u.target.value)}),t.jsx("p",{className:s.inlineHelp,children:n("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.")})]}),!te&&t.jsx("p",{className:s.inlineHelp,children:t.jsx("a",{href:"https://create.roblox.com/docs/cloud/auth/api-keys",target:"_blank",rel:"noreferrer",children:n("assets.settings.apiKeyGuide","Create a Roblox API key with Assets Read and Write permissions.")})}),t.jsxs("div",{className:s.buttonRow,children:[t.jsx(K,{text:Se,children:t.jsx("button",{type:"button",className:s.commandButton,disabled:_e,onClick:()=>{(async()=>{var u;o(!0);try{const _={apiKey:q,...g.trim()?{label:g.trim()}:{}},P=(h==null?void 0:h.storageProvider)==="localFile"?await Qa(h.id,_):await Za(_),le=P.profiles.find(ke=>{var Ee;return ke.id===(P.activeProfileId??((Ee=P.profile)==null?void 0:Ee.id))});E(P),V(P.activeProfileId??((u=P.profile)==null?void 0:u.id)??""),O(!le||le.creators.length===0),U(!1),G(""),l(""),x(n("assets.settings.apiKeySaved","Open Cloud API key saved locally."))}catch(_){x(_ instanceof Error?_.message:n("assets.settings.saveFailed","Failed to save upload settings."))}finally{o(!1)}})()},children:n("assets.settings.saveApiKey","Save API Key")})}),t.jsx(K,{text:ge,children:t.jsx("button",{type:"button",className:s.commandButton,disabled:me,onClick:()=>{(async()=>{o(!0);try{const u=await on(q||void 0);x(un(u.validation,n))}catch(u){x(u instanceof Error?u.message:n("assets.settings.testFailed","Connection test failed."))}finally{o(!1)}})()},children:n("assets.settings.testConnection","Test Connection")})}),t.jsx(K,{text:be,children:t.jsx("button",{type:"button",className:`${s.commandButton} ${s.dangerButton}`,disabled:xe,onClick:()=>{h&&k({kind:"apiKey",profileId:h.id})},children:n("assets.settings.removeApiKey","Unregister API Key")})})]})]}),t.jsx("div",{className:s.metadataList,children:h==null?void 0:h.creators.map(u=>t.jsxs("div",{className:s.metadataItem,children:[t.jsx("strong",{children:u.label}),t.jsx("span",{children:mn(u,n)}),u.id===h.defaultCreatorId&&t.jsx("code",{children:n("assets.settings.defaultCreatorBadge","Default")}),t.jsxs("span",{children:[n("assets.settings.field.validationStatus","Validation status"),": ",Pe(u.validationStatus,n)]}),t.jsxs("div",{className:s.buttonRow,children:[u.id!==h.defaultCreatorId&&h.storageProvider==="localFile"&&t.jsx("button",{type:"button",className:s.commandButton,disabled:j||S,onClick:()=>{(async()=>{if(h){o(!0);try{const _=await sn(h.id,u.id);E(_),x(n("assets.settings.defaultCreatorSaved","Open Cloud default Creator saved locally."))}catch(_){x(_ instanceof Error?_.message:n("assets.settings.saveFailed","Failed to save upload settings."))}finally{o(!1)}}})()},children:n("assets.settings.makeDefaultCreator","Make default")}),t.jsx(K,{text:b,children:t.jsx("button",{type:"button",className:`${s.commandButton} ${s.dangerButton}`,disabled:c,onClick:()=>k({kind:"creator",profileId:h.id,creatorPresetId:u.id}),children:n("assets.settings.unregisterCreator","Unregister Creator")})})]})]},u.id))}),F&&!ee&&t.jsx(K,{text:Ne,children:t.jsx("button",{type:"button",className:s.commandButton,disabled:j||S||w||!m,onClick:()=>{M("user"),T(""),$(""),O(!0)},children:n("assets.settings.addCreator","Add Creator")})}),J&&t.jsxs(t.Fragment,{children:[t.jsxs("div",{className:s.twoColumn,children:[t.jsxs("div",{className:s.field,children:[t.jsx("div",{className:s.fieldLabelRow,children:t.jsx("label",{htmlFor:"asset-settings-creator-type",children:n("assets.upload.creatorType","Creator type")})}),t.jsxs("select",{id:"asset-settings-creator-type",value:W,disabled:j||S||w||!m,onChange:u=>M(u.target.value),children:[t.jsx("option",{value:"user",children:n("assets.creator.user","User")}),t.jsx("option",{value:"group",children:n("assets.creator.group","Group")})]})]}),t.jsxs("div",{className:s.field,children:[t.jsxs("div",{className:s.fieldLabelRow,children:[t.jsx("label",{htmlFor:"asset-settings-creator-id",children:n("assets.upload.creatorId","Creator ID")}),t.jsx(Ue,{topicId:"openCloudCreatorId",variant:"field",state:{hasDefaultCreator:!!D}})]}),t.jsx("input",{id:"asset-settings-creator-id",value:Z,disabled:j||S||w||!m,onChange:u=>T(u.target.value)}),t.jsx("p",{className:s.inlineHelp,children:n("assets.settings.creatorId.inlineHelp","Default owner for new Roblox assets: your User ID or a Group ID.")})]})]}),t.jsxs("div",{className:s.field,children:[t.jsx("div",{className:s.fieldLabelRow,children:t.jsx("label",{htmlFor:"asset-settings-creator-label",children:n("assets.settings.creatorLabel","Creator label")})}),t.jsx("input",{id:"asset-settings-creator-label",value:Q,disabled:j||S||w||!m,onChange:u=>$(u.target.value),placeholder:n("assets.settings.creatorLabel.placeholder","Main studio group")}),t.jsx("p",{className:s.inlineHelp,children:n("assets.settings.creatorLabel.help","Optional. If left blank, WEPPY automatically saves a label like User 123 or Group 456.")})]}),!D&&t.jsx("p",{className:s.inlineHelp,children:n("assets.settings.creatorHelp","Use the numeric user ID from a profile URL or group ID from a group URL.")}),t.jsxs("div",{className:s.buttonRow,children:[t.jsx(K,{text:Ie,children:t.jsx("button",{type:"button",className:s.primaryButton,disabled:Ae,onClick:()=>{(async()=>{if(h){o(!0);try{const u=await tn(h.id,{creatorType:W,creatorId:B,makeDefault:!D,...Q.trim()?{label:Q.trim()}:{}});E(u),T(""),$(""),O(!1),x(n("assets.settings.defaultCreatorSaved","Open Cloud default Creator saved locally."))}catch(u){x(u instanceof Error?u.message:n("assets.settings.saveFailed","Failed to save upload settings."))}finally{o(!1)}}})()},children:f})}),F&&t.jsx("button",{type:"button",className:s.commandButton,disabled:j||S,onClick:()=>{M("user"),T(""),$(""),O(!1)},children:n("assets.settings.cancelCreator","Cancel")})]})]})]}),y&&t.jsx("div",{className:s.messageState,children:y}),t.jsx(Je,{open:I!==null,title:rt,message:it,cancelLabel:n("common.cancel","Cancel"),confirmLabel:ct,loading:S,onCancel:()=>k(null),onConfirm:()=>{ue()}})]})}const xn=12,bn=5e3;function re(e,a){return e instanceof Error&&e.message.trim().length>0?e.message:a}function Re(e,a){return e.some(n=>n.id===a.id)?e.map(n=>n.id===a.id?a:n):[a,...e]}function we(e,a){return Yt(e.filter(d=>Vt(d,a)))}function pe(e,a){return e?`${e.displayName} (${e.id})`:a??"unknown asset"}function fn(e){return e.length===0?"none":e.map(a=>pe(a)).join(", ")}function Ye(e){const a=`status ${e.status}`;return e.roblox.assetId?`Roblox asset ${e.roblox.assetId}; ${a}`:a}function yn(e,a){const d=pe(a);return e==="update"?`Updated metadata for asset: ${d}.`:e==="upload"?`Uploaded asset: ${d} -> ${Ye(a)}.`:e==="thumbnail-generate"?`Generated thumbnail for asset: ${d}.`:e==="status-refresh"?`Refreshed Roblox status for asset: ${d} -> ${Ye(a)}.`:e==="usage-scan"?`Scanned usage for asset: ${d} -> ${a.usage.references.length} reference(s).`:`Updated asset: ${d}.`}function jn(e){return e!=="upload"&&e!=="status-refresh"}function Le(e,a){if((a==null?void 0:a.id)===e)return a.category;const d=/^asset_(image|decal|audio|mesh|model|video|animation)_/.exec(e);return d!=null&&d[1]?d[1]:null}function Xe(e){return e.status==="processing"&&!!(e.roblox.operationId??e.roblox.operationPath)}function vn(e){return{scope:e.scope.kind,placeId:e.scope.kind==="place"?e.scope.placeId:void 0,category:e.category}}function Cn(e){if(e.pluginConnected&&e.activePlaceId!==null)return{placeId:e.activePlaceId,placeName:e.activePlaceName,studioConnected:!0};if(e.lastActivePlaceId!==null)return{placeId:e.lastActivePlaceId,placeName:e.lastActivePlaceName,studioConnected:!1};const a=e.places[0];return{placeId:(a==null?void 0:a.placeId)??null,placeName:(a==null?void 0:a.placeName)??null,studioConnected:!1}}function _n(e,a){if(typeof a=="number"){const d=e.places.find(n=>n.placeId===a);if(d)return{placeId:d.placeId,placeName:d.placeName,studioConnected:d.isConnected,overrideStillValid:!0}}return{...Cn(e),overrideStillValid:a===null}}function Sn(){const[e,a]=i.useState([]),[d,n]=i.useState(0),[r,N]=i.useState(null),[v,E]=i.useState("place"),[p,V]=i.useState("all"),[Y,U]=i.useState([]),[g,l]=i.useState(null),[X,G]=i.useState(null),[W,M]=i.useState(null),[Z,T]=i.useState(null),[Q,$]=i.useState(!1),[ee,O]=i.useState(!1),[y,x]=i.useState(!0),[I,k]=i.useState(null),[S,o]=i.useState(null),[j,L]=i.useState(null),ae=i.useRef(!0),q=i.useRef(new Map),B=i.useMemo(()=>e.find(c=>c.id===r)??null,[e,r]),H=i.useCallback(c=>{const b=q.current.get(c);b!==void 0&&(clearTimeout(b),q.current.delete(c))},[]),h=i.useCallback((c,b=xn)=>{if(!Xe(c)||b<=0){H(c.id);return}H(c.id),(async()=>{try{const f=await Te(vn(c),c.id);if(!ae.current)return;if(a(C=>Re(C,f)),Xe(f)&&b>1){const C=setTimeout(()=>{q.current.delete(f.id),h(f,b-1)},bn);q.current.set(f.id,C);return}H(f.id)}catch(f){if(!ae.current)return;H(c.id),o(re(f,"Asset Library status refresh failed."))}})()},[H]);i.useEffect(()=>()=>{ae.current=!1;for(const c of q.current.values())clearTimeout(c);q.current.clear()},[]);const te=i.useCallback(()=>({scope:v,placeId:v==="place"?W:void 0}),[W,v]),m=i.useCallback(c=>({...te(),category:c}),[te]),w=i.useCallback(async()=>{try{const c=await mt(),b=_n(c,g);return U(c.places),b.overrideStillValid||l(null),G(b.placeId),M(b.placeId),T(b.placeName),$(b.studioConnected),O(b.studioConnected),b.placeId}catch{return U([]),G(null),M(null),T(null),$(!1),O(!1),null}},[g]),D=i.useCallback(async()=>{o(null);try{const c=await w(),b={scope:v,placeId:v==="place"?c:void 0};if(v==="place"&&c===null){a([]),n(0),x(!1),o("No active place is connected for place-scoped assets.");return}const f=await Promise.all(Fe(p).map(A=>Et({...b,category:A}))),C=we(f.flatMap(A=>A.assets),p);a(C),n(C.length)}catch(c){o(re(c,"Failed to load Asset Library."))}finally{x(!1)}},[p,w,v]);i.useEffect(()=>{D()},[D]);const F=i.useCallback(async(c,b,f)=>{const C=Le(b,B);if(!C)return o("Asset category is unavailable."),null;k(c),o(null),L(null);try{const A=await f(m(C));return a(z=>Re(z,A)),N(A.id),jn(c)&&L(yn(c,A)),A}catch(A){return o(re(A,"Asset Library action failed.")),null}finally{k(null)}},[m,B]),J=i.useCallback(async()=>{k("rescan"),o(null),L(null);try{const c=await Promise.all(Fe(p).map(z=>Ut(m(z)))),b=we(c.flatMap(z=>z.assets),p),f=c.reduce((z,ue)=>z+ue.adoptedCount,0),C=c.reduce((z,ue)=>z+ue.skippedCount,0),A=we(c.flatMap(z=>z.adopted),p);a(b),n(b.length),L(`Rescan complete for ${p}: ${f} asset(s) added, ${C} skipped. Added: ${fn(A)}.`)}catch(c){o(re(c,"Asset Library rescan failed."))}finally{k(null)}},[p,m]),de=i.useCallback(async(c,b)=>{k("export-selection-rbxm"),o(null),L(null);try{const f=await Ht(m(c),b);return a(C=>Re(C,f.asset)),N(f.asset.id),L(`Exported Studio selection as RBXM asset: ${pe(f.asset)}${f.deduplicated?" (reused existing local asset)":""}.`),f}catch(f){return o(re(f,"Asset Library .rbxm export failed.")),null}finally{k(null)}},[m]),oe=i.useCallback((c,b)=>F("update",c,f=>Tt(f,c,b)),[F]),_e=i.useCallback(async(c,b)=>{const f=await F("upload",c,C=>Ft(C,c,b));return f&&h(f),f},[F,h]),Se=i.useCallback(async c=>{const b=Le(c,B);if(!b)return o("Asset category is unavailable."),!1;H(c);const f=e.find(C=>C.id===c)??B;k("delete"),o(null),L(null);try{return await Ot(m(b),c),a(C=>{const A=C.filter(z=>z.id!==c);return n(A.length),A}),N(C=>C===c?null:C),L(`Deleted asset: ${pe(f,c)}. Local files removed; uploaded Roblox assets were not deleted.`),!0}catch(C){return o(re(C,"Asset Library delete failed.")),!1}finally{k(null)}},[e,H,m,B]),me=i.useCallback(async(c,b)=>{const f=Le(c,B);if(!f)return o("Asset category is unavailable."),null;const C=e.find(A=>A.id===c)??B;k("import-rbxm"),o(null),L(null);try{const A=await Kt(m(f),c,b);return N(c),L(`Imported RBXM asset: ${pe(C,c)} -> ${A.importedCount} instance(s) to ${A.targetParent}.`),A}catch(A){return o(re(A,"Asset Library .rbxm import failed.")),null}finally{k(null)}},[e,m,B]),ge=i.useCallback(c=>F("thumbnail-generate",c,b=>Gt(b,c)),[F]),xe=i.useCallback(c=>(H(c),F("status-refresh",c,b=>Te(b,c))),[H,F]),be=i.useCallback((c,b)=>F("usage-scan",c,async f=>(await Mt(f,c,b)).asset),[F]),Ae=i.useCallback(c=>{E(c),N(null)},[]),Ie=i.useCallback(c=>{l(c),N(null)},[]),Ne=i.useCallback(c=>{zt(c)&&(V(c),N(null))},[]);return{assets:e,totalCount:d,selectedAsset:B,selectedAssetId:r,scope:v,categoryFilter:p,availablePlaces:Y,selectedPlaceId:X,activePlaceId:W,activePlaceName:Z,selectedPlaceIsConnected:Q,studioConnected:ee,loading:y,busyAction:I,error:S,lastMessage:j,setScope:Ae,setSelectedPlaceId:Ie,setCategoryFilter:Ne,selectAsset:N,refresh:D,rescan:J,exportSelectionRbxm:de,updateMetadata:oe,uploadAsset:_e,deleteAsset:Se,importRbxm:me,generateThumbnail:ge,refreshStatus:xe,scanUsage:be}}function An(e,a){return a("assets.count.shown","Shown assets: {count}").replace("{count}",String(e))}function In(e,a){return e===null?null:a("assets.place.id","Place ID {placeId}").replace("{placeId}",String(e))}function $n(){const{t:e}=he(),{trackEvent:a}=gt(),{tier:d,loading:n}=xt(),r=Sn(),[N,v]=i.useState(!1),[E,p]=i.useState(!1),[V,Y]=i.useState(!1),U=!n&&d==="pro",g=r.selectedAsset,l=(g==null?void 0:g.file.original.toLowerCase().endsWith(".rbxm"))??!1,X=(g==null?void 0:g.category)==="model"||(g==null?void 0:g.category)==="animation",G="game.Workspace",M=!!(U&&r.studioConnected&&g&&l&&X),Z=r.availablePlaces??[],T=r.selectedPlaceId??r.activePlaceId,Q=i.useMemo(()=>r.scope==="shared"?[e("assets.scope.shared","Shared")]:[r.activePlaceName??e("assets.scope.place","Current Place"),In(r.activePlaceId,e),r.selectedPlaceIsConnected?e("assets.place.connected","Connected"):null].filter(y=>!!y),[r.activePlaceId,r.activePlaceName,r.scope,r.selectedPlaceIsConnected,e]),$=i.useMemo(()=>$e(r.categoryFilter,e),[r.categoryFilter,e]),ee=An(r.totalCount,e),O=e("assets.detail.importRbxm.tooltip","Insert this local RBXM asset into {target} in the connected Studio place.").replace("{target}",G);return t.jsxs("div",{className:s.page,children:[t.jsx(bt,{title:e("assets.title","Assets"),description:e("assets.subtitle","Browse local originals, upload to Roblox, and inspect synced usage by place."),badge:t.jsx("span",{className:s.experimentalBadge,children:e("assets.experimental","Experimental")}),helpTopicId:"assets",helpState:{tier:d}}),t.jsxs("div",{className:s.toolbarShell,children:[t.jsxs("div",{className:s.toolbar,children:[t.jsxs("div",{className:s.segmented,role:"group","aria-label":e("assets.scope.label","Asset scope"),children:[t.jsx("button",{type:"button",className:r.scope==="place"?s.segmentedActive:"",onClick:()=>r.setScope("place"),children:e("assets.scope.place","Current Place")}),t.jsx("button",{type:"button",className:r.scope==="shared"?s.segmentedActive:"",onClick:()=>r.setScope("shared"),children:e("assets.scope.shared","Shared")})]}),r.scope==="place"&&Z.length>0?t.jsxs("label",{className:s.placeSelectorLabel,children:[t.jsx("span",{children:e("assets.place.selector","Asset place")}),t.jsx("select",{className:s.placeSelect,value:typeof T=="number"?String(T):"",onChange:y=>{const x=Number.parseInt(y.currentTarget.value,10);Number.isInteger(x)&&r.setSelectedPlaceId(x)},children:Z.map(y=>t.jsxs("option",{value:y.placeId,children:[y.placeName," (",y.placeId,")"]},y.placeId))})]}):null,t.jsxs("div",{className:s.listContextSummary,children:[Q.map((y,x)=>t.jsxs("span",{children:[x>0?t.jsx("span",{className:s.contextDivider,children:" · "}):null,y]},`${y}-${x}`)),t.jsx("span",{className:s.contextDivider,children:" · "}),t.jsx("span",{children:$}),t.jsx("span",{className:s.contextDivider,children:" · "}),t.jsx("strong",{children:ee})]}),t.jsxs("div",{className:s.toolbarActions,children:[t.jsx(K,{text:e("assets.rescan.tooltip","Scan inbox folders for the current filter."),children:t.jsxs("button",{type:"button",className:s.commandButton,disabled:r.busyAction==="rescan",onClick:()=>{a("dashboard_click_event",{click_target:"assets_rescan",page:"assets"}),r.rescan()},children:[t.jsx(qe,{size:15}),e("assets.rescan","Rescan")]})}),t.jsx(K,{text:E?"":e("assets.settings.open.tooltip","Open Roblox upload settings."),children:t.jsx("button",{type:"button",className:[s.iconButton,E?s.iconButtonActive:""].filter(Boolean).join(" "),onClick:()=>{a("dashboard_click_event",{click_target:"assets_open_settings",page:"assets"}),p(y=>!y)},"aria-label":e("assets.settings.open","Open settings"),"aria-controls":"asset-library-settings-panel","aria-expanded":E,children:t.jsx(Ze,{size:16})})})]}),t.jsxs("div",{className:s.categoryControl,children:[t.jsx("span",{id:"assets-category-filter-label",className:s.categoryControlLabel,children:e("assets.category.filter","Category")}),t.jsx("div",{className:s.categoryRail,role:"radiogroup","aria-labelledby":"assets-category-filter-label",children:at.map(y=>{const x=r.categoryFilter===y,I=$e(y,e);return t.jsx("button",{type:"button",role:"radio","aria-checked":x,className:[s.categoryButton,x?s.categoryButtonActive:""].filter(Boolean).join(" "),onClick:()=>{r.setCategoryFilter(y)},children:I},y)})})]})]}),t.jsx(gn,{open:E,tier:d,onClose:()=>p(!1)})]}),r.error&&t.jsx("div",{className:s.errorState,children:r.error}),r.lastMessage&&t.jsx("div",{className:s.messageState,children:r.lastMessage}),r.categoryFilter==="rbxm"&&t.jsxs("section",{className:s.rbxmGuide,"aria-label":e("assets.rbxmGuide.title","Save RBXM from Studio"),children:[t.jsx("h2",{children:e("assets.rbxmGuide.title","Save RBXM from Studio")}),t.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.")}),t.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.")})]}),!U&&!n&&t.jsx("div",{className:`${s.notice} ${s.proNotice}`,children:e("assets.basic.notice","Browse, preview, edit metadata, and scan usage on Basic. Roblox upload controls are available on Pro.")}),r.loading?t.jsx("div",{className:s.emptyState,children:e("common.loading","Loading...")}):t.jsx(Ua,{assets:r.assets,selectedAssetId:r.selectedAssetId,onSelect:r.selectAsset}),t.jsx(Ya,{asset:N||E||V?null:g,busyAction:r.busyAction,canUpload:U,canImportRbxm:M,importRbxmTooltip:O,importRbxmTargetParent:G,onClose:()=>r.selectAsset(null),onSave:async(y,x)=>{g&&await r.updateMetadata(g.id,{displayName:y,description:x})},onUpload:()=>v(!0),onDelete:()=>Y(!0),onImportRbxm:async()=>{g&&(a("dashboard_click_event",{click_target:"assets_import_rbxm",page:"assets"}),await r.importRbxm(g.id,{targetParent:G}))},onRefreshStatus:async()=>{g&&await r.refreshStatus(g.id)},onScanUsage:async()=>{g&&(a("dashboard_click_event",{click_target:"assets_usage_scan",page:"assets"}),await r.scanUsage(g.id,r.activePlaceId??void 0))}}),t.jsx(Je,{open:V&&!!g,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:r.busyAction==="delete",onCancel:()=>Y(!1),onConfirm:()=>{g&&(a("dashboard_click_event",{click_target:"assets_delete",page:"assets"}),r.deleteAsset(g.id).then(y=>{y&&Y(!1)}))}}),t.jsx(dn,{asset:g,open:N,canUpload:U,busyAction:r.busyAction,onClose:()=>{v(!1),r.selectAsset(null)},onBack:()=>v(!1),onOpenSettings:()=>{v(!1),p(!0)},onUpload:async y=>{if(!g)return;a("dashboard_click_event",{click_target:"assets_upload_submit",page:"assets"}),await r.uploadAsset(g.id,y)&&v(!1)}})]})}export{$n as Component};
@@ -0,0 +1 @@
1
+ import{r,a as w,u as V,b as G,c as D,d as F,j as e}from"./index-B9LVK3-K.js";import{I as P}from"./InfoLabel-ZfsTcz5c.js";import{G as U}from"./GameChangeDetail-DKAKmyGF.js";import{T as g}from"./TooltipText-ZamrETeK.js";function H(t){const i={scriptsModified:0,scriptsCreated:0,instancesCreated:0,instancesDeleted:0,instancesMoved:0,propertiesChanged:0,lightingChanged:!1,terrainChanged:!1,assetsInserted:0};for(const o of t)switch(o.category){case"script":o.changeType==="create"?i.scriptsCreated++:i.scriptsModified++;break;case"instance":o.changeType==="create"?i.instancesCreated++:o.changeType==="delete"?i.instancesDeleted++:o.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 W(t){if(typeof t=="number")return{placeId:String(t)}}function Y(t,i){const[o,h]=r.useState(""),[I,a]=r.useState(""),[d,x]=r.useState(),[E,L]=r.useState("completed"),[f,$]=r.useState([]),[O,R]=r.useState([]),[A,p]=r.useState([]),[_,j]=r.useState(),[b,v]=r.useState(),[S,C]=r.useState(),[N,T]=r.useState({scriptsModified:0,scriptsCreated:0,instancesCreated:0,instancesDeleted:0,instancesMoved:0,propertiesChanged:0,lightingChanged:!1,terrainChanged:!1,assetsInserted:0}),[k,u]=r.useState(!0),[q,y]=r.useState(null),m=r.useCallback(async()=>{if(t){u(!0),y(null);try{const s=W(i),[c,l]=await Promise.all([s?w.get(`/api/dashboard/changelog/${t}`,s):w.get(`/api/dashboard/changelog/${t}`),s?w.get(`/api/dashboard/changelog/${t}/changes`,s):w.get(`/api/dashboard/changelog/${t}/changes`)]);h(c.entryId),a(c.startTime),x(c.endTime),L(c.status),$(c.entries),R(c.failures),j(c.contextSummary),v(c.replayMetadata),C(c.verificationSummary),p(l.changes),T(H(l.changes))}catch(s){y(s instanceof Error?s.message:"Failed to load changelog detail")}finally{u(!1)}}},[t,i]);return r.useEffect(()=>{m()},[m]),{entryId:o,startTime:I,endTime:d,status:E,entries:f,failures:O,changes:A,changeSummary:N,contextSummary:_,replayMetadata:b,verificationSummary:S,loading:k,error:q,refresh:m}}const z={script:"📝",instance:"🧱",property:"🎨",lighting:"🌅",terrain:"⛰️",asset:"📦"};function J(t){return z[t]??"❓"}const Q="_page_q2jbi_2",X="_header_q2jbi_10",Z="_backLink_q2jbi_16",ee="_headerTitle_q2jbi_29",te="_headerTime_q2jbi_37",ne="_statusActive_q2jbi_44",ae="_statusCompleted_q2jbi_49",se="_section_q2jbi_54",ie="_sectionTitle_q2jbi_61",ce="_summaryGrid_q2jbi_74",re="_summaryCard_q2jbi_80",oe="_summaryCardActive_q2jbi_94",le="_summaryIcon_q2jbi_99",de="_summaryCount_q2jbi_105",me="_summaryLabel_q2jbi_112",ge="_contextGrid_q2jbi_121",he="_contextRow_q2jbi_127",ue="_contextKey_q2jbi_133",ye="_contextValue_q2jbi_141",xe="_timelineFilter_q2jbi_149",fe="_filterLabel_q2jbi_156",pe="_filterSelect_q2jbi_162",_e="_timeline_q2jbi_149",je="_timelineEntry_q2jbi_182",be="_timelineTime_q2jbi_199",ve="_timelineIcon_q2jbi_207",Se="_timelineBody_q2jbi_212",Ce="_timelineSummary_q2jbi_217",Ne="_timelineTarget_q2jbi_224",Te="_timelineConfidence_q2jbi_231",ke="_confidenceExact_q2jbi_240",qe="_confidencePartial_q2jbi_245",we="_confidenceAfterOnly_q2jbi_250",Ie="_confidenceIntentOnly_q2jbi_255",Ee="_confidenceUnknown_q2jbi_260",Le="_timelineExpanded_q2jbi_266",$e="_empty_q2jbi_338",Oe="_loading_q2jbi_347",Re="_error_q2jbi_356",n={page:Q,header:X,backLink:Z,headerTitle:ee,headerTime:te,statusActive:ne,statusCompleted:ae,section:se,sectionTitle:ie,summaryGrid:ce,summaryCard:re,summaryCardActive:oe,summaryIcon:le,summaryCount:de,summaryLabel:me,contextGrid:ge,contextRow:he,contextKey:ue,contextValue:ye,timelineFilter:xe,filterLabel:fe,filterSelect:pe,timeline:_e,timelineEntry:je,timelineTime:be,timelineIcon:ve,timelineBody:Se,timelineSummary:Ce,timelineTarget:Ne,timelineConfidence:Te,confidenceExact:ke,confidencePartial:qe,confidenceAfterOnly:we,confidenceIntentOnly:Ie,confidenceUnknown:Ee,timelineExpanded:Le,empty:$e,loading:Oe,error:Re},B=[{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 K(t){if(!t)return"--:--";const i=new Date(t);return`${String(i.getHours()).padStart(2,"0")}:${String(i.getMinutes()).padStart(2,"0")}`}function Ae(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 Ke(t,i){if(!t||!i)return"";const o=new Date(i).getTime()-new Date(t).getTime();return o<0?"":`${Math.round(o/6e4)}min`}function Me(t){switch(t){case"exact":return n.confidenceExact;case"partial":return n.confidencePartial;case"after-only":return n.confidenceAfterOnly;case"intent-only":return n.confidenceIntentOnly;default:return n.confidenceUnknown}}function Be(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 Ve(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 Ge(t){const i=new URLSearchParams(t).get("placeId");if(!i)return null;const o=Number.parseInt(i,10);return Number.isInteger(o)&&o>=0?o:null}function He(){var p,_,j,b,v,S,C,N,T,k,u,q,y,m;const{t}=V(),{id:i}=G(),o=D(),h=F(),I=r.useMemo(()=>Ge(h.search),[h.search]),a=Y(i,I),[d,x]=r.useState("all"),[E,L]=r.useState(null),f=r.useMemo(()=>[...d==="all"?a.changes:a.changes.filter(c=>c.category===d)].reverse(),[a.changes,d]);if(a.loading)return e.jsx("div",{className:n.loading,children:t("common.loading","Loading...")});if(a.error)return e.jsxs("div",{className:n.error,children:[a.error,e.jsx("br",{}),e.jsxs("span",{className:n.backLink,onClick:()=>o("/changelog"),children:["←"," ",t("changelog.detail.backToList","Back to list")]})]});const $=Ke(a.startTime,a.endTime),O=a.endTime?`${K(a.startTime)} → ${K(a.endTime)} (${$})`:`${K(a.startTime)} → ${t("changelog.card.inProgress","in progress")}`,R=!!((p=a.contextSummary)!=null&&p.intent||(_=a.contextSummary)!=null&&_.testScenario||(j=a.contextSummary)!=null&&j.expectedBehavior||(b=a.contextSummary)!=null&&b.observedBehavior),A=!!((v=a.verificationSummary)!=null&&v.label||(S=a.verificationSummary)!=null&&S.status||(C=a.verificationSummary)!=null&&C.testTimestamp);return e.jsxs("div",{className:n.page,children:[e.jsxs("div",{className:n.header,children:[e.jsxs("span",{className:n.backLink,onClick:()=>o("/changelog"),children:["←"," ",t("sidebar.changelog","Changelog")]}),e.jsx("span",{className:n.headerTitle,children:"|"}),e.jsx("span",{className:n.headerTime,children:O}),e.jsx(g,{text:a.status==="active"?t("changelog.card.active.tooltip","This session is still receiving new game changes."):t("changelog.card.completed.tooltip","This session has ended and no more changes are expected."),children:e.jsx("span",{className:a.status==="active"?n.statusActive:n.statusCompleted,children:a.status==="active"?t("changelog.card.active","Active"):t("changelog.card.completed","Completed")})})]}),e.jsxs("div",{className:n.section,children:[e.jsx("div",{className:n.sectionTitle,children:e.jsx(g,{text:t("changelog.detail.changeSummary.tooltip","Counts of extracted game changes grouped by category for this session."),children:e.jsx("span",{children:t("changelog.detail.changeSummary","Change Summary")})})}),e.jsx("div",{className:n.summaryGrid,children:B.map(s=>{const c=a.changeSummary;let l;switch(s.key){case"script":l=c.scriptsModified+c.scriptsCreated;break;case"instance":l=c.instancesCreated+c.instancesDeleted+c.instancesMoved;break;case"property":l=c.propertiesChanged;break;case"lighting":l=c.lightingChanged?1:0;break;case"terrain":l=c.terrainChanged?1:0;break;case"asset":l=c.assetsInserted;break;default:l=0}const M=d===s.key;return e.jsxs("div",{className:`${n.summaryCard} ${M?n.summaryCardActive:""}`,onClick:()=>x(M?"all":s.key),children:[e.jsx("span",{className:n.summaryIcon,children:s.icon}),e.jsx("div",{className:n.summaryCount,children:l}),e.jsx("div",{className:n.summaryLabel,children:t(s.labelKey,s.key)})]},s.key)})})]}),R&&e.jsxs("div",{className:n.section,children:[e.jsx("div",{className:n.sectionTitle,children:e.jsx(g,{text:t("changelog.detail.context.tooltip","Structured execution context captured for this changelog session."),children:e.jsx("span",{children:t("changelog.detail.context.title","Context Summary")})})}),e.jsxs("div",{className:n.contextGrid,children:[((N=a.contextSummary)==null?void 0:N.intent)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("changelog.card.sessionIntent","Session intent")}),e.jsx("span",{className:n.contextValue,children:a.contextSummary.intent})]}),((T=a.contextSummary)==null?void 0:T.testScenario)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("playtest.context.why","Why this test ran")}),e.jsx("span",{className:n.contextValue,children:a.contextSummary.testScenario})]}),((k=a.contextSummary)==null?void 0:k.expectedBehavior)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("playtest.context.expected","Expected")}),e.jsx("span",{className:n.contextValue,children:a.contextSummary.expectedBehavior})]}),((u=a.contextSummary)==null?void 0:u.observedBehavior)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("playtest.context.observed","Observed")}),e.jsx("span",{className:n.contextValue,children:a.contextSummary.observedBehavior})]})]})]}),A&&e.jsxs("div",{className:n.section,children:[e.jsx("div",{className:n.sectionTitle,children:e.jsx(g,{text:t("changelog.detail.verification.tooltip","Verification signals linked to this changelog session."),children:e.jsx("span",{children:t("changelog.detail.verification.title","Verification")})})}),e.jsxs("div",{className:n.contextGrid,children:[((q=a.verificationSummary)==null?void 0:q.label)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("changelog.detail.verification.label","Result")}),e.jsx("span",{className:n.contextValue,children:a.verificationSummary.label})]}),((y=a.verificationSummary)==null?void 0:y.status)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("changelog.detail.verification.status","Status")}),e.jsx("span",{className:n.contextValue,children:a.verificationSummary.status})]}),((m=a.verificationSummary)==null?void 0:m.testTimestamp)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("changelog.detail.verification.timestamp","Recorded at")}),e.jsx("span",{className:n.contextValue,children:a.verificationSummary.testTimestamp})]})]})]}),e.jsxs("div",{className:n.section,children:[e.jsx("div",{className:n.sectionTitle,children:e.jsx(g,{text:t("changelog.detail.changeTimeline.tooltip","Chronological list of extracted game changes for this session."),children:e.jsx("span",{children:t("changelog.detail.changeTimeline","Change Timeline")})})}),e.jsxs("div",{className:n.timelineFilter,children:[e.jsx("span",{className:n.filterLabel,children:e.jsx(P,{label:`${t("changelog.detail.filterCategory","Category")}:`,tooltip:t("changelog.detail.filterCategory.tooltip","Filter the timeline to a single change category.")})}),e.jsxs("select",{className:n.filterSelect,value:d,onChange:s=>x(s.target.value),children:[e.jsx("option",{value:"all",children:t("tools.filter.all","All")}),B.map(s=>e.jsxs("option",{value:s.key,children:[s.icon," ",t(s.labelKey,s.key)]},s.key))]})]}),f.length===0?e.jsx("div",{className:n.empty,children:t("changelog.detail.noChanges","No changes in this category")}):e.jsx("div",{className:n.timeline,children:f.map((s,c)=>{const l=E===c;return e.jsxs("div",{children:[e.jsxs("div",{className:n.timelineEntry,onClick:()=>L(l?null:c),children:[e.jsx("span",{className:n.timelineTime,children:Ae(s.timestamp)}),e.jsx("span",{className:n.timelineIcon,children:J(s.category)}),e.jsxs("div",{className:n.timelineBody,children:[e.jsxs("div",{className:n.timelineSummary,children:[s.summary,e.jsx(g,{text:Ve(t,s.confidence),children:e.jsx("span",{className:`${n.timelineConfidence} ${Me(s.confidence)}`,children:Be(t,s.confidence)})})]}),e.jsx("div",{className:n.timelineTarget,children:s.target})]})]}),l&&e.jsx("div",{className:n.timelineExpanded,children:e.jsx(U,{change:s})})]},c)})})]})]})}export{He as Component};
@@ -0,0 +1 @@
1
+ import{r as l,a as F,D,u as M,j as e,e as O,c as V,h as U,l as K,T as G}from"./index-B9LVK3-K.js";import{P as H}from"./PageHeader-Cqg4GMtU.js";import{C as Z}from"./ConfirmModal-C9EhZCHZ.js";import{C as Q}from"./CurrentPlaceScope-BMyP2w7Z.js";import{T as k}from"./TooltipText-ZamrETeK.js";import{T as q}from"./Tabs-B8mbzhmZ.js";import"./ConfirmModal.module-NrFlfTWy.js";const z=10;function J(t,o){return typeof o!="number"?t:`${t}?placeId=${encodeURIComponent(String(o))}`}function W(t){const o=(t==null?void 0:t.placeId)??null,[s,n]=l.useState([]),[u,_]=l.useState(0),[a,f]=l.useState(!1),[x,v]=l.useState(!0),[g,C]=l.useState(0),[d,y]=l.useState("all"),N=l.useRef(null),m=l.useCallback(async(h,b)=>{v(!0);try{const j={limit:String(z),offset:String(h)};b!=="all"&&(j.status=b),typeof o=="number"&&(j.placeId=String(o));const I=await F.get("/api/dashboard/changelog",j);n(I.entries),_(I.total),f(I.hasMore)}catch{n([]),_(0),f(!1)}finally{v(!1)}},[o]),S=l.useCallback(()=>{m(g,d)},[m,g,d]),i=l.useCallback(async()=>{await F.post(J("/api/dashboard/changelog/clear",o)),n([]),_(0),f(!1)},[o]);return l.useEffect(()=>{m(g,d)},[m,g,d]),l.useEffect(()=>{const h=new D;N.current=h,h.connect();const b=h.on("command",()=>{m(g,d)});return()=>{b(),h.disconnect(),N.current=null}},[m,g,d]),{entries:s,total:u,hasMore:a,loading:x,offset:g,statusFilter:d,setOffset:C,setStatusFilter:y,refresh:S,clear:i}}const X="_card_1n89u_2",Y="_header_1n89u_17",ee="_statusBadge_1n89u_24",te="_statusDot_1n89u_35",se="_active_1n89u_41",ae="_completed_1n89u_50",ne="_timeRange_1n89u_58",ce="_summaryList_1n89u_65",oe="_summaryItem_1n89u_71",ie="_summaryIcon_1n89u_80",le="_summaryText_1n89u_86",re="_progressBar_1n89u_91",ge="_progressFill_1n89u_99",de="_emptySummary_1n89u_112",me="_contextBlock_1n89u_120",he="_contextLabel_1n89u_129",pe="_contextValue_1n89u_137",c={card:X,header:Y,statusBadge:ee,statusDot:te,active:se,completed:ae,timeRange:ne,summaryList:ce,summaryItem:oe,summaryIcon:ie,summaryText:le,progressBar:re,progressFill:ge,emptySummary:de,contextBlock:me,contextLabel:he,contextValue:pe};function R(t){if(!t)return"--:--";const o=new Date(t);return`${String(o.getHours()).padStart(2,"0")}:${String(o.getMinutes()).padStart(2,"0")}`}function ue({entry:t,onClick:o}){var h,b,j,I,B,L,A,P,w,E;const{t:s}=M(),n=t.changeSummary,u=t.status==="active",_=t.isBootstrapOnly===!0,a=[],f=n.scriptsModified+n.scriptsCreated;if(f>0){const p=[];n.scriptsModified>0&&p.push(`${n.scriptsModified} ${s("changelog.card.modified","modified")}`),n.scriptsCreated>0&&p.push(`${n.scriptsCreated} ${s("changelog.card.created","created")}`);const T=`${f} ${s("changelog.card.scripts","scripts")} ${p.join(", ")}`;a.push({icon:"📝",text:T,tooltip:s("changelog.card.scripts.tooltip","Script changes made in this session.")})}const x=n.instancesCreated+n.instancesDeleted+n.instancesMoved;if(x>0){const p=[];n.instancesCreated>0&&p.push(`${n.instancesCreated} ${s("changelog.card.created","created")}`),n.instancesDeleted>0&&p.push(`${n.instancesDeleted} ${s("changelog.card.deleted","deleted")}`),n.instancesMoved>0&&p.push(`${n.instancesMoved} ${s("changelog.card.moved","moved")}`);const T=`${x} ${s("changelog.card.instances","instances")} ${p.join(", ")}`;a.push({icon:"🧱",text:T,tooltip:s("changelog.card.instances.tooltip","Instance create, delete, move, or clone changes in this session.")})}n.propertiesChanged>0&&a.push({icon:"🎨",text:`${n.propertiesChanged} ${s("changelog.card.propertiesChanged","properties changed")}`,tooltip:s("changelog.card.propertiesChanged.tooltip","Property value changes recorded for this session.")}),n.lightingChanged&&a.push({icon:"🌅",text:s("changelog.card.lightingConfigured","Lighting configured"),tooltip:s("changelog.card.lightingConfigured.tooltip","Lighting or atmosphere settings changed in this session.")}),n.terrainChanged&&a.push({icon:"⛰️",text:s("changelog.card.terrainConfigured","Terrain configured"),tooltip:s("changelog.card.terrainConfigured.tooltip","Terrain data or terrain settings changed in this session.")}),n.assetsInserted>0&&a.push({icon:"📦",text:`${n.assetsInserted} ${s("changelog.card.assetsInserted","assets inserted")}`,tooltip:s("changelog.card.assetsInserted.tooltip","Assets inserted into the place during this session.")});const v=R(t.startTime),g=u?s("changelog.card.inProgress","in progress"):t.endTime?R(t.endTime):"--:--",C=_?s("changelog.card.bootstrapStatus","Bootstrap"):u?s("changelog.card.active","Active"):s("changelog.card.completed","Completed"),d=_?s("changelog.card.bootstrapStatus.tooltip","This session only contains the initial sync bootstrap snapshot."):u?s("changelog.card.active.tooltip","This session is still receiving new game changes."):s("changelog.card.completed.tooltip","This session has ended and no more changes are expected."),y=_?s("changelog.card.bootstrapSummary","Initial sync snapshot"):s("changelog.card.noChanges","No changes yet"),N=_?s("changelog.card.bootstrapSummary.tooltip","Initial file sync writes are collapsed into a single bootstrap snapshot row."):s("changelog.card.noChanges.tooltip","No game changes have been extracted for this session yet."),m=(b=(h=t.contextSummary)==null?void 0:h.intent)==null?void 0:b.trim(),S=((L=(B=(I=(j=t.contextSummary)==null?void 0:j.affectedAreas)==null?void 0:I[0])==null?void 0:B.label)==null?void 0:L.trim())||((P=(A=t.contextSummary)==null?void 0:A.testScenario)==null?void 0:P.trim()),i=(E=(w=t.verificationSummary)==null?void 0:w.label)==null?void 0:E.trim();return e.jsxs("div",{className:c.card,onClick:o,children:[e.jsxs("div",{className:c.header,children:[e.jsx(k,{text:d,children:e.jsxs("span",{className:`${c.statusBadge} ${u?c.active:c.completed}`,children:[e.jsx("span",{className:c.statusDot}),C]})}),e.jsxs("span",{className:c.timeRange,children:[v,"~",g]})]}),e.jsx("div",{className:c.summaryList,children:a.length>0?a.map((p,T)=>e.jsxs("div",{className:c.summaryItem,children:[e.jsx("span",{className:c.summaryIcon,children:p.icon}),e.jsx(k,{text:p.tooltip,children:e.jsx("span",{className:c.summaryText,children:p.text})})]},T)):e.jsx(k,{text:N,children:e.jsx("span",{className:c.emptySummary,style:{display:"block"},children:y})})}),m&&e.jsxs("div",{className:c.contextBlock,children:[e.jsx("span",{className:c.contextLabel,children:s("changelog.card.sessionIntent","Session intent")}),e.jsx("span",{className:c.contextValue,children:m})]}),!m&&S&&e.jsxs("div",{className:c.contextBlock,children:[e.jsx("span",{className:c.contextLabel,children:s("changelog.card.representativeArea","Representative area")}),e.jsx("span",{className:c.contextValue,children:S})]}),i&&e.jsxs("div",{className:c.contextBlock,children:[e.jsx("span",{className:c.contextLabel,children:s("changelog.card.verification","Verification")}),e.jsx("span",{className:c.contextValue,children:i})]}),u&&e.jsx("div",{className:c.progressBar,children:e.jsx("div",{className:c.progressFill})})]})}const _e="_page_1tggr_2",fe="_limitNotice_1tggr_9",xe="_limitNoticeContent_1tggr_23",ye="_limitNoticeTitle_1tggr_28",be="_limitNoticeText_1tggr_35",ve="_primaryAction_1tggr_41",Ce="_clearButton_1tggr_67",Ne="_list_1tggr_88",Se="_empty_1tggr_95",je="_loading_1tggr_104",Ie="_pagination_1tggr_113",Te="_pageInfo_1tggr_121",$e="_btn_1tggr_127",r={page:_e,limitNotice:fe,limitNoticeContent:xe,limitNoticeTitle:ye,limitNoticeText:be,primaryAction:ve,clearButton:Ce,list:Ne,empty:Se,loading:je,pagination:Ie,pageInfo:Te,btn:$e},$=10;function ke(t,o){return typeof o!="number"?`/changelog/${t}`:`/changelog/${t}?placeId=${encodeURIComponent(String(o))}`}const Be=[{key:"all",labelKey:"changelog.filter.all"},{key:"active",labelKey:"changelog.filter.active"},{key:"completed",labelKey:"changelog.filter.completed"}];function Me(){const{t}=M(),{trackEvent:o,trackPageView:s}=O(),n=V(),[u,_]=l.useState(null),a=W({placeId:u}),f=U(),{show:x}=K(),[v,g]=l.useState(!1),[C,d]=l.useState(!1),y=!f.loading&&f.tier==="basic",N=y?a.entries.slice(0,3):a.entries,m=!y&&a.total>$,S=async()=>{d(!0);try{await a.clear(),x(t("toast.clearSuccess","Cleared successfully"),"success"),g(!1)}catch{x(t("toast.clearFailed","Failed to clear data"),"error")}finally{d(!1)}};return e.jsxs("div",{className:r.page,children:[e.jsx(H,{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:f.tier}}),e.jsx(Q,{surface:"changelog",selectable:!0,selectedPlaceId:u,onSelectedPlaceIdChange:i=>{_(i),a.setOffset(0)}}),e.jsx(q,{items:Be.map(i=>({key:i.key,label:t(i.labelKey,i.key.charAt(0).toUpperCase()+i.key.slice(1))})),value:a.statusFilter,onChange:i=>{const h=`changelog_${i}`;o("dashboard_click_event",{click_target:`changelog_tab_${i}`,page:"changelog",tab:h}),s({page:"changelog",tab:h}),a.setStatusFilter(i),a.setOffset(0)},rightActions:e.jsx("button",{className:r.clearButton,onClick:()=>{o("dashboard_click_event",{click_target:"changelog_clear",page:"changelog",tab:`changelog_${a.statusFilter}`}),g(!0)},children:t("common.clear","Clear")})}),a.loading&&a.entries.length===0&&e.jsx("div",{className:r.loading,children:t("common.loading","Loading...")}),!a.loading&&a.entries.length===0?e.jsx("div",{className:r.empty,children:t("changelog.empty","No changelog entries for the current place yet")}):e.jsx("div",{className:r.list,children:N.map(i=>e.jsx(ue,{entry:i,onClick:()=>n(ke(i.entryId,u))},i.entryId))}),m&&e.jsxs("div",{className:r.pagination,children:[e.jsx("button",{className:r.btn,disabled:a.offset===0,onClick:()=>a.setOffset(Math.max(0,a.offset-$)),children:t("tools.page.prev","Prev")}),e.jsxs("span",{className:r.pageInfo,children:[a.offset+1,"–",Math.min(a.offset+$,a.total)," / ",a.total]}),e.jsx("button",{className:r.btn,disabled:!a.hasMore,onClick:()=>a.setOffset(a.offset+$),children:t("tools.page.next","Next")})]}),y&&e.jsx(e.Fragment,{children:e.jsxs("div",{className:r.limitNotice,children:[e.jsxs("div",{className:r.limitNoticeContent,children:[e.jsx("div",{className:r.limitNoticeTitle,children:t("changelog.basic.limit.title","Basic preview shows the latest 3 sessions")}),e.jsx("div",{className:r.limitNoticeText,children:t("changelog.basic.limit.body","Full changelog timeline browsing is available with Pro.")})]}),e.jsx("a",{className:r.primaryAction,href:G.changelog,target:"_blank",rel:"noreferrer",onClick:()=>o("dashboard_click_event",{click_target:"upgrade_cta",placement:"changelog_limit_notice",page:"changelog",tab:`changelog_${a.statusFilter}`}),children:t("tier.upgrade","View Pro")})]})}),e.jsx(Z,{open:v,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:C,onCancel:()=>!C&&g(!1),onConfirm:S})]})}export{Me as Component};
@@ -0,0 +1 @@
1
+ import{r as u,j as s}from"./index-B9LVK3-K.js";import{s as a}from"./ConfirmModal.module-NrFlfTWy.js";function p({open:r,title:t,message:o,cancelLabel:c,confirmLabel:n,loading:e=!1,onCancel:l,onConfirm:d}){const i=u.useId();return r?s.jsx("div",{className:a.backdrop,onClick:e?void 0:l,children:s.jsxs("div",{className:a.modal,role:"dialog","aria-modal":"true","aria-labelledby":i,onClick:m=>m.stopPropagation(),children:[s.jsx("h2",{id:i,className:a.title,children:t}),s.jsx("p",{className:a.message,children:o}),s.jsxs("div",{className:a.actions,children:[s.jsx("button",{className:a.cancelButton,onClick:l,disabled:e,children:c}),s.jsx("button",{className:a.confirmButton,onClick:d,disabled:e,children:e?"...":n})]})]})}):null}export{p as C};
@@ -0,0 +1 @@
1
+ ._backdrop_1ozbv_1{position:fixed;top:0;right:0;bottom:0;left:0;background:#0c1018b8;display:grid;place-items:center;z-index:1000;padding:24px}._modal_1ozbv_12{width:min(420px,100%);background:var(--bg-overlay);border:1px solid var(--border);border-radius:18px;box-shadow:0 24px 48px #0307126b;padding:24px}._title_1ozbv_23{margin:0 0 12px;color:var(--text-primary);font-size:20px}._message_1ozbv_30{margin:0;color:var(--text-secondary);line-height:1.6}._actions_1ozbv_37{display:flex;justify-content:flex-end;gap:12px;margin-top:24px}._cancelButton_1ozbv_44,._confirmButton_1ozbv_45{border:0;border-radius:var(--radius);padding:10px 14px;font:inherit;cursor:pointer}._cancelButton_1ozbv_44{background:var(--border);border:1px solid transparent;color:var(--text-primary)}._confirmButton_1ozbv_45{background:var(--error-bg);border:1px solid var(--error-border);color:var(--error-text)}._cancelButton_1ozbv_44:disabled,._confirmButton_1ozbv_45:disabled{cursor:not-allowed;opacity:.6}._pathBlock_1ozbv_75{display:grid;gap:6px}._pathLabel_1ozbv_80{font-size:12px;font-weight:700;color:var(--text-secondary)}._pathCode_1ozbv_86{display:block;overflow-wrap:anywhere;padding:10px 12px;border-radius:12px;border:1px solid var(--border);background:var(--bg-secondary);color:var(--text-primary);font-size:12px;line-height:1.5}._bodyGrid_1ozbv_98{display:grid;gap:14px;margin-top:18px}._warningList_1ozbv_104{margin:0;padding-left:18px;color:var(--text-secondary);line-height:1.6}._errorMessage_1ozbv_111{margin-top:0;color:var(--error-text)}
@@ -0,0 +1 @@
1
+ const o="_backdrop_1ozbv_1",t="_modal_1ozbv_12",_="_title_1ozbv_23",s="_message_1ozbv_30",n="_actions_1ozbv_37",a="_cancelButton_1ozbv_44",c="_confirmButton_1ozbv_45",e="_pathBlock_1ozbv_75",b="_pathLabel_1ozbv_80",r="_pathCode_1ozbv_86",i="_bodyGrid_1ozbv_98",l="_warningList_1ozbv_104",d="_errorMessage_1ozbv_111",p={backdrop:o,modal:t,title:_,message:s,actions:n,cancelButton:a,confirmButton:c,pathBlock:e,pathLabel:b,pathCode:r,bodyGrid:i,warningList:l,errorMessage:d};export{p as s};
@@ -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_17f6d_2{display:flex;flex-direction:column;gap:16px;width:100%;max-width:1180px}._card_17f6d_11{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:16px 20px}._topologyCard_17f6d_19{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:18px 20px 20px}._topologyDisconnected_17f6d_26{border-color:var(--error-border)}._topologyHeader_17f6d_30{display:flex;justify-content:space-between;gap:16px;align-items:flex-start;margin-bottom:18px}._topologyIntro_17f6d_38{margin:-6px 0 0;color:var(--text-secondary);font-size:13px;line-height:1.5}._topologyNetwork_17f6d_45{position:relative}._topologyLinks_17f6d_49{position:absolute;top:0;right:0;bottom:0;left:0;z-index:0;width:100%;height:100%;pointer-events:none;overflow:visible}._topologyLink_17f6d_49{stroke:color-mix(in srgb,var(--accent) 62%,var(--border));stroke-linecap:round;stroke-width:1.5;opacity:.82}._topologyLink_agent_17f6d_66{stroke:color-mix(in srgb,var(--accent) 58%,var(--border))}._topologyLink_studio_17f6d_70{stroke:color-mix(in srgb,var(--accent) 66%,var(--border))}._topologyGrid_17f6d_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_17f6d_83{min-width:0;display:flex;flex-direction:column;gap:10px}._topologyColumnHeader_17f6d_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_17f6d_101{min-height:28px}._topologyCount_17f6d_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_17f6d_120{display:flex;flex-direction:column;gap:8px;justify-content:flex-start;min-height:178px}._topologyListCentered_17f6d_128{justify-content:center}._topologyNode_17f6d_132{min-width:0;border:1px solid var(--border);border-radius:8px;background:var(--bg-secondary);padding:10px 12px}._topologyNodeTitle_17f6d_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_17f6d_140 strong,._topologyNodeTitle_17f6d_140 span{min-width:0}._topologyNodeMeta_17f6d_156,._topologyNodeSubtle_17f6d_157{margin-top:6px;color:var(--text-secondary);font-family:var(--font-code);font-size:11px;line-height:1.4;overflow-wrap:anywhere}._topologyNodeSubtle_17f6d_157{color:var(--text-muted)}._topologyState_17f6d_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_17f6d_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_17f6d_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_17f6d_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_17f6d_213:hover{border-color:var(--border-highlight);background:var(--accent-dim);color:var(--accent)}._topologyServerColumn_17f6d_236{min-width:0;display:flex;flex-direction:column;gap:10px}._topologyServer_17f6d_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_17f6d_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_17f6d_267{display:flex;flex-direction:column;align-items:center;gap:8px;min-width:0;width:100%}._topologyServerTitle_17f6d_276{color:var(--text-primary);font-family:var(--font-label);font-size:15px;font-weight:700}._topologyServerMeta_17f6d_283{color:var(--text-secondary);font-family:var(--font-code);font-size:11px;overflow-wrap:anywhere}._routingSummaryCompact_17f6d_290{display:flex;justify-content:center;width:100%;min-width:0}._disabled_17f6d_298{opacity:.4;pointer-events:none}._cardHeader_17f6d_304{font-family:var(--font-label);font-weight:500;font-size:11px;text-transform:uppercase;letter-spacing:.05em;color:var(--text-secondary);margin-bottom:12px;display:flex;align-items:center;justify-content:space-between}._cardHint_17f6d_317{margin:-4px 0 12px;color:var(--text-muted);font-size:12px;line-height:1.5}._clearButton_17f6d_324{border:1px solid var(--error-border);background:var(--error-bg);color:var(--error-text);border-radius:var(--radius-sm);padding:6px 12px;cursor:pointer}._serverGrid_17f6d_334{display:grid;grid-template-columns:auto 1fr;gap:4px 16px;font-family:var(--font-code);font-size:13px}._serverGrid_17f6d_334 dt{color:var(--text-muted)}._serverGrid_17f6d_334 dd{color:var(--text-primary);margin:0}._statusRow_17f6d_352{display:flex;align-items:center;gap:16px;margin-bottom:12px}._metaItem_17f6d_359{font-family:var(--font-code);font-size:12px;color:var(--text-secondary)}._table_17f6d_366{width:100%;border-collapse:collapse;font-family:var(--font-code);font-size:12px}._table_17f6d_366 th{text-align:left;color:var(--text-muted);font-weight:400;padding:4px 8px 4px 0;border-bottom:1px solid var(--border)}._table_17f6d_366 td{padding:6px 8px 6px 0;color:var(--text-primary)}._tableWrap_17f6d_386{overflow-x:auto}._table_17f6d_366 tr:hover td{background:var(--accent-dim)}._routingSummary_17f6d_290{display:inline-flex;align-items:center;gap:10px;margin-bottom:12px;flex-wrap:wrap}._manageLink_17f6d_402{display:inline-flex;align-items:center;height:24px;padding:0 8px;border:1px solid var(--border);border-radius:var(--radius-sm);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_17f6d_402:hover{border-color:var(--border-highlight);background:var(--accent-dim);color:var(--accent);text-decoration:none}._segment_17f6d_428,._segmentActive_17f6d_429{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_17f6d_428:last-child,._segmentActive_17f6d_429:last-child{border-right:none}._segment_17f6d_428:hover:not(:disabled){background:var(--accent-dim);color:var(--accent)}._segmentActive_17f6d_429{background:var(--accent-dim);color:var(--text-primary);font-weight:600}._segment_17f6d_428:disabled,._segmentActive_17f6d_429:disabled{cursor:default;opacity:.55}._targetPrimary_17f6d_463{white-space:nowrap}._monoMuted_17f6d_467{color:var(--text-secondary)}._copyIconButton_17f6d_471{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-sm);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_17f6d_471:hover{color:var(--accent);border-color:var(--border-highlight);background:var(--accent-dim)}._routingBadge_17f6d_496{display:inline-flex;align-items:center;min-height:22px;padding:0 8px;border:1px solid var(--border-highlight);border-radius:var(--radius-sm);background:var(--accent-dim);color:var(--text-primary);font-family:var(--font-label);font-size:11px;font-weight:600}._toggleBtn_17f6d_511{background:none;border:none;color:var(--text-secondary);cursor:pointer;font-size:12px;padding:0 4px;transition:color var(--transition)}._toggleBtn_17f6d_511:hover{color:var(--accent)}._disconnected_17f6d_526{text-align:center;padding:32px 16px}._disconnected_17f6d_526 h3{color:var(--error);font-size:16px;margin:0 0 8px}._disconnected_17f6d_526 p{color:var(--text-secondary);font-size:13px;margin:0 0 4px}._disconnectedActions_17f6d_543{display:flex;gap:8px;justify-content:center;margin-top:16px}._btn_17f6d_550{font-family:var(--font-label);font-size:12px;padding:6px 14px;border-radius:var(--radius-sm);border:1px solid var(--border);background:var(--bg-secondary);color:var(--text-primary);cursor:pointer;transition:background var(--transition),border-color var(--transition)}._btn_17f6d_550:hover{border-color:var(--accent);background:var(--accent-dim)}._activity_active_17f6d_568,._activity_stale_17f6d_569,._activity_unknown_17f6d_570{display:inline-block;width:7px;height:7px;border-radius:50%;margin-right:6px;vertical-align:middle}._activity_active_17f6d_568{background:var(--success);box-shadow:0 0 4px var(--success)}._activity_stale_17f6d_569{background:var(--text-muted)}._activity_unknown_17f6d_570{background:var(--text-muted);opacity:.4}._killBtn_17f6d_594{font-family:var(--font-label);font-size:11px;padding:3px 10px;border-radius:var(--radius-sm);border:1px solid var(--error-border);background:var(--error-bg);color:var(--error-text);cursor:pointer;transition:background var(--transition),border-color var(--transition)}._killBtn_17f6d_594:hover{background:var(--error-bg);border-color:var(--error-border);color:var(--error-text);filter:brightness(1.15)}._emptyRow_17f6d_614{color:var(--text-muted);font-style:italic}@media(max-width:980px){._topologyHeader_17f6d_30{flex-direction:column;align-items:stretch}._topologyGrid_17f6d_74{grid-template-columns:1fr;gap:10px}._topologyColumnHeaderSpacer_17f6d_101{display:none}._topologyServer_17f6d_236{min-height:150px}}@media(max-width:640px){._card_17f6d_11,._topologyCard_17f6d_19{padding:14px}._topologyNodeTitle_17f6d_140{flex-wrap:wrap}._topologyState_17f6d_170{margin-left:0}}