@powerportalspro/react-fluent 5.0.0 → 6.0.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/EULA.txt +263 -0
- package/README.md +38 -0
- package/dist/index.cjs +459 -58
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +462 -61
- package/dist/index.js.map +1 -1
- package/package.json +7 -6
package/dist/index.cjs
CHANGED
|
@@ -2483,6 +2483,7 @@ var ImageViewer = react.forwardRef(function ImageViewer2({
|
|
|
2483
2483
|
const selectionRef = react.useRef(selection);
|
|
2484
2484
|
selectionRef.current = selection;
|
|
2485
2485
|
const prevTransformRef = react.useRef({ angle, zoom, pan, flipH, flipV });
|
|
2486
|
+
const resizingRef = react.useRef(false);
|
|
2486
2487
|
const dragRef = react.useRef(null);
|
|
2487
2488
|
const [isDragging, setIsDragging] = react.useState(false);
|
|
2488
2489
|
const zoomRef = react.useRef(zoom);
|
|
@@ -2512,6 +2513,7 @@ var ImageViewer = react.forwardRef(function ImageViewer2({
|
|
|
2512
2513
|
const cur = { angle, zoom, pan, flipH, flipV };
|
|
2513
2514
|
const transformChanged = prev.angle !== cur.angle || prev.zoom !== cur.zoom || prev.pan.x !== cur.pan.x || prev.pan.y !== cur.pan.y || prev.flipH !== cur.flipH || prev.flipV !== cur.flipV;
|
|
2514
2515
|
if (transformChanged) {
|
|
2516
|
+
resizingRef.current = false;
|
|
2515
2517
|
const sel = selectionRef.current;
|
|
2516
2518
|
const imgEl = imgRef.current;
|
|
2517
2519
|
if (sel && imgEl) {
|
|
@@ -2542,6 +2544,51 @@ var ImageViewer = react.forwardRef(function ImageViewer2({
|
|
|
2542
2544
|
}
|
|
2543
2545
|
prevTransformRef.current = cur;
|
|
2544
2546
|
}, [angle, zoom, pan, flipH, flipV]);
|
|
2547
|
+
react.useEffect(() => {
|
|
2548
|
+
if (!toolbar) return;
|
|
2549
|
+
const container = imageContainerRef.current;
|
|
2550
|
+
if (!container) return;
|
|
2551
|
+
let prevMetrics = imgRef.current ? readImageLayoutMetrics(imgRef.current) : null;
|
|
2552
|
+
const observer = new ResizeObserver(() => {
|
|
2553
|
+
const imgEl = imgRef.current;
|
|
2554
|
+
if (!imgEl) return;
|
|
2555
|
+
const newMetrics = readImageLayoutMetrics(imgEl);
|
|
2556
|
+
if (!newMetrics) return;
|
|
2557
|
+
const sel = selectionRef.current;
|
|
2558
|
+
const layoutChanged = !prevMetrics || prevMetrics.layoutW !== newMetrics.layoutW || prevMetrics.layoutH !== newMetrics.layoutH || prevMetrics.offsetLeft !== newMetrics.offsetLeft || prevMetrics.offsetTop !== newMetrics.offsetTop;
|
|
2559
|
+
if (sel && prevMetrics && layoutChanged) {
|
|
2560
|
+
const natural = containerRectToImageNatural(
|
|
2561
|
+
sel,
|
|
2562
|
+
imgEl,
|
|
2563
|
+
angleRef.current,
|
|
2564
|
+
zoomRef.current,
|
|
2565
|
+
panRef.current,
|
|
2566
|
+
flipHRef.current,
|
|
2567
|
+
flipVRef.current,
|
|
2568
|
+
prevMetrics
|
|
2569
|
+
);
|
|
2570
|
+
if (natural) {
|
|
2571
|
+
const reprojected = imageNaturalRectToContainer(
|
|
2572
|
+
natural,
|
|
2573
|
+
imgEl,
|
|
2574
|
+
angleRef.current,
|
|
2575
|
+
zoomRef.current,
|
|
2576
|
+
panRef.current,
|
|
2577
|
+
flipHRef.current,
|
|
2578
|
+
flipVRef.current,
|
|
2579
|
+
newMetrics
|
|
2580
|
+
);
|
|
2581
|
+
if (reprojected) {
|
|
2582
|
+
resizingRef.current = true;
|
|
2583
|
+
setSelection(reprojected);
|
|
2584
|
+
}
|
|
2585
|
+
}
|
|
2586
|
+
}
|
|
2587
|
+
prevMetrics = newMetrics;
|
|
2588
|
+
});
|
|
2589
|
+
observer.observe(container);
|
|
2590
|
+
return () => observer.disconnect();
|
|
2591
|
+
}, [toolbar]);
|
|
2545
2592
|
const onDirtyChangedRef = react.useRef(onDirtyChanged);
|
|
2546
2593
|
onDirtyChangedRef.current = onDirtyChanged;
|
|
2547
2594
|
react.useEffect(() => {
|
|
@@ -3295,7 +3342,7 @@ var ImageViewer = react.forwardRef(function ImageViewer2({
|
|
|
3295
3342
|
// pointermove (which is what changes the selection during
|
|
3296
3343
|
// a drag) calls setSelection — that triggers a re-render
|
|
3297
3344
|
// which reads the current dragRef value.
|
|
3298
|
-
transition: dragRef.current ? "none" : "left 120ms ease-out, top 120ms ease-out, width 120ms ease-out, height 120ms ease-out"
|
|
3345
|
+
transition: dragRef.current || resizingRef.current ? "none" : "left 120ms ease-out, top 120ms ease-out, width 120ms ease-out, height 120ms ease-out"
|
|
3299
3346
|
},
|
|
3300
3347
|
children: [
|
|
3301
3348
|
showThirds && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.thirdsGuide, "aria-hidden": "true", children: [
|
|
@@ -3456,6 +3503,21 @@ function useImageSrc(source) {
|
|
|
3456
3503
|
return source.value ? `data:${resolveMimeType(source)};base64,${source.value}` : null;
|
|
3457
3504
|
return bytesUrlRef.current;
|
|
3458
3505
|
}
|
|
3506
|
+
function readImageLayoutMetrics(imageEl) {
|
|
3507
|
+
const layoutW = imageEl.offsetWidth;
|
|
3508
|
+
const layoutH = imageEl.offsetHeight;
|
|
3509
|
+
const naturalW = imageEl.naturalWidth;
|
|
3510
|
+
const naturalH = imageEl.naturalHeight;
|
|
3511
|
+
if (layoutW === 0 || layoutH === 0 || naturalW === 0 || naturalH === 0) return null;
|
|
3512
|
+
return {
|
|
3513
|
+
layoutW,
|
|
3514
|
+
layoutH,
|
|
3515
|
+
offsetLeft: imageEl.offsetLeft,
|
|
3516
|
+
offsetTop: imageEl.offsetTop,
|
|
3517
|
+
naturalW,
|
|
3518
|
+
naturalH
|
|
3519
|
+
};
|
|
3520
|
+
}
|
|
3459
3521
|
function getDisplayedImageBounds(imageEl, angle, zoom, pan, flipH, flipV) {
|
|
3460
3522
|
const layoutW = imageEl.offsetWidth;
|
|
3461
3523
|
const layoutH = imageEl.offsetHeight;
|
|
@@ -3498,15 +3560,13 @@ function getDisplayedImageBounds(imageEl, angle, zoom, pan, flipH, flipV) {
|
|
|
3498
3560
|
}
|
|
3499
3561
|
return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };
|
|
3500
3562
|
}
|
|
3501
|
-
function containerRectToImageNatural(rect, imageEl, angle, zoom, pan, flipH, flipV) {
|
|
3502
|
-
const
|
|
3503
|
-
|
|
3504
|
-
const naturalW =
|
|
3505
|
-
const naturalH = imageEl.naturalHeight;
|
|
3506
|
-
if (layoutW === 0 || layoutH === 0 || naturalW === 0 || naturalH === 0) return null;
|
|
3563
|
+
function containerRectToImageNatural(rect, imageEl, angle, zoom, pan, flipH, flipV, metricsOverride) {
|
|
3564
|
+
const m = metricsOverride ?? readImageLayoutMetrics(imageEl);
|
|
3565
|
+
if (!m) return null;
|
|
3566
|
+
const { layoutW, layoutH, naturalW, naturalH } = m;
|
|
3507
3567
|
const containScale = Math.min(layoutW / naturalW, layoutH / naturalH);
|
|
3508
|
-
const imgCenterX =
|
|
3509
|
-
const imgCenterY =
|
|
3568
|
+
const imgCenterX = m.offsetLeft + layoutW / 2;
|
|
3569
|
+
const imgCenterY = m.offsetTop + layoutH / 2;
|
|
3510
3570
|
const sx = zoom * (flipH ? -1 : 1);
|
|
3511
3571
|
const sy = zoom * (flipV ? -1 : 1);
|
|
3512
3572
|
if (sx === 0 || sy === 0) return null;
|
|
@@ -3539,15 +3599,13 @@ function containerRectToImageNatural(rect, imageEl, angle, zoom, pan, flipH, fli
|
|
|
3539
3599
|
}
|
|
3540
3600
|
return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };
|
|
3541
3601
|
}
|
|
3542
|
-
function imageNaturalRectToContainer(rect, imageEl, angle, zoom, pan, flipH, flipV) {
|
|
3543
|
-
const
|
|
3544
|
-
|
|
3545
|
-
const naturalW =
|
|
3546
|
-
const naturalH = imageEl.naturalHeight;
|
|
3547
|
-
if (layoutW === 0 || layoutH === 0 || naturalW === 0 || naturalH === 0) return null;
|
|
3602
|
+
function imageNaturalRectToContainer(rect, imageEl, angle, zoom, pan, flipH, flipV, metricsOverride) {
|
|
3603
|
+
const m = metricsOverride ?? readImageLayoutMetrics(imageEl);
|
|
3604
|
+
if (!m) return null;
|
|
3605
|
+
const { layoutW, layoutH, naturalW, naturalH } = m;
|
|
3548
3606
|
const containScale = Math.min(layoutW / naturalW, layoutH / naturalH);
|
|
3549
|
-
const imgCenterX =
|
|
3550
|
-
const imgCenterY =
|
|
3607
|
+
const imgCenterX = m.offsetLeft + layoutW / 2;
|
|
3608
|
+
const imgCenterY = m.offsetTop + layoutH / 2;
|
|
3551
3609
|
const sx = zoom * (flipH ? -1 : 1);
|
|
3552
3610
|
const sy = zoom * (flipV ? -1 : 1);
|
|
3553
3611
|
const rad = angle * Math.PI / 180;
|
|
@@ -4425,6 +4483,69 @@ function ZipViewer({
|
|
|
4425
4483
|
}
|
|
4426
4484
|
);
|
|
4427
4485
|
}
|
|
4486
|
+
function ZipEntryIcon({ fileName, className }) {
|
|
4487
|
+
switch (getFileExtension(fileName)) {
|
|
4488
|
+
case "pdf":
|
|
4489
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactIcons.DocumentPdf20Regular, { className });
|
|
4490
|
+
case "xls":
|
|
4491
|
+
case "xlsx":
|
|
4492
|
+
case "csv":
|
|
4493
|
+
case "ods":
|
|
4494
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactIcons.DocumentTable20Regular, { className });
|
|
4495
|
+
case "ppt":
|
|
4496
|
+
case "pptx":
|
|
4497
|
+
case "odp":
|
|
4498
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactIcons.SlideText20Regular, { className });
|
|
4499
|
+
case "png":
|
|
4500
|
+
case "jpg":
|
|
4501
|
+
case "jpeg":
|
|
4502
|
+
case "gif":
|
|
4503
|
+
case "bmp":
|
|
4504
|
+
case "webp":
|
|
4505
|
+
case "svg":
|
|
4506
|
+
case "ico":
|
|
4507
|
+
case "tif":
|
|
4508
|
+
case "tiff":
|
|
4509
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactIcons.Image20Regular, { className });
|
|
4510
|
+
case "mp4":
|
|
4511
|
+
case "mov":
|
|
4512
|
+
case "avi":
|
|
4513
|
+
case "mkv":
|
|
4514
|
+
case "webm":
|
|
4515
|
+
case "m4v":
|
|
4516
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactIcons.Video20Regular, { className });
|
|
4517
|
+
case "mp3":
|
|
4518
|
+
case "wav":
|
|
4519
|
+
case "ogg":
|
|
4520
|
+
case "flac":
|
|
4521
|
+
case "m4a":
|
|
4522
|
+
case "aac":
|
|
4523
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactIcons.MusicNote220Regular, { className });
|
|
4524
|
+
case "zip":
|
|
4525
|
+
case "7z":
|
|
4526
|
+
case "rar":
|
|
4527
|
+
case "tar":
|
|
4528
|
+
case "gz":
|
|
4529
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactIcons.FolderZip20Regular, { className });
|
|
4530
|
+
case "txt":
|
|
4531
|
+
case "md":
|
|
4532
|
+
case "markdown":
|
|
4533
|
+
case "log":
|
|
4534
|
+
case "json":
|
|
4535
|
+
case "xml":
|
|
4536
|
+
case "yaml":
|
|
4537
|
+
case "yml":
|
|
4538
|
+
case "html":
|
|
4539
|
+
case "htm":
|
|
4540
|
+
case "js":
|
|
4541
|
+
case "ts":
|
|
4542
|
+
case "cs":
|
|
4543
|
+
case "css":
|
|
4544
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactIcons.DocumentText20Regular, { className });
|
|
4545
|
+
default:
|
|
4546
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactIcons.Document20Regular, { className });
|
|
4547
|
+
}
|
|
4548
|
+
}
|
|
4428
4549
|
function ZipTreeNode({ node, depth, expanded, selected, onToggle, onSelect }) {
|
|
4429
4550
|
const styles = useFileViewerStyles();
|
|
4430
4551
|
const isExpanded = expanded.has(node.fullPath);
|
|
@@ -4483,7 +4604,7 @@ function ZipTreeNode({ node, depth, expanded, selected, onToggle, onSelect }) {
|
|
|
4483
4604
|
style: indent,
|
|
4484
4605
|
children: [
|
|
4485
4606
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.zipChevronSpacer }),
|
|
4486
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4607
|
+
/* @__PURE__ */ jsxRuntime.jsx(ZipEntryIcon, { fileName: node.name, className: styles.zipIcon }),
|
|
4487
4608
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.zipName, children: node.name })
|
|
4488
4609
|
]
|
|
4489
4610
|
}
|
|
@@ -5128,11 +5249,13 @@ var useFileViewerStyles = reactComponents.makeStyles({
|
|
|
5128
5249
|
outlineOffset: "-1px"
|
|
5129
5250
|
}
|
|
5130
5251
|
},
|
|
5252
|
+
// Selection style ported from the Blazor zip viewer: a subtle accent tint over
|
|
5253
|
+
// the row (text stays its normal color), intensifying slightly on hover so the
|
|
5254
|
+
// neutral row-hover doesn't wash out the selection.
|
|
5131
5255
|
zipRowSelected: {
|
|
5132
|
-
backgroundColor: reactComponents.tokens.
|
|
5133
|
-
color: reactComponents.tokens.colorBrandForeground2,
|
|
5256
|
+
backgroundColor: `color-mix(in srgb, ${reactComponents.tokens.colorBrandBackground} 12%, transparent)`,
|
|
5134
5257
|
":hover": {
|
|
5135
|
-
backgroundColor: reactComponents.tokens.
|
|
5258
|
+
backgroundColor: `color-mix(in srgb, ${reactComponents.tokens.colorBrandBackground} 18%, transparent)`
|
|
5136
5259
|
}
|
|
5137
5260
|
},
|
|
5138
5261
|
zipChevron: {
|
|
@@ -8907,7 +9030,13 @@ function MainGridImpl({
|
|
|
8907
9030
|
(row) => row.properties?.[columnName],
|
|
8908
9031
|
{
|
|
8909
9032
|
id: columnName,
|
|
8910
|
-
|
|
9033
|
+
// Headers normally show the server-resolved Dataverse display name, which bypasses the
|
|
9034
|
+
// client `t()` — so the ?ppp-show-keys aid couldn't reach them. Consult key-mode here too:
|
|
9035
|
+
// when it's on, show the column's localization key (the one a consumer would override),
|
|
9036
|
+
// keyed by the column's OWN owning table (`resolvedColumn.tableName` — the related table
|
|
9037
|
+
// for a linked-entity column, not the grid's primary table). For linked columns the name
|
|
9038
|
+
// is a dotted alias path, so take the segment after the last dot as the real column name.
|
|
9039
|
+
header: () => react$1.isKeyModeEnabled() ? `tables.${resolvedColumn.tableName}.columns.${columnName.split(".").pop() ?? columnName}.label` : resolvedColumn.displayName,
|
|
8911
9040
|
cell: (cellCtx) => {
|
|
8912
9041
|
const rowRecord = cellCtx.row.original;
|
|
8913
9042
|
const rowId = rowRecord.id;
|
|
@@ -11671,15 +11800,11 @@ function ManyToManyLookupEdit({
|
|
|
11671
11800
|
return relatedPrimaryName;
|
|
11672
11801
|
}, [resolvedColumns, relatedPrimaryName]);
|
|
11673
11802
|
const lastSeededRecordIdRef = react.useRef(void 0);
|
|
11674
|
-
const lastSeededViewIdRef = react.useRef(void 0);
|
|
11675
11803
|
react.useEffect(() => {
|
|
11676
11804
|
if (initialLoad.status !== react$1.QueryStatus.Success || !initialLoad.data) return;
|
|
11677
11805
|
if (!primaryNameColumn || !parentRecord) return;
|
|
11678
|
-
if (lastSeededRecordIdRef.current === parentRefId
|
|
11679
|
-
return;
|
|
11680
|
-
}
|
|
11806
|
+
if (lastSeededRecordIdRef.current === parentRefId) return;
|
|
11681
11807
|
lastSeededRecordIdRef.current = parentRefId;
|
|
11682
|
-
lastSeededViewIdRef.current = selectedViewId;
|
|
11683
11808
|
const seeded = initialLoad.data.tableRecords.map((r) => ({
|
|
11684
11809
|
id: r.id,
|
|
11685
11810
|
displayName: resolveDisplayName(r, primaryNameColumn) ?? "",
|
|
@@ -11688,7 +11813,7 @@ function ManyToManyLookupEdit({
|
|
|
11688
11813
|
setInitialSelection(seeded);
|
|
11689
11814
|
setPendingAdds([]);
|
|
11690
11815
|
setPendingRemoveIds([]);
|
|
11691
|
-
}, [initialLoad.status, initialLoad.data, parentRecord, primaryNameColumn,
|
|
11816
|
+
}, [initialLoad.status, initialLoad.data, parentRecord, primaryNameColumn, parentRefId]);
|
|
11692
11817
|
const [query, setQuery] = react.useState("");
|
|
11693
11818
|
const [debouncedQuery, setDebouncedQuery] = react.useState("");
|
|
11694
11819
|
const [searchResults, setSearchResults] = react.useState([]);
|
|
@@ -11800,7 +11925,6 @@ function ManyToManyLookupEdit({
|
|
|
11800
11925
|
setPendingAdds([]);
|
|
11801
11926
|
setPendingRemoveIds([]);
|
|
11802
11927
|
lastSeededRecordIdRef.current = void 0;
|
|
11803
|
-
lastSeededViewIdRef.current = void 0;
|
|
11804
11928
|
},
|
|
11805
11929
|
// Cancel/Discard: just drop the pending adds/removes; the
|
|
11806
11930
|
// seed-guard refs stay so the initial selection (already loaded
|
|
@@ -13455,27 +13579,57 @@ function NavMenu({ children, width, className, style }) {
|
|
|
13455
13579
|
useNavSelectedStyles();
|
|
13456
13580
|
const location = reactRouterDom.useLocation();
|
|
13457
13581
|
const navigate = reactRouterDom.useNavigate();
|
|
13458
|
-
const { allRoutes,
|
|
13582
|
+
const { allRoutes, groups, defaultOpenIndexes } = react.useMemo(
|
|
13459
13583
|
() => collectNavTree(children),
|
|
13460
13584
|
[children]
|
|
13461
13585
|
);
|
|
13462
|
-
const
|
|
13586
|
+
const selectedRoute = react.useMemo(
|
|
13463
13587
|
() => bestRouteMatch(allRoutes, location.pathname),
|
|
13464
13588
|
[allRoutes, location.pathname]
|
|
13465
13589
|
);
|
|
13590
|
+
const [openIndexes, setOpenIndexes] = react.useState(
|
|
13591
|
+
() => /* @__PURE__ */ new Set([
|
|
13592
|
+
...defaultOpenIndexes,
|
|
13593
|
+
// Seed the active route's group too, so it's open on first paint
|
|
13594
|
+
// (the effect below only fires after mount).
|
|
13595
|
+
...selectedRoute && selectedRoute.groupIndex >= 0 ? [selectedRoute.groupIndex] : []
|
|
13596
|
+
])
|
|
13597
|
+
);
|
|
13598
|
+
const selectedGroupIndex = selectedRoute?.groupIndex ?? -1;
|
|
13599
|
+
react.useEffect(() => {
|
|
13600
|
+
if (selectedGroupIndex < 0) return;
|
|
13601
|
+
setOpenIndexes(
|
|
13602
|
+
(prev) => prev.has(selectedGroupIndex) ? prev : new Set(prev).add(selectedGroupIndex)
|
|
13603
|
+
);
|
|
13604
|
+
}, [selectedGroupIndex]);
|
|
13605
|
+
const openCategories = react.useMemo(
|
|
13606
|
+
() => groups.filter((_, index) => openIndexes.has(index)),
|
|
13607
|
+
[groups, openIndexes]
|
|
13608
|
+
);
|
|
13466
13609
|
const handleSelect = (_, data) => {
|
|
13467
13610
|
const value = data.value;
|
|
13468
13611
|
if (typeof value === "string" && value.startsWith("/")) {
|
|
13469
13612
|
navigate(value);
|
|
13470
13613
|
}
|
|
13471
13614
|
};
|
|
13615
|
+
const handleCategoryToggle = (_, data) => {
|
|
13616
|
+
const index = groups.indexOf(data.value);
|
|
13617
|
+
if (index < 0) return;
|
|
13618
|
+
setOpenIndexes((prev) => {
|
|
13619
|
+
const next = new Set(prev);
|
|
13620
|
+
if (next.has(index)) next.delete(index);
|
|
13621
|
+
else next.add(index);
|
|
13622
|
+
return next;
|
|
13623
|
+
});
|
|
13624
|
+
};
|
|
13472
13625
|
const navStyle = width ? { ...style, minWidth: width, maxWidth: width } : style;
|
|
13473
13626
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
13474
13627
|
reactNav.Nav,
|
|
13475
13628
|
{
|
|
13476
|
-
selectedValue:
|
|
13629
|
+
selectedValue: selectedRoute?.to ?? "",
|
|
13477
13630
|
onNavItemSelect: handleSelect,
|
|
13478
|
-
|
|
13631
|
+
openCategories,
|
|
13632
|
+
onNavCategoryItemToggle: handleCategoryToggle,
|
|
13479
13633
|
className: reactComponents.mergeClasses("ppp-nav-menu", styles.nav, className),
|
|
13480
13634
|
style: navStyle,
|
|
13481
13635
|
children
|
|
@@ -13505,42 +13659,46 @@ function NavItem({ to, icon, children }) {
|
|
|
13505
13659
|
}
|
|
13506
13660
|
function collectNavTree(children) {
|
|
13507
13661
|
const allRoutes = [];
|
|
13508
|
-
const
|
|
13509
|
-
const
|
|
13662
|
+
const groups = [];
|
|
13663
|
+
const defaultOpenIndexes = [];
|
|
13664
|
+
const visit = (nodes, groupIndex) => {
|
|
13510
13665
|
react.Children.forEach(nodes, (child) => {
|
|
13511
13666
|
if (!react.isValidElement(child)) return;
|
|
13512
13667
|
if (child.type === NavGroup) {
|
|
13513
13668
|
const props = child.props;
|
|
13514
13669
|
const value = props.value ?? `group:${props.label}`;
|
|
13515
|
-
|
|
13516
|
-
|
|
13670
|
+
const index = groups.length;
|
|
13671
|
+
groups.push(value);
|
|
13672
|
+
if (props.defaultExpanded) defaultOpenIndexes.push(index);
|
|
13673
|
+
visit(props.children, index);
|
|
13517
13674
|
return;
|
|
13518
13675
|
}
|
|
13519
13676
|
if (child.type === NavItem) {
|
|
13520
13677
|
const props = child.props;
|
|
13521
13678
|
allRoutes.push({
|
|
13522
13679
|
to: props.to,
|
|
13523
|
-
match: props.match ?? (props.to === "/" ? "exact" : "prefix")
|
|
13680
|
+
match: props.match ?? (props.to === "/" ? "exact" : "prefix"),
|
|
13681
|
+
groupIndex
|
|
13524
13682
|
});
|
|
13525
13683
|
return;
|
|
13526
13684
|
}
|
|
13527
13685
|
const wrapperChildren = child.props.children;
|
|
13528
|
-
if (wrapperChildren !== void 0) visit(wrapperChildren);
|
|
13686
|
+
if (wrapperChildren !== void 0) visit(wrapperChildren, groupIndex);
|
|
13529
13687
|
});
|
|
13530
13688
|
};
|
|
13531
|
-
visit(children);
|
|
13532
|
-
return { allRoutes,
|
|
13689
|
+
visit(children, -1);
|
|
13690
|
+
return { allRoutes, groups, defaultOpenIndexes };
|
|
13533
13691
|
}
|
|
13534
13692
|
function bestRouteMatch(routes, pathname) {
|
|
13535
13693
|
const normalize = (p) => p.length > 1 && p.endsWith("/") ? p.slice(0, -1) : p;
|
|
13536
13694
|
const target = normalize(pathname);
|
|
13537
13695
|
let best;
|
|
13538
13696
|
let bestLen = -1;
|
|
13539
|
-
for (const
|
|
13540
|
-
const route = normalize(to);
|
|
13541
|
-
const matches = route === target || match === "prefix" && (route === "/" || target.startsWith(route + "/"));
|
|
13697
|
+
for (const candidate of routes) {
|
|
13698
|
+
const route = normalize(candidate.to);
|
|
13699
|
+
const matches = route === target || candidate.match === "prefix" && (route === "/" || target.startsWith(route + "/"));
|
|
13542
13700
|
if (matches && route.length > bestLen) {
|
|
13543
|
-
best =
|
|
13701
|
+
best = candidate;
|
|
13544
13702
|
bestLen = route.length;
|
|
13545
13703
|
}
|
|
13546
13704
|
}
|
|
@@ -14283,8 +14441,28 @@ var useStyles12 = reactComponents.makeStyles({
|
|
|
14283
14441
|
mergedButtons: {
|
|
14284
14442
|
display: "flex",
|
|
14285
14443
|
flexWrap: "wrap",
|
|
14286
|
-
gap: reactComponents.tokens.
|
|
14444
|
+
gap: reactComponents.tokens.spacingHorizontalL
|
|
14445
|
+
},
|
|
14446
|
+
// One culture group: language label + inspect button + download button, kept together.
|
|
14447
|
+
mergedCulture: {
|
|
14448
|
+
display: "flex",
|
|
14449
|
+
alignItems: "center",
|
|
14450
|
+
gap: reactComponents.tokens.spacingHorizontalXS
|
|
14451
|
+
},
|
|
14452
|
+
mergedCultureLabel: { fontSize: reactComponents.tokens.fontSizeBase200 },
|
|
14453
|
+
dialogSurface: { maxWidth: "1100px", width: "90vw" },
|
|
14454
|
+
dialogToolbar: {
|
|
14455
|
+
display: "flex",
|
|
14456
|
+
alignItems: "center",
|
|
14457
|
+
gap: reactComponents.tokens.spacingHorizontalM,
|
|
14458
|
+
flexWrap: "wrap",
|
|
14459
|
+
marginBottom: reactComponents.tokens.spacingVerticalS
|
|
14287
14460
|
},
|
|
14461
|
+
// Scroll viewport for the merged grid so a tall result set scrolls inside the dialog.
|
|
14462
|
+
dialogGrid: { maxHeight: "60vh", overflowY: "auto", overflowX: "auto" },
|
|
14463
|
+
filterInput: { minWidth: "260px" },
|
|
14464
|
+
pager: { display: "flex", alignItems: "center", gap: reactComponents.tokens.spacingHorizontalS },
|
|
14465
|
+
grow: { flex: 1 },
|
|
14288
14466
|
sectionBody: {
|
|
14289
14467
|
display: "flex",
|
|
14290
14468
|
flexDirection: "column",
|
|
@@ -14303,6 +14481,15 @@ function downloadBytes(fileName, data, contentType = "application/json") {
|
|
|
14303
14481
|
anchor.click();
|
|
14304
14482
|
URL.revokeObjectURL(url);
|
|
14305
14483
|
}
|
|
14484
|
+
var kindKeyOf = (kind) => KIND_KEY[Number(kind)] ?? "tablemetadata";
|
|
14485
|
+
function cultureLabel(culture) {
|
|
14486
|
+
try {
|
|
14487
|
+
const name = new Intl.DisplayNames(void 0, { type: "language" }).of(culture);
|
|
14488
|
+
return name && name.toLowerCase() !== culture.toLowerCase() ? `${name} (${culture})` : culture;
|
|
14489
|
+
} catch {
|
|
14490
|
+
return culture;
|
|
14491
|
+
}
|
|
14492
|
+
}
|
|
14306
14493
|
function LocalizationAdmin({ className }) {
|
|
14307
14494
|
const styles = useStyles12();
|
|
14308
14495
|
const t = react$1.useT();
|
|
@@ -14312,6 +14499,7 @@ function LocalizationAdmin({ className }) {
|
|
|
14312
14499
|
const [isReloading, setIsReloading] = react.useState(false);
|
|
14313
14500
|
const [isDownloading, setIsDownloading] = react.useState(false);
|
|
14314
14501
|
const [message, setMessage] = react.useState();
|
|
14502
|
+
const [mergedDialogCulture, setMergedDialogCulture] = react.useState(null);
|
|
14315
14503
|
const loadOverview = react.useCallback(async () => {
|
|
14316
14504
|
try {
|
|
14317
14505
|
const value = await ppp.getLocalizationOverviewAsync();
|
|
@@ -14469,17 +14657,44 @@ function LocalizationAdmin({ className }) {
|
|
|
14469
14657
|
/* @__PURE__ */ jsxRuntime.jsx(LocalizationTranslator, {}),
|
|
14470
14658
|
availableCultures.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Section, { headerText: t("app.localization-admin.download-merged-title"), borderVisible: true, children: /* @__PURE__ */ jsxRuntime.jsx(SectionColumn, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.sectionBody, children: [
|
|
14471
14659
|
/* @__PURE__ */ jsxRuntime.jsx(reactComponents.Text, { children: t("app.localization-admin.download-merged-description") }),
|
|
14472
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.mergedButtons, children: availableCultures.map((culture) => /* @__PURE__ */ jsxRuntime.
|
|
14473
|
-
|
|
14474
|
-
|
|
14475
|
-
|
|
14476
|
-
|
|
14477
|
-
|
|
14478
|
-
|
|
14479
|
-
|
|
14480
|
-
|
|
14481
|
-
|
|
14482
|
-
|
|
14660
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.mergedButtons, children: availableCultures.map((culture) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.mergedCulture, children: [
|
|
14661
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.mergedCultureLabel, children: cultureLabel(culture) }),
|
|
14662
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14663
|
+
reactComponents.Tooltip,
|
|
14664
|
+
{
|
|
14665
|
+
content: t("app.localization-admin.view-merged-tooltip", [
|
|
14666
|
+
cultureLabel(culture)
|
|
14667
|
+
]),
|
|
14668
|
+
relationship: "label",
|
|
14669
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14670
|
+
reactComponents.Button,
|
|
14671
|
+
{
|
|
14672
|
+
appearance: "outline",
|
|
14673
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.EyeRegular, {}),
|
|
14674
|
+
onClick: () => setMergedDialogCulture(culture)
|
|
14675
|
+
}
|
|
14676
|
+
)
|
|
14677
|
+
}
|
|
14678
|
+
),
|
|
14679
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14680
|
+
reactComponents.Tooltip,
|
|
14681
|
+
{
|
|
14682
|
+
content: t("app.localization-admin.download-merged-tooltip", [
|
|
14683
|
+
cultureLabel(culture)
|
|
14684
|
+
]),
|
|
14685
|
+
relationship: "label",
|
|
14686
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14687
|
+
reactComponents.Button,
|
|
14688
|
+
{
|
|
14689
|
+
appearance: "subtle",
|
|
14690
|
+
disabled: isDownloading,
|
|
14691
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.ArrowDownloadRegular, {}),
|
|
14692
|
+
onClick: () => onDownloadMerged(culture)
|
|
14693
|
+
}
|
|
14694
|
+
)
|
|
14695
|
+
}
|
|
14696
|
+
)
|
|
14697
|
+
] }, culture)) })
|
|
14483
14698
|
] }) }) }),
|
|
14484
14699
|
/* @__PURE__ */ jsxRuntime.jsx(Section, { headerText: t("app.localization-admin.sources-title"), borderVisible: true, children: /* @__PURE__ */ jsxRuntime.jsx(SectionColumn, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.sectionBody, children: [
|
|
14485
14700
|
/* @__PURE__ */ jsxRuntime.jsx(reactComponents.Text, { children: t("app.localization-admin.sources-description") }),
|
|
@@ -14510,7 +14725,22 @@ function LocalizationAdmin({ className }) {
|
|
|
14510
14725
|
] }) }) })
|
|
14511
14726
|
] });
|
|
14512
14727
|
}
|
|
14513
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
14728
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: reactComponents.mergeClasses("ppp-localization-admin", styles.root, className), children: [
|
|
14729
|
+
content,
|
|
14730
|
+
mergedDialogCulture !== null && /* @__PURE__ */ jsxRuntime.jsx(
|
|
14731
|
+
MergedSourcesDialog,
|
|
14732
|
+
{
|
|
14733
|
+
culture: mergedDialogCulture,
|
|
14734
|
+
label: cultureLabel(mergedDialogCulture),
|
|
14735
|
+
onClose: () => setMergedDialogCulture(null),
|
|
14736
|
+
onDownload: () => onDownloadMerged(mergedDialogCulture),
|
|
14737
|
+
isDownloading,
|
|
14738
|
+
ppp,
|
|
14739
|
+
t,
|
|
14740
|
+
styles
|
|
14741
|
+
}
|
|
14742
|
+
)
|
|
14743
|
+
] });
|
|
14514
14744
|
}
|
|
14515
14745
|
function ConfigRow({ styles, label, value }) {
|
|
14516
14746
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
@@ -14560,6 +14790,177 @@ function SourceRow({
|
|
|
14560
14790
|
)) }) })
|
|
14561
14791
|
] });
|
|
14562
14792
|
}
|
|
14793
|
+
var MERGED_PAGE_SIZE = 100;
|
|
14794
|
+
function MergedSourcesDialog({
|
|
14795
|
+
culture,
|
|
14796
|
+
label,
|
|
14797
|
+
onClose,
|
|
14798
|
+
onDownload,
|
|
14799
|
+
isDownloading,
|
|
14800
|
+
ppp,
|
|
14801
|
+
t,
|
|
14802
|
+
styles
|
|
14803
|
+
}) {
|
|
14804
|
+
const [entries, setEntries] = react.useState(null);
|
|
14805
|
+
const [loadError, setLoadError] = react.useState();
|
|
14806
|
+
const [filter, setFilter] = react.useState("");
|
|
14807
|
+
const [page, setPage] = react.useState(0);
|
|
14808
|
+
const [sortState, setSortState] = react.useState({
|
|
14809
|
+
sortColumn: "key",
|
|
14810
|
+
sortDirection: "ascending"
|
|
14811
|
+
});
|
|
14812
|
+
react.useEffect(() => {
|
|
14813
|
+
let cancelled = false;
|
|
14814
|
+
void (async () => {
|
|
14815
|
+
try {
|
|
14816
|
+
const value = await ppp.getMergedLocalizationEntriesAsync(culture);
|
|
14817
|
+
if (!cancelled) {
|
|
14818
|
+
setEntries(value);
|
|
14819
|
+
setLoadError(void 0);
|
|
14820
|
+
}
|
|
14821
|
+
} catch (reason) {
|
|
14822
|
+
if (!cancelled) {
|
|
14823
|
+
setEntries(null);
|
|
14824
|
+
setLoadError(reason instanceof Error ? reason.message : String(reason));
|
|
14825
|
+
}
|
|
14826
|
+
}
|
|
14827
|
+
})();
|
|
14828
|
+
return () => {
|
|
14829
|
+
cancelled = true;
|
|
14830
|
+
};
|
|
14831
|
+
}, [ppp, culture]);
|
|
14832
|
+
const columns = react.useMemo(
|
|
14833
|
+
() => [
|
|
14834
|
+
reactComponents.createTableColumn({
|
|
14835
|
+
columnId: "key",
|
|
14836
|
+
compare: (a, b) => a.key.localeCompare(b.key),
|
|
14837
|
+
renderHeaderCell: () => t("app.localization-admin.merged-column-key"),
|
|
14838
|
+
renderCell: (item) => item.key
|
|
14839
|
+
}),
|
|
14840
|
+
reactComponents.createTableColumn({
|
|
14841
|
+
columnId: "kind",
|
|
14842
|
+
compare: (a, b) => Number(a.sourceKind) - Number(b.sourceKind),
|
|
14843
|
+
renderHeaderCell: () => t("app.localization-admin.merged-column-kind"),
|
|
14844
|
+
renderCell: (item) => t(`app.localization-admin.kind-${kindKeyOf(item.sourceKind)}`)
|
|
14845
|
+
}),
|
|
14846
|
+
reactComponents.createTableColumn({
|
|
14847
|
+
columnId: "source",
|
|
14848
|
+
compare: (a, b) => a.sourceDisplayName.localeCompare(b.sourceDisplayName),
|
|
14849
|
+
renderHeaderCell: () => t("app.localization-admin.merged-column-source"),
|
|
14850
|
+
renderCell: (item) => item.sourceDisplayName
|
|
14851
|
+
}),
|
|
14852
|
+
reactComponents.createTableColumn({
|
|
14853
|
+
columnId: "value",
|
|
14854
|
+
compare: (a, b) => a.value.localeCompare(b.value),
|
|
14855
|
+
renderHeaderCell: () => t("app.localization-admin.merged-column-value"),
|
|
14856
|
+
renderCell: (item) => item.value
|
|
14857
|
+
})
|
|
14858
|
+
],
|
|
14859
|
+
[t]
|
|
14860
|
+
);
|
|
14861
|
+
const filtered = react.useMemo(() => {
|
|
14862
|
+
if (!entries) return [];
|
|
14863
|
+
const q = filter.trim().toLowerCase();
|
|
14864
|
+
const base = q ? entries.filter(
|
|
14865
|
+
(e) => e.key.toLowerCase().includes(q) || e.value.toLowerCase().includes(q) || e.sourceDisplayName.toLowerCase().includes(q)
|
|
14866
|
+
) : entries;
|
|
14867
|
+
return [...base];
|
|
14868
|
+
}, [entries, filter]);
|
|
14869
|
+
const sorted = react.useMemo(() => {
|
|
14870
|
+
const column = columns.find((c) => c.columnId === sortState.sortColumn);
|
|
14871
|
+
if (!column?.compare) return filtered;
|
|
14872
|
+
const sign = sortState.sortDirection === "ascending" ? 1 : -1;
|
|
14873
|
+
return [...filtered].sort((a, b) => sign * column.compare(a, b));
|
|
14874
|
+
}, [filtered, columns, sortState]);
|
|
14875
|
+
react.useEffect(() => {
|
|
14876
|
+
setPage(0);
|
|
14877
|
+
}, [filter, sortState]);
|
|
14878
|
+
const pageCount = Math.max(1, Math.ceil(sorted.length / MERGED_PAGE_SIZE));
|
|
14879
|
+
const currentPage = Math.min(page, pageCount - 1);
|
|
14880
|
+
const paged = sorted.slice(currentPage * MERGED_PAGE_SIZE, currentPage * MERGED_PAGE_SIZE + MERGED_PAGE_SIZE);
|
|
14881
|
+
const columnSizingOptions = react.useMemo(
|
|
14882
|
+
() => ({
|
|
14883
|
+
key: { minWidth: 200, defaultWidth: 320 },
|
|
14884
|
+
kind: { minWidth: 110, defaultWidth: 140 },
|
|
14885
|
+
source: { minWidth: 200, defaultWidth: 300 },
|
|
14886
|
+
value: { minWidth: 200, defaultWidth: 360 }
|
|
14887
|
+
}),
|
|
14888
|
+
[]
|
|
14889
|
+
);
|
|
14890
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Dialog, { open: true, onOpenChange: (_event, data) => !data.open && onClose(), children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogSurface, { className: styles.dialogSurface, children: /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.DialogBody, { children: [
|
|
14891
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogTitle, { children: t("app.localization-admin.merged-dialog-title", [label]) }),
|
|
14892
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogContent, { children: loadError !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MessageBar, { intent: "error", children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MessageBarBody, { children: t("app.localization-admin.merged-load-failed", [loadError]) }) }) : entries === null ? /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Spinner, {}) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
14893
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.dialogToolbar, children: [
|
|
14894
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14895
|
+
reactComponents.Input,
|
|
14896
|
+
{
|
|
14897
|
+
className: styles.filterInput,
|
|
14898
|
+
value: filter,
|
|
14899
|
+
onChange: (_event, data) => setFilter(data.value),
|
|
14900
|
+
contentBefore: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.SearchRegular, {}),
|
|
14901
|
+
placeholder: t("app.localization-admin.merged-filter-placeholder")
|
|
14902
|
+
}
|
|
14903
|
+
),
|
|
14904
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.lastReloaded, children: t("app.localization-admin.merged-count", [sorted.length, entries.length]) }),
|
|
14905
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.grow }),
|
|
14906
|
+
pageCount > 1 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: styles.pager, children: [
|
|
14907
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14908
|
+
reactComponents.Button,
|
|
14909
|
+
{
|
|
14910
|
+
size: "small",
|
|
14911
|
+
appearance: "subtle",
|
|
14912
|
+
disabled: currentPage === 0,
|
|
14913
|
+
onClick: () => setPage(currentPage - 1),
|
|
14914
|
+
children: t("app.localization-admin.merged-prev")
|
|
14915
|
+
}
|
|
14916
|
+
),
|
|
14917
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.lastReloaded, children: t("app.localization-admin.merged-page", [currentPage + 1, pageCount]) }),
|
|
14918
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14919
|
+
reactComponents.Button,
|
|
14920
|
+
{
|
|
14921
|
+
size: "small",
|
|
14922
|
+
appearance: "subtle",
|
|
14923
|
+
disabled: currentPage >= pageCount - 1,
|
|
14924
|
+
onClick: () => setPage(currentPage + 1),
|
|
14925
|
+
children: t("app.localization-admin.merged-next")
|
|
14926
|
+
}
|
|
14927
|
+
)
|
|
14928
|
+
] })
|
|
14929
|
+
] }),
|
|
14930
|
+
sorted.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MessageBar, { intent: "info", children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MessageBarBody, { children: t("app.localization-admin.merged-empty") }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.dialogGrid, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14931
|
+
reactComponents.DataGrid,
|
|
14932
|
+
{
|
|
14933
|
+
items: paged,
|
|
14934
|
+
columns,
|
|
14935
|
+
sortable: true,
|
|
14936
|
+
resizableColumns: true,
|
|
14937
|
+
sortState,
|
|
14938
|
+
onSortChange: (_event, next) => setSortState(next),
|
|
14939
|
+
columnSizingOptions,
|
|
14940
|
+
getRowId: (item) => item.key,
|
|
14941
|
+
size: "small",
|
|
14942
|
+
children: [
|
|
14943
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactComponents.DataGridHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DataGridRow, { children: ({ renderHeaderCell }) => /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DataGridHeaderCell, { children: renderHeaderCell() }) }) }),
|
|
14944
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactComponents.DataGridBody, { children: ({ item, rowId }) => /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DataGridRow, { children: ({ renderCell }) => /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DataGridCell, { children: renderCell(item) }) }, rowId) })
|
|
14945
|
+
]
|
|
14946
|
+
}
|
|
14947
|
+
) })
|
|
14948
|
+
] }) }),
|
|
14949
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactComponents.DialogActions, { children: [
|
|
14950
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14951
|
+
reactComponents.Button,
|
|
14952
|
+
{
|
|
14953
|
+
appearance: "primary",
|
|
14954
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.ArrowDownloadRegular, {}),
|
|
14955
|
+
disabled: isDownloading,
|
|
14956
|
+
onClick: onDownload,
|
|
14957
|
+
children: t("app.localization-admin.merged-download-button")
|
|
14958
|
+
}
|
|
14959
|
+
),
|
|
14960
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactComponents.Button, { appearance: "secondary", icon: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.DismissRegular, {}), onClick: onClose, children: t("app.buttons.close.label") })
|
|
14961
|
+
] })
|
|
14962
|
+
] }) }) });
|
|
14963
|
+
}
|
|
14563
14964
|
var useStyles13 = reactComponents.makeStyles({
|
|
14564
14965
|
root: {
|
|
14565
14966
|
display: "flex",
|