@mohsinonxrm/pptb-commandbar-studio 0.5.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 (127) hide show
  1. package/CHANGELOG.md +99 -0
  2. package/LICENSE +661 -0
  3. package/README.md +316 -0
  4. package/dist/assets/BulkPublishModal-_JCQ9G-Z.js +29 -0
  5. package/dist/assets/CommandEditorPanel-BfdeUs_f.js +1 -0
  6. package/dist/assets/CommandPalette-D2Kh5NZ1.js +1 -0
  7. package/dist/assets/ConflictDrawer-BLiuWHeb.js +1 -0
  8. package/dist/assets/DiffViewer-BVDCd534.js +7 -0
  9. package/dist/assets/IconPickerModal-BAiIRU4A.js +1 -0
  10. package/dist/assets/ImportXmlModal-D-Ns-mYi.js +3 -0
  11. package/dist/assets/LocalizationEditor-C-TZ2Vqd.js +1 -0
  12. package/dist/assets/MonacoEditor-5dvTziHE.js +2 -0
  13. package/dist/assets/NewButtonModal-DOTUaBiJ.js +1 -0
  14. package/dist/assets/NewGroupModal-CXy9X9y5.js +1 -0
  15. package/dist/assets/NewTabModal-DiGzXYTp.js +1 -0
  16. package/dist/assets/RuleEditorPanel-DT_uPW8s.js +1 -0
  17. package/dist/assets/ScalingEditorPanel-BFnC7t_K.js +1 -0
  18. package/dist/assets/TabDisplayRulesPanel-CdKjedy-.js +1 -0
  19. package/dist/assets/UrlComposerModal-DFtXdVW3.js +1 -0
  20. package/dist/assets/WebResourceBrowser-FvaNo4rt.js +1 -0
  21. package/dist/assets/XmlDrawer-BXAxH3A8.js +2 -0
  22. package/dist/assets/abap-DLDM7-KI.js +1 -0
  23. package/dist/assets/apex-DNDY2TF8.js +1 -0
  24. package/dist/assets/azcli-Y6nb8tq_.js +1 -0
  25. package/dist/assets/bat-BwHxbl9M.js +1 -0
  26. package/dist/assets/bicep-CFznDFnq.js +2 -0
  27. package/dist/assets/cameligo-Bf6VGUru.js +1 -0
  28. package/dist/assets/clojure-Dnu-v4kV.js +1 -0
  29. package/dist/assets/codicon-ngg6Pgfi.ttf +0 -0
  30. package/dist/assets/coffee-Bd8akH9Z.js +1 -0
  31. package/dist/assets/cpp-BbWJElDN.js +1 -0
  32. package/dist/assets/csharp-Co3qMtFm.js +1 -0
  33. package/dist/assets/csp-D-4FJmMZ.js +1 -0
  34. package/dist/assets/css-DdJfP1eB.js +3 -0
  35. package/dist/assets/css.worker-DBVD8oXr.js +93 -0
  36. package/dist/assets/cssMode-DFSY9yCW.js +1 -0
  37. package/dist/assets/cypher-cTPe9QuQ.js +1 -0
  38. package/dist/assets/dart-BOtBlQCF.js +1 -0
  39. package/dist/assets/dnd-DHB99ZH7.js +5 -0
  40. package/dist/assets/dockerfile-BG73LgW2.js +1 -0
  41. package/dist/assets/ecl-BEgZUVRK.js +1 -0
  42. package/dist/assets/elixir-BkW5O-1t.js +1 -0
  43. package/dist/assets/flow9-BeJ5waoc.js +1 -0
  44. package/dist/assets/fluent-icons-DiKr_qRE.js +1 -0
  45. package/dist/assets/fluent-ui-kUA2U4Gr.js +43 -0
  46. package/dist/assets/freemarker2-B8bME0pA.js +3 -0
  47. package/dist/assets/fsharp-PahG7c26.js +1 -0
  48. package/dist/assets/go-acbASCJo.js +1 -0
  49. package/dist/assets/graphql-BxJiqAUM.js +1 -0
  50. package/dist/assets/handlebars-zIyCxTW6.js +1 -0
  51. package/dist/assets/hcl-DtV1sZF8.js +1 -0
  52. package/dist/assets/html-B5hFqu3X.js +1 -0
  53. package/dist/assets/html.worker-CwpTb9lJ.js +470 -0
  54. package/dist/assets/htmlMode-BmPxEBms.js +1 -0
  55. package/dist/assets/index-D9lerlVA.css +1 -0
  56. package/dist/assets/index-G361fmC5.js +6 -0
  57. package/dist/assets/ini-Kd9XrMLS.js +1 -0
  58. package/dist/assets/java-CXBNlu9o.js +1 -0
  59. package/dist/assets/javascript-BQGsYMat.js +1 -0
  60. package/dist/assets/json.worker-BoL8UZqY.js +58 -0
  61. package/dist/assets/jsonMode-CR0b-9Un.js +7 -0
  62. package/dist/assets/julia-cl7-CwDS.js +1 -0
  63. package/dist/assets/kotlin-s7OhZKlX.js +1 -0
  64. package/dist/assets/less-9HpZscsL.js +2 -0
  65. package/dist/assets/lexon-OrD6JF1K.js +1 -0
  66. package/dist/assets/liquid-DLq8jbP8.js +1 -0
  67. package/dist/assets/lspLanguageFeatures-C3buAG32.js +4 -0
  68. package/dist/assets/lua-Cyyb5UIc.js +1 -0
  69. package/dist/assets/m3-B8OfTtLu.js +1 -0
  70. package/dist/assets/markdown-BFxVWTOG.js +1 -0
  71. package/dist/assets/mdx-5ni22WXY.js +1 -0
  72. package/dist/assets/mips-CiqrrVzr.js +1 -0
  73. package/dist/assets/monaco-BLZnQb2P.js +918 -0
  74. package/dist/assets/monaco-Dvl_Svmm.css +1 -0
  75. package/dist/assets/msdax-DmeGPVcC.js +1 -0
  76. package/dist/assets/mysql-C_tMU-Nz.js +1 -0
  77. package/dist/assets/objective-c-BDtDVThU.js +1 -0
  78. package/dist/assets/pascal-vHIfCaH5.js +1 -0
  79. package/dist/assets/pascaligo-DtZ0uQbO.js +1 -0
  80. package/dist/assets/perl-Ub6l9XKa.js +1 -0
  81. package/dist/assets/pgsql-BlNEE0v7.js +1 -0
  82. package/dist/assets/php-BBUBE1dy.js +1 -0
  83. package/dist/assets/pla-DSh2-awV.js +1 -0
  84. package/dist/assets/postiats-CocnycG-.js +1 -0
  85. package/dist/assets/powerquery-tScXyioY.js +1 -0
  86. package/dist/assets/powershell-COWaemsV.js +1 -0
  87. package/dist/assets/protobuf-Brw8urJB.js +2 -0
  88. package/dist/assets/pug-8SOpv6rk.js +1 -0
  89. package/dist/assets/python-F20Pd69B.js +1 -0
  90. package/dist/assets/qsharp-Bw9ernYp.js +1 -0
  91. package/dist/assets/r-j7ic8hl3.js +1 -0
  92. package/dist/assets/razor-3xmsG6cc.js +1 -0
  93. package/dist/assets/redis-Bu5POkcn.js +1 -0
  94. package/dist/assets/redshift-Bs9aos_-.js +1 -0
  95. package/dist/assets/restructuredtext-CqXO7rUv.js +1 -0
  96. package/dist/assets/ruby-zBfavPgS.js +1 -0
  97. package/dist/assets/rust-BzKRNQWT.js +1 -0
  98. package/dist/assets/sb-BBc9UKZt.js +1 -0
  99. package/dist/assets/scala-D9hQfWCl.js +1 -0
  100. package/dist/assets/scheme-BPhDTwHR.js +1 -0
  101. package/dist/assets/scss-CBJaRo0y.js +3 -0
  102. package/dist/assets/server.browser-DfdiBs1P.js +11 -0
  103. package/dist/assets/shell-DiJ1NA_G.js +1 -0
  104. package/dist/assets/solidity-Db0IVjzk.js +1 -0
  105. package/dist/assets/sophia-CnS9iZB_.js +1 -0
  106. package/dist/assets/sparql-CJmd_6j2.js +1 -0
  107. package/dist/assets/sql-ClhHkBeG.js +1 -0
  108. package/dist/assets/st-CHwy0fLd.js +1 -0
  109. package/dist/assets/swift-CnmFD0ga.js +1 -0
  110. package/dist/assets/systemverilog-Bs9z6M-B.js +1 -0
  111. package/dist/assets/tcl-Dm6ycUr_.js +1 -0
  112. package/dist/assets/ts.worker-BH9nVgjN.js +67718 -0
  113. package/dist/assets/tsMode-Cyusk9p4.js +11 -0
  114. package/dist/assets/twig-Csy3S7wG.js +1 -0
  115. package/dist/assets/typescript-BXT-ECX3.js +1 -0
  116. package/dist/assets/typespec-Btyra-wh.js +1 -0
  117. package/dist/assets/vb-Db0cS2oM.js +1 -0
  118. package/dist/assets/webResourceService-Ck07E3GN.js +1 -0
  119. package/dist/assets/wgsl-BTesnYfV.js +298 -0
  120. package/dist/assets/xml-Cwzeco8o.js +1 -0
  121. package/dist/assets/xmlGenerator-DEaVrfZJ.js +130 -0
  122. package/dist/assets/yaml-BHUePD-R.js +1 -0
  123. package/dist/index.html +18 -0
  124. package/dist/stats.html +4949 -0
  125. package/index.html +12 -0
  126. package/npm-shrinkwrap.json +13252 -0
  127. package/package.json +104 -0
package/README.md ADDED
@@ -0,0 +1,316 @@
1
+ # Command Bar Studio for Power Platform ToolBox
2
+
3
+ A fully featured visual designer for Dataverse **classic ribbon / command bar
4
+ customizations** — the spiritual successor to [Ribbon Workbench](https://www.develop1.net/public/rwb/ribbonworkbench.aspx)
5
+ reimagined with React 18, Fluent UI v9, and live Dataverse integration via
6
+ [Power Platform ToolBox](https://www.powerplatformtoolbox.com/).
7
+
8
+ ![Version](https://img.shields.io/badge/version-0.5.0--beta-orange)
9
+ ![React](https://img.shields.io/badge/React-18-61DAFB?logo=react)
10
+ ![TypeScript](https://img.shields.io/badge/TypeScript-5.8-3178C6?logo=typescript)
11
+ ![Fluent UI](https://img.shields.io/badge/Fluent%20UI-v9-0078D4?logo=microsoft)
12
+ ![PPTB Types](https://img.shields.io/badge/%40pptb%2Ftypes-1.2.3-orange)
13
+ ![License](https://img.shields.io/badge/license-AGPL--3.0--only-green)
14
+ ![Tests](https://img.shields.io/badge/tests-148%20passing-brightgreen)
15
+
16
+ > **Classic commands only.** CBS targets Dataverse `RibbonDiffXml` — the
17
+ > classic commanding system. It does not modify Power Fx / Modern Commanding
18
+ > defined in the Command Designer.
19
+
20
+ ---
21
+
22
+ ## ✨ Features
23
+
24
+ ### 🎨 Visual Ribbon Canvas
25
+ - **Classic ribbon view** — faithful tabbed ribbon with groups, large icon tiles, and @dnd-kit drag-and-drop reorder with a styled `DragOverlay` ghost (brand border, shadow, `grabbing` cursor) and animated 2 px drop-line indicators between button slots
26
+ - **Modern command bar view** — flat command bar exactly as rendered in Unified Interface
27
+ - **List view** — sortable data grid of all buttons with inline visibility toggle
28
+ - All 4 ribbon locations: **Home Grid**, **Sub Grid**, **Form**, **Application**
29
+ - Tab drag-to-reorder, inline rename (double-click), `+ Add tab`
30
+ - Context menus on buttons and groups — hide/show, duplicate, move, rename, delete, override OOB
31
+
32
+ ### 📋 Properties Pane
33
+ - Identity: label, translations (multi-LCID), tooltip, icon picker, image16/32, kind, sequence, template alias
34
+ - Command binding with action summary chips
35
+ - Display rules + Enable rules pill lists with inline add/remove
36
+ - Scaling summary with link to full editor
37
+ - Advanced: form ribbon scope selector, `Mscrm.OpenRecordItem` override toggle, client-type filter shortcuts
38
+ - Conflict banner — surfaces managed-solution provenance via solution-layer API
39
+
40
+ ### ⚡ Command Editor
41
+ - JavaScript function: library (with Browse… to Web Resource Browser), function name, positional CrmParameter editor
42
+ - URL action: address, PassParams, WinMode, named CrmParameters with querystring key
43
+ - **Power Fx expression** — inline Monaco editor (syntax-highlighted, word wrap) with variable hints (`ThisRecord`, `Selection`, `Self`) and async-rule note
44
+ - Custom API / Web API action
45
+ - Enable rules + Display rules binding
46
+ - References tab showing exact buttons + tab/group breadcrumb
47
+ - Versions tab from history
48
+ - Security advisory: all command definitions are visible in browser source
49
+
50
+ ### 📐 Rule Editor
51
+ - All 30 RuleStep kinds from `RibbonTypes.xsd` — Enable rules and Display rules
52
+ - Drag-to-reorder steps
53
+ - OrRule with nested "Add nested step"
54
+ - InvertResult + Default value toggles per step
55
+ - Plain-English `summarizeRule()` output
56
+ - CustomRule async note (Promise\<boolean\> on Unified Interface)
57
+
58
+ ### 🔤 Localization Editor
59
+ - Multi-LCID label / tooltip title / tooltip body per button
60
+ - Locale chip row with active/inactive state
61
+ - "Insert line break" (`&#x200b;&#x200b;`)
62
+ - 20 built-in LCIDs; add any custom LCID by number
63
+
64
+ ### 🖼️ Icon Picker
65
+ - **Fluent icons** tab — 85 icon catalogue with category filter + regular/filled variant; auto-uploads selected icon as SVG web resource
66
+ - **Web resources** tab — browseable list of SVG resources in the org with search
67
+ - **Custom upload** tab — drag-and-drop SVG → create web resource
68
+
69
+ ### 🗂️ Scaling Editor
70
+ - MaxSize + Scale step sequence management
71
+ - Document-order-based scaling behavior per MS docs (order of `<Scale>` elements, not Sequence values)
72
+ - Validation: non-overlapping MaxSize/Scale ranges
73
+
74
+ ### 🗃️ Tab Display Rules Editor
75
+ - `EntityRule` (all 4 contexts) + `PageRule`
76
+ - Info note: entity-scoped tabs can only use EntityRule; global tabs can use both
77
+
78
+ ### 🌐 Web Resource Browser
79
+ - Virtualized list with type filter, custom-only toggle, search
80
+ - Upload new resource directly from the browser
81
+ - Edit JS/CSS/XML files in Monaco
82
+
83
+ ### 🔗 URL Action Composer
84
+ - Base URL, PassParams (full 6-parameter table per MS docs), custom CrmParameters
85
+ - Live URL preview; `&` → `&amp;` escaping handled automatically
86
+ - WinMode: Navigate / Dialog / Popup
87
+
88
+ ### 📊 XML Drawer + Diff Viewer
89
+ - Per-location RibbonDiffXml view in Monaco (read-only + editable import path)
90
+ - "Format XML" button
91
+ - Monaco `DiffEditor` compare-to-baseline
92
+ - CBS-specific completions: `$LocLabels:`, `$webresource:`, `Command=`, `ModernImage=`
93
+
94
+ ### 🔄 Publish Pipeline
95
+ - Correct delta-only `RibbonDiffXml` — only changed elements emitted
96
+ - Solution ZIP packaging with `behavior=2` (shell-only) root component — does **not** pull in all entity subcomponents
97
+ - 5-minute import polling with progress beats
98
+ - Post-publish `ribbonmetadatasettoprocess` monitoring — surfaces compile errors that `publishCustomizations` silently swallows
99
+ - `Mscrm.OpenRecordItem` override support — emitted as a system-command override when the user defines a JS action on it
100
+
101
+ ### 🧩 Solution Conflict Drawer
102
+ - Provenance detection via `msdyn_componentlayer` (falls back to namespace heuristic when unavailable)
103
+ - Banner in properties pane for managed-solution buttons
104
+ - Live solution-layer fetch in the drawer
105
+
106
+ ### ⌨️ Keyboard Shortcuts + Command Palette
107
+ - `Ctrl+K` — Command Palette (search buttons, commands, rules, entities, actions)
108
+ - `Ctrl+Z/Y`, `Ctrl+Shift+Z` — Undo / Redo (80-entry stack)
109
+ - `Ctrl+D` — Duplicate selected button
110
+ - `Ctrl+S` — Open Bulk Publish
111
+ - `Delete/Backspace` — Delete button (with OOB confirm)
112
+ - `F2` — Inline rename tab / group
113
+ - Arrow keys — navigate buttons on canvas
114
+
115
+ ### 💾 Persistence
116
+ - Auto-save ribbon state to `localStorage` keyed by org URL + entity
117
+ - Restore-from-previous-session banner on startup
118
+ - Pane widths, collapsed state, view mode all persisted
119
+
120
+ ---
121
+
122
+ ## 🖼️ Interface Overview
123
+
124
+ ```
125
+ ┌─────────────────────────────────────────────────────────────────┐
126
+ │ TopBar: Solution picker │ Ctrl+K │ Undo/Redo │ Save │ Publish │
127
+ │ SubHeader: Breadcrumb │ N changes since publish │ Preview … │
128
+ ├──────────────────┬──────────────────────────────┬───────────────┤
129
+ │ Left Pane │ Ribbon Canvas │ Properties │
130
+ │ • Tables │ Location: Home/Sub/Form/App │ • Identity │
131
+ │ (solution │ Tab strip (drag-reorder) │ • Command │
132
+ │ scope only) │ View: Classic / Modern / List│ • Rules │
133
+ │ • Solution │ Groups + Buttons (DnD) │ • Scaling │
134
+ │ Elements │ │ • Advanced │
135
+ │ – Buttons │ │ │
136
+ │ – Commands │ │ │
137
+ │ – Rules │ │ │
138
+ │ – Templates │ │ │
139
+ ├──────────────────┴──────────────────────────────┴───────────────┤
140
+ │ Bottom Panel: Commands │ Display Rules │ Enable Rules │ History │
141
+ │ │ Console (runtime + publish log) │
142
+ └─────────────────────────────────────────────────────────────────┘
143
+ ```
144
+
145
+ ---
146
+
147
+ ## 🚀 Getting Started
148
+
149
+ Command Bar Studio runs **inside [Power Platform ToolBox](https://www.powerplatformtoolbox.com/)**. It requires the PPTB host to be available — authentication and Dataverse connectivity are provided by the host.
150
+
151
+ 1. Install Power Platform ToolBox
152
+ 2. Connect to a Dataverse environment
153
+ 3. Open Command Bar Studio from the tool list
154
+ 4. Pick an unmanaged solution from the TopBar
155
+ 5. Select a table from the left pane
156
+ 6. Edit ribbon buttons visually; click **Publish** when done
157
+
158
+ ---
159
+
160
+ ## 🛠️ Development
161
+
162
+ ### Setup
163
+
164
+ ```bash
165
+ git clone https://github.com/mohsinonxrm/pptb-mxrm-commandbar-studio.git
166
+ cd pptb-mxrm-commandbar-studio
167
+ npm install
168
+ ```
169
+
170
+ ### Common scripts
171
+
172
+ ```bash
173
+ # Vite dev server (standalone — no PPTB host; ribbon APIs not available)
174
+ npm run dev
175
+
176
+ # TypeScript-only check (fast)
177
+ npm run typecheck
178
+
179
+ # Production build
180
+ npm run build
181
+
182
+ # Preview the production build locally
183
+ npm run preview
184
+
185
+ # Run tests
186
+ npm test
187
+
188
+ # Run tests with coverage
189
+ npm run test:coverage
190
+ ```
191
+
192
+ ### Standalone vs PPTB-embedded
193
+
194
+ CBS runs in two modes:
195
+
196
+ - **Standalone** (`npm run dev`) — opens in a regular browser tab. Useful for UI
197
+ iteration. All Dataverse calls fail because `window.dataverseAPI` is absent; the
198
+ canvas and editors can still be exercised with the restore-from-localStorage path.
199
+ - **Embedded in PPTB** — loads inside the PPTB iframe. The host injects
200
+ `window.dataverseAPI` (typed) and `window.toolboxAPI`. All publish, load, and
201
+ web-resource operations work against the active connection.
202
+
203
+ ---
204
+
205
+ ## 📦 Tech Stack
206
+
207
+ | Technology | Version | Purpose |
208
+ |---|---|---|
209
+ | **React** | 18.3 | UI framework |
210
+ | **TypeScript** | 5.8 | Strict mode, discriminated unions throughout |
211
+ | **Vite** | 7 | Build tooling + HMR |
212
+ | **Fluent UI v9** | 9.62 | Microsoft design system (Drawer, Dialog, DataGrid, Combobox…) |
213
+ | **Monaco Editor** | 0.55 | XML / JS / diff editing across XmlDrawer, DiffViewer, Command Editor |
214
+ | **@dnd-kit** | 6.3 | Drag-to-reorder for tabs, ribbon buttons (DragOverlay ghost + DroppableSlot indicators), and rule steps |
215
+ | **@fluentui-contrib/react-data-grid-react-window** | 1.4 | Virtualized entity list + web resource browser |
216
+ | **Zustand** | 5 | Global state (ribbons, selection, UI, session) |
217
+ | **fflate** | 0.8 | ZIP compression for solution package + ribbon XML decompression |
218
+ | **@pptb/types** | 1.2.3 | Power Platform ToolBox host API types (`window.dataverseAPI`, `window.toolboxAPI`) |
219
+ | **Vitest** | 3 | Test runner — 148 tests across 8 suites |
220
+
221
+ ---
222
+
223
+ ## 📁 Project Layout
224
+
225
+ ```
226
+ src/
227
+ components/
228
+ shell/ — TopBar, SubHeader, Layout (resizable 4-pane)
229
+ ribbon-canvas/ — RibbonCanvas, ClassicRibbon, ModernCommandBar, RibbonListView
230
+ properties-pane/ — PropertiesPane + 6 section components
231
+ bottom-panel/ — BottomPanel (Commands / Rules / History / Console tabs)
232
+ panels/ — CommandEditor, RuleEditor, ScalingEditor, TabDisplayRules,
233
+ ConflictDrawer, WebResourceBrowser, UrlComposer,
234
+ DiffViewer, XmlDrawer
235
+ modals/ — BulkPublish, IconPicker, LocalizationEditor, NewButton/Group/Tab,
236
+ HideOobWarning, ImportXml, MoveToFlyout
237
+ command-palette/ — CommandPalette (Ctrl+K)
238
+ shared/ — MonacoEditor, FluentIcon, CrmParameterEditor,
239
+ RuleStepEditor, RuleStepPicker, ResizableHandle
240
+ services/
241
+ xmlGenerator.ts — Delta-only RibbonDiffXml generator (all 30 rule kinds)
242
+ xmlParser.ts — Merged ribbon XML parser (all 30 rule kinds)
243
+ xmlValidator.ts — Pre-import validation with user-friendly messages
244
+ dataverse/
245
+ ribbonService.ts — RetrieveEntityRibbon / RetrieveApplicationRibbon
246
+ publishService.ts — Solution ZIP packaging + import + ribbonmetadatasettoprocess poll
247
+ ribbonProvenanceService.ts — msdyn_componentlayer solution-layer provenance
248
+ conflictService.ts — fetchConflictLayersForElement
249
+ webResourceService.ts — loadWebResources / loadWebResourceByName / loadWebResourceContent
250
+ store/
251
+ ribbonStore.ts — Ribbon state, 80-entry undo/redo, mutationsSincePublish
252
+ selectionStore.ts — Selected location / tab / group / button
253
+ uiStore.ts — Modal open states, pane widths, view mode (persisted)
254
+ sessionStore.ts — Solutions, entities, connection, publisher prefix
255
+ runtimeLogStore.ts — Console tab entries
256
+ utils/
257
+ ruleEngine.ts — summarizeRule() + evaluateRule() for all 30 kinds
258
+ idGenerator.ts — Publisher-prefixed unique ribbon IDs
259
+ webResourceBrowserCallback.ts — Module-level callback registry for WRB selection
260
+ ribbonProvenance.ts — applyProvenanceToRibbons + heuristicOrigin
261
+ monacoCompletions.ts — $LocLabels: / $webresource: / Command= completions
262
+ types/
263
+ ribbon.ts — Full domain model: RibbonButton, RuleStep (30 kinds), …
264
+ __tests__/ — 148 Vitest tests
265
+ __fixtures__/ — ribbon/account-full.xml, all-rule-kinds.xml, ribbondiff/…
266
+ ```
267
+
268
+ ---
269
+
270
+ ## 🤝 Contributing
271
+
272
+ Contributions are welcome! Please read the [Conventional Commits](https://www.conventionalcommits.org/) guide —
273
+ all commits must follow the format enforced by `commitlint`.
274
+
275
+ 1. Fork the repository
276
+ 2. Create a feature branch: `git checkout -b feat/my-feature`
277
+ 3. Commit: `git commit -m 'feat(canvas): add drag overlay'`
278
+ 4. Push: `git push origin feat/my-feature`
279
+ 5. Open a Pull Request → `dev`
280
+
281
+ **Branch model:**
282
+ - `dev` — working branch; all PRs target this
283
+ - `main` — protected; only release-tagged merges
284
+
285
+ ---
286
+
287
+ ## 📋 Roadmap
288
+
289
+ - [x] ~~ClassicRibbon drag migration to `@dnd-kit` with `DragOverlay` ghost~~ ✅ shipped in 0.5.0
290
+ - [ ] `QueueUpdateRibbonClientMetadata` for targeted ribbon-only publish (vs. broad `publishCustomizations`)
291
+ - [ ] Power Fx LSP / language server integration
292
+ - [ ] Import error line highlighting in Monaco
293
+ - [ ] Accessibility audit — verify full WCAG 2.1 AA compliance against spec §28
294
+ - [ ] ClassicRibbon button drag: migrate from `useDraggable` to `useSortable` for live in-place reordering animation
295
+
296
+ ---
297
+
298
+ ## 📄 License
299
+
300
+ Licensed under the [GNU Affero General Public License v3.0 (AGPL-3.0-only)](LICENSE). See `LICENSE` for details.
301
+
302
+ ---
303
+
304
+ ## 🙏 Acknowledgments
305
+
306
+ - **[Scott Durrow](https://www.develop1.net/)** — creator of [Ribbon Workbench](https://www.develop1.net/public/rwb/ribbonworkbench.aspx),
307
+ the original community tool for Dataverse ribbon customization and the direct
308
+ inspiration for Command Bar Studio. CBS exists to carry that work forward inside
309
+ the Power Platform ToolBox ecosystem.
310
+ - **[Power Platform ToolBox](https://github.com/PowerPlatformToolBox/desktop-app)** — host platform providing authenticated Dataverse access
311
+ - **[Fluent UI](https://react.fluentui.dev/)** — Microsoft design system
312
+ - **[Monaco Editor](https://microsoft.github.io/monaco-editor/)** — VS Code editor component
313
+
314
+ ---
315
+
316
+ Built with ❤️ for the Power Platform community
@@ -0,0 +1,29 @@
1
+ import{cw as i,cx as Pe}from"./fluent-icons-DiKr_qRE.js";import{r as S,b as pe}from"./monaco-BLZnQb2P.js";import{d as _,h as X,z as je,s as ee,i as se,u as I}from"./index-G361fmC5.js";import{g as Ce,w as $e,e as $,s as me}from"./xmlGenerator-DEaVrfZJ.js";import{d as ve,h as Ie,i as Re,f as ke,g as Le,u as q,w as O,a1 as N,Q as ie,a as T,C as oe,F as te,n as ze,O as be,I as Xe,J as De,R as Ee,B as Me,A as Te,e as Ue}from"./fluent-ui-kUA2U4Gr.js";import"./dnd-DHB99ZH7.js";const x=window.dataverseAPI;function de(e){const t=e.data?.progress;return!!(typeof t=="object"&&t!==null&&t.completed===!0||typeof e.progress=="number"&&e.progress>=100||typeof t=="number"&&t>=100||e.completedon||e.data?.completedon||e.statuscode===30)}async function he(e,t){const n=_.getState();t?.("Generating RibbonDiffXml…"),n.logInfo("publish",`Generating RibbonDiffXml for ${e.entityLogicalName}.`);const b=Ce({current:e.current,baseline:e.baseline,commands:e.commands,enableRules:e.enableRules,displayRules:e.displayRules,locLabels:e.locLabels,entityLogicalName:e.entityLogicalName,location:e.current.location}),h=X.getState().formRibbonScope,m=X.getState().selectedFormId,c=e.current.location==="Application"?"application":e.current.location==="Form"&&h==="form"?"form":"entity",R=$e(b,e.entityLogicalName,c,c==="form"?m:void 0),g=[];if(c==="entity"&&e.entityLogicalName?g.push({type:1,schemaName:e.entityLogicalName,behavior:2}):c==="form"&&e.entityLogicalName&&m&&(g.push({type:1,schemaName:e.entityLogicalName,behavior:2}),g.push({type:60,id:m,behavior:0})),c==="application"&&e.ribbonCustomizationIds?.length)for(const p of e.ribbonCustomizationIds)g.push({type:50,id:p,behavior:0});const w=Fe({uniqueName:e.solutionUniqueName,publisherUniqueName:e.publisherUniqueName,publisherName:e.publisherName,publisherPrefix:e.publisherPrefix,version:e.solutionVersion,rootComponents:g});t?.("Packaging solution ZIP…"),n.logInfo("publish","Packaging solution ZIP...");const l=je({"customizations.xml":ee(R),"solution.xml":ee(w),"[Content_Types].xml":ee('<?xml version="1.0" encoding="utf-8"?><Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="xml" ContentType="application/xml"/></Types>')});let P="";for(let p=0;p<l.length;p++)P+=String.fromCharCode(l[p]);const a=btoa(P);t?.("Importing solution…"),n.logInfo("publish","Importing solution via deploySolution...");const u=typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`${Date.now()}-${Math.random().toString(16).slice(2)}-${Math.random().toString(16).slice(2)}`;n.logInfo("publish",`Import job id: ${u}`),await x.deploySolution(a,{importJobId:u,overwriteUnmanagedCustomizations:!0,publishWorkflows:!1}),t?.("Waiting for import to complete…"),n.logInfo("publish",`Polling import job ${u}...`);const f=150,j=2e3;let k=await x.getImportJobStatus(u),v=0;for(;!de(k)&&v<f;)await new Promise(p=>setTimeout(p,j)),k=await x.getImportJobStatus(u),v++,v%15===0&&t?.(`Still importing… (${v*2}s elapsed)`);if(!de(k)){const p=Math.round(f*j/1e3);throw n.logError("publish",`Solution import did not complete within ${p}s. Check Solutions › History in maker.powerapps.com for job ${u} — the import may still succeed there.`),new Error(`Solution import did not signal completion within ${p} seconds. Check Solutions › History for job ${u}.`)}if(e.publishCustomizations!==!1){t?.("Publishing customizations…"),n.logInfo("publish","Publishing customizations...");const p=new Date;e.entityLogicalName&&e.entityLogicalName!=="{!EntityLogicalName}"?await x.publishCustomizations(e.entityLogicalName):await x.publishCustomizations(),await Ve(e.entityLogicalName,p,n,t)}t?.("Published successfully!"),n.logInfo("publish","Publish completed successfully.")}async function Ve(e,t,n,b){const c=e&&e!=="{!EntityLogicalName}"?`entityname eq '${e}'`:null,g=`ribbonmetadatasettoprocess?$select=entityname,processedon,completedon,exceptionmessage,retrycount,status&$orderby=createdon desc&$top=10&$filter=createdon gt ${t.toISOString().replace(/\.\d+Z$/,"Z")}`+(c?` and (${c})`:"");for(let w=0;w<15;w++){await new Promise(l=>setTimeout(l,2e3));try{const l=await x.queryData(g),P=Array.isArray(l)?l:Array.isArray(l?.value)?l.value:[];if(P.length===0)continue;const a=P.find(f=>f.exceptionmessage);if(a){const j=`Ribbon-metadata compile failed for ${a.entityname||e}: `+a.exceptionmessage;throw n.logError("publish",j),b?.(`⚠ ${j}`),new Error(j)}const u=P.find(f=>f.completedon||f.processedon||f.status===4);if(u){const f=u.entityname||e;n.logInfo("publish",`Ribbon metadata compiled successfully for ${f}.`);return}w===Math.floor(15/2)&&(b?.("Waiting for ribbon-metadata compilation…"),n.logInfo("publish","Ribbon metadata job found; waiting for completion…"))}catch(l){if(l instanceof Error&&l.message.includes("Ribbon-metadata compile failed"))throw l;n.logWarn("publish",`Could not read ribbonmetadatasettoprocess (${l instanceof Error?l.message:String(l)}). Ribbon metadata verification skipped.`);return}}n.logInfo("publish","Ribbon metadata job not observed within 30 s. The publish appears complete — open the entity to confirm your changes are live.")}function qe(e){const t=e.entityLogicalNames.map(b=>`<entity>${$(b)}</entity>`).join(""),n=e.publishDependencies?"<nodes/><securityroles/><settings/><workflows/><templates/><plugins/><sdkmessageprocessingsteps/><serviceendpoints/><webresources/>":"<nodes/>";return`<importexportxml><entities>${t}</entities>${n}</importexportxml>`}async function Oe(e,t){const n=_.getState(),b=e.entityLogicalNames.filter(Boolean);if(b.length===0){e.includeApplicationRibbon&&(t?.("Publishing all customizations..."),await x.publishCustomizations());return}const h=qe({entityLogicalNames:b,publishDependencies:e.publishDependencies});t?.("Publishing selected components with PublishXml..."),n.logInfo("publish",`PublishXml request for ${b.length} table(s).`);try{await x.execute({operationName:"PublishXml",operationType:"action",parameters:{ParameterXml:h}}),e.includeApplicationRibbon&&(t?.("Publishing application ribbon..."),await x.publishCustomizations()),n.logInfo("publish","PublishXml completed successfully.")}catch(m){n.logWarn("publish",`PublishXml failed, falling back to publishCustomizations(): ${m instanceof Error?m.message:String(m)}`);for(const c of b)t?.(`Fallback publish for ${c}...`),await x.publishCustomizations(c);e.includeApplicationRibbon&&(t?.("Fallback publish for application ribbon..."),await x.publishCustomizations())}}async function Be(e,t){const n=_.getState(),b=2e3,h=600*1e3;e?.("Starting asynchronous publish (PublishAllXmlAsync)..."),n.logInfo("publish","Calling PublishAllXmlAsync action.");const c=(await x.execute({operationName:"PublishAllXmlAsync",operationType:"action"}))?.AsyncOperationId;if(!c)throw new Error("PublishAllXmlAsync did not return AsyncOperationId.");n.logInfo("publish",`PublishAllXmlAsync job id: ${c}`),e?.("Async publish job started. Waiting for completion...");const R=Date.now();let g=0,w;for(;Date.now()-R<h;){g+=1;const l=await x.retrieve("asyncoperation",c,["asyncoperationid","statecode","statuscode","name","message","friendlymessage","completedon"]);if(w=l.statuscode,l.statecode===3||!!l.completedon){if(typeof l.statuscode=="number"&&l.statuscode!==30){const a=l.friendlymessage||l.message||`statuscode=${l.statuscode}`;throw new Error(`Asynchronous publish failed: ${a}`)}return e?.("Asynchronous publish completed successfully."),n.logInfo("publish",`PublishAllXmlAsync completed in ${g} poll(s).`),{asyncOperationId:c,statusCode:l.statuscode}}e?.(`Waiting for async publish job... (poll ${g})`),await new Promise(a=>setTimeout(a,b))}throw new Error(`Asynchronous publish timed out after ${Math.round(h/1e3)} seconds (last status: ${w??"unknown"}).`)}function Fe(e){const t=e.publisherUniqueName?.trim()||"DefaultPublisher",n=e.publisherName?.trim()||t,b=e.publisherPrefix?.trim()||"new",h=e.rootComponents.length===0?"<RootComponents/>":`<RootComponents>
2
+ ${e.rootComponents.map(m=>{const c=[`type="${m.type}"`];return m.schemaName&&c.push(`schemaName="${$(m.schemaName)}"`),m.id&&c.push(`id="{${$(m.id)}}"`),c.push(`behavior="${m.behavior}"`),`<RootComponent ${c.join(" ")} />`}).join(`
3
+ `)}
4
+ </RootComponents>`;return`<?xml version="1.0" encoding="utf-8"?>
5
+ <ImportExportXml version="9.1.0.0" SolutionPackageVersion="9.1" languagecode="1033" generatedBy="CommandBarStudio">
6
+ <SolutionManifest>
7
+ <UniqueName>${$(e.uniqueName)}</UniqueName>
8
+ <LocalizedNames>
9
+ <LocalizedName description="${$(e.uniqueName)}" languagecode="1033"/>
10
+ </LocalizedNames>
11
+ <Descriptions/>
12
+ <Version>${$(e.version)}</Version>
13
+ <Managed>0</Managed>
14
+ <Publisher>
15
+ <UniqueName>${$(t)}</UniqueName>
16
+ <LocalizedNames>
17
+ <LocalizedName description="${$(n)}" languagecode="1033"/>
18
+ </LocalizedNames>
19
+ <Descriptions/>
20
+ <EMailAddress/>
21
+ <SupportingWebsiteUrl/>
22
+ <CustomizationPrefix>${$(b)}</CustomizationPrefix>
23
+ <CustomizationOptionValuePrefix>10000</CustomizationOptionValuePrefix>
24
+ <Addresses/>
25
+ </Publisher>
26
+ ${h}
27
+ <MissingDependencies/>
28
+ </SolutionManifest>
29
+ </ImportExportXml>`}const _e=Pe({content:{display:"flex",flexDirection:"column",gap:N.spacingVerticalM},entityList:{display:"flex",flexDirection:"column",gap:N.spacingVerticalXS,maxHeight:"240px",overflowY:"auto",border:`1px solid ${N.colorNeutralStroke2}`,borderRadius:N.borderRadiusMedium,padding:N.spacingVerticalXS},progressList:{display:"flex",flexDirection:"column",gap:N.spacingVerticalXS},progressRow:{display:"flex",alignItems:"center",gap:N.spacingHorizontalS}}),Qe=()=>{const e=_e(),t=se(s=>s.bulkPublishOpen),n=se(s=>s.closeBulkPublish),b=se(s=>s.openXmlDrawer),h=I(s=>s.ribbons),m=I(s=>s.baseline),c=I(s=>s.commands),R=I(s=>s.displayRules),g=I(s=>s.enableRules),w=I(s=>s.locLabels),l=I(s=>s.markPublished),P=I(s=>s.mutationsSincePublish),a=X(s=>s.activeSolution),u=X(s=>s.activeEntity),f=X(s=>s.entities),j=X(s=>s.publisherPrefix),k=X(s=>s.solutionRibbonComponentIds),v=Array.isArray(k)&&k.length>0,[p,W]=S.useState(u?[u.logicalName]:[]),[C,ge]=S.useState(!1),[L,H]=S.useState(!1),[fe,A]=S.useState({}),[B,ne]=S.useState(!1),[U,ye]=S.useState(!1),[le,xe]=S.useState(!0),[J,Se]=S.useState("targeted"),[ae,D]=S.useState(""),[Ne,we]=S.useState(""),[V,re]=S.useState(a?.version??"1.0.0.0"),[F,Z]=S.useState([]),G=pe.useMemo(()=>{const o=(V||a?.version||"1.0.0.0").split(".").map(y=>Number.parseInt(y,10)||0);for(;o.length<4;)o.push(0);return o[3]+=1,o.slice(0,4).join(".")},[a?.version,V]);pe.useEffect(()=>{re(a?.version??"1.0.0.0")},[a?.version]);const Ae=s=>{W(o=>o.includes(s)?o.filter(y=>y!==s):[...o,s])},Y=s=>{A(o=>{const y={...o};for(const E of p)y[E]=s;return C&&(y.Application=s),y})},ce=async s=>{if(!a)return;H(!0),D(""),Z([]);const o={};p.forEach(d=>o[d]="pending"),C&&(o.Application="pending"),A(o);let y=!1;const E=[],M=_.getState(),Q=d=>d instanceof Error?d.message:String(d);if(u&&p.includes(u.logicalName)){A(r=>({...r,[u.logicalName]:"publishing"}));const d=["HomepageGrid","SubGrid","Form"].filter(r=>me(h[r],m[r]).hasAnyChange);if(d.length===0)M.logInfo("publish",`Entity ribbon publish skipped (${u.logicalName}) — no changes vs. baseline.`),A(r=>({...r,[u.logicalName]:"success"}));else try{for(const r of d)M.logInfo("publish",`Publishing ${r} ribbon for ${u.logicalName}…`),await he({current:h[r],baseline:m[r],commands:c,displayRules:R,enableRules:g,locLabels:w,entityLogicalName:u.logicalName,solutionUniqueName:a.uniqueName,publisherUniqueName:a.publisherUniqueName,publisherName:a.publisherName,publisherPrefix:a.publisherPrefix||j,solutionVersion:U?G:V,publishCustomizations:!1},z=>D(z));A(r=>({...r,[u.logicalName]:"success"}))}catch(r){y=!0;const z=Q(r);E.push({scope:u.logicalName,message:z}),M.logError("publish",`Entity ribbon publish failed (${u.logicalName}): ${z}`),A(K=>({...K,[u.logicalName]:"error"}))}}if(C)if(!me(h.Application,m.Application).hasAnyChange)M.logInfo("publish","Application ribbon publish skipped — no changes vs. baseline."),A(r=>({...r,Application:"success"}));else{A(r=>({...r,Application:"publishing"}));try{await he({current:h.Application,baseline:m.Application,commands:c,displayRules:R,enableRules:g,locLabels:w,entityLogicalName:"{!EntityLogicalName}",solutionUniqueName:a.uniqueName,publisherUniqueName:a.publisherUniqueName,publisherName:a.publisherName,publisherPrefix:a.publisherPrefix||j,solutionVersion:U?G:V,ribbonCustomizationIds:k??[],publishCustomizations:!1},r=>D(r)),A(r=>({...r,Application:"success"}))}catch(r){y=!0;const z=Q(r);E.push({scope:"Application ribbon",message:z}),M.logError("publish",`Application ribbon publish failed: ${z}`),A(K=>({...K,Application:"error"}))}}if(s==="publish"&&!y)try{Y("publishing"),J==="targeted"?await Oe({entityLogicalNames:p,includeApplicationRibbon:C,publishDependencies:le},d=>D(d)):await Be(d=>D(d)),Y("success"),l()}catch(d){y=!0;const r=Q(d);E.push({scope:"Publish customizations",message:r}),M.logError("publish",`Publish customizations failed: ${r}`),Y("error")}Z(E),ne(!y),H(!1)},ue=()=>{H(!1),A({}),ne(!1),D(""),Z([]),n()};return i.jsx(ve,{open:t,onOpenChange:()=>!L&&ue(),children:i.jsxs(Ie,{style:{maxWidth:"640px",maxHeight:"92vh",display:"flex",flexDirection:"column"},children:[i.jsx(Re,{children:"Publish to Dataverse"}),i.jsxs(ke,{style:{flex:1,minHeight:0,overflow:"hidden"},children:[i.jsx(Le,{style:{overflowY:"auto",maxHeight:"100%"},children:i.jsxs("div",{className:e.content,children:[!a&&i.jsx(q,{intent:"warning",children:i.jsx(O,{children:"No solution selected. Please select a solution first."})}),i.jsx(q,{intent:"info",children:i.jsxs(O,{children:["Publishing typically takes 5-30 seconds per table. Open users will see the updated ribbon on next page load. You have ",i.jsx("strong",{children:P})," ","change(s) since last publish."]})}),F.length>0&&i.jsx(q,{intent:"error",layout:"multiline",children:i.jsxs(O,{children:[i.jsxs("strong",{children:["Publish failed (",F.length," error",F.length!==1?"s":"",")"]}),i.jsx("ul",{style:{margin:`${N.spacingVerticalXS} 0 0`,paddingLeft:20},children:F.map((s,o)=>i.jsxs("li",{style:{fontFamily:N.fontFamilyMonospace},children:[i.jsxs("strong",{children:[s.scope,":"]})," ",s.message]},o))}),i.jsxs("div",{style:{marginTop:N.spacingVerticalS},children:["Full details are in the ",i.jsx("strong",{children:"Console"})," tab of the bottom panel."]})]})}),!L&&!B&&i.jsxs(i.Fragment,{children:[i.jsx(ie,{weight:"semibold",children:"Select tables to publish:"}),i.jsxs("div",{style:{display:"flex",gap:N.spacingHorizontalS},children:[i.jsx(T,{appearance:"subtle",size:"small",onClick:()=>W(f.map(s=>s.logicalName)),children:"Select all"}),i.jsx(T,{appearance:"subtle",size:"small",onClick:()=>W([]),children:"Deselect all"})]}),i.jsx("div",{className:e.entityList,children:f.map(s=>i.jsx(oe,{label:`${s.displayName||s.logicalName} (${s.logicalName})`,checked:p.includes(s.logicalName),onChange:()=>Ae(s.logicalName)},s.logicalName))}),i.jsxs("div",{children:[i.jsx(oe,{label:"Include Application Ribbon",checked:C&&v,disabled:!v,onChange:(s,o)=>ge(o.checked===!0)}),!v&&i.jsxs(ie,{size:100,style:{color:N.colorNeutralForeground3,display:"block",marginLeft:28,marginTop:2},children:["This solution doesn't include the Application Ribbon component. In maker.powerapps.com, open the solution and choose"," ",i.jsx("strong",{children:"Add existing → Application Ribbons"}),", then reload here."]})]}),i.jsx(te,{label:"Publish strategy",children:i.jsxs(ze,{selectedOptions:[J],onOptionSelect:(s,o)=>{(o.optionValue==="targeted"||o.optionValue==="allAsync")&&Se(o.optionValue)},children:[i.jsx(be,{value:"targeted",children:"Targeted publish (PublishXml)"}),i.jsx(be,{value:"allAsync",children:"Async publish all (PublishAllXmlAsync)"})]})}),i.jsx(q,{intent:"info",children:i.jsx(O,{children:J==="targeted"?"Targeted mode publishes selected tables/components using PublishXml.":"Async mode runs PublishAllXmlAsync and tracks the background system job."})}),i.jsx(te,{label:"Solution version",children:i.jsx(Xe,{size:"small",value:U?G:V,onChange:(s,o)=>re(o.value),disabled:U})}),i.jsx(De,{label:"Increment solution version",checked:U,onChange:(s,o)=>ye(o.checked===!0)}),i.jsx(oe,{label:"Publish dependencies (commands, rules, web resources)",checked:le,onChange:(s,o)=>xe(o.checked===!0)}),i.jsx(te,{label:"Publish comment",children:i.jsx(Ee,{resize:"vertical",value:Ne,onChange:(s,o)=>we(o.value)})}),i.jsx(T,{appearance:"subtle",onClick:()=>{b(),n()},children:"View RibbonDiffXml"})]}),(L||B)&&i.jsxs("div",{className:e.progressList,children:[[...p,...C?["Application"]:[]].map(s=>{const o=fe[s]??"pending";return i.jsxs("div",{className:e.progressRow,children:[i.jsx(Me,{appearance:"filled",color:o==="success"?"success":o==="error"?"danger":o==="publishing"?"informative":"subtle",size:"small",children:o}),i.jsx(ie,{children:s}),o==="publishing"&&i.jsx(Te,{thickness:"large",style:{flex:1}})]},s)}),ae&&i.jsx(q,{intent:"info",children:i.jsx(O,{children:ae})})]})]})}),i.jsxs(Ue,{children:[i.jsx(T,{appearance:"secondary",onClick:ue,disabled:L,children:B?"Close":"Cancel"}),!B&&i.jsxs(i.Fragment,{children:[i.jsx(T,{appearance:"secondary",onClick:()=>{ce("save")},disabled:L||p.length===0&&!C||!a,children:"Save only"}),i.jsx(T,{appearance:"primary",onClick:()=>{ce("publish")},disabled:L||p.length===0&&!C||!a,children:L?"Publishing...":`Publish (${p.length+(C?1:0)})`})]})]})]})]})})};export{Qe as BulkPublishModal,Qe as default};
@@ -0,0 +1 @@
1
+ import{cw as e,x as Ee,h as Me,aw as z,a as U,cx as xe}from"./fluent-icons-DiKr_qRE.js";import{r as j}from"./monaco-BLZnQb2P.js";import{i as B,u as R,w as De,g as Le}from"./index-G361fmC5.js";import{S as V,F as v,I as S,C as We,B as L,a as m,Q as x,a1 as l,x as $e,l as Te,m as _e,k as Ue,K as Ve,T as E,j as ee,u as M,w as D}from"./fluent-ui-kUA2U4Gr.js";import{M as pe}from"./MonacoEditor-5dvTziHE.js";import{l as He,a as Oe,s as Xe}from"./webResourceService-Ck07E3GN.js";import"./dnd-DHB99ZH7.js";const qe=xe({root:{display:"flex",flexDirection:"column",gap:l.spacingVerticalXS},param:{display:"flex",gap:l.spacingHorizontalS,alignItems:"flex-end",padding:l.spacingVerticalXS,border:`1px solid ${l.colorNeutralStroke2}`,borderRadius:l.borderRadiusMedium},typeSelect:{width:"140px",flexShrink:0},valueField:{flex:1},actions:{display:"flex",gap:l.spacingHorizontalXS,flexShrink:0},addButton:{alignSelf:"flex-start"},hint:{color:l.colorNeutralForeground3,fontSize:l.fontSizeBase100}}),Je=[{label:"Context",values:["PrimaryControl","PrimaryControlId","SelectedControl","CommandProperties"]},{label:"Record",values:["PrimaryEntityTypeCode","PrimaryEntityTypeName","FirstPrimaryItemId","PrimaryItemIds"]},{label:"Selection context",values:["SelectedEntityTypeCode","SelectedEntityTypeName","FirstSelectedItemId"]},{label:"Grid selection",values:["SelectedControlSelectedItemCount","SelectedControlSelectedItemIds","SelectedControlSelectedItemReferences","SelectedControlAllItemCount","SelectedControlAllItemIds","SelectedControlAllItemReferences","SelectedControlUnselectedItemCount","SelectedControlUnselectedItemIds","SelectedControlUnselectedItemReferences"]},{label:"Org/User",values:["OrgName","OrgLcid","UserLcid"]}],he=({params:n,onChange:F,urlMode:N=!1})=>{const y=qe(),C=(i,p)=>{const h=[...n];h[i]=p,F(h)},H=i=>{F(n.filter((p,h)=>h!==i))},O=(i,p)=>{const h=[...n],d=i+p;d<0||d>=h.length||([h[i],h[d]]=[h[d],h[i]],F(h))},W=()=>{F([...n,{kind:"CrmParameter",value:"PrimaryControl"}])};return e.jsxs("div",{className:y.root,children:[n.map((i,p)=>e.jsxs("div",{className:y.param,children:[e.jsx("div",{className:y.typeSelect,children:e.jsxs(V,{value:i.kind,onChange:(h,d)=>{const f=d.value;f==="CrmParameter"?C(p,{kind:f,value:"PrimaryControl"}):f==="BoolParameter"?C(p,{kind:f,value:!1}):f==="IntParameter"||f==="DecimalParameter"?C(p,{kind:f,value:0}):C(p,{kind:"StringParameter",value:""})},children:[e.jsx("option",{value:"CrmParameter",children:"CrmParameter"}),e.jsx("option",{value:"StringParameter",children:"String"}),e.jsx("option",{value:"BoolParameter",children:"Boolean"}),e.jsx("option",{value:"IntParameter",children:"Integer"}),e.jsx("option",{value:"DecimalParameter",children:"Decimal"})]})}),N&&e.jsx(v,{label:"Name (querystring key)",style:{width:"130px",flexShrink:0},children:e.jsx(S,{value:i.name??"",onChange:(h,d)=>C(p,{...i,name:d.value||void 0}),placeholder:"key"})}),e.jsx("div",{className:y.valueField,children:i.kind==="CrmParameter"?e.jsx(V,{value:i.value,onChange:(h,d)=>C(p,{...i,value:d.value}),children:Je.map(h=>h.values.map(d=>e.jsx("option",{value:d,children:d},d)))}):i.kind==="BoolParameter"?e.jsx(We,{checked:i.value,onChange:(h,d)=>C(p,{...i,value:d.checked}),label:"true"}):e.jsx(S,{type:i.kind==="StringParameter"?"text":"number",value:String(i.value),onChange:(h,d)=>{const f=i.kind==="StringParameter"?d.value:i.kind==="IntParameter"?parseInt(d.value):parseFloat(d.value);C(p,{...i,value:f})}})}),N&&i.kind==="CrmParameter"&&!i.name&&e.jsx(L,{appearance:"filled",color:"warning",size:"small",title:"Name required for URL actions"}),e.jsxs("div",{className:y.actions,children:[e.jsx(m,{appearance:"subtle",size:"small",icon:e.jsx(Ee,{}),onClick:()=>O(p,-1),disabled:p===0,"aria-label":"Move up"}),e.jsx(m,{appearance:"subtle",size:"small",icon:e.jsx(Me,{}),onClick:()=>O(p,1),disabled:p===n.length-1,"aria-label":"Move down"}),e.jsx(m,{appearance:"subtle",size:"small",icon:e.jsx(z,{}),onClick:()=>H(p),"aria-label":"Remove parameter"})]})]},p)),N&&e.jsxs(x,{className:y.hint,children:["For URL actions, each CrmParameter must have a ",e.jsx("code",{children:"name"})," attribute (querystring key)."]}),e.jsx(m,{className:y.addButton,appearance:"secondary",size:"small",icon:e.jsx(U,{}),onClick:W,children:"Add parameter"})]})},Ge=xe({drawer:{width:"640px",maxWidth:"90vw"},body:{display:"flex",flexDirection:"column",gap:l.spacingVerticalS,padding:l.spacingVerticalM,overflowY:"auto"},actionCard:{border:`1px solid ${l.colorNeutralStroke2}`,borderRadius:l.borderRadiusMedium,padding:l.spacingVerticalM,display:"flex",flexDirection:"column",gap:l.spacingVerticalS},actionHeader:{display:"flex",alignItems:"center",justifyContent:"space-between"},row:{display:"flex",gap:l.spacingHorizontalS,alignItems:"flex-end"},ruleRow:{display:"inline-flex",alignItems:"center",gap:l.spacingHorizontalXS},ruleRemoveBtn:{minWidth:"20px",width:"20px",height:"20px"},ruleChip:{cursor:"pointer"},rulePills:{display:"flex",flexWrap:"wrap",gap:l.spacingHorizontalXS},versionsList:{display:"flex",flexDirection:"column",gap:l.spacingVerticalXS},versionRow:{border:`1px solid ${l.colorNeutralStroke2}`,borderRadius:l.borderRadiusMedium,padding:l.spacingVerticalXS,display:"flex",justifyContent:"space-between",gap:l.spacingHorizontalS},versionMeta:{fontSize:l.fontSizeBase100,color:l.colorNeutralForeground3},securityNote:{fontSize:l.fontSizeBase100},codePanel:{border:`1px solid ${l.colorNeutralStroke2}`,borderRadius:l.borderRadiusMedium,padding:l.spacingVerticalS,display:"flex",flexDirection:"column",gap:l.spacingVerticalS}}),ls=()=>{const n=Ge(),F=B(s=>s.commandEditorOpen),N=B(s=>s.commandEditorId),y=B(s=>s.closeCommandEditor),C=B(s=>s.openCommandEditor),H=B(s=>s.openRuleEditor),O=B(s=>s.openWebResourceBrowser),W=R(s=>s.commands),i=R(s=>s.upsertCommand),p=R(s=>s.renameCommandId),h=R(s=>s.ribbons),d=R(s=>s.displayRules),f=R(s=>s.enableRules),be=R(s=>s.past),je=R(s=>s.upsertEnableRule),ve=R(s=>s.upsertDisplayRule),[P,fe]=j.useState("actions"),[w,se]=j.useState(""),[ge,ae]=j.useState(""),[ye,le]=j.useState(""),[ne,Q]=j.useState(null),[X,re]=j.useState(!1),[ie,q]=j.useState(!1),[Y,I]=j.useState(null),[te,$]=j.useState(""),[Ce,J]=j.useState(!1),[A,oe]=j.useState(null),t=W.find(s=>s.id===N),we=s=>{const a=s.trim();return a.startsWith("$webresource:")?a.slice(13).trim():a},Re=s=>{if(!s)return"";const a=Uint8Array.from(atob(s),u=>u.charCodeAt(0));return new TextDecoder().decode(a)},Se=s=>{const a=new TextEncoder().encode(s);let u="";for(let r=0;r<a.length;r+=1)u+=String.fromCharCode(a[r]);return btoa(u)},Ne=s=>{const a=s.split(".").pop()?.toLowerCase()??"";return{html:1,css:2,js:3,xml:4,png:5,jpg:6,gif:7,xsl:9,ico:10,svg:11,resx:12}[a]??3};j.useEffect(()=>{t&&se(t.id)},[t]);const G=j.useMemo(()=>t?w.trim()?/\s/.test(w)?"Command ID cannot contain whitespace.":w!==t.id&&W.some(s=>s.id.toLowerCase()===w.toLowerCase())?"A command with this ID already exists.":"":"Command ID is required.":"",[w,t,W]),Z=j.useMemo(()=>Object.entries(h).flatMap(([s,a])=>a.tabs.flatMap(u=>u.groups.flatMap(r=>r.buttons.filter(o=>o.commandId===N).map(o=>({location:s,tab:u,group:r,button:o}))))),[h,N]),ce=Z.length;if(!t)return null;const de=async(s,a)=>{const u=t.actions[s];if(!u||u.kind!=="javascript")return;const r=we(u.library);if(!r){I("JavaScript library must be a valid $webresource path."),Q(s),re(a),$(""),oe(null);return}Q(s),re(a),q(!0),I(null),J(!1),oe(r);try{const o=await He(r);if(!o){$(""),I(`Web resource not found: ${r}`);return}const c=await Oe(o.id);$(Re(c))}catch(o){I(o instanceof Error?o.message:"Failed to load web resource content."),$("")}finally{q(!1)}},Pe=async()=>{if(!(!X||ne===null||!A)){q(!0),I(null);try{await Xe(A,Se(te),Ne(A),A.split("/").pop()),J(!1)}catch(s){I(s instanceof Error?s.message:"Failed to save web resource content.")}finally{q(!1)}}},k=s=>{i({...t,...s})},g=(s,a)=>{const u=[...t.actions];u[s]=a,k({actions:u})},K=s=>{k({actions:t.actions.filter((a,u)=>u!==s)})},T=s=>{const a=s==="javascript"?{kind:"javascript",library:"$webresource:",functionName:"",params:[]}:s==="url"?{kind:"url",address:"https://",passParams:!1,params:[]}:s==="powerFx"?{kind:"powerFx",expression:""}:{kind:"customApi",actionName:"",boundParameter:"",inputParameters:[],outputParameters:[]};k({actions:[...t.actions,a]})},Ie=(s,a)=>{const u=ne===a;if(s.kind==="javascript")return e.jsxs("div",{className:n.actionCard,children:[e.jsxs("div",{className:n.actionHeader,children:[e.jsx(L,{appearance:"filled",color:"success",size:"small",children:"JavaScript"}),e.jsx(m,{appearance:"subtle",size:"small",icon:e.jsx(z,{}),onClick:()=>K(a),"aria-label":"Remove action"})]}),e.jsx(v,{label:"Library (Web Resource)",children:e.jsxs("div",{style:{display:"flex",gap:"4px",alignItems:"center"},children:[e.jsx(S,{style:{flex:1},value:s.library,onChange:(r,o)=>g(a,{...s,library:o.value}),placeholder:"$webresource:publisher_/scripts/myfile.js"}),e.jsx(m,{appearance:"subtle",size:"small",onClick:()=>{De.set(r=>{g(a,{...s,library:`$webresource:${r.name}`})}),O()},children:"Browse…"})]})}),e.jsx(v,{label:"Function name",children:e.jsx(S,{value:s.functionName,onChange:(r,o)=>g(a,{...s,functionName:o.value}),placeholder:"MyNamespace.myFunction"})}),e.jsx(M,{intent:"info",children:e.jsx(D,{children:"Read-only function preview and Monaco editing are available in the web resource browser integration path."})}),e.jsx(ee,{children:"Parameters (positional)"}),e.jsx(he,{params:s.params,onChange:r=>g(a,{...s,params:r}),urlMode:!1}),e.jsxs("div",{className:n.row,children:[e.jsx(m,{appearance:"subtle",size:"small",onClick:()=>{de(a,!1)},children:"Function preview"}),e.jsx(m,{appearance:"subtle",size:"small",onClick:()=>{de(a,!0)},children:"Open in Monaco"})]}),u&&e.jsxs("div",{className:n.codePanel,children:[e.jsxs("div",{className:n.row,children:[e.jsx(x,{weight:"semibold",children:X?"Monaco Editor":"Function Preview"}),A&&e.jsx(x,{size:200,style:{fontFamily:l.fontFamilyMonospace},children:A})]}),Y&&e.jsx(M,{intent:"error",children:e.jsx(D,{children:Y})}),ie?e.jsx(x,{style:{color:l.colorNeutralForeground3},children:"Loading source…"}):e.jsx("div",{style:{height:240},children:e.jsx(pe,{language:"javascript",value:te,readOnly:!X,onChange:r=>{$(r),J(!0)},options:{wordWrap:"on"}})}),e.jsxs("div",{className:n.row,children:[e.jsx(m,{appearance:"subtle",size:"small",onClick:()=>{Q(null),I(null),J(!1)},children:"Close"}),X&&e.jsx(m,{appearance:"primary",size:"small",onClick:()=>{Pe()},disabled:!Ce||ie||!!Y,children:"Save Web Resource"})]})]})]},a);if(s.kind==="url"){const r=s.address.trim().startsWith("https://");return e.jsxs("div",{className:n.actionCard,children:[e.jsxs("div",{className:n.actionHeader,children:[e.jsx(L,{appearance:"filled",color:"informative",size:"small",children:"URL"}),e.jsx(m,{appearance:"subtle",size:"small",icon:e.jsx(z,{}),onClick:()=>K(a),"aria-label":"Remove action"})]}),e.jsx(M,{intent:"warning",children:e.jsx(D,{children:e.jsx(x,{className:n.securityNote,children:"⚠ Ampersands in URLs are automatically escaped as & in the generated XML."})})}),e.jsx(v,{label:"Address",validationState:r?"none":"error",validationMessage:r?void 0:"URL must start with https://",children:e.jsx(S,{value:s.address,onChange:(o,c)=>g(a,{...s,address:c.value}),placeholder:"https://..."})}),e.jsx(v,{label:"Open in (WinMode)",children:e.jsxs(V,{value:String(s.winMode??0),onChange:(o,c)=>g(a,{...s,winMode:parseInt(c.value)}),children:[e.jsx("option",{value:"0",children:"Navigate (0)"}),e.jsx("option",{value:"1",children:"Dialog (1)"}),e.jsx("option",{value:"2",children:"Popup (2)"})]})}),e.jsx(v,{children:e.jsxs(m,{appearance:s.passParams?"primary":"subtle",size:"small",onClick:()=>g(a,{...s,passParams:!s.passParams}),children:[s.passParams?"✓ PassParams ON":"PassParams OFF"," — appends typename, type, id, orgname…"]})}),e.jsx(ee,{children:"Parameters (named)"}),e.jsx(he,{params:s.params,onChange:o=>g(a,{...s,params:o}),urlMode:!0})]},a)}return s.kind==="powerFx"?e.jsxs("div",{className:n.actionCard,children:[e.jsxs("div",{className:n.actionHeader,children:[e.jsx(L,{appearance:"filled",color:"brand",size:"small",children:"Power Fx"}),e.jsx(m,{appearance:"subtle",size:"small",icon:e.jsx(z,{}),onClick:()=>K(a),"aria-label":"Remove action"})]}),e.jsx(v,{label:"Expression",children:e.jsx("div",{style:{height:120,border:`1px solid ${l.colorNeutralStroke1}`,borderRadius:l.borderRadiusMedium,overflow:"hidden"},children:e.jsx(pe,{language:"javascript",value:s.expression,onChange:r=>g(a,{...s,expression:r??""}),options:{minimap:{enabled:!1},lineNumbers:"off",fontSize:13,scrollBeyondLastLine:!1,wordWrap:"on",lineDecorationsWidth:4,lineNumbersMinChars:0,glyphMargin:!1,folding:!1,renderLineHighlight:"none"}})})}),e.jsx(M,{intent:"info",children:e.jsxs(D,{children:["Variables: ",e.jsx("code",{children:"ThisRecord"}),", ",e.jsx("code",{children:"Selection"}),", ",e.jsx("code",{children:"Self"}),". Power Fx rules can return a Promise on Unified Interface (resolves false after 10 s if unresolved)."]})})]},a):s.kind==="customApi"?e.jsxs("div",{className:n.actionCard,children:[e.jsxs("div",{className:n.actionHeader,children:[e.jsx(L,{appearance:"filled",color:"warning",size:"small",children:"Custom API"}),e.jsx(m,{appearance:"subtle",size:"small",icon:e.jsx(z,{}),onClick:()=>K(a),"aria-label":"Remove action"})]}),e.jsx(v,{label:"Action logical name",children:e.jsx(S,{value:s.actionName,onChange:(r,o)=>g(a,{...s,actionName:o.value}),placeholder:"new_ExecuteBusinessAction"})}),e.jsx(v,{label:"Bound parameter (optional)",children:e.jsx(S,{value:s.boundParameter??"",onChange:(r,o)=>g(a,{...s,boundParameter:o.value}),placeholder:"Target"})}),e.jsx(v,{label:"Input parameters (name=value per line)",children:e.jsx(S,{value:s.inputParameters.map(r=>`${r.name}=${r.value}`).join("; "),onChange:(r,o)=>{const c=o.value.split(";").map(b=>b.trim()).filter(Boolean).map(b=>{const[_,...Be]=b.split("=");return{name:(_??"").trim(),value:Be.join("=").trim()}}).filter(b=>b.name.length>0);g(a,{...s,inputParameters:c})},placeholder:"ParamA=ValueA; ParamB=ValueB"})})]},a):null},ke=()=>e.jsxs(e.Fragment,{children:[t.actions.map((s,a)=>Ie(s,a)),t.actions.length===0&&e.jsx(x,{italic:!0,style:{color:l.colorNeutralForeground3},children:"No actions defined — button will do nothing when clicked."}),e.jsxs("div",{className:n.row,children:[e.jsx(v,{label:"Action type",style:{minWidth:"220px"},children:e.jsxs(V,{onChange:(s,a)=>{const u=a.value;u&&T(u)},value:"",children:[e.jsx("option",{value:"",children:"Add action..."}),e.jsx("option",{value:"javascript",children:"JavaScript function"}),e.jsx("option",{value:"url",children:"URL action"}),e.jsx("option",{value:"powerFx",children:"Power Fx expression"}),e.jsx("option",{value:"customApi",children:"Custom action / Web API"})]})}),e.jsx(m,{icon:e.jsx(U,{}),appearance:"secondary",size:"small",onClick:()=>T("javascript"),children:"Add JavaScript function"}),e.jsx(m,{icon:e.jsx(U,{}),appearance:"secondary",size:"small",onClick:()=>T("url"),children:"Add URL action"}),e.jsx(m,{icon:e.jsx(U,{}),appearance:"secondary",size:"small",onClick:()=>T("powerFx"),children:"Add Power Fx action"}),e.jsx(m,{icon:e.jsx(U,{}),appearance:"secondary",size:"small",onClick:()=>T("customApi"),children:"Add Custom API action"})]})]}),ze=()=>e.jsxs(e.Fragment,{children:[e.jsx(v,{label:"Command ID",children:e.jsx(S,{value:w,onChange:(s,a)=>se(a.value),style:{fontFamily:l.fontFamilyMonospace}})}),G&&e.jsx(x,{style:{color:l.colorPaletteRedForeground1,fontSize:l.fontSizeBase100},children:G}),e.jsx(m,{appearance:"secondary",size:"small",disabled:!w.trim()||!!G||w===t.id,onClick:()=>{if(!w.trim()||G)return;const s=w.trim();p(t.id,s)&&C(s)},children:"Apply ID change"}),e.jsx(x,{style:{color:l.colorNeutralForeground3,fontSize:l.fontSizeBase200},children:"Naming convention: Publisher.EntityName.ButtonName.Command"}),e.jsx(M,{intent:"warning",children:e.jsx(D,{children:e.jsxs(x,{className:n.securityNote,children:["⚠ ",e.jsx("strong",{children:"Security:"})," All command definitions are visible in browser source regardless of button visibility. Do not embed sensitive logic, credentials, or privileged information in command parameters or function names."]})})})]}),ue=s=>{const a=s==="enable"?t.enableRules:t.displayRules,u=(s==="enable"?f:d).map(c=>c.id).filter(c=>!a.includes(c)),r=s==="enable"?ge:ye,o=()=>{const c=new Set([...f.map(_=>_.id),...d.map(_=>_.id)]),b=Le("New",s==="enable"?"Enable":"Display",c);s==="enable"?je({id:b,steps:[]}):ve({id:b,steps:[]}),H(b,s)};return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:n.rulePills,children:[a.map(c=>e.jsxs("div",{className:n.ruleRow,children:[e.jsx(L,{appearance:"outline",size:"medium",className:n.ruleChip,onClick:()=>H(c,s),role:"button",tabIndex:0,children:c}),e.jsx(m,{appearance:"subtle",size:"small",className:n.ruleRemoveBtn,icon:e.jsx(z,{}),"aria-label":`Unbind ${c}`,onClick:()=>{k(s==="enable"?{enableRules:t.enableRules.filter(b=>b!==c)}:{displayRules:t.displayRules.filter(b=>b!==c)})}})]},c)),a.length===0&&e.jsxs(x,{italic:!0,style:{color:l.colorNeutralForeground3},children:["No ",s," rules — always ",s==="enable"?"enabled":"visible","."]})]}),e.jsxs("div",{className:n.row,children:[e.jsx(v,{label:`Bind existing ${s} rule`,style:{minWidth:"260px"},children:e.jsxs(V,{value:r,onChange:(c,b)=>s==="enable"?ae(b.value):le(b.value),children:[e.jsx("option",{value:"",children:"Select a rule…"}),u.map(c=>e.jsx("option",{value:c,children:c},c))]})}),e.jsx(m,{appearance:"secondary",size:"small",disabled:!r,onClick:()=>{r&&(s==="enable"?(k({enableRules:[...t.enableRules,r]}),ae("")):(k({displayRules:[...t.displayRules,r]}),le("")))},children:"Bind selected"}),e.jsxs(m,{appearance:"subtle",size:"small",onClick:o,children:["Create new ",s," rule"]})]}),s==="enable"&&e.jsx(M,{intent:"info",children:e.jsxs(D,{children:["Disabled buttons are ",e.jsx("strong",{children:"hidden"})," in the modern command bar (Unified Interface). In the classic ribbon, disabled buttons remain visible but do not respond to clicks."]})})]})},Fe=()=>e.jsxs(e.Fragment,{children:[e.jsxs(x,{children:["Referenced by ",e.jsx("strong",{children:ce})," button(s)."]}),Z.length>0&&e.jsx("div",{className:n.versionsList,children:Z.map(s=>e.jsx("div",{className:n.versionRow,children:e.jsxs("div",{children:[e.jsx(x,{weight:"semibold",style:{fontFamily:l.fontFamilyMonospace},children:s.button.id}),e.jsxs(x,{className:n.versionMeta,children:[s.location," → ",s.tab.label," → ",s.group.label]})]})},`${s.location}:${s.tab.id}:${s.group.id}:${s.button.id}`))})]}),me=be.filter(s=>s.target===t.id||s.detail.includes(t.id)).slice().reverse(),Ae=()=>e.jsx(e.Fragment,{children:me.length===0?e.jsx(x,{style:{color:l.colorNeutralForeground3},children:"No command-specific history entries yet."}):e.jsx("div",{className:n.versionsList,children:me.map((s,a)=>e.jsxs("div",{className:n.versionRow,children:[e.jsxs("div",{children:[e.jsx(x,{weight:"semibold",children:s.op}),e.jsx(x,{className:n.versionMeta,children:s.detail})]}),e.jsx(x,{className:n.versionMeta,children:new Date(s.ts).toLocaleString()})]},`${s.ts}-${a}`))})});return e.jsxs($e,{position:"end",open:F,onOpenChange:()=>y(),className:n.drawer,children:[e.jsx(Te,{children:e.jsx(_e,{action:e.jsx(m,{appearance:"subtle",icon:e.jsx(z,{}),onClick:y,"aria-label":"Close command editor"}),children:e.jsx(x,{size:400,weight:"semibold",style:{fontFamily:l.fontFamilyMonospace},children:t.id})})}),e.jsxs(Ue,{className:n.body,children:[e.jsxs(Ve,{selectedValue:P,onTabSelect:(s,a)=>fe(a.value),children:[e.jsx(E,{value:"actions",children:"Actions"}),e.jsx(E,{value:"enableRules",children:"Enable rules"}),e.jsx(E,{value:"displayRules",children:"Display rules"}),e.jsx(E,{value:"settings",children:"Settings"}),e.jsxs(E,{value:"references",children:["References (",ce,")"]}),e.jsx(E,{value:"versions",children:"Versions"})]}),e.jsx(ee,{}),P==="actions"&&ke(),P==="enableRules"&&ue("enable"),P==="displayRules"&&ue("display"),P==="settings"&&ze(),P==="references"&&Fe(),P==="versions"&&Ae()]})]})};export{ls as CommandEditorPanel,ls as default};
@@ -0,0 +1 @@
1
+ import{cw as a,bL as te,cx as oe}from"./fluent-icons-DiKr_qRE.js";import{r as u}from"./monaco-BLZnQb2P.js";import{i,u as c,h as E,e as b}from"./index-G361fmC5.js";import{a1 as t,B as ae,Q as S}from"./fluent-ui-kUA2U4Gr.js";import"./dnd-DHB99ZH7.js";const ne=oe({backdrop:{position:"fixed",inset:0,backgroundColor:"rgba(0,0,0,0.5)",zIndex:1e3,display:"flex",alignItems:"flex-start",justifyContent:"center",paddingTop:"10vh"},palette:{width:"640px",maxWidth:"90vw",backgroundColor:t.colorNeutralBackground1,borderRadius:t.borderRadiusLarge,boxShadow:t.shadow64,overflow:"hidden"},searchRow:{display:"flex",alignItems:"center",padding:`${t.spacingVerticalM} ${t.spacingHorizontalM}`,borderBottom:`1px solid ${t.colorNeutralStroke1}`,gap:t.spacingHorizontalS},searchInput:{flex:1,border:"none",outline:"none",fontSize:t.fontSizeBase400,backgroundColor:"transparent"},results:{maxHeight:"400px",overflowY:"auto"},group:{paddingTop:t.spacingVerticalXS},groupLabel:{padding:`${t.spacingVerticalXXS} ${t.spacingHorizontalM}`,color:t.colorNeutralForeground3,fontSize:t.fontSizeBase100,fontWeight:t.fontWeightSemibold,textTransform:"uppercase",letterSpacing:"0.08em"},item:{display:"flex",alignItems:"center",gap:t.spacingHorizontalS,padding:`${t.spacingVerticalXS} ${t.spacingHorizontalM}`,cursor:"pointer","&:hover":{backgroundColor:t.colorNeutralBackground1Hover}},itemSelected:{backgroundColor:t.colorNeutralBackground1Hover},itemLabel:{flex:1},itemSub:{color:t.colorNeutralForeground3,fontSize:t.fontSizeBase200},footer:{padding:`${t.spacingVerticalXS} ${t.spacingHorizontalM}`,borderTop:`1px solid ${t.colorNeutralStroke1}`,color:t.colorNeutralForeground3,fontSize:t.fontSizeBase100,display:"flex",gap:t.spacingHorizontalL}}),de=()=>{const l=ne(),m=i(e=>e.commandPaletteOpen),w=i(e=>e.setCommandPaletteOpen),R=i(e=>e.openBulkPublish),B=i(e=>e.openXmlDrawer),M=i(e=>e.openImportXml),L=i(e=>e.openCommandEditor),N=i(e=>e.openRuleEditor),X=i(e=>e.openNewGroup),D=i(e=>e.openNewButton),T=i(e=>e.openLocalizationEditor),v=i(e=>e.themeMode),H=i(e=>e.setThemeMode),P=c(e=>e.undo),W=c(e=>e.redo),O=c(e=>e.commands),G=c(e=>e.displayRules),V=c(e=>e.enableRules),y=c(e=>e.ribbons),F=E(e=>e.entities),A=E(e=>e.setActiveEntity),U=b(e=>e.location),Q=b(e=>e.tabId),h=b(e=>e.selectedButtonId),K=b(e=>e.selectedGroupId),[s,C]=u.useState(""),[g,d]=u.useState(0),$=u.useRef(null),n=u.useCallback(()=>{w(!1),C(""),d(0)},[w]);u.useEffect(()=>{m&&setTimeout(()=>$.current?.focus(),50)},[m]);const Z=()=>{const e=[],Y=y[U].tabs.find(o=>o.id===Q)?.groups[0]?.id??null,x=K??Y,J=[{id:"publish",label:"Publish all",subtitle:"Save and publish changes to Dataverse",kind:"action",action:()=>{R(),n()}},{id:"view-xml",label:"View RibbonDiffXml",subtitle:"Open XML drawer",kind:"action",action:()=>{B(),n()}},{id:"import-xml",label:"Import XML",subtitle:"Import RibbonDiffXml from clipboard",kind:"action",action:()=>{M(),n()}},{id:"new-group",label:"New group",subtitle:"Create a new ribbon group in current tab",kind:"action",action:()=>{X(),n()}},{id:"new-button",label:"New button",subtitle:x?"Create a new button in selected/current group":"Select a tab/group with at least one group first",kind:"action",action:()=>{x&&(D(x),n())}},{id:"edit-labels",label:"Edit localized labels",subtitle:h?"Open localization editor for selected button":"Select a button first",kind:"action",action:()=>{h&&(T(h),n())}},{id:"toggle-theme",label:`Toggle theme (${v==="dark"?"Dark":"Light"})`,subtitle:"Switch between light and dark",kind:"action",action:()=>{H(v==="dark"?"light":"dark"),n()}},{id:"undo",label:"Undo",subtitle:"Ctrl+Z",kind:"action",action:()=>{P(),n()}},{id:"redo",label:"Redo",subtitle:"Ctrl+Shift+Z",kind:"action",action:()=>{W(),n()}}];if(e.push(...J),!s.startsWith("@")&&!s.startsWith("/")){const o=Object.entries(y).flatMap(([_,ee])=>ee.tabs.flatMap(j=>j.groups.flatMap(z=>z.buttons.map(k=>({id:`btn-${k.id}`,label:k.label||k.id,subtitle:`${_} → ${j.label} → ${z.label}`,kind:"button",action:()=>{n()}})))));e.push(...o.slice(0,20))}return O.forEach(o=>{e.push({id:`cmd-${o.id}`,label:o.id,subtitle:`${o.actions.length} action(s)`,kind:"command",action:()=>{L(o.id),n()}})}),G.forEach(o=>{e.push({id:`dr-${o.id}`,label:o.id,subtitle:`Display rule — ${o.steps.length} step(s)`,kind:"rule",action:()=>{N(o.id,"display"),n()}})}),V.forEach(o=>{e.push({id:`er-${o.id}`,label:o.id,subtitle:`Enable rule — ${o.steps.length} step(s)`,kind:"rule",action:()=>{N(o.id,"enable"),n()}})}),(s.startsWith("@")||!s)&&F.slice(0,30).forEach(o=>{e.push({id:`ent-${o.logicalName}`,label:o.displayName,subtitle:o.logicalName,kind:"entity",action:()=>{A(o),n()}})}),e},f=s.startsWith("@")||s.startsWith("/")?s.slice(1):s,I=Z(),p=f?I.filter(e=>e.label.toLowerCase().includes(f.toLowerCase())||(e.subtitle??"").toLowerCase().includes(f.toLowerCase())):I,q=e=>{e.key==="ArrowDown"?(e.preventDefault(),d(r=>Math.min(r+1,p.length-1))):e.key==="ArrowUp"?(e.preventDefault(),d(r=>Math.max(r-1,0))):e.key==="Enter"?p[g]?.action():e.key==="Escape"&&n()};return m?a.jsx("div",{className:l.backdrop,onClick:n,role:"presentation",children:a.jsxs("div",{className:l.palette,onClick:e=>e.stopPropagation(),role:"dialog","aria-modal":"true","aria-label":"Command palette",children:[a.jsxs("div",{className:l.searchRow,children:[a.jsx(te,{style:{color:t.colorNeutralForeground3,flexShrink:0}}),a.jsx("input",{ref:$,className:l.searchInput,value:s,onChange:e=>{C(e.target.value),d(0)},onKeyDown:q,placeholder:"Search commands, buttons, entities… Use @ for entities, / for actions","aria-label":"Command palette search"})]}),a.jsxs("div",{className:l.results,role:"listbox",children:[p.map((e,r)=>a.jsxs("div",{className:`${l.item} ${r===g?l.itemSelected:""}`,onClick:e.action,role:"option","aria-selected":r===g,onMouseEnter:()=>d(r),children:[a.jsx(ae,{appearance:"outline",size:"small",children:e.kind}),a.jsxs("div",{className:l.itemLabel,children:[a.jsx(S,{children:e.label}),e.subtitle&&a.jsx(S,{className:l.itemSub,block:!0,children:e.subtitle})]})]},e.id)),p.length===0&&a.jsx("div",{className:l.item,children:a.jsx(S,{style:{color:t.colorNeutralForeground3},children:"No results"})})]}),a.jsxs("div",{className:l.footer,children:[a.jsx("span",{children:"↑↓ navigate"}),a.jsx("span",{children:"↵ select"}),a.jsx("span",{children:"Esc close"}),a.jsx("span",{children:"@ entities"}),a.jsx("span",{children:"/ actions"})]})]})}):null};export{de as CommandPalette,de as default};
@@ -0,0 +1 @@
1
+ import{cw as e,aw as k,b9 as C,bl as D,cx as B}from"./fluent-icons-DiKr_qRE.js";import{r as d}from"./monaco-BLZnQb2P.js";import{i as u,u as I}from"./index-G361fmC5.js";import{x as M,l as R,m as H,H as L,a as N,k as E,Q as a,a1 as o,u as x,w as h,G as F,B as z,V as O}from"./fluent-ui-kUA2U4Gr.js";import"./dnd-DHB99ZH7.js";function $(){return window.dataverseAPI}function P(i){const l=i.map(s=>{const r=s.publisherid,c=s.versionnumber,m=typeof c=="number"?c:Number(c??0)||0;return{solutionId:String(s.solutionid??""),solutionName:String(s.friendlyname??s.uniquename??"Unknown Solution"),publisher:String(r?.friendlyname??r?.customizationprefix??"Unknown Publisher"),managed:!!s.ismanaged,importedOn:s.modifiedon?String(s.modifiedon):void 0,wins:!1,versionNumber:m}});return l.sort((s,r)=>s.versionNumber-r.versionNumber),l.length>0&&(l[l.length-1].wins=!0),l.map(({versionNumber:s,...r})=>r)}async function A(i){if(!i)return null;const r=(await $().getSolutions(["solutionid","friendlyname","uniquename","ismanaged","publisherid","versionnumber","modifiedon"])).value;return r.length<=1?null:{elementId:i,elementKind:"button",solutions:P(r)}}const W=B({drawer:{width:"560px",maxWidth:"95vw"},body:{display:"flex",flexDirection:"column",gap:o.spacingHorizontalM,padding:o.spacingHorizontalM,overflowY:"auto"},solutionRow:{display:"flex",flexDirection:"column",gap:o.spacingHorizontalXS,padding:o.spacingHorizontalS,border:`1px solid ${o.colorNeutralStroke2}`,borderRadius:o.borderRadiusMedium,backgroundColor:o.colorNeutralBackground2},solutionRowWinner:{border:`2px solid ${o.colorBrandStroke1}`,backgroundColor:o.colorBrandBackground2},solutionHeader:{display:"flex",alignItems:"center",gap:o.spacingHorizontalS},elementId:{fontFamily:o.fontFamilyMonospace,fontSize:o.fontSizeBase200,backgroundColor:o.colorNeutralBackground4,padding:`2px ${o.spacingHorizontalXS}`,borderRadius:o.borderRadiusSmall,wordBreak:"break-all"}}),_=()=>{const i=W(),l=u(n=>n.conflictDrawerOpen),s=u(n=>n.conflictElementId),r=u(n=>n.closeConflictDrawer),c=u(n=>n.openXmlDrawer),m=I(n=>n.conflicts),[p,b]=d.useState(null),[j,f]=d.useState(!1),[w,g]=d.useState(null);d.useEffect(()=>{if(!l||!s){b(null),g(null),f(!1);return}let n=!1;return f(!0),g(null),A(s).then(t=>{n||b(t)}).catch(t=>{n||g(t instanceof Error?t.message:"Failed to load conflict layers")}).finally(()=>{n||f(!1)}),()=>{n=!0}},[l,s]);const v=m.filter(n=>n.elementId===s),y=d.useMemo(()=>p||v[0],[p,v]),S=y?[...y.solutions].sort((n,t)=>n.wins===t.wins?0:n.wins?1:-1):[];return e.jsxs(M,{className:i.drawer,open:l,position:"end",onOpenChange:(n,t)=>!t.open&&r(),children:[e.jsx(R,{children:e.jsx(H,{action:e.jsx(N,{appearance:"subtle",icon:e.jsx(k,{}),onClick:r,"aria-label":"Close"}),children:e.jsx(L,{children:"Solution Conflicts"})})}),e.jsx(E,{children:e.jsxs("div",{className:i.body,children:[s&&e.jsxs("div",{children:[e.jsx(a,{size:200,style:{color:o.colorNeutralForeground3},children:"Conflicting element:"}),e.jsx("div",{className:i.elementId,children:s})]}),e.jsx(x,{intent:"warning",children:e.jsx(h,{children:e.jsx(a,{size:200,children:"Multiple solutions customize this element. Dataverse applies them in solution import order — the most recently imported solution wins."})})}),e.jsx(x,{intent:"info",children:e.jsx(h,{children:e.jsxs(a,{size:200,children:[e.jsx("strong",{children:"To resolve:"})," Merge changes into one solution, or use solution layering to control evaluation order. Managed solutions appear as read-only layers — to resolve, merge the customization into your unmanaged solution."]})})}),j&&e.jsx("div",{style:{display:"flex",justifyContent:"center",padding:o.spacingHorizontalM},children:e.jsx(F,{label:"Loading solution layers..."})}),w&&e.jsx(x,{intent:"error",children:e.jsx(h,{children:w})}),!j&&S.length===0&&e.jsx(a,{style:{color:o.colorNeutralForeground3,textAlign:"center"},children:"No conflict details available from environment layers."}),S.map((n,t)=>e.jsxs("div",{className:`${i.solutionRow} ${n.wins?i.solutionRowWinner:""}`,children:[e.jsxs("div",{className:i.solutionHeader,children:[e.jsx(a,{weight:"semibold",children:n.solutionName}),n.wins&&e.jsx(z,{appearance:"filled",color:"brand",children:"WINS"}),n.managed&&e.jsx(O,{content:"Managed solution — read-only",relationship:"label",children:e.jsx(C,{style:{color:o.colorNeutralForeground3}})}),e.jsx(z,{appearance:"outline",size:"small",children:n.managed?"Managed":"Unmanaged"})]}),e.jsxs(a,{size:200,style:{color:o.colorNeutralForeground3},children:["Publisher: ",n.publisher]}),n.importedOn&&e.jsxs(a,{size:200,style:{color:o.colorNeutralForeground3},children:["Imported: ",new Date(n.importedOn).toLocaleString()]}),e.jsx("div",{style:{display:"flex",gap:o.spacingHorizontalS,flexWrap:"wrap"},children:e.jsx(N,{appearance:"subtle",size:"small",icon:e.jsx(D,{}),onClick:c,children:"View XML diff"})})]},`${n.solutionId}-${t}`))]})})]})};export{_ as ConflictDrawer,_ as default};
@@ -0,0 +1,7 @@
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/monaco-BLZnQb2P.js","assets/monaco-Dvl_Svmm.css"])))=>i.map(i=>d[i]);
2
+ import{b as g,r as b,_ as M}from"./monaco-BLZnQb2P.js";import{cw as s,aw as E,cx as C}from"./fluent-icons-DiKr_qRE.js";import{i as x,u as m}from"./index-G361fmC5.js";import{g as N}from"./xmlGenerator-DEaVrfZJ.js";import{x as O,l as _,m as V,H as $,a as S,k as X,u as I,w as G,Q as T,B as D,G as A,a1 as r}from"./fluent-ui-kUA2U4Gr.js";import"./dnd-DHB99ZH7.js";const P=g.lazy(()=>M(()=>import("./monaco-BLZnQb2P.js").then(n=>n.i),__vite__mapDeps([0,1])).then(n=>({default:n.DiffEditor}))),W=["HomepageGrid","SubGrid","Form","Application"],U=C({drawer:{},body:{display:"flex",flexDirection:"column",flex:"1 1 auto",minHeight:0,overflow:"hidden",gap:r.spacingHorizontalS},statsBar:{display:"flex",alignItems:"center",gap:r.spacingHorizontalS,padding:`${r.spacingVerticalXS} ${r.spacingHorizontalM}`,flexShrink:0},toggleRow:{display:"flex",alignItems:"center",gap:r.spacingHorizontalS,padding:`${r.spacingVerticalXS} ${r.spacingHorizontalM}`,borderBottom:`1px solid ${r.colorNeutralStroke2}`,flexShrink:0},editorWrap:{flex:1,height:0,minHeight:"400px",overflow:"hidden",position:"relative"}});function F(n,o){const l=n.split(`
3
+ `),c=o.split(`
4
+ `);let d=0,t=0;const f=new Set(l),a=new Set(c);for(const i of c)f.has(i)||d++;for(const i of l)a.has(i)||t++;return{added:d,removed:t}}function B(n,o,l,c,d,t,f){const a=[];for(const i of W){const p=f?o[i]:n[i],u=o[i];try{a.push(`<!-- ${i} -->
5
+ `+N({location:i,current:p,baseline:u,commands:l,displayRules:c,enableRules:d,locLabels:t,entityLogicalName:p.entityLogicalName}))}catch(h){a.push(`<!-- ${i}: Error generating XML: ${String(h)} -->`)}}return a.join(`
6
+
7
+ `)}const ee=()=>{const n=U(),o=x(e=>e.diffViewerOpen),l=x(e=>e.diffViewerMode),c=x(e=>e.closeDiffViewer),d=x(e=>e.themeMode),[t,f]=g.useState(!0),a=m(e=>e.ribbons),i=m(e=>e.baseline),p=m(e=>e.commands),u=m(e=>e.displayRules),h=m(e=>e.enableRules),y=m(e=>e.locLabels),k=d==="dark",j=b.useMemo(()=>B(a,i,p,u,h,y,!0),[o]),w=b.useMemo(()=>B(a,i,p,u,h,y,!1),[o,a,i,p,u,h,y]),{added:L,removed:R}=F(j,w),v=g.useRef(null),z=g.useCallback(e=>{v.current=e,e.updateOptions({renderSideBySide:t})},[]);return g.useEffect(()=>{v.current?.updateOptions({renderSideBySide:t})},[t]),s.jsxs(O,{className:n.drawer,open:o,position:"end",size:"full",onOpenChange:(e,H)=>!H.open&&c(),children:[s.jsx(_,{children:s.jsx(V,{action:s.jsx(S,{appearance:"subtle",icon:s.jsx(E,{}),onClick:c,"aria-label":"Close"}),children:s.jsx($,{children:l==="compare"?"Compare to baseline":"Diff viewer"})})}),s.jsx(X,{style:{display:"flex",flexDirection:"column",flex:"1 1 auto",minHeight:0,overflow:"hidden"},children:s.jsxs("div",{className:n.body,children:[s.jsx(I,{intent:"info",children:s.jsx(G,{children:s.jsx(T,{size:200,children:l==="compare"?"Showing current state vs. last published baseline.":"Showing the change introduced by this history entry."})})}),s.jsxs("div",{className:n.toggleRow,children:[s.jsxs(D,{appearance:"tint",color:"success",children:["+",L," lines"]}),s.jsxs(D,{appearance:"tint",color:"danger",children:["-",R," lines"]}),s.jsx("div",{style:{flex:1}}),s.jsx(S,{appearance:t?"primary":"subtle",size:"small",onClick:()=>f(!0),children:"Side by side"}),s.jsx(S,{appearance:t?"subtle":"primary",size:"small",onClick:()=>f(!1),children:"Unified"})]}),s.jsx("div",{className:n.editorWrap,children:s.jsx(b.Suspense,{fallback:s.jsx("div",{style:{display:"flex",alignItems:"center",justifyContent:"center",height:"100%"},children:s.jsx(A,{size:"medium",label:"Loading diff editor…"})}),children:s.jsx(P,{original:j,modified:w,language:"xml",theme:k?"vs-dark":"vs",height:"100%",onMount:z,options:{readOnly:!0,renderSideBySide:t,lineNumbers:"on",minimap:{enabled:!1},scrollBeyondLastLine:!1,automaticLayout:!0,wordWrap:"on"}})})})]})})]})};export{ee as DiffViewer,ee as default};
@@ -0,0 +1 @@
1
+ import{cw as o,aw as re,bL as E,ad as ae,cx as se}from"./fluent-icons-DiKr_qRE.js";import{r as t,b as te}from"./monaco-BLZnQb2P.js";import{i as M,u as ne,e as C,h as ie,F as le,d as ce,f as de}from"./index-G361fmC5.js";import{b as U,s as G,p as ue}from"./webResourceService-Ck07E3GN.js";import{d as ge,h as pe,f as he,i as me,H as be,a as k,g as ye,K as fe,T as L,I as F,b as we,O as xe,J as Se,a1 as r,Q as y,B as Ce,e as ke}from"./fluent-ui-kUA2U4Gr.js";import"./dnd-DHB99ZH7.js";function _(s){return s.replace(/([A-Z])/g,(n,i,c)=>(c>0?"_":"")+n.toLowerCase())}function ve(s){const n=new TextEncoder().encode(s);let i="";for(let c=0;c<n.length;c++)i+=String.fromCharCode(n[c]);return btoa(i)}const je=[{category:"Actions",keywords:["Add","Delete","Edit","Save","Copy","Paste","Undo","Redo","Send","Print","Refresh"]},{category:"Communication",keywords:["Mail","Chat","Phone","Call","Message"]},{category:"Navigation",keywords:["Arrow","Chevron","Navigation","Home","Back","Forward"]},{category:"System",keywords:["Settings","Info","Warning","Dismiss","Question","Checkmark","Error"]},{category:"Security",keywords:["Lock","Shield","Key","Fingerprint"]},{category:"People",keywords:["Person","People","Contact","User"]},{category:"Business",keywords:["Building","Briefcase","Money","Credit","Cart","Tag","Receipt"]},{category:"Files",keywords:["Document","Folder","Attach","Upload","Download","File"]},{category:"Web",keywords:["Globe","Link","Open","Browser","World"]},{category:"Time",keywords:["Calendar","Clock","Timer","History"]},{category:"Rating",keywords:["Star","Heart","Thumb"]},{category:"View",keywords:["Eye","Zoom","View","Window","Preview"]},{category:"Layout",keywords:["Grid","List","Table","Panel","Column","Row"]},{category:"Development",keywords:["Code","Bug","Branch","Wrench","Tool","Terminal"]},{category:"Media",keywords:["Play","Pause","Stop","Video","Audio","Camera"]},{category:"Analytics",keywords:["Chart","Data","Poll","Graph","Trend"]}],Re=["Add","Delete","Edit","Save","Copy","Cut","ClipboardPaste","Share","Mail","Chat","Phone","Search","Filter","ArrowLeft","ArrowRight","ArrowUp","ArrowDown","ChevronDown","ChevronUp","Navigation","Home","Settings","Info","Warning","Checkmark","Dismiss","QuestionCircle","LockClosed","LockOpen","Shield","Person","People","PersonAdd","Building","Briefcase","Money","CreditCard","Cart","Tag","Document","DocumentBulletList","Folder","FolderOpen","Attach","ArrowDownload","ArrowUpload","Globe","Link","Open","Calendar","Clock","Timer","Star","Heart","ThumbLike","ThumbDislike","Eye","EyeOff","ZoomIn","ZoomOut","Maximize","Minimize","Grid","List","Table","TableSimple","Code","Bug","Play","Pause","Stop","Refresh","ArrowSync","ArrowUndo","ArrowRedo","Printer","Send","Rocket","Sparkle","Trophy","Lightbulb","Bot","DataBar","ChartMultiple","Poll"];function Be(s){for(const n of je)if(n.keywords.some(i=>s.includes(i)))return n.category;return"General"}const O=Re.map(s=>({name:s,category:Be(s)})),Ae=["All",...Array.from(new Set(O.map(s=>s.category))).sort()],Ie=se({surface:{width:"720px",maxWidth:"95vw",height:"min(580px, 90vh)",maxHeight:"90vh",overflow:"hidden"},dialogBody:{display:"flex",flexDirection:"column",height:"100%",minHeight:0},body:{display:"flex",flexDirection:"column",flex:1,minHeight:0,overflow:"hidden",gap:r.spacingHorizontalS},toolbar:{display:"flex",alignItems:"center",gap:r.spacingHorizontalS,flexWrap:"wrap",flexShrink:0},categoryPicker:{minWidth:"180px",maxWidth:"220px"},iconGrid:{display:"grid",gridTemplateColumns:"repeat(auto-fill, minmax(72px, 1fr))",gap:r.spacingHorizontalXS,overflowY:"auto",flex:1,minHeight:0,padding:r.spacingHorizontalXS},iconTile:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:"4px",padding:r.spacingHorizontalXS,borderRadius:r.borderRadiusMedium,border:"1px solid transparent",cursor:"pointer",minHeight:"64px",":hover":{backgroundColor:r.colorNeutralBackground3,border:`1px solid ${r.colorNeutralStroke1}`}},iconTileSelected:{backgroundColor:r.colorBrandBackground2,border:`1px solid ${r.colorBrandStroke1}`},iconLabel:{fontSize:r.fontSizeBase100,textAlign:"center",lineHeight:1.2,wordBreak:"break-word",color:r.colorNeutralForeground2},webResourceList:{flex:1,overflowY:"auto"},webResourceRow:{display:"flex",alignItems:"center",gap:r.spacingHorizontalS,padding:`${r.spacingHorizontalXS} ${r.spacingHorizontalS}`,cursor:"pointer",borderRadius:r.borderRadiusMedium,":hover":{backgroundColor:r.colorNeutralBackground3}},uploadArea:{flex:1,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:r.spacingHorizontalM,border:`2px dashed ${r.colorNeutralStroke2}`,borderRadius:r.borderRadiusMedium,color:r.colorNeutralForeground3}}),$e=()=>{const s=Ie(),n=M(e=>e.iconPickerOpen),i=M(e=>e.closeIconPicker),c=ne(e=>e.setButtonProp),f=C(e=>e.selectedButtonId),w=C(e=>e.selectedGroupId),v=C(e=>e.tabId),j=C(e=>e.location),D=ie(e=>e.publisherPrefix),[d,$]=t.useState("fluent"),[R,V]=t.useState(""),[x,X]=t.useState("All"),[B,Z]=t.useState("regular"),[l,Q]=t.useState(null),[b,A]=t.useState(""),[z,I]=t.useState([]),[H,W]=t.useState(!1),[T,Y]=t.useState(""),[P,S]=t.useState(!1);te.useEffect(()=>{!n||d!=="webresource"||(W(!0),U("svg").then(e=>I(e)).catch(()=>I([])).finally(()=>W(!1)))},[n,d]);const q=t.useMemo(()=>{const e=T.toLowerCase();return z.filter(a=>!e||a.name.toLowerCase().includes(e))},[T,z]),K=t.useMemo(()=>{const e=R.toLowerCase();return O.filter(a=>(x==="All"||a.category===x)&&(e===""||a.name.toLowerCase().includes(e)))},[R,x]),J=async()=>{if(!l||!f||!w)return;const e=D||"new",a=_(l),u=ce.getState();S(!0);try{const g=await de(l,32);if(!g)throw new Error(`Could not serialize Fluent icon "${l}"`);const p=`${e}_/icons/${a}.svg`,N=ve(g),{id:h}=await G(p,N,11,`${a}.svg`);try{await ue(h)}catch(m){u.logWarn("webresource",`Created icon web resource ${p} but publish failed: ${m instanceof Error?m.message:String(m)}. It will publish with the next Publish.`)}c(j,v,w,f,{icon:a,image16:`$webresource:${p}`,image32:`$webresource:${p}`}),u.logInfo("webresource",`Icon web resource ready: ${p}`)}catch(g){u.logWarn("webresource",`Fluent icon "${l}" could not be uploaded as a web resource (${g instanceof Error?g.message:String(g)}). Using preview-only; add a real icon via the Web resource tab.`),c(j,v,w,f,{icon:a,image16:void 0,image32:void 0})}finally{S(!1),i()}},ee=()=>{!b||!f||!w||(c(j,v,w,f,{image16:b,image32:b}),i())},oe=async e=>{S(!0);try{const a=await new Promise((p,N)=>{const h=new FileReader;h.onerror=()=>N(h.error??new Error("Failed to read SVG")),h.onload=()=>{const m=String(h.result??"");p(m.includes(",")?m.split(",")[1]??"":m)},h.readAsDataURL(e)}),u=`${D??"new"}_/icons/${e.name}`;await G(u,a,11,e.name),A(`$webresource:${u}`),$("webresource");const g=await U("svg");I(g)}finally{S(!1)}};return o.jsx(ge,{open:n,onOpenChange:(e,a)=>!a.open&&i(),children:o.jsx(pe,{className:s.surface,children:o.jsxs(he,{className:s.dialogBody,children:[o.jsx(me,{action:o.jsx(k,{appearance:"subtle",icon:o.jsx(re,{}),onClick:i,"aria-label":"Close"}),children:o.jsx(be,{children:"Choose Icon"})}),o.jsxs(ye,{className:s.body,children:[o.jsxs(fe,{selectedValue:d,onTabSelect:(e,a)=>$(a.value),size:"small",children:[o.jsx(L,{value:"fluent",children:"Fluent icons"}),o.jsx(L,{value:"webresource",children:"Web resources"}),o.jsx(L,{value:"upload",children:"Upload SVG"})]}),d==="fluent"&&o.jsxs(o.Fragment,{children:[o.jsxs("div",{className:s.toolbar,children:[o.jsx(F,{contentBefore:o.jsx(E,{}),placeholder:"Search icons…",value:R,onChange:(e,a)=>V(a.value),size:"small",style:{flex:1}}),o.jsx(we,{className:s.categoryPicker,placeholder:"Category",value:x,onOptionSelect:(e,a)=>X(String(a.optionValue??"All")),children:Ae.map(e=>o.jsx(xe,{value:e,text:e,children:e},e))}),o.jsx(Se,{label:B==="regular"?"Regular":"Filled",checked:B==="filled",onChange:(e,a)=>Z(a.checked?"filled":"regular")})]}),o.jsx("div",{className:s.iconGrid,children:K.map(e=>o.jsxs("div",{className:`${s.iconTile} ${l===e.name?s.iconTileSelected:""}`,onClick:()=>Q(e.name),role:"option","aria-selected":l===e.name,title:`${e.name} — ${e.category}`,children:[o.jsx(le,{name:_(e.name),size:24,variant:B}),o.jsx("span",{className:s.iconLabel,children:e.name})]},e.name))}),l&&o.jsxs("div",{style:{display:"flex",alignItems:"center",gap:r.spacingHorizontalS,padding:r.spacingHorizontalXS,backgroundColor:r.colorNeutralBackground3,borderRadius:r.borderRadiusMedium,flexShrink:0},children:[o.jsxs(y,{size:200,style:{fontFamily:r.fontFamilyMonospace},children:['ModernImage="',l,'"']}),o.jsx(Ce,{appearance:"tint",color:"success",children:"Selected"})]})]}),d==="webresource"&&o.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:r.spacingHorizontalS,flex:1},children:[o.jsx(F,{contentBefore:o.jsx(E,{}),placeholder:"Search SVG web resources...",value:T,onChange:(e,a)=>Y(a.value),size:"small"}),o.jsxs("div",{className:s.webResourceList,children:[H&&o.jsx(y,{size:200,style:{color:r.colorNeutralForeground3},children:"Loading web resources..."}),!H&&q.slice(0,200).map(e=>{const a=`$webresource:${e.name}`,u=b===a;return o.jsx("div",{className:s.webResourceRow,onClick:()=>A(a),style:{backgroundColor:u?r.colorBrandBackground2:void 0},children:o.jsx(y,{size:200,style:{fontFamily:r.fontFamilyMonospace},children:a})},e.id)})]}),o.jsx(F,{placeholder:"$webresource:publisher_/icons/…",value:b,onChange:(e,a)=>A(a.value)}),o.jsx(y,{size:100,style:{color:r.colorNeutralForeground3},children:"Both image16 and image32 will be set to this path. Use SVG for best results across all DPI levels."})]}),d==="upload"&&o.jsxs("div",{className:s.uploadArea,children:[o.jsx(ae,{fontSize:48,style:{opacity:.4}}),o.jsx(y,{children:"Drag an SVG file here, or click to browse"}),o.jsx(y,{size:200,style:{color:r.colorNeutralForeground3},children:"The file will be uploaded as a web resource in the active solution."}),o.jsx("input",{type:"file",accept:".svg",style:{display:"none"},id:"icon-upload-input",onChange:e=>{const a=e.target.files?.[0];a&&oe(a)}}),o.jsx("label",{htmlFor:"icon-upload-input",style:{display:"inline-block",cursor:"pointer",padding:"6px 12px",background:r.colorBrandBackground,color:r.colorNeutralForegroundOnBrand,borderRadius:r.borderRadiusMedium,fontSize:r.fontSizeBase300},children:P?"Uploading...":"Browse for SVG"})]})]}),o.jsxs(ke,{children:[o.jsx(k,{appearance:"secondary",onClick:i,children:"Cancel"}),d==="fluent"&&o.jsx(k,{appearance:"primary",disabled:!l||P,onClick:()=>{J()},children:P?"Adding icon…":`Use ${l??"icon"}`}),d==="webresource"&&o.jsx(k,{appearance:"primary",disabled:!b,onClick:ee,children:"Use web resource"})]})]})})})};export{$e as IconPickerModal,$e as default};
@@ -0,0 +1,3 @@
1
+ import{cw as s}from"./fluent-icons-DiKr_qRE.js";import{r as g}from"./monaco-BLZnQb2P.js";import{i as A,u as j,e as C}from"./index-G361fmC5.js";import{M as $}from"./MonacoEditor-5dvTziHE.js";import{d as v,h as T,i as w,f as O,g as H,K as M,T as S,j as X,u as I,w as R,e as k,a as y}from"./fluent-ui-kUA2U4Gr.js";import"./dnd-DHB99ZH7.js";function h(i,p){const l=i.indexOf(p);return l<0?void 0:`Line ${i.slice(0,l).split(/\r?\n/).length}`}function B(i,p,l){const c=[],a=new DOMParser().parseFromString(i,"application/xml"),r=a.querySelector("parsererror");if(r){const n=r.textContent?.trim()??"Unknown",e=n.match(/line\s+(\d+)/i);return c.push({message:`XML parse error: ${n}`,lineHint:e?`Line ${e[1]}`:void 0}),c}const o=new Set([]);a.querySelectorAll("[Id]").forEach(n=>{const e=n.getAttribute("Id")??"";if(/\s/.test(e)){const t=h(i,`Id="${e}"`);c.push({message:`Element ID "${e}" contains invalid whitespace characters`,elementId:e,lineHint:t})}}),a.querySelectorAll("[LabelText]").forEach(n=>{const e=n.getAttribute("LabelText")??"",t=e.match(/^\$LocLabels:(.+)$/);if(t&&o.size>0&&!o.has(t[1])){const d=n.getAttribute("Id")??"",m=h(i,d?`Id="${d}"`:`LabelText="${e}"`);c.push({message:`Button label reference "$LocLabels:${t[1]}" has no matching LocLabel entry`,elementId:d||void 0,lineHint:m})}}),(i.includes("& ")||i.includes(`&
2
+ `))&&c.push({message:'URL may contain an unescaped "&" — all ampersands in XML must be written as &amp;',lineHint:h(i,"& ")??h(i,`&
3
+ `)}),a.querySelectorAll("Group").forEach(n=>{const e=[];n.querySelectorAll(":scope > Controls > Button, :scope > Controls > FlyoutAnchor, :scope > Controls > SplitButton").forEach(t=>{const d=parseInt(t.getAttribute("Sequence")??"0",10);if(e.includes(d)){const m=n.getAttribute("Id")??"?";c.push({message:`Two elements share Sequence "${d}" in group "${m}"`,elementId:m,lineHint:h(i,`Sequence="${d}"`)})}e.push(d)})});const u=new Set(["EntityPrivilegeRule","EntityPropertyRule","DeviceTypeRule","OptionSetRule","CrmOutlookClientVersionRule"]);return a.querySelectorAll("EnableRules > EnableRule").forEach(n=>{const e=n.getAttribute("Id")??"";u.forEach(t=>{n.querySelector(t)&&c.push({message:`Enable rule "${e}" contains "${t}" which is only valid in DisplayRules per the schema`,elementId:e,lineHint:h(i,`<${t}`)})})}),a.querySelectorAll("OrRule").forEach(n=>{const e=n.querySelectorAll(":scope > Or").length;e<2&&c.push({message:`OrRule requires at least 2 <Or> children (found ${e})`,lineHint:h(i,"<OrRule")})}),c}function P(i,p){const l=j.getState(),c=C.getState().location,a=new DOMParser().parseFromString(i,"application/xml");if(!a.querySelector("parsererror")&&(a.querySelectorAll("CommandDefinition").forEach(r=>{const o=r.getAttribute("Id");if(!o)return;const u=[],n=[];r.querySelectorAll("EnableRules > EnableRule").forEach(e=>{const t=e.getAttribute("Id");t&&u.push(t)}),r.querySelectorAll("DisplayRules > DisplayRule").forEach(e=>{const t=e.getAttribute("Id");t&&n.push(t)}),l.upsertCommand({id:o,enableRules:u,displayRules:n,actions:[]})}),a.querySelectorAll("LocLabel").forEach(r=>{const o=r.getAttribute("Id");if(!o)return;const u=[];r.querySelectorAll("Title").forEach(n=>{const e=Number(n.getAttribute("languagecode")??0),t=n.getAttribute("description")??"";e&&u.push({languageCode:e,description:t})}),l.upsertLocLabel({id:o,titles:u})}),a.querySelectorAll("EnableRules > EnableRule").forEach(r=>{const o=r.getAttribute("Id");o&&l.upsertEnableRule({id:o,steps:[]})}),a.querySelectorAll("DisplayRules > DisplayRule").forEach(r=>{const o=r.getAttribute("Id");o&&l.upsertDisplayRule({id:o,steps:[]})}),p==="replace")){const r=structuredClone(l.ribbons),o=r[c];a.querySelectorAll("CustomAction").forEach(u=>{const n=u.getAttribute("Location")??"",e=Number(u.getAttribute("Sequence")??0),t=u.querySelector("CommandUIDefinition > Button");if(!t)return;const d=t.getAttribute("Id")??"",m=t.getAttribute("LabelText")??d,E=t.getAttribute("Command")??"",q=t.getAttribute("TemplateAlias")??"o1";if(!d)return;let x=!1;for(const L of o.tabs){for(const f of L.groups)if(n.startsWith(f.id)){f.buttons.find(D=>D.id===d)||f.buttons.push({id:d,label:m,commandId:E,templateAlias:q,sequence:e,kind:"button",hidden:!1,oob:!1,custom:!0,managed:!1}),x=!0;break}if(x)break}}),l.loadRibbons(r)}}const Y=()=>{const i=A(e=>e.importXmlOpen),p=A(e=>e.closeImportXml),[l,c]=g.useState(""),[b,a]=g.useState([]),[r,o]=g.useState("replace"),u=()=>{const e=B(l);return a(e),e.length===0},n=()=>{u()&&(P(l,r),p())};return s.jsx(v,{open:i,onOpenChange:()=>p(),children:s.jsxs(T,{style:{maxWidth:"960px",width:"92vw",height:"80vh",maxHeight:"860px"},children:[s.jsx(w,{children:"Import RibbonDiffXml"}),s.jsxs(O,{style:{height:"100%",display:"flex",flexDirection:"column"},children:[s.jsxs(H,{style:{flex:1,minHeight:0,display:"flex",flexDirection:"column"},children:[s.jsxs(M,{selectedValue:r,onTabSelect:(e,t)=>o(t.value),children:[s.jsx(S,{value:"replace",children:"Replace current"}),s.jsx(S,{value:"append",children:"Merge / append"})]}),s.jsx(X,{style:{margin:"8px 0"}}),s.jsx("div",{style:{flex:1,minHeight:0},children:s.jsx($,{language:"xml",value:l,onChange:c,readOnly:!1,height:"100%",options:{wordWrap:"on",lineNumbers:"on",padding:{top:8}}})}),b.length>0&&s.jsx("div",{style:{marginTop:"8px",display:"flex",flexDirection:"column",gap:"4px"},children:b.map((e,t)=>s.jsx(I,{intent:"error",children:s.jsxs(R,{children:[e.message,e.lineHint?` (${e.lineHint})`:""]})},t))}),b.length===0&&l&&s.jsx(I,{intent:"success",children:s.jsx(R,{children:"XML is valid."})})]}),s.jsxs(k,{children:[s.jsx(y,{appearance:"secondary",onClick:p,children:"Cancel"}),s.jsx(y,{appearance:"secondary",onClick:u,disabled:!l.trim(),children:"Validate"}),s.jsx(y,{appearance:"primary",onClick:n,disabled:!l.trim(),children:"Import"})]})]})]})})};export{Y as ImportXmlModal,Y as default};
@@ -0,0 +1 @@
1
+ import{cw as a,aw as X,a as U,ar as O,cx as _,c7 as K}from"./fluent-icons-DiKr_qRE.js";import{r as z,b as E}from"./monaco-BLZnQb2P.js";import{i as y,u as T}from"./index-G361fmC5.js";import{d as M,h as P,f as V,i as G,H as J,B as w,a as h,g as Q,I as Y,Q as R,a1 as o,V as $,e as q}from"./fluent-ui-kUA2U4Gr.js";import"./dnd-DHB99ZH7.js";const m={1033:{name:"English (US)",flag:"🇺🇸"},1031:{name:"German",flag:"🇩🇪"},1034:{name:"Spanish",flag:"🇪🇸"},1036:{name:"French",flag:"🇫🇷"},1040:{name:"Italian",flag:"🇮🇹"},1041:{name:"Japanese",flag:"🇯🇵"},1042:{name:"Korean",flag:"🇰🇷"},1043:{name:"Dutch",flag:"🇳🇱"},1044:{name:"Norwegian",flag:"🇳🇴"},1045:{name:"Polish",flag:"🇵🇱"},1046:{name:"Portuguese (Brazil)",flag:"🇧🇷"},1049:{name:"Russian",flag:"🇷🇺"},1053:{name:"Swedish",flag:"🇸🇪"},1054:{name:"Thai",flag:"🇹🇭"},1055:{name:"Turkish",flag:"🇹🇷"},1057:{name:"Indonesian",flag:"🇮🇩"},1058:{name:"Ukrainian",flag:"🇺🇦"},1066:{name:"Vietnamese",flag:"🇻🇳"},2052:{name:"Chinese (Simplified)",flag:"🇨🇳"},3082:{name:"Spanish (Spain)",flag:"🇪🇸"}},Z=Object.keys(m).map(Number),ee=_({surface:{width:"760px",maxWidth:"95vw",maxHeight:"80vh"},body:{display:"flex",flexDirection:"column",gap:o.spacingHorizontalM,overflowY:"auto"},chipRow:{display:"flex",flexWrap:"wrap",gap:o.spacingHorizontalXS,alignItems:"center"},chip:{cursor:"pointer",userSelect:"none"},table:{width:"100%",borderCollapse:"collapse"},th:{textAlign:"left",fontSize:o.fontSizeBase100,fontWeight:o.fontWeightSemibold,color:o.colorNeutralForeground3,paddingBottom:o.spacingHorizontalXS,borderBottom:`1px solid ${o.colorNeutralStroke2}`},td:{verticalAlign:"top",paddingTop:o.spacingHorizontalXS,paddingBottom:o.spacingHorizontalXS,paddingRight:o.spacingHorizontalS,borderBottom:`1px solid ${o.colorNeutralStroke3}`},langCell:{whiteSpace:"nowrap",width:"160px"},actionCell:{width:"40px"},insertBreakBtn:{fontSize:o.fontSizeBase100,height:"20px",minWidth:"unset",padding:`0 ${o.spacingHorizontalXS}`},noteBar:{backgroundColor:o.colorNeutralBackground3,borderRadius:o.borderRadiusMedium,padding:`${o.spacingHorizontalXS} ${o.spacingHorizontalS}`,fontSize:o.fontSizeBase100,color:o.colorNeutralForeground3}}),se=()=>{const n=ee(),g=y(e=>e.localizationEditorOpen),s=y(e=>e.localizationEditorButtonId),p=y(e=>e.closeLocalizationEditor),u=T(e=>e.locLabels),C=T(e=>e.upsertLocLabel),f=s?`${s}.LabelText`:null,x=s?`${s}.ToolTipTitle`:null,b=s?`${s}.ToolTipDescription`:null,v=z.useCallback(()=>{const e=u.find(i=>i.id===f),l=u.find(i=>i.id===x),t=u.find(i=>i.id===b),d=new Set([1033]);return e?.titles.forEach(i=>d.add(i.languageCode)),l?.titles.forEach(i=>d.add(i.languageCode)),t?.titles.forEach(i=>d.add(i.languageCode)),Array.from(d).sort((i,r)=>i===1033?-1:r===1033?1:i-r).map(i=>({lcid:i,label:e?.titles.find(r=>r.languageCode===i)?.description??"",tooltipTitle:l?.titles.find(r=>r.languageCode===i)?.description??"",tooltipBody:t?.titles.find(r=>r.languageCode===i)?.description??""}))},[u,f,x,b]),[c,j]=z.useState([]),[B,N]=z.useState("");E.useEffect(()=>{g&&j(v())},[g,v]);const S=(e,l,t)=>{j(d=>d.map(i=>i.lcid===e?{...i,[l]:t}:i))},k=(e,l,t)=>{if(!t)return;const d=t.selectionStart??t.value.length,i=t.selectionEnd??t.value.length,r=c.find(W=>W.lcid===e)?.[l]??"",F=r.slice(0,d)+"​​"+r.slice(i);S(e,l,F)},I=()=>{const e=parseInt(B,10);!e||c.find(l=>l.lcid===e)||(j(l=>[...l,{lcid:e,label:"",tooltipTitle:"",tooltipBody:""}]),N(""))},L=e=>{e!==1033&&j(l=>l.filter(t=>t.lcid!==e))},H=()=>{if(!f||!x||!b)return;const e=l=>c.filter(t=>t[l]).map(t=>({languageCode:t.lcid,description:t[l]}));e("label").length>0&&C({id:f,titles:e("label")}),e("tooltipTitle").length>0&&C({id:x,titles:e("tooltipTitle")}),e("tooltipBody").length>0&&C({id:b,titles:e("tooltipBody")}),p()},A=c.find(e=>e.lcid===1033);return a.jsx(M,{open:g,onOpenChange:(e,l)=>!l.open&&p(),children:a.jsx(P,{className:n.surface,children:a.jsxs(V,{children:[a.jsxs(G,{action:a.jsx(h,{appearance:"subtle",icon:a.jsx(X,{}),onClick:p,"aria-label":"Close"}),children:[a.jsxs(J,{children:["Translations — ",A?.label||s||"Button"]}),a.jsxs(w,{appearance:"tint",size:"small",style:{marginLeft:8},children:[c.length," language",c.length!==1?"s":""]})]}),a.jsxs(Q,{className:n.body,children:[a.jsxs("div",{className:n.chipRow,children:[c.map(e=>{const l=m[e.lcid];return a.jsxs(w,{className:n.chip,appearance:e.label?"filled":"outline",color:e.label?"brand":"informative",size:"medium",children:[l?.flag??"🌐"," ",l?.name??`LCID ${e.lcid}`,e.lcid!==1033&&a.jsx("span",{style:{marginLeft:4,cursor:"pointer",opacity:.7},onClick:()=>L(e.lcid),"aria-label":`Remove ${l?.name}`,children:"×"})]},e.lcid)}),a.jsxs("div",{style:{display:"flex",gap:4,alignItems:"center"},children:[a.jsx(Y,{size:"small",style:{width:"180px"},placeholder:"LCID or language…",value:B,onChange:(e,l)=>N(l.value),list:"lcid-list",onKeyDown:e=>e.key==="Enter"&&I()}),a.jsx("datalist",{id:"lcid-list",children:Z.filter(e=>!c.find(l=>l.lcid===e)).map(e=>a.jsxs("option",{value:String(e),children:[m[e]?.flag," ",m[e]?.name," (",e,")"]},e))}),a.jsx(h,{size:"small",appearance:"subtle",icon:a.jsx(U,{}),onClick:I,"aria-label":"Add language"})]})]}),a.jsx("div",{className:n.noteBar,children:'💡 LCID 1033 (English US) is the base language and cannot be removed. Use "Insert ​​" to force a line break in long labels.'}),a.jsxs("table",{className:n.table,children:[a.jsx("thead",{children:a.jsxs("tr",{children:[a.jsx("th",{className:n.th,style:{width:"160px"},children:"Language"}),a.jsx("th",{className:n.th,children:"Label"}),a.jsx("th",{className:n.th,children:"Tooltip title"}),a.jsx("th",{className:n.th,children:"Tooltip body"}),a.jsx("th",{className:n.th,style:{width:"40px"}})]})}),a.jsx("tbody",{children:c.map(e=>{const l=m[e.lcid];return a.jsxs("tr",{children:[a.jsxs("td",{className:`${n.td} ${n.langCell}`,children:[a.jsxs(R,{size:200,children:[l?.flag??"🌐"," ",l?.name??`LCID ${e.lcid}`]}),a.jsx("br",{}),a.jsx(R,{size:100,style:{color:o.colorNeutralForeground3},children:e.lcid})]}),a.jsx("td",{className:n.td,children:a.jsx(D,{value:e.label,onChange:t=>S(e.lcid,"label",t),onInsertBreak:t=>k(e.lcid,"label",t)})}),a.jsx("td",{className:n.td,children:a.jsx(D,{value:e.tooltipTitle,onChange:t=>S(e.lcid,"tooltipTitle",t),onInsertBreak:t=>k(e.lcid,"tooltipTitle",t)})}),a.jsx("td",{className:n.td,children:a.jsx(ae,{value:e.tooltipBody,onChange:t=>S(e.lcid,"tooltipBody",t)})}),a.jsx("td",{className:`${n.td} ${n.actionCell}`,children:e.lcid!==1033&&a.jsx($,{content:"Remove this language",relationship:"label",children:a.jsx(h,{appearance:"subtle",size:"small",icon:a.jsx(O,{}),onClick:()=>L(e.lcid),"aria-label":"Remove language"})})})]},e.lcid)})})]})]}),a.jsxs(q,{children:[a.jsx(h,{appearance:"secondary",onClick:p,children:"Cancel"}),a.jsx(h,{appearance:"primary",onClick:H,children:"Save translations"})]})]})})})};function D({value:n,onChange:g,onInsertBreak:s}){const p=E.useRef(null);return a.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:2},children:[a.jsx("input",{ref:p,style:{width:"100%",fontFamily:"inherit",fontSize:13,padding:"3px 6px",border:"1px solid var(--colorNeutralStroke1)",borderRadius:4,boxSizing:"border-box"},value:n,onChange:u=>g(u.target.value)}),a.jsx($,{content:"Insert Dataverse line break (​​)",relationship:"label",children:a.jsxs("button",{type:"button",onClick:()=>s(p.current),style:{fontSize:11,border:"none",background:"none",color:"var(--colorNeutralForeground3)",cursor:"pointer",padding:0,textAlign:"left",display:"flex",alignItems:"center",gap:2},children:[a.jsx(K,{fontSize:12})," Insert ⏎"]})})]})}function ae({value:n,onChange:g}){return a.jsx("textarea",{style:{width:"100%",fontFamily:"inherit",fontSize:13,padding:"3px 6px",border:"1px solid var(--colorNeutralStroke1)",borderRadius:4,boxSizing:"border-box",resize:"vertical",minHeight:"42px"},value:n,onChange:s=>g(s.target.value),rows:2})}export{se as LocalizationEditor,se as default};
@@ -0,0 +1,2 @@
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/monaco-BLZnQb2P.js","assets/monaco-Dvl_Svmm.css"])))=>i.map(i=>d[i]);
2
+ import{r as l,b as f,_ as h}from"./monaco-BLZnQb2P.js";import{cw as t}from"./fluent-icons-DiKr_qRE.js";import{i as u}from"./index-G361fmC5.js";import{G as x}from"./fluent-ui-kUA2U4Gr.js";const _=f.lazy(()=>h(()=>import("./monaco-BLZnQb2P.js").then(o=>o.i),__vite__mapDeps([0,1]))),v=({language:o,value:r,onChange:s,readOnly:a=!1,height:i="100%",options:n={},onMount:m})=>{const d=u(e=>e.themeMode)==="dark"?"vs-dark":"vs",c={readOnly:a,minimap:{enabled:!1},wordWrap:o==="xml"?"on":"off",scrollBeyondLastLine:!1,automaticLayout:!0,...n},p=e=>{s&&e!==void 0&&s(e)};return t.jsx(l.Suspense,{fallback:t.jsx(x,{size:"medium",label:"Loading editor…"}),children:t.jsx(_,{height:i,language:o,value:r,theme:d,options:c,onChange:p,onMount:m})})};export{v as M};
@@ -0,0 +1 @@
1
+ import{cw as e}from"./fluent-icons-DiKr_qRE.js";import{r as b}from"./monaco-BLZnQb2P.js";import{i as f,u as j,e as l,h as c}from"./index-G361fmC5.js";import{d as $,h as E,i as k,f as F,g as P,F as g,I as R,S as T,Q as A,e as L,a as B}from"./fluent-ui-kUA2U4Gr.js";import"./dnd-DHB99ZH7.js";const z=()=>{const n=f(t=>t.newButtonGroupId),a=f(t=>t.closeNewButton),C=j(t=>t.createButton),S=j(t=>t.upsertCommand),v=l(t=>t.selectButtonInContext),y=c(t=>t.publisherPrefix),I=c(t=>t.activeSolution),i=l(t=>t.location),r=l(t=>t.tabId),w=c(t=>t.activeEntity),N=n!==null,[s,u]=b.useState("New Button"),[d,p]=b.useState("button"),D=()=>{if(!n||!i)return;const t=I?.publisherPrefix?.trim()||y?.trim()||"new",o=w?.logicalName??"global",m=s.replace(/\s+/g,""),x=`${t}.${o}.${m}.Button`,h=`${t}.${o}.${m}.Command`;C({location:i,tabId:r,groupId:n,button:{id:x,label:s,kind:d,sequence:50,templateAlias:"o1",commandId:h,hidden:!1,oob:!1,custom:!0,managed:!1}}),S({id:h,enableRules:[],displayRules:[],actions:[]}),v(i,r,n,x),u("New Button"),p("button"),a()};return e.jsx($,{open:N,onOpenChange:()=>a(),children:e.jsxs(E,{children:[e.jsx(k,{children:"New button"}),e.jsxs(F,{children:[e.jsxs(P,{children:[e.jsx(g,{label:"Label",required:!0,children:e.jsx(R,{value:s,onChange:(t,o)=>u(o.value),autoFocus:!0})}),e.jsx(g,{label:"Kind",children:e.jsxs(T,{value:d,onChange:(t,o)=>p(o.value),children:[e.jsx("option",{value:"button",children:"Button"}),e.jsx("option",{value:"flyout",children:"Flyout anchor"}),e.jsx("option",{value:"splitButton",children:"Split button"})]})}),e.jsx(A,{size:200,style:{display:"block",marginTop:"8px"},children:"A command definition will be created automatically. You can edit it in the Command Editor."})]}),e.jsxs(L,{children:[e.jsx(B,{appearance:"secondary",onClick:a,children:"Cancel"}),e.jsx(B,{appearance:"primary",onClick:D,disabled:!s.trim(),children:"Create button"})]})]})]})})};export{z as NewButtonModal,z as default};
@@ -0,0 +1 @@
1
+ import{cw as e}from"./fluent-icons-DiKr_qRE.js";import{r as u}from"./monaco-BLZnQb2P.js";import{i as p,u as G,h as d,e as x}from"./index-G361fmC5.js";import{d as S,h as C,i as F,f as L,g as N,F as h,I as D,S as I,Q as T,e as E,a as b}from"./fluent-ui-kUA2U4Gr.js";import"./dnd-DHB99ZH7.js";const B=()=>{const m=p(o=>o.newGroupOpen),s=p(o=>o.closeNewGroup),j=G(o=>o.createGroup),g=d(o=>o.publisherPrefix),l=x(o=>o.location),n=x(o=>o.tabId),y=d(o=>o.activeEntity),[a,i]=u.useState("New Group"),[r,c]=u.useState("Flexible2"),f=()=>{if(!l||!n)return;const o=g||"new",t=y?.logicalName??"global",v=a.replace(/\s+/g,""),w=`${o}.${t}.${v}.Group`;j({location:l,tabId:n,group:{id:w,label:a,sequence:50,template:r,buttons:[]}}),i("New Group"),c("Flexible2"),s()};return e.jsx(S,{open:m,onOpenChange:()=>s(),children:e.jsxs(C,{children:[e.jsx(F,{children:"New group"}),e.jsxs(L,{children:[e.jsxs(N,{children:[e.jsx(h,{label:"Label",required:!0,children:e.jsx(D,{value:a,onChange:(o,t)=>i(t.value),autoFocus:!0})}),e.jsx(h,{label:"Group template",children:e.jsxs(I,{value:r,onChange:(o,t)=>c(t.value),children:[e.jsx("option",{value:"Flexible2",children:"Flexible2 (recommended)"}),e.jsx("option",{value:"Flexible",children:"Flexible"}),e.jsx("option",{value:"Layout2",children:"Layout2"}),e.jsx("option",{value:"Layout3",children:"Layout3"}),e.jsx("option",{value:"Layout4",children:"Layout4"})]})}),e.jsx(T,{size:200,style:{display:"block",marginTop:"8px"},children:"The group template defines how buttons scale when the ribbon is resized."})]}),e.jsxs(E,{children:[e.jsx(b,{appearance:"secondary",onClick:s,children:"Cancel"}),e.jsx(b,{appearance:"primary",onClick:f,disabled:!a.trim(),children:"Create group"})]})]})]})})};export{B as NewGroupModal,B as default};
@@ -0,0 +1 @@
1
+ import{cw as e,aw as k,cx as I}from"./fluent-icons-DiKr_qRE.js";import{r as x}from"./monaco-BLZnQb2P.js";import{e as z,u as B,h as g,i as m}from"./index-G361fmC5.js";import{d as F,h as M,f as R,i as $,H as E,a as i,g as H,u as A,w as L,Q as r,F as j,I as f,a1 as s,e as O}from"./fluent-ui-kUA2U4Gr.js";import"./dnd-DHB99ZH7.js";const _=I({surface:{width:"480px",maxWidth:"95vw"},body:{display:"flex",flexDirection:"column",gap:s.spacingHorizontalM},hint:{fontFamily:s.fontFamilyMonospace,fontSize:s.fontSizeBase100,color:s.colorNeutralForeground3,backgroundColor:s.colorNeutralBackground3,padding:`${s.spacingHorizontalXS} ${s.spacingHorizontalS}`,borderRadius:s.borderRadiusMedium}}),W=()=>{const l=_(),[n,c]=x.useState("New Tab"),[d,u]=x.useState(""),b=z(a=>a.location),y=B(a=>a.createTab),T=g(a=>a.activeEntity),S=g(a=>a.publisherPrefix),N=m(a=>a.newTabOpen),t=m(a=>a.closeNewTab),w=S||"new",C=T?.logicalName??"entity",D=n.replace(/\s+/g,""),p=`${w}.${C}.${D}.Tab`,h=d||p,v=()=>{y(b,{id:h,label:n,sequence:100,tabDisplayRules:[],groups:[]}),c("New Tab"),u(""),t()};return e.jsx(F,{open:N,onOpenChange:(a,o)=>!o.open&&t(),children:e.jsx(M,{className:l.surface,children:e.jsxs(R,{children:[e.jsx($,{action:e.jsx(i,{appearance:"subtle",icon:e.jsx(k,{}),onClick:t,"aria-label":"Close"}),children:e.jsx(E,{children:"Add Tab"})}),e.jsxs(H,{className:l.body,children:[e.jsx(A,{intent:"info",children:e.jsx(L,{children:e.jsx(r,{size:200,children:"Tabs are hidden by default. Add a Tab Display Rule to make the tab visible."})})}),e.jsx(j,{label:"Tab label",required:!0,children:e.jsx(f,{value:n,onChange:(a,o)=>c(o.value),placeholder:"My Tab"})}),e.jsx(j,{label:"Tab ID",hint:"Leave blank to auto-generate from label",children:e.jsx(f,{value:d,onChange:(a,o)=>u(o.value),placeholder:p})}),e.jsxs("div",{children:[e.jsx(r,{size:100,style:{color:s.colorNeutralForeground3},children:"Generated ID:"}),e.jsx("div",{className:l.hint,children:h})]}),e.jsxs(r,{size:200,style:{color:s.colorNeutralForeground3},children:["Location: ",e.jsx("strong",{children:b})]})]}),e.jsxs(O,{children:[e.jsx(i,{appearance:"secondary",onClick:t,children:"Cancel"}),e.jsx(i,{appearance:"primary",disabled:!n.trim(),onClick:v,children:"Create tab"})]})]})})})};export{W as NewTabModal,W as default};