@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.
- package/CHANGELOG.md +99 -0
- package/LICENSE +661 -0
- package/README.md +316 -0
- package/dist/assets/BulkPublishModal-_JCQ9G-Z.js +29 -0
- package/dist/assets/CommandEditorPanel-BfdeUs_f.js +1 -0
- package/dist/assets/CommandPalette-D2Kh5NZ1.js +1 -0
- package/dist/assets/ConflictDrawer-BLiuWHeb.js +1 -0
- package/dist/assets/DiffViewer-BVDCd534.js +7 -0
- package/dist/assets/IconPickerModal-BAiIRU4A.js +1 -0
- package/dist/assets/ImportXmlModal-D-Ns-mYi.js +3 -0
- package/dist/assets/LocalizationEditor-C-TZ2Vqd.js +1 -0
- package/dist/assets/MonacoEditor-5dvTziHE.js +2 -0
- package/dist/assets/NewButtonModal-DOTUaBiJ.js +1 -0
- package/dist/assets/NewGroupModal-CXy9X9y5.js +1 -0
- package/dist/assets/NewTabModal-DiGzXYTp.js +1 -0
- package/dist/assets/RuleEditorPanel-DT_uPW8s.js +1 -0
- package/dist/assets/ScalingEditorPanel-BFnC7t_K.js +1 -0
- package/dist/assets/TabDisplayRulesPanel-CdKjedy-.js +1 -0
- package/dist/assets/UrlComposerModal-DFtXdVW3.js +1 -0
- package/dist/assets/WebResourceBrowser-FvaNo4rt.js +1 -0
- package/dist/assets/XmlDrawer-BXAxH3A8.js +2 -0
- package/dist/assets/abap-DLDM7-KI.js +1 -0
- package/dist/assets/apex-DNDY2TF8.js +1 -0
- package/dist/assets/azcli-Y6nb8tq_.js +1 -0
- package/dist/assets/bat-BwHxbl9M.js +1 -0
- package/dist/assets/bicep-CFznDFnq.js +2 -0
- package/dist/assets/cameligo-Bf6VGUru.js +1 -0
- package/dist/assets/clojure-Dnu-v4kV.js +1 -0
- package/dist/assets/codicon-ngg6Pgfi.ttf +0 -0
- package/dist/assets/coffee-Bd8akH9Z.js +1 -0
- package/dist/assets/cpp-BbWJElDN.js +1 -0
- package/dist/assets/csharp-Co3qMtFm.js +1 -0
- package/dist/assets/csp-D-4FJmMZ.js +1 -0
- package/dist/assets/css-DdJfP1eB.js +3 -0
- package/dist/assets/css.worker-DBVD8oXr.js +93 -0
- package/dist/assets/cssMode-DFSY9yCW.js +1 -0
- package/dist/assets/cypher-cTPe9QuQ.js +1 -0
- package/dist/assets/dart-BOtBlQCF.js +1 -0
- package/dist/assets/dnd-DHB99ZH7.js +5 -0
- package/dist/assets/dockerfile-BG73LgW2.js +1 -0
- package/dist/assets/ecl-BEgZUVRK.js +1 -0
- package/dist/assets/elixir-BkW5O-1t.js +1 -0
- package/dist/assets/flow9-BeJ5waoc.js +1 -0
- package/dist/assets/fluent-icons-DiKr_qRE.js +1 -0
- package/dist/assets/fluent-ui-kUA2U4Gr.js +43 -0
- package/dist/assets/freemarker2-B8bME0pA.js +3 -0
- package/dist/assets/fsharp-PahG7c26.js +1 -0
- package/dist/assets/go-acbASCJo.js +1 -0
- package/dist/assets/graphql-BxJiqAUM.js +1 -0
- package/dist/assets/handlebars-zIyCxTW6.js +1 -0
- package/dist/assets/hcl-DtV1sZF8.js +1 -0
- package/dist/assets/html-B5hFqu3X.js +1 -0
- package/dist/assets/html.worker-CwpTb9lJ.js +470 -0
- package/dist/assets/htmlMode-BmPxEBms.js +1 -0
- package/dist/assets/index-D9lerlVA.css +1 -0
- package/dist/assets/index-G361fmC5.js +6 -0
- package/dist/assets/ini-Kd9XrMLS.js +1 -0
- package/dist/assets/java-CXBNlu9o.js +1 -0
- package/dist/assets/javascript-BQGsYMat.js +1 -0
- package/dist/assets/json.worker-BoL8UZqY.js +58 -0
- package/dist/assets/jsonMode-CR0b-9Un.js +7 -0
- package/dist/assets/julia-cl7-CwDS.js +1 -0
- package/dist/assets/kotlin-s7OhZKlX.js +1 -0
- package/dist/assets/less-9HpZscsL.js +2 -0
- package/dist/assets/lexon-OrD6JF1K.js +1 -0
- package/dist/assets/liquid-DLq8jbP8.js +1 -0
- package/dist/assets/lspLanguageFeatures-C3buAG32.js +4 -0
- package/dist/assets/lua-Cyyb5UIc.js +1 -0
- package/dist/assets/m3-B8OfTtLu.js +1 -0
- package/dist/assets/markdown-BFxVWTOG.js +1 -0
- package/dist/assets/mdx-5ni22WXY.js +1 -0
- package/dist/assets/mips-CiqrrVzr.js +1 -0
- package/dist/assets/monaco-BLZnQb2P.js +918 -0
- package/dist/assets/monaco-Dvl_Svmm.css +1 -0
- package/dist/assets/msdax-DmeGPVcC.js +1 -0
- package/dist/assets/mysql-C_tMU-Nz.js +1 -0
- package/dist/assets/objective-c-BDtDVThU.js +1 -0
- package/dist/assets/pascal-vHIfCaH5.js +1 -0
- package/dist/assets/pascaligo-DtZ0uQbO.js +1 -0
- package/dist/assets/perl-Ub6l9XKa.js +1 -0
- package/dist/assets/pgsql-BlNEE0v7.js +1 -0
- package/dist/assets/php-BBUBE1dy.js +1 -0
- package/dist/assets/pla-DSh2-awV.js +1 -0
- package/dist/assets/postiats-CocnycG-.js +1 -0
- package/dist/assets/powerquery-tScXyioY.js +1 -0
- package/dist/assets/powershell-COWaemsV.js +1 -0
- package/dist/assets/protobuf-Brw8urJB.js +2 -0
- package/dist/assets/pug-8SOpv6rk.js +1 -0
- package/dist/assets/python-F20Pd69B.js +1 -0
- package/dist/assets/qsharp-Bw9ernYp.js +1 -0
- package/dist/assets/r-j7ic8hl3.js +1 -0
- package/dist/assets/razor-3xmsG6cc.js +1 -0
- package/dist/assets/redis-Bu5POkcn.js +1 -0
- package/dist/assets/redshift-Bs9aos_-.js +1 -0
- package/dist/assets/restructuredtext-CqXO7rUv.js +1 -0
- package/dist/assets/ruby-zBfavPgS.js +1 -0
- package/dist/assets/rust-BzKRNQWT.js +1 -0
- package/dist/assets/sb-BBc9UKZt.js +1 -0
- package/dist/assets/scala-D9hQfWCl.js +1 -0
- package/dist/assets/scheme-BPhDTwHR.js +1 -0
- package/dist/assets/scss-CBJaRo0y.js +3 -0
- package/dist/assets/server.browser-DfdiBs1P.js +11 -0
- package/dist/assets/shell-DiJ1NA_G.js +1 -0
- package/dist/assets/solidity-Db0IVjzk.js +1 -0
- package/dist/assets/sophia-CnS9iZB_.js +1 -0
- package/dist/assets/sparql-CJmd_6j2.js +1 -0
- package/dist/assets/sql-ClhHkBeG.js +1 -0
- package/dist/assets/st-CHwy0fLd.js +1 -0
- package/dist/assets/swift-CnmFD0ga.js +1 -0
- package/dist/assets/systemverilog-Bs9z6M-B.js +1 -0
- package/dist/assets/tcl-Dm6ycUr_.js +1 -0
- package/dist/assets/ts.worker-BH9nVgjN.js +67718 -0
- package/dist/assets/tsMode-Cyusk9p4.js +11 -0
- package/dist/assets/twig-Csy3S7wG.js +1 -0
- package/dist/assets/typescript-BXT-ECX3.js +1 -0
- package/dist/assets/typespec-Btyra-wh.js +1 -0
- package/dist/assets/vb-Db0cS2oM.js +1 -0
- package/dist/assets/webResourceService-Ck07E3GN.js +1 -0
- package/dist/assets/wgsl-BTesnYfV.js +298 -0
- package/dist/assets/xml-Cwzeco8o.js +1 -0
- package/dist/assets/xmlGenerator-DEaVrfZJ.js +130 -0
- package/dist/assets/yaml-BHUePD-R.js +1 -0
- package/dist/index.html +18 -0
- package/dist/stats.html +4949 -0
- package/index.html +12 -0
- package/npm-shrinkwrap.json +13252 -0
- 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
|
+

|
|
9
|
+

|
|
10
|
+

|
|
11
|
+

|
|
12
|
+

|
|
13
|
+

|
|
14
|
+

|
|
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" (`​​`)
|
|
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; `&` → `&` 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 &',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};
|