@blocklet/labels 1.5.213 → 1.6.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/dist/components/label/context.d.ts +3 -2
- package/dist/components/label/index.d.ts +0 -1
- package/dist/components/label/types.d.ts +2 -2
- package/dist/index.d.ts +5 -0
- package/dist/index.es.js +632 -321
- package/dist/index.umd.js +626 -308
- package/dist/label2/github-label-picker.d.ts +14 -0
- package/dist/label2/labels-context.d.ts +46 -3
- package/dist/label2/labels-input.d.ts +6 -0
- package/dist/label2/labels2.d.ts +10 -0
- package/dist/label2/tree.d.ts +13 -3
- package/dist/types.d.ts +23 -8
- package/package.json +3 -3
- package/dist/components/label/LabelManager.stories.d.ts +0 -8
- package/dist/components/label/LabelPicker.stories.d.ts +0 -5
- package/dist/components/label/LabelTree.stories.d.ts +0 -8
- package/dist/components/label/label-delete-dialog.d.ts +0 -9
- package/dist/components/label/label-form-dialog.d.ts +0 -9
- package/dist/components/label/label-manager.d.ts +0 -12
package/dist/index.es.js
CHANGED
|
@@ -6,27 +6,20 @@ var __publicField = (obj, key, value) => {
|
|
|
6
6
|
};
|
|
7
7
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
8
8
|
import { createContext, useRef, useState, useCallback, useEffect, useMemo, useContext } from "react";
|
|
9
|
-
import { ExpandMore,
|
|
9
|
+
import { ExpandMore, Edit, LabelOutlined } from "@mui/icons-material";
|
|
10
10
|
import Box from "@mui/material/Box";
|
|
11
11
|
import { styled } from "@mui/material/styles";
|
|
12
12
|
import { Tree } from "react-arborist";
|
|
13
13
|
import { Icon } from "@iconify/react";
|
|
14
14
|
import omit from "lodash/omit";
|
|
15
15
|
import Select, { components } from "react-select";
|
|
16
|
-
import
|
|
17
|
-
import Button from "@mui/material/Button";
|
|
18
|
-
import IconButton from "@mui/material/IconButton";
|
|
19
|
-
import { TranslationTextField, TranslationTag } from "@blocklet/translation-input";
|
|
20
|
-
import { useSetState, useReactive, useRequest } from "ahooks";
|
|
21
|
-
import TextField from "@mui/material/TextField";
|
|
22
|
-
import ClickAwayListener from "@mui/material/ClickAwayListener";
|
|
23
|
-
import { GithubPicker } from "react-color";
|
|
24
|
-
import Dialog from "@arcblock/ux/lib/Dialog";
|
|
25
|
-
import Alert from "@mui/material/Alert";
|
|
26
|
-
import { ClickAwayListener as ClickAwayListener$1, Box as Box$1, Chip, IconButton as IconButton$1, Button as Button$1, getContrastRatio, alpha } from "@mui/material";
|
|
16
|
+
import { ClickAwayListener, Box as Box$1, Chip, IconButton, Button, getContrastRatio, alpha, useTheme, ButtonBase, Popper, Autocomplete, InputBase, autocompleteClasses, TextField } from "@mui/material";
|
|
27
17
|
import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
|
|
18
|
+
import { useReactive, useRequest } from "ahooks";
|
|
28
19
|
import { createContainer } from "unstated-next";
|
|
29
20
|
import { arrayToTree } from "performant-array-to-tree";
|
|
21
|
+
import CloseIcon from "@mui/icons-material/Close";
|
|
22
|
+
import DoneIcon from "@mui/icons-material/Done";
|
|
30
23
|
const materialSymbolsLabelRounded = (props) => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", width: "1.2em", height: "1.2em", ...props, children: /* @__PURE__ */ jsx("path", { fill: "currentColor", d: "M5 19q-.825 0-1.413-.587Q3 17.825 3 17V7q0-.825.587-1.412Q4.175 5 5 5h10q.5 0 .938.225q.437.225.712.625l3.525 5q.375.525.375 1.15q0 .625-.375 1.15l-3.525 5q-.275.4-.712.625Q15.5 19 15 19Z" }) });
|
|
31
24
|
const materialSymbolsCheckSmall = (props) => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", width: "1.2em", height: "1.2em", ...props, children: /* @__PURE__ */ jsx("path", { fill: "currentColor", d: "m10 16.4l-4-4L7.4 11l2.6 2.6L16.6 7L18 8.4Z" }) });
|
|
32
25
|
const LabelTreeContext = createContext({});
|
|
@@ -152,15 +145,6 @@ const flatten = (data) => {
|
|
|
152
145
|
return acc;
|
|
153
146
|
}, []);
|
|
154
147
|
};
|
|
155
|
-
const copyTree = (data) => {
|
|
156
|
-
return data.map((item) => {
|
|
157
|
-
var _a;
|
|
158
|
-
if ((_a = item.children) == null ? void 0 : _a.length) {
|
|
159
|
-
item.children = copyTree(item.children);
|
|
160
|
-
}
|
|
161
|
-
return item;
|
|
162
|
-
});
|
|
163
|
-
};
|
|
164
148
|
const safeParseJSON = (json, defaultValue = null) => {
|
|
165
149
|
try {
|
|
166
150
|
return JSON.parse(json);
|
|
@@ -356,287 +340,6 @@ function LabelPicker({
|
|
|
356
340
|
}
|
|
357
341
|
) });
|
|
358
342
|
}
|
|
359
|
-
function LabelFormDialog({ open, initialLabel, onSubmit, onClose, ...rest }) {
|
|
360
|
-
const isNew = !(initialLabel == null ? void 0 : initialLabel.id);
|
|
361
|
-
const [state, setState] = useSetState({
|
|
362
|
-
name: (initialLabel == null ? void 0 : initialLabel.name) || "",
|
|
363
|
-
color: (initialLabel == null ? void 0 : initialLabel.color) || "#ddd",
|
|
364
|
-
slug: (initialLabel == null ? void 0 : initialLabel.id) || "",
|
|
365
|
-
translation: (initialLabel == null ? void 0 : initialLabel.translation) || {}
|
|
366
|
-
});
|
|
367
|
-
const isValidColor = (color) => /^#([0-9A-F]{3}){1,2}$/i.test(color);
|
|
368
|
-
const canSubmit = useMemo(() => {
|
|
369
|
-
if (isNew) {
|
|
370
|
-
return state.name && state.color && state.slug && isValidColor(state.color);
|
|
371
|
-
}
|
|
372
|
-
return state.name && state.color && isValidColor(state.color);
|
|
373
|
-
}, [state, isNew]);
|
|
374
|
-
const [colorPickerVisible, setColorPickerVisible] = useState(false);
|
|
375
|
-
const handleSubmit = () => {
|
|
376
|
-
onSubmit({ ...initialLabel, name: state.name, color: state.color, id: state.slug, translation: state.translation });
|
|
377
|
-
};
|
|
378
|
-
const handleColorChange = (color) => {
|
|
379
|
-
setState({ color: color.hex });
|
|
380
|
-
setTimeout(() => setColorPickerVisible(false));
|
|
381
|
-
};
|
|
382
|
-
const handleColorTextChange = (e) => {
|
|
383
|
-
setState({ color: e.target.value });
|
|
384
|
-
};
|
|
385
|
-
return /* @__PURE__ */ jsx(
|
|
386
|
-
Dialog,
|
|
387
|
-
{
|
|
388
|
-
open,
|
|
389
|
-
showCloseButton: true,
|
|
390
|
-
maxWidth: "lg",
|
|
391
|
-
title: isNew ? "Create label" : "Edit label",
|
|
392
|
-
actions: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
393
|
-
/* @__PURE__ */ jsx(Button, { color: "inherit", variant: "contained", size: "small", onClick: onClose, children: "Cancel" }),
|
|
394
|
-
/* @__PURE__ */ jsx(Button, { color: "primary", variant: "contained", size: "small", onClick: handleSubmit, disabled: !canSubmit, children: isNew ? "Create" : "Save Changes" })
|
|
395
|
-
] }),
|
|
396
|
-
onClose,
|
|
397
|
-
...rest,
|
|
398
|
-
children: /* @__PURE__ */ jsxs(Box, { width: 600, minHeight: 320, children: [
|
|
399
|
-
/* @__PURE__ */ jsx(
|
|
400
|
-
TranslationTextField,
|
|
401
|
-
{
|
|
402
|
-
label: "Name",
|
|
403
|
-
value: state.name,
|
|
404
|
-
placeholder: "New label",
|
|
405
|
-
size: "small",
|
|
406
|
-
fullWidth: true,
|
|
407
|
-
onChange: (e) => setState({ name: e.target.value }),
|
|
408
|
-
translationInputProps: {
|
|
409
|
-
value: state.translation,
|
|
410
|
-
onChange: (v) => setState({ translation: v })
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
),
|
|
414
|
-
/* @__PURE__ */ jsx(
|
|
415
|
-
TextField,
|
|
416
|
-
{
|
|
417
|
-
label: "Slug",
|
|
418
|
-
value: state.slug,
|
|
419
|
-
size: "small",
|
|
420
|
-
fullWidth: true,
|
|
421
|
-
disabled: !isNew,
|
|
422
|
-
onChange: (e) => setState({ slug: e.target.value }),
|
|
423
|
-
sx: { mt: 2 }
|
|
424
|
-
}
|
|
425
|
-
),
|
|
426
|
-
(initialLabel == null ? void 0 : initialLabel.parent) && /* @__PURE__ */ jsx(TextField, { label: "Parent", value: initialLabel.parent.name, size: "small", fullWidth: true, disabled: true, sx: { mt: 2 } }),
|
|
427
|
-
/* @__PURE__ */ jsx(ClickAwayListener, { onClickAway: () => setColorPickerVisible(false), children: /* @__PURE__ */ jsxs(Box, { sx: { position: "relative", mt: 2 }, children: [
|
|
428
|
-
/* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
|
|
429
|
-
/* @__PURE__ */ jsx(
|
|
430
|
-
Box,
|
|
431
|
-
{
|
|
432
|
-
sx: { width: 30, height: 30, bgcolor: state.color, borderRadius: 1 },
|
|
433
|
-
onClick: () => setColorPickerVisible(true)
|
|
434
|
-
}
|
|
435
|
-
),
|
|
436
|
-
/* @__PURE__ */ jsx(
|
|
437
|
-
TextField,
|
|
438
|
-
{
|
|
439
|
-
label: "",
|
|
440
|
-
value: state.color,
|
|
441
|
-
size: "small",
|
|
442
|
-
onChange: handleColorTextChange,
|
|
443
|
-
inputProps: { maxLength: 7 },
|
|
444
|
-
sx: { width: 100, ".MuiInputBase-root": { height: 32 } }
|
|
445
|
-
}
|
|
446
|
-
)
|
|
447
|
-
] }),
|
|
448
|
-
colorPickerVisible && /* @__PURE__ */ jsx(Box, { sx: { position: "absolute", top: 48, zIndex: 1 }, children: /* @__PURE__ */ jsx(GithubPicker, { color: state.color, onChangeComplete: handleColorChange }) })
|
|
449
|
-
] }) })
|
|
450
|
-
] })
|
|
451
|
-
}
|
|
452
|
-
);
|
|
453
|
-
}
|
|
454
|
-
function LabelDeleteDialog({ open, label, onSubmit, onClose, ...rest }) {
|
|
455
|
-
return /* @__PURE__ */ jsx(
|
|
456
|
-
Dialog,
|
|
457
|
-
{
|
|
458
|
-
open,
|
|
459
|
-
showCloseButton: true,
|
|
460
|
-
maxWidth: "md",
|
|
461
|
-
title: "Delete",
|
|
462
|
-
actions: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
463
|
-
/* @__PURE__ */ jsx(Button, { color: "inherit", variant: "contained", size: "small", onClick: onClose, children: "Cancel" }),
|
|
464
|
-
/* @__PURE__ */ jsx(Button, { color: "primary", variant: "contained", size: "small", onClick: onSubmit, children: "Delete" })
|
|
465
|
-
] }),
|
|
466
|
-
onClose,
|
|
467
|
-
...rest,
|
|
468
|
-
children: /* @__PURE__ */ jsxs(Box, { width: 600, minHeight: 280, children: [
|
|
469
|
-
/* @__PURE__ */ jsx(Alert, { severity: "info", sx: { mb: 2 }, children: "Are you sure you want to delete these labels ?" }),
|
|
470
|
-
/* @__PURE__ */ jsx(LabelTree, { data: [label] })
|
|
471
|
-
] })
|
|
472
|
-
}
|
|
473
|
-
);
|
|
474
|
-
}
|
|
475
|
-
const StyledLabelTree = styled(LabelTree)`
|
|
476
|
-
.label-tree-item {
|
|
477
|
-
&:before {
|
|
478
|
-
content: '';
|
|
479
|
-
position: absolute;
|
|
480
|
-
top: 0;
|
|
481
|
-
left: 0;
|
|
482
|
-
right: 0;
|
|
483
|
-
border-top: 1px solid #ddd;
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
& [role='treeitem']:first-of-type > .label-tree-item {
|
|
487
|
-
&:before {
|
|
488
|
-
display: none;
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
[role='treeitem'] {
|
|
492
|
-
box-sizing: border-box;
|
|
493
|
-
padding: 0 16px;
|
|
494
|
-
}
|
|
495
|
-
`;
|
|
496
|
-
function LabelManager({ data, api, ...rest }) {
|
|
497
|
-
const [editingLabel, setEditingLabel] = useState(null);
|
|
498
|
-
const [deletingLabel, setDeletingLabel] = useState(null);
|
|
499
|
-
const [copy, setCopy] = useState(copyTree(data));
|
|
500
|
-
const flattened = useMemo(() => flatten(copy), [copy]);
|
|
501
|
-
const treeData = useMemo(() => {
|
|
502
|
-
const format = (nodes, parent) => {
|
|
503
|
-
return nodes.map((node) => {
|
|
504
|
-
if (parent) {
|
|
505
|
-
node.parent = parent;
|
|
506
|
-
}
|
|
507
|
-
if (node.children) {
|
|
508
|
-
node.children = format(node.children, node);
|
|
509
|
-
}
|
|
510
|
-
return node;
|
|
511
|
-
});
|
|
512
|
-
};
|
|
513
|
-
return format(copy);
|
|
514
|
-
}, [copy]);
|
|
515
|
-
const updateNode = (label) => {
|
|
516
|
-
var _a, _b;
|
|
517
|
-
if (!label.parent) {
|
|
518
|
-
setCopy(copy.map((item) => item.id === label.id ? { ...label } : item));
|
|
519
|
-
} else {
|
|
520
|
-
label.parent.children = (_b = (_a = label.parent) == null ? void 0 : _a.children) == null ? void 0 : _b.map((item) => item.id === label.id ? { ...label } : item);
|
|
521
|
-
updateNode(label.parent);
|
|
522
|
-
}
|
|
523
|
-
};
|
|
524
|
-
const addNode = (label) => {
|
|
525
|
-
if (label.parent) {
|
|
526
|
-
label.parent.children = label.parent.children || [];
|
|
527
|
-
label.parent.children.push(label);
|
|
528
|
-
setCopy([...copy]);
|
|
529
|
-
} else {
|
|
530
|
-
setCopy([...copy, label]);
|
|
531
|
-
}
|
|
532
|
-
};
|
|
533
|
-
const deleteNode = (label) => {
|
|
534
|
-
var _a;
|
|
535
|
-
if (label.parent) {
|
|
536
|
-
label.parent.children = (_a = label.parent.children) == null ? void 0 : _a.filter((item) => item.id !== label.id);
|
|
537
|
-
} else {
|
|
538
|
-
setCopy(copy.filter((item) => item.id !== label.id));
|
|
539
|
-
}
|
|
540
|
-
};
|
|
541
|
-
const handleAdd = (parent) => {
|
|
542
|
-
if (editingLabel) {
|
|
543
|
-
return;
|
|
544
|
-
}
|
|
545
|
-
const newLabel = { id: "", name: "New label", parent, color: "#dddddd" };
|
|
546
|
-
setEditingLabel(newLabel);
|
|
547
|
-
};
|
|
548
|
-
const handleEdit = (label) => {
|
|
549
|
-
if (editingLabel) {
|
|
550
|
-
return;
|
|
551
|
-
}
|
|
552
|
-
setEditingLabel(label);
|
|
553
|
-
};
|
|
554
|
-
const handleSubmit = async (payload) => {
|
|
555
|
-
if (!editingLabel) {
|
|
556
|
-
return;
|
|
557
|
-
}
|
|
558
|
-
const { parent, children, translation, ...submitData } = payload;
|
|
559
|
-
if (!editingLabel.id) {
|
|
560
|
-
await api.createLabel({ ...submitData, translation: JSON.stringify(translation), parentId: parent == null ? void 0 : parent.id });
|
|
561
|
-
addNode(payload);
|
|
562
|
-
} else {
|
|
563
|
-
await api.updateLabel({ ...submitData, translation: JSON.stringify(translation), parentId: parent == null ? void 0 : parent.id });
|
|
564
|
-
updateNode(payload);
|
|
565
|
-
}
|
|
566
|
-
setEditingLabel(null);
|
|
567
|
-
};
|
|
568
|
-
const handleDelete = async () => {
|
|
569
|
-
if (!deletingLabel) {
|
|
570
|
-
return;
|
|
571
|
-
}
|
|
572
|
-
await api.deleteLabel(deletingLabel.id);
|
|
573
|
-
deleteNode(deletingLabel);
|
|
574
|
-
setDeletingLabel(null);
|
|
575
|
-
};
|
|
576
|
-
const renderItem = (children, label) => {
|
|
577
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
578
|
-
/* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", flexWrap: "wrap" }, className: "label-name", children: [
|
|
579
|
-
/* @__PURE__ */ jsx(Box, { children }),
|
|
580
|
-
label.translation && /* @__PURE__ */ jsx(Box, { sx: { display: "flex", alignItems: "center", gap: 0.5, ml: 2 }, className: "label-translation", children: Object.keys(label.translation).map((key) => {
|
|
581
|
-
var _a;
|
|
582
|
-
const value = (_a = label.translation) == null ? void 0 : _a[key];
|
|
583
|
-
if (value) {
|
|
584
|
-
return /* @__PURE__ */ jsx(TranslationTag, { locale: key, value }, key);
|
|
585
|
-
}
|
|
586
|
-
return null;
|
|
587
|
-
}) })
|
|
588
|
-
] }),
|
|
589
|
-
/* @__PURE__ */ jsxs(Box, { sx: { display: "flex", gap: 1, flex: "0 0 auto" }, className: "label-action", children: [
|
|
590
|
-
/* @__PURE__ */ jsx(IconButton, { color: "inherit", size: "small", sx: { color: "grey.500" }, onClick: () => handleAdd(label), children: /* @__PURE__ */ jsx(Add, { sx: { fontSize: 20 } }) }),
|
|
591
|
-
/* @__PURE__ */ jsx(IconButton, { color: "inherit", size: "small", sx: { color: "grey.500" }, onClick: () => handleEdit(label), children: /* @__PURE__ */ jsx(EditOutlined, { sx: { fontSize: 18 } }) }),
|
|
592
|
-
/* @__PURE__ */ jsx(IconButton, { color: "inherit", size: "small", sx: { color: "grey.500" }, onClick: () => setDeletingLabel(label), children: /* @__PURE__ */ jsx(DeleteOutlineOutlined, { sx: { fontSize: 20 } }) })
|
|
593
|
-
] })
|
|
594
|
-
] });
|
|
595
|
-
};
|
|
596
|
-
return /* @__PURE__ */ jsxs(Box, { ...rest, className: "label-container", children: [
|
|
597
|
-
/* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
|
|
598
|
-
/* @__PURE__ */ jsx(Typography, { component: "h2", variant: "h6", children: "Manage labels" }),
|
|
599
|
-
/* @__PURE__ */ jsx(
|
|
600
|
-
Button,
|
|
601
|
-
{
|
|
602
|
-
color: "primary",
|
|
603
|
-
variant: "contained",
|
|
604
|
-
size: "small",
|
|
605
|
-
sx: { textTransform: "none" },
|
|
606
|
-
onClick: () => handleAdd(),
|
|
607
|
-
children: "New label"
|
|
608
|
-
}
|
|
609
|
-
)
|
|
610
|
-
] }),
|
|
611
|
-
/* @__PURE__ */ jsxs(Box, { sx: { mt: 2, border: 1, borderColor: "grey.300", borderRadius: 1, overflow: "hidden" }, children: [
|
|
612
|
-
/* @__PURE__ */ jsxs(Box, { sx: { p: 2, fontSize: 14, fontWeight: "bold", bgcolor: "grey.200" }, className: "label-header", children: [
|
|
613
|
-
flattened.length,
|
|
614
|
-
" labels"
|
|
615
|
-
] }),
|
|
616
|
-
/* @__PURE__ */ jsx(Box, { sx: { pt: 0.5 }, children: /* @__PURE__ */ jsx(StyledLabelTree, { data: treeData, selected: [], renderItem, rowHeight: 64 }) })
|
|
617
|
-
] }),
|
|
618
|
-
/* @__PURE__ */ jsx(
|
|
619
|
-
LabelFormDialog,
|
|
620
|
-
{
|
|
621
|
-
open: !!editingLabel,
|
|
622
|
-
onClose: () => setEditingLabel(null),
|
|
623
|
-
initialLabel: editingLabel,
|
|
624
|
-
onSubmit: handleSubmit
|
|
625
|
-
},
|
|
626
|
-
editingLabel == null ? void 0 : editingLabel.id
|
|
627
|
-
),
|
|
628
|
-
/* @__PURE__ */ jsx(
|
|
629
|
-
LabelDeleteDialog,
|
|
630
|
-
{
|
|
631
|
-
open: !!deletingLabel,
|
|
632
|
-
onClose: () => setDeletingLabel(null),
|
|
633
|
-
label: deletingLabel,
|
|
634
|
-
onSubmit: handleDelete
|
|
635
|
-
},
|
|
636
|
-
deletingLabel == null ? void 0 : deletingLabel.id
|
|
637
|
-
)
|
|
638
|
-
] });
|
|
639
|
-
}
|
|
640
343
|
class TreeNode {
|
|
641
344
|
constructor({ data, parent, children }) {
|
|
642
345
|
__publicField(this, "data");
|
|
@@ -653,6 +356,10 @@ class TreeNode {
|
|
|
653
356
|
this.children.push(...nodes);
|
|
654
357
|
nodes.forEach((node) => node.setParent(this));
|
|
655
358
|
}
|
|
359
|
+
removeChild(node) {
|
|
360
|
+
this.children = this.children.filter((x) => x !== node);
|
|
361
|
+
node.setParent(void 0);
|
|
362
|
+
}
|
|
656
363
|
isLeaf(node) {
|
|
657
364
|
var _a;
|
|
658
365
|
return !((_a = node.children) == null ? void 0 : _a.length);
|
|
@@ -686,6 +393,11 @@ class TreeNode {
|
|
|
686
393
|
}
|
|
687
394
|
return nodes;
|
|
688
395
|
}
|
|
396
|
+
clone() {
|
|
397
|
+
const cloned = new TreeNode({ data: this.data });
|
|
398
|
+
cloned.add(...this.children);
|
|
399
|
+
return cloned;
|
|
400
|
+
}
|
|
689
401
|
}
|
|
690
402
|
class Label {
|
|
691
403
|
constructor(data) {
|
|
@@ -697,7 +409,7 @@ class Label {
|
|
|
697
409
|
this.id = data.id;
|
|
698
410
|
this.name = data.name;
|
|
699
411
|
this.icon = data.icon;
|
|
700
|
-
this.color = data.color;
|
|
412
|
+
this.color = data.color || "#ddd";
|
|
701
413
|
this.translation = this._normalizeTranslation(data.translation);
|
|
702
414
|
}
|
|
703
415
|
_normalizeTranslation(translation) {
|
|
@@ -719,7 +431,22 @@ class Label {
|
|
|
719
431
|
}
|
|
720
432
|
}
|
|
721
433
|
class LabelTreeNode extends TreeNode {
|
|
434
|
+
getName(locale) {
|
|
435
|
+
return this.data.getName(locale);
|
|
436
|
+
}
|
|
437
|
+
isSystemLabel() {
|
|
438
|
+
return this.data.id.startsWith("system:");
|
|
439
|
+
}
|
|
440
|
+
getFullName(locale) {
|
|
441
|
+
const parents = this.getAllParents();
|
|
442
|
+
parents.shift();
|
|
443
|
+
if (locale) {
|
|
444
|
+
return parents.map((item) => item.getName(locale)).join(" / ");
|
|
445
|
+
}
|
|
446
|
+
return parents.map((item) => item.data.name).join(" / ");
|
|
447
|
+
}
|
|
722
448
|
}
|
|
449
|
+
__publicField(LabelTreeNode, "Label", Label);
|
|
723
450
|
const mapToTree = (items, parent) => {
|
|
724
451
|
return items.map((item) => {
|
|
725
452
|
const node = new LabelTreeNode({ data: new Label(item.data), parent });
|
|
@@ -730,13 +457,14 @@ const mapToTree = (items, parent) => {
|
|
|
730
457
|
};
|
|
731
458
|
const initLabelTree = (data) => {
|
|
732
459
|
const treeData = arrayToTree(data);
|
|
733
|
-
const root = new LabelTreeNode({ data: {}
|
|
460
|
+
const root = new LabelTreeNode({ data: {} });
|
|
461
|
+
root.add(...mapToTree(treeData));
|
|
734
462
|
return root;
|
|
735
463
|
};
|
|
736
464
|
const createEmptyLabelTree = () => {
|
|
737
465
|
return new LabelTreeNode({ data: {}, children: [] });
|
|
738
466
|
};
|
|
739
|
-
const useLabels = ({ loading, data }) => {
|
|
467
|
+
const useLabels = ({ loading, data, createLabel: createLabelAPI }) => {
|
|
740
468
|
const { locale } = useLocaleContext();
|
|
741
469
|
const state = useReactive({
|
|
742
470
|
loading: true,
|
|
@@ -769,16 +497,19 @@ const useLabels = ({ loading, data }) => {
|
|
|
769
497
|
() => state.stats.slice(0, 12).map((x) => nodesKeyById[x.id]),
|
|
770
498
|
[nodesKeyById, state.stats]
|
|
771
499
|
);
|
|
772
|
-
const getLabelsByIds = (
|
|
773
|
-
|
|
774
|
-
|
|
500
|
+
const getLabelsByIds = useCallback(
|
|
501
|
+
(ids) => {
|
|
502
|
+
return ids.map((id) => nodesKeyById[id]).filter(Boolean);
|
|
503
|
+
},
|
|
504
|
+
[nodesKeyById]
|
|
505
|
+
);
|
|
775
506
|
const getLabelName = (id) => {
|
|
776
507
|
var _a;
|
|
777
508
|
return (_a = nodesKeyById[id]) == null ? void 0 : _a.data.getName(locale);
|
|
778
509
|
};
|
|
779
510
|
const getRelatedLabels = (id) => {
|
|
780
511
|
const node = nodesKeyById[id];
|
|
781
|
-
if (!node) {
|
|
512
|
+
if (!node || node.parent === state.tree) {
|
|
782
513
|
return [];
|
|
783
514
|
}
|
|
784
515
|
const siblings = node.getAllSiblings();
|
|
@@ -787,9 +518,70 @@ const useLabels = ({ loading, data }) => {
|
|
|
787
518
|
const getRecommended = (id) => {
|
|
788
519
|
const related = getRelatedLabels(id);
|
|
789
520
|
const set = /* @__PURE__ */ new Set([...related.map((x) => x.data.id), id]);
|
|
790
|
-
return [...related, ...popularLabels.filter((x) => !set.has(x.data.id))];
|
|
521
|
+
return [...related, ...popularLabels.filter((x) => !set.has(x.data.id))].filter((x) => !!counts[x.data.id]);
|
|
522
|
+
};
|
|
523
|
+
const createLabel = async (name) => {
|
|
524
|
+
const saved = await createLabelAPI({ name });
|
|
525
|
+
const node = new LabelTreeNode({ data: new LabelTreeNode.Label(saved) });
|
|
526
|
+
state.tree.add(node);
|
|
527
|
+
state.tree = state.tree.clone();
|
|
528
|
+
return node.data;
|
|
529
|
+
};
|
|
530
|
+
const addLabelNode = (payload) => {
|
|
531
|
+
const parent = payload.parentId ? nodesKeyById[payload.parentId] : state.tree;
|
|
532
|
+
const node = new LabelTreeNode({ data: new LabelTreeNode.Label(payload) });
|
|
533
|
+
parent.add(node);
|
|
534
|
+
state.tree = state.tree.clone();
|
|
535
|
+
};
|
|
536
|
+
const updateLabelNode = (id, payload) => {
|
|
537
|
+
const existing = nodesKeyById[id];
|
|
538
|
+
if (existing && existing.parent) {
|
|
539
|
+
const node = new LabelTreeNode({ data: new LabelTreeNode.Label(payload) });
|
|
540
|
+
node.add(...existing.children);
|
|
541
|
+
if (existing.parent.data.id == payload.parentId) {
|
|
542
|
+
existing.parent.children = existing.parent.children.map((x) => {
|
|
543
|
+
if (x.data.id === id) {
|
|
544
|
+
node.setParent(existing.parent);
|
|
545
|
+
return node;
|
|
546
|
+
}
|
|
547
|
+
return x;
|
|
548
|
+
});
|
|
549
|
+
} else {
|
|
550
|
+
const parent = nodesKeyById[payload.parentId];
|
|
551
|
+
if (parent) {
|
|
552
|
+
existing.parent.children = existing.parent.children.filter((x) => x.data.id !== id);
|
|
553
|
+
parent.add(node);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
state.tree = state.tree.clone();
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
const removeLabelNode = (id) => {
|
|
560
|
+
const node = nodesKeyById[id];
|
|
561
|
+
if (node == null ? void 0 : node.parent) {
|
|
562
|
+
node.parent.removeChild(node);
|
|
563
|
+
state.tree = state.tree.clone();
|
|
564
|
+
}
|
|
565
|
+
};
|
|
566
|
+
const getFullLabelName = (id) => {
|
|
567
|
+
var _a;
|
|
568
|
+
return ((_a = nodesKeyById[id]) == null ? void 0 : _a.getFullName(locale)) ?? id;
|
|
569
|
+
};
|
|
570
|
+
return {
|
|
571
|
+
...state,
|
|
572
|
+
flattenedLabels: flattened,
|
|
573
|
+
popularLabels,
|
|
574
|
+
counts,
|
|
575
|
+
getLabelsByIds,
|
|
576
|
+
getLabelName,
|
|
577
|
+
getRelatedLabels,
|
|
578
|
+
getRecommended,
|
|
579
|
+
createLabel,
|
|
580
|
+
addLabelNode,
|
|
581
|
+
updateLabelNode,
|
|
582
|
+
removeLabelNode,
|
|
583
|
+
getFullLabelName
|
|
791
584
|
};
|
|
792
|
-
return { ...state, popularLabels, counts, getLabelsByIds, getLabelName, getRelatedLabels, getRecommended };
|
|
793
585
|
};
|
|
794
586
|
const LabelsContainer = createContainer(useLabels);
|
|
795
587
|
const LabelsContext = createContext({});
|
|
@@ -802,7 +594,7 @@ const useLabelsUpdateOnDestroy = () => {
|
|
|
802
594
|
};
|
|
803
595
|
}, []);
|
|
804
596
|
};
|
|
805
|
-
function LabelsProvider({ fetchLabels, children }) {
|
|
597
|
+
function LabelsProvider({ fetchLabels, createLabel, children }) {
|
|
806
598
|
const { locale } = useLocaleContext();
|
|
807
599
|
const [updateCounter, setUpdateCounter] = useState(1);
|
|
808
600
|
const { loading, data } = useRequest(fetchLabels, {
|
|
@@ -869,9 +661,9 @@ function LabelsProvider({ fetchLabels, children }) {
|
|
|
869
661
|
getFullLabelName
|
|
870
662
|
};
|
|
871
663
|
}, [loading, labels, getLabelsById, parseLabelIds, stringifyLabelIds, localizedLabels, getFullLabelName]);
|
|
872
|
-
return /* @__PURE__ */ jsx(LabelsContext.Provider, { value, children: /* @__PURE__ */ jsx(LabelsContainer.Provider, { initialState: { loading, data }, children }) });
|
|
664
|
+
return /* @__PURE__ */ jsx(LabelsContext.Provider, { value, children: /* @__PURE__ */ jsx(LabelsContainer.Provider, { initialState: { loading, data, createLabel }, children }) });
|
|
873
665
|
}
|
|
874
|
-
const getContrastTextColor = (bgcolor) => {
|
|
666
|
+
const getContrastTextColor$1 = (bgcolor) => {
|
|
875
667
|
try {
|
|
876
668
|
const ratio = getContrastRatio(bgcolor, "#fff");
|
|
877
669
|
return ratio > 3.5 ? "#fff" : "#111";
|
|
@@ -879,7 +671,7 @@ const getContrastTextColor = (bgcolor) => {
|
|
|
879
671
|
return "#111";
|
|
880
672
|
}
|
|
881
673
|
};
|
|
882
|
-
const getAlphaColor = (color, alpha$1) => {
|
|
674
|
+
const getAlphaColor$1 = (color, alpha$1) => {
|
|
883
675
|
try {
|
|
884
676
|
if (color) {
|
|
885
677
|
return alpha(color, alpha$1);
|
|
@@ -903,7 +695,7 @@ function Labels({ labels, editable, onChange, sx, renderLabel }) {
|
|
|
903
695
|
}, 300);
|
|
904
696
|
};
|
|
905
697
|
if (editing) {
|
|
906
|
-
return /* @__PURE__ */ jsx(ClickAwayListener
|
|
698
|
+
return /* @__PURE__ */ jsx(ClickAwayListener, { onClickAway: () => editing && setEditing(false), children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(LabelPicker, { data: allLabels, value: labels || [], onChange: handleOnChange }) }) });
|
|
907
699
|
}
|
|
908
700
|
const labelObjects = getLabelsById(labels || []).filter((x) => !x.id.startsWith("system:"));
|
|
909
701
|
const mergedSx = [
|
|
@@ -928,23 +720,542 @@ function Labels({ labels, editable, onChange, sx, renderLabel }) {
|
|
|
928
720
|
height: 20,
|
|
929
721
|
borderRadius: 1,
|
|
930
722
|
fontSize: 12,
|
|
931
|
-
bgcolor: getAlphaColor(item.color, 0.8),
|
|
932
|
-
color: getContrastTextColor(item.color)
|
|
723
|
+
bgcolor: getAlphaColor$1(item.color || "#ddd", 0.8),
|
|
724
|
+
color: getContrastTextColor$1(item.color || "#ddd")
|
|
933
725
|
}
|
|
934
726
|
},
|
|
935
727
|
item.id
|
|
936
728
|
);
|
|
937
729
|
}),
|
|
938
|
-
editable && !isEmpty && /* @__PURE__ */ jsx(IconButton
|
|
939
|
-
editable && isEmpty && /* @__PURE__ */ jsx(Button
|
|
730
|
+
editable && !isEmpty && /* @__PURE__ */ jsx(IconButton, { color: "inherit", size: "small", onClick: () => setEditing(true), sx: { color: "grey.400" }, children: /* @__PURE__ */ jsx(Edit, { sx: { fontSize: 20 } }) }),
|
|
731
|
+
editable && isEmpty && /* @__PURE__ */ jsx(Button, { color: "inherit", variant: "outlined", startIcon: /* @__PURE__ */ jsx(LabelOutlined, {}), onClick: () => setEditing(true), children: "Edit labels" })
|
|
940
732
|
] });
|
|
941
733
|
}
|
|
734
|
+
const mdiTagPlusOutline = (props) => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", width: "1.2em", height: "1.2em", ...props, children: /* @__PURE__ */ jsx("path", { fill: "currentColor", d: "M6.5 5A1.5 1.5 0 1 0 8 6.5A1.5 1.5 0 0 0 6.5 5m0 0A1.5 1.5 0 1 0 8 6.5A1.5 1.5 0 0 0 6.5 5m14.91 6.58l-9-9A2 2 0 0 0 11 2H4a2 2 0 0 0-2 2v7a2 2 0 0 0 .59 1.42l.41.4a5.62 5.62 0 0 1 2.08-.74L4 11V4h7l9 9l-7 7l-1.08-1.08a5.57 5.57 0 0 1-.74 2.08l.41.41A2 2 0 0 0 13 22a2 2 0 0 0 1.41-.59l7-7A2 2 0 0 0 22 13a2 2 0 0 0-.59-1.42M6.5 5A1.5 1.5 0 1 0 8 6.5A1.5 1.5 0 0 0 6.5 5M10 19H7v3H5v-3H2v-2h3v-3h2v3h3Z" }) });
|
|
735
|
+
function PopperComponent$1({
|
|
736
|
+
disablePortal,
|
|
737
|
+
anchorEl,
|
|
738
|
+
open,
|
|
739
|
+
...other
|
|
740
|
+
}) {
|
|
741
|
+
return /* @__PURE__ */ jsx(
|
|
742
|
+
Box$1,
|
|
743
|
+
{
|
|
744
|
+
...other,
|
|
745
|
+
sx: (theme) => ({
|
|
746
|
+
[`& .${autocompleteClasses.paper}`]: {
|
|
747
|
+
boxShadow: "none",
|
|
748
|
+
margin: 0,
|
|
749
|
+
color: "inherit",
|
|
750
|
+
fontSize: 13
|
|
751
|
+
},
|
|
752
|
+
[`& .${autocompleteClasses.listbox}`]: {
|
|
753
|
+
backgroundColor: theme.palette.mode === "light" ? "#fff" : "#1c2128",
|
|
754
|
+
padding: 0,
|
|
755
|
+
[`& .${autocompleteClasses.option}`]: {
|
|
756
|
+
minHeight: "auto",
|
|
757
|
+
alignItems: "flex-start",
|
|
758
|
+
padding: 1,
|
|
759
|
+
borderBottom: `1px solid ${theme.palette.mode === "light" ? " #eaecef" : "#30363d"}`,
|
|
760
|
+
'&[aria-selected="true"]': {
|
|
761
|
+
backgroundColor: "transparent"
|
|
762
|
+
},
|
|
763
|
+
[`&.${autocompleteClasses.focused}, &.${autocompleteClasses.focused}[aria-selected="true"]`]: {
|
|
764
|
+
backgroundColor: theme.palette.action.hover
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
},
|
|
768
|
+
[`&.${autocompleteClasses.popperDisablePortal}`]: {
|
|
769
|
+
position: "relative"
|
|
770
|
+
}
|
|
771
|
+
})
|
|
772
|
+
}
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
function GithubLabelPicker({
|
|
776
|
+
value = [],
|
|
777
|
+
onChange,
|
|
778
|
+
title,
|
|
779
|
+
noLabelsText,
|
|
780
|
+
buttonSx,
|
|
781
|
+
actions,
|
|
782
|
+
trigger,
|
|
783
|
+
multiple = true
|
|
784
|
+
}) {
|
|
785
|
+
const { locale } = useLocaleContext();
|
|
786
|
+
const { flattenedLabels: labels, getLabelsByIds, loading, createLabel } = LabelsContainer.useContainer();
|
|
787
|
+
const [anchorEl, setAnchorEl] = useState(null);
|
|
788
|
+
const [pendingValue, setPendingValue] = useState([]);
|
|
789
|
+
const pendingOptions = useMemo(() => getLabelsByIds(pendingValue), [getLabelsByIds, pendingValue]);
|
|
790
|
+
const [inputValue, setInputValue] = useState("");
|
|
791
|
+
const exists = useMemo(
|
|
792
|
+
() => labels.some((x) => x.data.getName(locale).toLowerCase() === inputValue.toLowerCase()),
|
|
793
|
+
[inputValue, labels, locale]
|
|
794
|
+
);
|
|
795
|
+
const theme = useTheme();
|
|
796
|
+
const handleClick = (event) => {
|
|
797
|
+
setPendingValue(value);
|
|
798
|
+
setAnchorEl(event.currentTarget);
|
|
799
|
+
};
|
|
800
|
+
const handleClose = () => {
|
|
801
|
+
onChange == null ? void 0 : onChange(pendingValue);
|
|
802
|
+
setInputValue("");
|
|
803
|
+
if (anchorEl) {
|
|
804
|
+
anchorEl.focus();
|
|
805
|
+
}
|
|
806
|
+
setAnchorEl(null);
|
|
807
|
+
};
|
|
808
|
+
const handleCreate = async () => {
|
|
809
|
+
const { id: id2 } = await createLabel(inputValue);
|
|
810
|
+
setPendingValue([...pendingValue, id2]);
|
|
811
|
+
};
|
|
812
|
+
const open = Boolean(anchorEl);
|
|
813
|
+
const id = open ? "github-label-picker" : void 0;
|
|
814
|
+
if (loading) {
|
|
815
|
+
return null;
|
|
816
|
+
}
|
|
817
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
818
|
+
/* @__PURE__ */ jsx(
|
|
819
|
+
Box$1,
|
|
820
|
+
{
|
|
821
|
+
onClick: handleClick,
|
|
822
|
+
sx: {
|
|
823
|
+
display: "flex",
|
|
824
|
+
alignItems: "center"
|
|
825
|
+
},
|
|
826
|
+
children: trigger || /* @__PURE__ */ jsx(
|
|
827
|
+
Box$1,
|
|
828
|
+
{
|
|
829
|
+
component: ButtonBase,
|
|
830
|
+
disableRipple: true,
|
|
831
|
+
"aria-describedby": id,
|
|
832
|
+
sx: [
|
|
833
|
+
(t) => ({
|
|
834
|
+
width: "100%",
|
|
835
|
+
fontSize: 13,
|
|
836
|
+
color: t.palette.mode === "light" ? "#586069" : "#8b949e",
|
|
837
|
+
fontWeight: 600,
|
|
838
|
+
"&:hover": {
|
|
839
|
+
color: t.palette.mode === "light" ? "primary.main" : "#58a6ff"
|
|
840
|
+
},
|
|
841
|
+
"& svg": {
|
|
842
|
+
width: 22,
|
|
843
|
+
height: 22
|
|
844
|
+
}
|
|
845
|
+
}),
|
|
846
|
+
...Array.isArray(buttonSx) ? buttonSx : [buttonSx]
|
|
847
|
+
],
|
|
848
|
+
children: /* @__PURE__ */ jsx(mdiTagPlusOutline, {})
|
|
849
|
+
}
|
|
850
|
+
)
|
|
851
|
+
}
|
|
852
|
+
),
|
|
853
|
+
/* @__PURE__ */ jsx(
|
|
854
|
+
Box$1,
|
|
855
|
+
{
|
|
856
|
+
component: Popper,
|
|
857
|
+
id,
|
|
858
|
+
open,
|
|
859
|
+
anchorEl,
|
|
860
|
+
placement: "bottom-start",
|
|
861
|
+
sx: (t) => ({
|
|
862
|
+
border: `1px solid ${t.palette.mode === "light" ? "#e1e4e8" : "#30363d"}`,
|
|
863
|
+
boxShadow: `0 8px 24px ${t.palette.mode === "light" ? "rgba(149, 157, 165, 0.2)" : "rgb(1, 4, 9)"}`,
|
|
864
|
+
borderRadius: "4px",
|
|
865
|
+
width: 300,
|
|
866
|
+
zIndex: t.zIndex.modal,
|
|
867
|
+
fontSize: 13,
|
|
868
|
+
color: t.palette.mode === "light" ? "#24292e" : "#c9d1d9",
|
|
869
|
+
backgroundColor: t.palette.mode === "light" ? "#fff" : "#1c2128"
|
|
870
|
+
}),
|
|
871
|
+
children: /* @__PURE__ */ jsx(ClickAwayListener, { onClickAway: handleClose, children: /* @__PURE__ */ jsxs(Box$1, { children: [
|
|
872
|
+
title && /* @__PURE__ */ jsx(
|
|
873
|
+
Box$1,
|
|
874
|
+
{
|
|
875
|
+
sx: {
|
|
876
|
+
borderBottom: `1px solid ${theme.palette.mode === "light" ? "#eaecef" : "#30363d"}`,
|
|
877
|
+
padding: "8px 10px",
|
|
878
|
+
fontWeight: 600
|
|
879
|
+
},
|
|
880
|
+
children: title
|
|
881
|
+
}
|
|
882
|
+
),
|
|
883
|
+
/* @__PURE__ */ jsx(
|
|
884
|
+
Autocomplete,
|
|
885
|
+
{
|
|
886
|
+
open: true,
|
|
887
|
+
multiple: true,
|
|
888
|
+
inputValue,
|
|
889
|
+
onInputChange: (event, newInputValue, reason) => {
|
|
890
|
+
if (reason === "reset") {
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
setInputValue(newInputValue);
|
|
894
|
+
},
|
|
895
|
+
onClose: (event, reason) => {
|
|
896
|
+
if (reason === "escape") {
|
|
897
|
+
handleClose();
|
|
898
|
+
}
|
|
899
|
+
},
|
|
900
|
+
value: pendingOptions,
|
|
901
|
+
onChange: (event, newValue, reason) => {
|
|
902
|
+
if (event.type === "keydown" && event.key === "Backspace" && reason === "removeOption") {
|
|
903
|
+
return;
|
|
904
|
+
}
|
|
905
|
+
setPendingValue(newValue.map((x) => x.data.id));
|
|
906
|
+
if (!multiple) {
|
|
907
|
+
onChange == null ? void 0 : onChange(newValue.length ? [newValue[newValue.length - 1].data.id] : []);
|
|
908
|
+
setAnchorEl(null);
|
|
909
|
+
}
|
|
910
|
+
},
|
|
911
|
+
disableCloseOnSelect: true,
|
|
912
|
+
PopperComponent: PopperComponent$1,
|
|
913
|
+
renderTags: () => null,
|
|
914
|
+
noOptionsText: noLabelsText || "No labels",
|
|
915
|
+
renderOption: (props, option, { selected }) => /* @__PURE__ */ jsxs("li", { ...props, children: [
|
|
916
|
+
/* @__PURE__ */ jsx(
|
|
917
|
+
Box$1,
|
|
918
|
+
{
|
|
919
|
+
component: DoneIcon,
|
|
920
|
+
sx: { width: 17, height: 17, mr: "5px", ml: "-2px" },
|
|
921
|
+
style: {
|
|
922
|
+
visibility: selected ? "visible" : "hidden"
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
),
|
|
926
|
+
/* @__PURE__ */ jsx(
|
|
927
|
+
Box$1,
|
|
928
|
+
{
|
|
929
|
+
component: "span",
|
|
930
|
+
sx: {
|
|
931
|
+
width: 14,
|
|
932
|
+
height: 14,
|
|
933
|
+
flexShrink: 0,
|
|
934
|
+
borderRadius: "3px",
|
|
935
|
+
mr: 1,
|
|
936
|
+
mt: "2px"
|
|
937
|
+
},
|
|
938
|
+
style: { backgroundColor: option.data.color || "#ddd" }
|
|
939
|
+
}
|
|
940
|
+
),
|
|
941
|
+
/* @__PURE__ */ jsx(
|
|
942
|
+
Box$1,
|
|
943
|
+
{
|
|
944
|
+
sx: {
|
|
945
|
+
flexGrow: 1,
|
|
946
|
+
"& span": {
|
|
947
|
+
color: theme.palette.mode === "light" ? "#586069" : "#8b949e"
|
|
948
|
+
}
|
|
949
|
+
},
|
|
950
|
+
children: option.data.getName(locale)
|
|
951
|
+
}
|
|
952
|
+
),
|
|
953
|
+
/* @__PURE__ */ jsx(
|
|
954
|
+
Box$1,
|
|
955
|
+
{
|
|
956
|
+
component: CloseIcon,
|
|
957
|
+
sx: { opacity: 0.6, width: 18, height: 18 },
|
|
958
|
+
style: {
|
|
959
|
+
visibility: selected ? "visible" : "hidden"
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
)
|
|
963
|
+
] }),
|
|
964
|
+
options: [...labels].sort((a, b) => {
|
|
965
|
+
let ai = value.indexOf(a.data.id);
|
|
966
|
+
ai = ai === -1 ? value.length + labels.indexOf(a) : ai;
|
|
967
|
+
let bi = value.indexOf(b.data.id);
|
|
968
|
+
bi = bi === -1 ? value.length + labels.indexOf(b) : bi;
|
|
969
|
+
return ai - bi;
|
|
970
|
+
}),
|
|
971
|
+
getOptionLabel: (option) => option.data.getName(locale),
|
|
972
|
+
renderInput: (params) => /* @__PURE__ */ jsx(
|
|
973
|
+
Box$1,
|
|
974
|
+
{
|
|
975
|
+
component: InputBase,
|
|
976
|
+
ref: params.InputProps.ref,
|
|
977
|
+
inputProps: params.inputProps,
|
|
978
|
+
autoFocus: true,
|
|
979
|
+
placeholder: "Filter labels",
|
|
980
|
+
sx: (t) => ({
|
|
981
|
+
padding: 1,
|
|
982
|
+
width: "100%",
|
|
983
|
+
borderBottom: `1px solid ${t.palette.mode === "light" ? "#eaecef" : "#30363d"}`,
|
|
984
|
+
"& input": {
|
|
985
|
+
borderRadius: "4px",
|
|
986
|
+
backgroundColor: t.palette.mode === "light" ? "#fff" : "#0d1117",
|
|
987
|
+
padding: 1,
|
|
988
|
+
transition: t.transitions.create(["border-color", "box-shadow"]),
|
|
989
|
+
border: `1px solid ${t.palette.mode === "light" ? "#eaecef" : "#30363d"}`,
|
|
990
|
+
fontSize: 14,
|
|
991
|
+
"&:focus": {
|
|
992
|
+
boxShadow: `0px 0px 0px 3px ${t.palette.mode === "light" ? alpha(t.palette.primary.light, 0.4) : "rgb(12, 45, 107)"}`,
|
|
993
|
+
borderColor: t.palette.mode === "light" ? t.palette.primary.light : "#388bfd"
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
})
|
|
997
|
+
}
|
|
998
|
+
)
|
|
999
|
+
}
|
|
1000
|
+
),
|
|
1001
|
+
/* @__PURE__ */ jsxs(Box$1, { children: [
|
|
1002
|
+
inputValue && !exists && /* @__PURE__ */ jsx(
|
|
1003
|
+
Box$1,
|
|
1004
|
+
{
|
|
1005
|
+
sx: {
|
|
1006
|
+
display: "flex",
|
|
1007
|
+
alignItems: "center",
|
|
1008
|
+
gap: 1,
|
|
1009
|
+
width: "100%",
|
|
1010
|
+
height: 36,
|
|
1011
|
+
px: 2,
|
|
1012
|
+
borderTop: "1px solid #eee",
|
|
1013
|
+
fontSize: 14,
|
|
1014
|
+
color: "grey.600",
|
|
1015
|
+
cursor: "pointer",
|
|
1016
|
+
textDecoration: "none"
|
|
1017
|
+
},
|
|
1018
|
+
onClick: handleCreate,
|
|
1019
|
+
children: /* @__PURE__ */ jsxs("span", { children: [
|
|
1020
|
+
'Create new label "',
|
|
1021
|
+
inputValue,
|
|
1022
|
+
'"'
|
|
1023
|
+
] })
|
|
1024
|
+
}
|
|
1025
|
+
),
|
|
1026
|
+
actions
|
|
1027
|
+
] })
|
|
1028
|
+
] }) })
|
|
1029
|
+
}
|
|
1030
|
+
)
|
|
1031
|
+
] });
|
|
1032
|
+
}
|
|
1033
|
+
function Tag(props) {
|
|
1034
|
+
const { label, onDelete, ...rest } = props;
|
|
1035
|
+
return /* @__PURE__ */ jsxs(
|
|
1036
|
+
Box$1,
|
|
1037
|
+
{
|
|
1038
|
+
...rest,
|
|
1039
|
+
sx: {
|
|
1040
|
+
boxSizing: "content-box",
|
|
1041
|
+
display: "flex",
|
|
1042
|
+
alignItems: "center",
|
|
1043
|
+
height: 24,
|
|
1044
|
+
margin: "2px",
|
|
1045
|
+
padding: "0 4px 0 10px",
|
|
1046
|
+
border: (theme) => `1px solid ${theme.palette.mode === "dark" ? "#303030" : "#e8e8e8"}`,
|
|
1047
|
+
overflow: "hidden",
|
|
1048
|
+
lineHeight: "22px",
|
|
1049
|
+
fontSize: 14,
|
|
1050
|
+
color: "grey.800",
|
|
1051
|
+
bgcolor: (theme) => theme.palette.mode === "dark" ? "rgba(255,255,255,0.08)" : "#fafafa",
|
|
1052
|
+
borderRadius: "2px",
|
|
1053
|
+
outline: 0,
|
|
1054
|
+
"&:focus": {
|
|
1055
|
+
borderColor: (theme) => `${theme.palette.mode === "dark" ? "#177ddc" : "#40a9ff"}`,
|
|
1056
|
+
bgcolor: (theme) => `${theme.palette.mode === "dark" ? "#003b57" : "#e6f7ff"}`
|
|
1057
|
+
},
|
|
1058
|
+
"& span": {
|
|
1059
|
+
overflow: "hidden",
|
|
1060
|
+
whiteSpace: "nowrap",
|
|
1061
|
+
textOverflow: "ellipsis"
|
|
1062
|
+
},
|
|
1063
|
+
"& svg": {
|
|
1064
|
+
ml: 0.5,
|
|
1065
|
+
p: "4px",
|
|
1066
|
+
fontSize: "12px",
|
|
1067
|
+
color: "grey.500",
|
|
1068
|
+
cursor: "pointer"
|
|
1069
|
+
}
|
|
1070
|
+
},
|
|
1071
|
+
children: [
|
|
1072
|
+
/* @__PURE__ */ jsx("span", { children: label }),
|
|
1073
|
+
/* @__PURE__ */ jsx(CloseIcon, { onClick: onDelete })
|
|
1074
|
+
]
|
|
1075
|
+
}
|
|
1076
|
+
);
|
|
1077
|
+
}
|
|
1078
|
+
function PopperComponent(props) {
|
|
1079
|
+
return /* @__PURE__ */ jsx(
|
|
1080
|
+
Popper,
|
|
1081
|
+
{
|
|
1082
|
+
...props,
|
|
1083
|
+
sx: (theme) => ({
|
|
1084
|
+
[`& .${autocompleteClasses.paper}`]: {
|
|
1085
|
+
border: `1px solid ${theme.palette.mode === "light" ? "#e1e4e8" : "#30363d"}`,
|
|
1086
|
+
boxShadow: `0 8px 24px ${theme.palette.mode === "light" ? "rgba(149, 157, 165, 0.2)" : "rgb(1, 4, 9)"}`,
|
|
1087
|
+
borderRadius: "4px",
|
|
1088
|
+
color: "inherit",
|
|
1089
|
+
fontSize: 13
|
|
1090
|
+
},
|
|
1091
|
+
[`& .${autocompleteClasses.listbox}`]: {
|
|
1092
|
+
backgroundColor: theme.palette.mode === "light" ? "#fff" : "#1c2128",
|
|
1093
|
+
padding: 0,
|
|
1094
|
+
[`& .${autocompleteClasses.option}`]: {
|
|
1095
|
+
minHeight: "auto",
|
|
1096
|
+
alignItems: "flex-start",
|
|
1097
|
+
padding: 1,
|
|
1098
|
+
borderBottom: `1px solid ${theme.palette.mode === "light" ? " #eaecef" : "#30363d"}`,
|
|
1099
|
+
'&[aria-selected="true"]': {
|
|
1100
|
+
backgroundColor: "transparent"
|
|
1101
|
+
},
|
|
1102
|
+
[`&.${autocompleteClasses.focused}, &.${autocompleteClasses.focused}[aria-selected="true"]`]: {
|
|
1103
|
+
backgroundColor: theme.palette.action.hover
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
},
|
|
1107
|
+
[`&.${autocompleteClasses.popperDisablePortal}`]: {
|
|
1108
|
+
position: "relative"
|
|
1109
|
+
}
|
|
1110
|
+
})
|
|
1111
|
+
}
|
|
1112
|
+
);
|
|
1113
|
+
}
|
|
1114
|
+
function LabelsInput({ value = [], onChange, ...rest }) {
|
|
1115
|
+
const { locale } = useLocaleContext();
|
|
1116
|
+
const { flattenedLabels: labels, getLabelsByIds, loading } = LabelsContainer.useContainer();
|
|
1117
|
+
const valueOptions = useMemo(() => getLabelsByIds(value), [getLabelsByIds, value]);
|
|
1118
|
+
if (loading) {
|
|
1119
|
+
return null;
|
|
1120
|
+
}
|
|
1121
|
+
return /* @__PURE__ */ jsx(
|
|
1122
|
+
Autocomplete,
|
|
1123
|
+
{
|
|
1124
|
+
multiple: true,
|
|
1125
|
+
disableClearable: true,
|
|
1126
|
+
forcePopupIcon: false,
|
|
1127
|
+
size: "small",
|
|
1128
|
+
PopperComponent,
|
|
1129
|
+
value: valueOptions,
|
|
1130
|
+
onChange: (event, newValue) => {
|
|
1131
|
+
onChange(newValue.map((x) => x.data.id));
|
|
1132
|
+
},
|
|
1133
|
+
options: [...labels].sort((a, b) => {
|
|
1134
|
+
let ai = value.indexOf(a.data.id);
|
|
1135
|
+
ai = ai === -1 ? value.length + labels.indexOf(a) : ai;
|
|
1136
|
+
let bi = value.indexOf(b.data.id);
|
|
1137
|
+
bi = bi === -1 ? value.length + labels.indexOf(b) : bi;
|
|
1138
|
+
return ai - bi;
|
|
1139
|
+
}),
|
|
1140
|
+
getOptionLabel: (option) => option.data.getName(locale),
|
|
1141
|
+
renderOption: (props, option, { selected }) => /* @__PURE__ */ jsxs("li", { ...props, children: [
|
|
1142
|
+
/* @__PURE__ */ jsx(
|
|
1143
|
+
Box$1,
|
|
1144
|
+
{
|
|
1145
|
+
component: DoneIcon,
|
|
1146
|
+
sx: { width: 17, height: 17, mr: "5px", ml: "-2px" },
|
|
1147
|
+
style: {
|
|
1148
|
+
visibility: selected ? "visible" : "hidden"
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
),
|
|
1152
|
+
/* @__PURE__ */ jsx(
|
|
1153
|
+
Box$1,
|
|
1154
|
+
{
|
|
1155
|
+
component: "span",
|
|
1156
|
+
sx: {
|
|
1157
|
+
width: 14,
|
|
1158
|
+
height: 14,
|
|
1159
|
+
flexShrink: 0,
|
|
1160
|
+
borderRadius: "3px",
|
|
1161
|
+
mr: 1,
|
|
1162
|
+
mt: "2px"
|
|
1163
|
+
},
|
|
1164
|
+
style: { backgroundColor: option.data.color || "#ddd" }
|
|
1165
|
+
}
|
|
1166
|
+
),
|
|
1167
|
+
/* @__PURE__ */ jsx(
|
|
1168
|
+
Box$1,
|
|
1169
|
+
{
|
|
1170
|
+
sx: {
|
|
1171
|
+
flexGrow: 1,
|
|
1172
|
+
"& span": {
|
|
1173
|
+
color: (theme) => theme.palette.mode === "light" ? "#586069" : "#8b949e"
|
|
1174
|
+
}
|
|
1175
|
+
},
|
|
1176
|
+
children: option.data.getName(locale)
|
|
1177
|
+
}
|
|
1178
|
+
),
|
|
1179
|
+
/* @__PURE__ */ jsx(
|
|
1180
|
+
Box$1,
|
|
1181
|
+
{
|
|
1182
|
+
component: CloseIcon,
|
|
1183
|
+
sx: { opacity: 0.6, width: 18, height: 18 },
|
|
1184
|
+
style: {
|
|
1185
|
+
visibility: selected ? "visible" : "hidden"
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
)
|
|
1189
|
+
] }),
|
|
1190
|
+
renderTags: (tagValue, getTagProps) => tagValue.map((option, index) => /* @__PURE__ */ jsx(Tag, { label: option.data.getName(locale), ...getTagProps({ index }) })),
|
|
1191
|
+
style: { minWidth: 300 },
|
|
1192
|
+
renderInput: (params) => /* @__PURE__ */ jsx(TextField, { ...params, placeholder: "Labels" }),
|
|
1193
|
+
...rest
|
|
1194
|
+
}
|
|
1195
|
+
);
|
|
1196
|
+
}
|
|
1197
|
+
const getContrastTextColor = (bgcolor) => {
|
|
1198
|
+
try {
|
|
1199
|
+
const ratio = getContrastRatio(bgcolor, "#fff");
|
|
1200
|
+
return ratio > 3.5 ? "#fff" : "#111";
|
|
1201
|
+
} catch {
|
|
1202
|
+
return "#111";
|
|
1203
|
+
}
|
|
1204
|
+
};
|
|
1205
|
+
const getAlphaColor = (color, alpha$1) => {
|
|
1206
|
+
try {
|
|
1207
|
+
if (color) {
|
|
1208
|
+
return alpha(color, alpha$1);
|
|
1209
|
+
}
|
|
1210
|
+
} catch {
|
|
1211
|
+
return color;
|
|
1212
|
+
}
|
|
1213
|
+
return color;
|
|
1214
|
+
};
|
|
1215
|
+
function Labels2({ labels, sx, renderLabel }) {
|
|
1216
|
+
const { getLabelsByIds, loading, getFullLabelName } = LabelsContainer.useContainer();
|
|
1217
|
+
if (loading) {
|
|
1218
|
+
return null;
|
|
1219
|
+
}
|
|
1220
|
+
const labelNodes = getLabelsByIds(labels || []).filter((x) => !x.data.id.startsWith("system:"));
|
|
1221
|
+
const mergedSx = [
|
|
1222
|
+
{ display: "flex", gap: 1, alignItems: "center", flexWrap: "wrap" },
|
|
1223
|
+
...Array.isArray(sx) ? sx : [sx]
|
|
1224
|
+
];
|
|
1225
|
+
return /* @__PURE__ */ jsx(Box$1, { sx: mergedSx, children: labelNodes.map((item) => {
|
|
1226
|
+
if (!item) {
|
|
1227
|
+
return null;
|
|
1228
|
+
}
|
|
1229
|
+
if (renderLabel) {
|
|
1230
|
+
return renderLabel(item);
|
|
1231
|
+
}
|
|
1232
|
+
return /* @__PURE__ */ jsx(
|
|
1233
|
+
Chip,
|
|
1234
|
+
{
|
|
1235
|
+
label: getFullLabelName(item.data.id),
|
|
1236
|
+
variant: "filled",
|
|
1237
|
+
size: "small",
|
|
1238
|
+
sx: {
|
|
1239
|
+
height: 20,
|
|
1240
|
+
borderRadius: 1,
|
|
1241
|
+
fontSize: 12,
|
|
1242
|
+
bgcolor: getAlphaColor(item.data.color, 0.8),
|
|
1243
|
+
color: getContrastTextColor(item.data.color)
|
|
1244
|
+
}
|
|
1245
|
+
},
|
|
1246
|
+
item.data.id
|
|
1247
|
+
);
|
|
1248
|
+
}) });
|
|
1249
|
+
}
|
|
942
1250
|
export {
|
|
943
|
-
|
|
1251
|
+
GithubLabelPicker,
|
|
944
1252
|
LabelPicker,
|
|
945
1253
|
LabelTree,
|
|
1254
|
+
LabelTreeNode,
|
|
946
1255
|
Labels,
|
|
1256
|
+
Labels2,
|
|
947
1257
|
LabelsContainer,
|
|
1258
|
+
LabelsInput,
|
|
948
1259
|
LabelsProvider,
|
|
949
1260
|
useLabelsContext,
|
|
950
1261
|
useLabelsUpdateOnDestroy
|