@evergis/react 4.0.149 → 4.0.150
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/Dashboard/containers/AttachmentContainer/components/ShowMoreButton.d.ts +3 -0
- package/dist/components/Dashboard/containers/AttachmentContainer/styled.d.ts +6 -0
- package/dist/components/Dashboard/containers/AttachmentContainer/useAttachmentContainer.d.ts +3 -9
- package/dist/components/Dashboard/containers/StructuredDataContainer/types.d.ts +4 -0
- package/dist/components/Dashboard/elements/ElementTable/components/AttachmentsCell.d.ts +4 -1
- package/dist/components/Dashboard/elements/ElementTable/components/AttachmentsCellPopup/index.d.ts +10 -0
- package/dist/components/Dashboard/elements/ElementTable/components/AttachmentsCellPopup/styled.d.ts +9 -0
- package/dist/components/Dashboard/elements/ElementTable/components/AttachmentsCellPopup.d.ts +10 -0
- package/dist/components/Dashboard/elements/ElementTable/constants.d.ts +12 -0
- package/dist/components/Dashboard/elements/ElementTable/hooks/useAttachmentsCell.d.ts +5 -20
- package/dist/components/Dashboard/elements/ElementTable/hooks/useAttachmentsCellEdit.d.ts +28 -0
- package/dist/components/Dashboard/elements/ElementTable/styled.d.ts +17 -1
- package/dist/components/Dashboard/elements/ElementTable/types.d.ts +44 -0
- package/dist/components/Dashboard/hooks/index.d.ts +1 -0
- package/dist/components/Dashboard/hooks/useAttachmentsView.d.ts +25 -0
- package/dist/components/Dashboard/types.d.ts +10 -0
- package/dist/components/Dashboard/utils/interpolateTranslation.d.ts +8 -0
- package/dist/components/Dashboard/utils/sliceShownOtherItems.d.ts +5 -0
- package/dist/index.js +347 -59
- package/dist/index.js.map +1 -1
- package/dist/react.esm.js +346 -60
- package/dist/react.esm.js.map +1 -1
- package/package.json +2 -2
- package/dist/components/Dashboard/grid/components/GridResizer/styled.d.ts +0 -11
package/dist/index.js
CHANGED
|
@@ -5596,12 +5596,22 @@ const ServerNotificationsProvider = ({ url, initialized, apiClient, children })
|
|
|
5596
5596
|
}, children: children }));
|
|
5597
5597
|
};
|
|
5598
5598
|
|
|
5599
|
+
const INTERPOLATION_PATTERN = /\{\{\s*(\w+)\s*\}\}/g;
|
|
5600
|
+
/**
|
|
5601
|
+
* Подставляет в строку перевода переменные вида `{{total}}` — так, как это делает i18next.
|
|
5602
|
+
*
|
|
5603
|
+
* Нужна запасному переводчику, когда хост не передал свой `t` (например, в Storybook): без неё
|
|
5604
|
+
* `defaultValue` с переменными уходит в интерфейс как есть. Переменная без значения остаётся
|
|
5605
|
+
* в тексте, чтобы пропуск был виден.
|
|
5606
|
+
*/
|
|
5607
|
+
const interpolateTranslation = (text, values = {}) => text.replace(INTERPOLATION_PATTERN, (match, name) => values[name] === undefined || values[name] === null ? match : String(values[name]));
|
|
5608
|
+
|
|
5599
5609
|
const useGlobalContext = () => {
|
|
5600
5610
|
const { t, language, themeName, api, ewktGeometry, ewktExtent, zoomLevel, projectName, projectAlias, notification } = React.useContext(GlobalContext) || {};
|
|
5601
5611
|
const translate = React.useCallback((value, options) => {
|
|
5602
5612
|
if (t)
|
|
5603
5613
|
return t(value, options);
|
|
5604
|
-
return options?.defaultValue ?? value;
|
|
5614
|
+
return interpolateTranslation(options?.defaultValue ?? value, options);
|
|
5605
5615
|
}, [t]);
|
|
5606
5616
|
return React.useMemo(() => ({
|
|
5607
5617
|
t: translate,
|
|
@@ -6027,6 +6037,30 @@ const useAttachmentPreviewImages = ({ items, active, }) => {
|
|
|
6027
6037
|
}), [items, blobUrls, failedLinks]);
|
|
6028
6038
|
};
|
|
6029
6039
|
|
|
6040
|
+
/**
|
|
6041
|
+
* Вид списка вложений: плитка или строки и сколько файлов из списка показано.
|
|
6042
|
+
*
|
|
6043
|
+
* Общий для контейнера вложений и колонки таблицы: список у них один и тот же, и считать
|
|
6044
|
+
* видимое дважды незачем. Предел приходит числом, а не опциями конфига, — у колонки опций
|
|
6045
|
+
* вида нет, он у неё зашит константой.
|
|
6046
|
+
*/
|
|
6047
|
+
const useAttachmentsView = ({ items, limit, initialViewMode = "grid", }) => {
|
|
6048
|
+
const [viewMode, setViewMode] = React.useState(initialViewMode);
|
|
6049
|
+
const [showMore, setShowMore] = React.useState(false);
|
|
6050
|
+
const visibleItems = React.useMemo(() => (limit && !showMore ? items.slice(0, limit) : items), [items, limit, showMore]);
|
|
6051
|
+
const hiddenCount = items.length - visibleItems.length;
|
|
6052
|
+
const handleSetViewMode = React.useCallback((mode) => setViewMode(mode), []);
|
|
6053
|
+
return {
|
|
6054
|
+
visibleItems,
|
|
6055
|
+
hiddenCount,
|
|
6056
|
+
hasMore: hiddenCount > 0,
|
|
6057
|
+
showMore,
|
|
6058
|
+
setShowMore,
|
|
6059
|
+
viewMode,
|
|
6060
|
+
setViewMode: handleSetViewMode,
|
|
6061
|
+
};
|
|
6062
|
+
};
|
|
6063
|
+
|
|
6030
6064
|
const useAutoCompleteControl = (items) => {
|
|
6031
6065
|
const [value, setValue] = React.useState("");
|
|
6032
6066
|
const [options, setOptions] = React.useState([]);
|
|
@@ -8567,9 +8601,23 @@ const AttachmentsViewControls = styled.div.withConfig({ displayName: "Attachment
|
|
|
8567
8601
|
font-size: 1rem;
|
|
8568
8602
|
}
|
|
8569
8603
|
`;
|
|
8604
|
+
/**
|
|
8605
|
+
* Счётчик файлов у подписи — плоский чип в строку подписи.
|
|
8606
|
+
*
|
|
8607
|
+
* Шрифт ставится на текст чипа, а не на корень: текст задаёт себе шрифт шорткатом `font` из темы,
|
|
8608
|
+
* и размер с корня до цифры не доходит — чип выходил высоким, во весь шрифт описания.
|
|
8609
|
+
*/
|
|
8570
8610
|
const AttachmentsCountChip = styled(uilibGl.Chip).withConfig({ displayName: "AttachmentsCountChip", componentId: "sc-117ib6u" }) `
|
|
8571
|
-
|
|
8572
|
-
|
|
8611
|
+
&& {
|
|
8612
|
+
padding: 0.0625rem 0.25rem;
|
|
8613
|
+
border-radius: 0.75rem;
|
|
8614
|
+
}
|
|
8615
|
+
|
|
8616
|
+
span {
|
|
8617
|
+
font-size: 0.625rem;
|
|
8618
|
+
line-height: 0.75rem;
|
|
8619
|
+
font-weight: bold;
|
|
8620
|
+
}
|
|
8573
8621
|
`;
|
|
8574
8622
|
const AttachmentsContent = styled.div.withConfig({ displayName: "AttachmentsContent", componentId: "sc-1j2thff" }) `
|
|
8575
8623
|
width: 100%;
|
|
@@ -8852,38 +8900,30 @@ const AttachmentsList = ({ items, isEdit, onPreview, onDelete, }) => {
|
|
|
8852
8900
|
return (jsxRuntime.jsx(ListContainer, { children: items.map(item => (jsxRuntime.jsx(AttachmentItem, { item: item, viewMode: "list", isEdit: isEdit, onPreview: onPreview, onDelete: onDelete }, item.link))) }));
|
|
8853
8901
|
};
|
|
8854
8902
|
|
|
8855
|
-
const ShowMoreButton = ({ hiddenCount, onClick, }) => {
|
|
8903
|
+
const ShowMoreButton = ({ hiddenCount, iconKind = "arrow_down", onClick, }) => {
|
|
8856
8904
|
const { t } = useGlobalContext();
|
|
8857
|
-
return (jsxRuntime.jsxs(ShowMoreButton$1, { onClick: onClick, children: [t("showMore", { ns: "dashboard", defaultValue: "Показать ещё" }), " ", hiddenCount, jsxRuntime.jsx(uilibGl.Icon, { kind:
|
|
8905
|
+
return (jsxRuntime.jsxs(ShowMoreButton$1, { onClick: onClick, children: [t("showMore", { ns: "dashboard", defaultValue: "Показать ещё" }), " ", hiddenCount, jsxRuntime.jsx(uilibGl.Icon, { kind: iconKind })] }));
|
|
8858
8906
|
};
|
|
8859
8907
|
|
|
8908
|
+
/**
|
|
8909
|
+
* Сколько элементов показывать сразу. Заданы обе опции — выигрывает меньшая, не задана ни одна —
|
|
8910
|
+
* предела нет и список показывается целиком.
|
|
8911
|
+
*/
|
|
8912
|
+
const getShownItemsLimit = ({ shownItems, otherItems } = {}) => shownItems && otherItems ? Math.min(shownItems, otherItems) : shownItems || otherItems;
|
|
8860
8913
|
const sliceShownOtherItems = (data, options = {}, showMore) => {
|
|
8861
|
-
const
|
|
8862
|
-
|
|
8863
|
-
return (shownItems || otherItems) && !showMore ? (data?.slice(0, limit) || []) : data;
|
|
8914
|
+
const limit = getShownItemsLimit(options);
|
|
8915
|
+
return limit && !showMore ? (data?.slice(0, limit) || []) : data;
|
|
8864
8916
|
};
|
|
8865
8917
|
|
|
8866
8918
|
const useAttachmentContainer = ({ type, elementConfig, valueOverride, }) => {
|
|
8867
8919
|
const { items, attributeName } = useAttachmentItems({ type, elementConfig, valueOverride });
|
|
8868
8920
|
const { options } = elementConfig || {};
|
|
8869
|
-
const
|
|
8870
|
-
const [viewMode, setViewMode] = React.useState(initialViewMode);
|
|
8871
|
-
const [showMore, setShowMore] = React.useState(false);
|
|
8872
|
-
const visibleItems = React.useMemo(() => sliceShownOtherItems(items, options, showMore), [items, options, showMore]);
|
|
8873
|
-
const hiddenCount = items.length - visibleItems.length;
|
|
8874
|
-
const hasMore = hiddenCount > 0;
|
|
8875
|
-
const handleSetViewMode = React.useCallback((mode) => setViewMode(mode), []);
|
|
8876
|
-
return {
|
|
8921
|
+
const view = useAttachmentsView({
|
|
8877
8922
|
items,
|
|
8878
|
-
|
|
8879
|
-
|
|
8880
|
-
|
|
8881
|
-
|
|
8882
|
-
setShowMore,
|
|
8883
|
-
viewMode,
|
|
8884
|
-
setViewMode: handleSetViewMode,
|
|
8885
|
-
attributeName,
|
|
8886
|
-
};
|
|
8923
|
+
limit: getShownItemsLimit(options),
|
|
8924
|
+
initialViewMode: options?.viewMode === "list" ? "list" : "grid",
|
|
8925
|
+
});
|
|
8926
|
+
return { ...view, items, attributeName };
|
|
8887
8927
|
};
|
|
8888
8928
|
|
|
8889
8929
|
const AttachmentContainer = React.memo(({ type, elementConfig, renderElement }) => {
|
|
@@ -11488,6 +11528,9 @@ const toSchemaAttribute = (params) => {
|
|
|
11488
11528
|
multiline: description?.multiline,
|
|
11489
11529
|
colorPicker: description?.colorPicker,
|
|
11490
11530
|
style: description?.style,
|
|
11531
|
+
// Настройки загрузки файлов в колонку вложений: у источника их тоже нет.
|
|
11532
|
+
parentResourceId: description?.parentResourceId,
|
|
11533
|
+
fileExtensions: description?.fileExtensions,
|
|
11491
11534
|
};
|
|
11492
11535
|
};
|
|
11493
11536
|
/**
|
|
@@ -13778,6 +13821,8 @@ const AddButton = ({ multiple = true, accept, onSelectFiles, onSelectFromCatalog
|
|
|
13778
13821
|
value: AddAttachmentSource.Catalog,
|
|
13779
13822
|
icon: "folder_outline",
|
|
13780
13823
|
text: t("attachments.fromCatalog", { ns: "common", defaultValue: "Из каталога" }),
|
|
13824
|
+
// Диалог каталога выдаёт виджету приложение: не выдан — и выбирать нечем.
|
|
13825
|
+
disabled: !onSelectFromCatalog,
|
|
13781
13826
|
},
|
|
13782
13827
|
{
|
|
13783
13828
|
value: AddAttachmentSource.Link,
|
|
@@ -13785,7 +13830,7 @@ const AddButton = ({ multiple = true, accept, onSelectFiles, onSelectFromCatalog
|
|
|
13785
13830
|
text: t("attachments.fromLink", { ns: "common", defaultValue: "По ссылке" }),
|
|
13786
13831
|
disabled: !onSelectFromLink,
|
|
13787
13832
|
},
|
|
13788
|
-
], [t, onSelectFromLink]);
|
|
13833
|
+
], [t, onSelectFromCatalog, onSelectFromLink]);
|
|
13789
13834
|
const handleMenuSelect = React.useCallback(([{ value }]) => {
|
|
13790
13835
|
if (value === AddAttachmentSource.Pc) {
|
|
13791
13836
|
inputRef.current?.click();
|
|
@@ -15500,6 +15545,92 @@ const ElementSvg = React.memo(({ type, elementConfig, ...rest }) => {
|
|
|
15500
15545
|
return (jsxRuntime.jsx(SvgImage, { url: getSvgUrl({ elementConfig, layerInfo, attributes }), width: width, height: height, fontColor: fontColor }));
|
|
15501
15546
|
});
|
|
15502
15547
|
|
|
15548
|
+
/**
|
|
15549
|
+
* Вложения ячейки в поп-апе. Ширина своя, а не по ячейке: колонка таблицы бывает узкой,
|
|
15550
|
+
* а внутри стоит полный список вложений с плиткой и кнопкой добавления.
|
|
15551
|
+
*
|
|
15552
|
+
* Список взят у контейнера вложений карточки, а величины у поп-апа свои, с макета: имя файла
|
|
15553
|
+
* крупнее и ссылочного цвета, значок в строку имени, «Показать ещё» серое. Переопределены они
|
|
15554
|
+
* здесь, а не в самих компонентах, чтобы вложения в карточке объекта остались как были.
|
|
15555
|
+
*/
|
|
15556
|
+
const AttachmentsPopupBox = styled.div.withConfig({ displayName: "AttachmentsPopupBox", componentId: "sc-1dv1wz6" }) `
|
|
15557
|
+
display: flex;
|
|
15558
|
+
flex-direction: column;
|
|
15559
|
+
box-sizing: border-box;
|
|
15560
|
+
width: 19.5rem;
|
|
15561
|
+
padding: 1.25rem;
|
|
15562
|
+
|
|
15563
|
+
${AttachmentsLabel} {
|
|
15564
|
+
gap: 0 0.25rem;
|
|
15565
|
+
line-height: 0.875rem;
|
|
15566
|
+
}
|
|
15567
|
+
|
|
15568
|
+
${AttachmentsViewControls} {
|
|
15569
|
+
gap: 0 0.5rem;
|
|
15570
|
+
|
|
15571
|
+
${uilibGl.IconToggleButton}, ${uilibGl.Icon} {
|
|
15572
|
+
width: 0.875rem;
|
|
15573
|
+
height: 0.875rem;
|
|
15574
|
+
}
|
|
15575
|
+
|
|
15576
|
+
${uilibGl.Icon}:after {
|
|
15577
|
+
font-size: 0.875rem;
|
|
15578
|
+
}
|
|
15579
|
+
}
|
|
15580
|
+
|
|
15581
|
+
${ListItemMeta} {
|
|
15582
|
+
${ListIcon}, ${ImagePreviewContainer}, ${GridImagePreview} {
|
|
15583
|
+
width: 1rem;
|
|
15584
|
+
height: 1rem;
|
|
15585
|
+
background-size: contain;
|
|
15586
|
+
}
|
|
15587
|
+
}
|
|
15588
|
+
|
|
15589
|
+
${ListItemDescription} {
|
|
15590
|
+
gap: 0;
|
|
15591
|
+
}
|
|
15592
|
+
|
|
15593
|
+
${ListItemName} {
|
|
15594
|
+
font-size: 1rem;
|
|
15595
|
+
line-height: 1.125rem;
|
|
15596
|
+
color: ${({ theme }) => theme.palette.primary};
|
|
15597
|
+
}
|
|
15598
|
+
|
|
15599
|
+
${ListItemDate} {
|
|
15600
|
+
font-size: 0.75rem;
|
|
15601
|
+
line-height: 0.875rem;
|
|
15602
|
+
}
|
|
15603
|
+
|
|
15604
|
+
${ShowMoreButton$1} {
|
|
15605
|
+
gap: 0 0.25rem;
|
|
15606
|
+
margin-top: 0.5rem;
|
|
15607
|
+
line-height: 0.875rem;
|
|
15608
|
+
color: ${({ theme }) => theme.palette.textSecondary};
|
|
15609
|
+
|
|
15610
|
+
${uilibGl.Icon} {
|
|
15611
|
+
width: 0.875rem;
|
|
15612
|
+
height: 0.875rem;
|
|
15613
|
+
}
|
|
15614
|
+
|
|
15615
|
+
${uilibGl.Icon}:after {
|
|
15616
|
+
font-size: 0.875rem;
|
|
15617
|
+
color: ${({ theme }) => theme.palette.textSecondary};
|
|
15618
|
+
}
|
|
15619
|
+
}
|
|
15620
|
+
`;
|
|
15621
|
+
|
|
15622
|
+
/**
|
|
15623
|
+
* Полный список вложений колонки — тот же набор, что у контейнера вложений в карточке объекта:
|
|
15624
|
+
* шапка с подписью, счётчиком и переключателем вида, сам список, «Показать ещё» и добавление.
|
|
15625
|
+
*
|
|
15626
|
+
* Кнопка добавления и корзины у файлов появляются только на правку: на чтение поп-ап нужен
|
|
15627
|
+
* ровно затем, чтобы развернуть свёрнутый счётчик.
|
|
15628
|
+
*/
|
|
15629
|
+
const AttachmentsCellPopup = React.memo(({ alias, state }) => {
|
|
15630
|
+
const { items, visibleItems, editable, viewMode, setViewMode, hasMore, hiddenCount, onShowMore, accept, onPreview, onDelete, onUpload, onSelectFromCatalog, onOpenLinkDialog, } = state;
|
|
15631
|
+
return (jsxRuntime.jsxs(AttachmentsPopupBox, { children: [jsxRuntime.jsx(AttachmentsHeader, { alias: alias, count: items.length, viewMode: viewMode, onChangeViewMode: setViewMode }), jsxRuntime.jsx(AttachmentsContent, { children: viewMode === "grid" ? (jsxRuntime.jsx(AttachmentsGrid, { items: visibleItems, isEdit: editable, onPreview: onPreview, onDelete: onDelete })) : (jsxRuntime.jsx(AttachmentsList, { items: visibleItems, isEdit: editable, onPreview: onPreview, onDelete: onDelete })) }), hasMore && jsxRuntime.jsx(ShowMoreButton, { hiddenCount: hiddenCount, iconKind: "expand", onClick: onShowMore }), editable && (jsxRuntime.jsx(AddButton, { accept: accept, onSelectFiles: onUpload, onSelectFromCatalog: onSelectFromCatalog, onSelectFromLink: onOpenLinkDialog }))] }));
|
|
15632
|
+
});
|
|
15633
|
+
|
|
15503
15634
|
/**
|
|
15504
15635
|
* Насколько тело таблицы заехало под липкую шапку. Пишется на таблицу при прокрутке, читается
|
|
15505
15636
|
* стилем тела: ровно на эту величину тело и отсекается.
|
|
@@ -15525,6 +15656,18 @@ const MIN_COLUMN_WIDTH = 48;
|
|
|
15525
15656
|
* без валидной строки не собрать.
|
|
15526
15657
|
*/
|
|
15527
15658
|
const DEFAULT_CELL_COLOR = "#000000";
|
|
15659
|
+
/**
|
|
15660
|
+
* Сколько вложений ячейка показывает сама. Больше — все схлопываются в одну строку со значком
|
|
15661
|
+
* ссылки и счётчиком: колонка в таблице узкая, и списком там помещается ровно один файл.
|
|
15662
|
+
*/
|
|
15663
|
+
const ATTACHMENTS_INLINE_LIMIT = 1;
|
|
15664
|
+
/**
|
|
15665
|
+
* Сколько файлов видно в поп-апе вложений сразу, остальные прячутся за «Показать ещё N».
|
|
15666
|
+
* Величина с макета и опцией не выносится: поп-ап у колонки один на все таблицы.
|
|
15667
|
+
*/
|
|
15668
|
+
const ATTACHMENTS_SHOWN_ITEMS = 3;
|
|
15669
|
+
/** Вид списка, с которого поп-ап вложений открывается. */
|
|
15670
|
+
const ATTACHMENTS_VIEW_MODE = "list";
|
|
15528
15671
|
|
|
15529
15672
|
/**
|
|
15530
15673
|
* Собственный бокс таблицы. Без размеров в `options` представления узел ничего не меняет:
|
|
@@ -15751,10 +15894,42 @@ const CellField = styled.div.withConfig({ displayName: "CellField", componentId:
|
|
|
15751
15894
|
*/
|
|
15752
15895
|
const AttachmentsCellBox = styled.div.withConfig({ displayName: "AttachmentsCellBox", componentId: "sc-1ayq7sq" }) `
|
|
15753
15896
|
display: flex;
|
|
15754
|
-
|
|
15755
|
-
|
|
15756
|
-
gap: 0.25rem;
|
|
15897
|
+
align-items: center;
|
|
15898
|
+
gap: 0.375rem;
|
|
15757
15899
|
padding: 0.375rem 0.25rem;
|
|
15900
|
+
min-width: 0;
|
|
15901
|
+
line-height: 1.25rem;
|
|
15902
|
+
/* Пустая ячейка на чтении не делает по клику ничего — и на указатель ей меняться незачем. */
|
|
15903
|
+
cursor: ${({ $interactive }) => ($interactive ? "pointer" : "default")};
|
|
15904
|
+
`;
|
|
15905
|
+
/**
|
|
15906
|
+
* Значок файла в ячейке. Тот же, что в списке вложений, только с макетную величину строки
|
|
15907
|
+
* таблицы: в контейнере строка свободнее и значок там крупнее.
|
|
15908
|
+
*/
|
|
15909
|
+
const AttachmentsCellIcon = styled(ListIcon).withConfig({ displayName: "AttachmentsCellIcon", componentId: "sc-wf195o" }) `
|
|
15910
|
+
width: 1rem;
|
|
15911
|
+
height: 1rem;
|
|
15912
|
+
background-size: contain;
|
|
15913
|
+
`;
|
|
15914
|
+
/**
|
|
15915
|
+
* Подпись файла или счётчика свёрнутых. Ссылочная: по ней и кликают — одиночный файл открывает
|
|
15916
|
+
* галерею, счётчик разворачивает список.
|
|
15917
|
+
*/
|
|
15918
|
+
const AttachmentsCellLabel = styled.div.withConfig({ displayName: "AttachmentsCellLabel", componentId: "sc-11wbjsl" }) `
|
|
15919
|
+
color: ${({ theme }) => theme.palette.primary};
|
|
15920
|
+
|
|
15921
|
+
${cellWrapMixin};
|
|
15922
|
+
`;
|
|
15923
|
+
/** Значок ссылки у счётчика свёрнутых файлов — в цвет подписи. */
|
|
15924
|
+
const AttachmentsCellLinkIcon = styled(uilibGl.Icon).withConfig({ displayName: "AttachmentsCellLinkIcon", componentId: "sc-oxcx2o" }) `
|
|
15925
|
+
flex-shrink: 0;
|
|
15926
|
+
width: 1rem;
|
|
15927
|
+
height: 1rem;
|
|
15928
|
+
|
|
15929
|
+
&:after {
|
|
15930
|
+
font-size: 1rem;
|
|
15931
|
+
color: ${({ theme }) => theme.palette.primary};
|
|
15932
|
+
}
|
|
15758
15933
|
`;
|
|
15759
15934
|
/**
|
|
15760
15935
|
* Ячейка цвета: плашка или палитра слева, значение справа.
|
|
@@ -15762,7 +15937,7 @@ const AttachmentsCellBox = styled.div.withConfig({ displayName: "AttachmentsCell
|
|
|
15762
15937
|
* Отступы те же, что у текстовой ячейки: в одном ряду с обычными колонками значения обязаны
|
|
15763
15938
|
* стоять на одной линии.
|
|
15764
15939
|
*/
|
|
15765
|
-
const ColorCellBox = styled.div.withConfig({ displayName: "ColorCellBox", componentId: "sc-
|
|
15940
|
+
const ColorCellBox = styled.div.withConfig({ displayName: "ColorCellBox", componentId: "sc-1x8c5gd" }) `
|
|
15766
15941
|
display: flex;
|
|
15767
15942
|
align-items: center;
|
|
15768
15943
|
gap: 0.375rem;
|
|
@@ -15777,38 +15952,119 @@ const ColorCellBox = styled.div.withConfig({ displayName: "ColorCellBox", compon
|
|
|
15777
15952
|
* Плашка цвета. Повторяет маркер легенды графика: цвет всюду обозначается одинаково, где бы он
|
|
15778
15953
|
* ни показывался.
|
|
15779
15954
|
*/
|
|
15780
|
-
const ColorSwatch = styled.div.withConfig({ displayName: "ColorSwatch", componentId: "sc-
|
|
15955
|
+
const ColorSwatch = styled.div.withConfig({ displayName: "ColorSwatch", componentId: "sc-1h7m0yr" }) `
|
|
15781
15956
|
flex-shrink: 0;
|
|
15782
15957
|
width: 0.75rem;
|
|
15783
15958
|
height: 0.75rem;
|
|
15784
15959
|
background-color: ${({ $color }) => $color};
|
|
15785
15960
|
border-radius: ${({ theme: { borderRadius } }) => borderRadius.tiny};
|
|
15786
15961
|
`;
|
|
15787
|
-
const TableEmpty = styled.div.withConfig({ displayName: "TableEmpty", componentId: "sc-
|
|
15962
|
+
const TableEmpty = styled.div.withConfig({ displayName: "TableEmpty", componentId: "sc-10hkdmv" }) `
|
|
15788
15963
|
padding: 0.75rem 0.25rem;
|
|
15789
15964
|
color: ${({ theme }) => theme.palette.textSecondary};
|
|
15790
15965
|
`;
|
|
15791
15966
|
|
|
15792
15967
|
/**
|
|
15793
|
-
*
|
|
15968
|
+
* Добавление и удаление файлов в колонке вложений.
|
|
15969
|
+
*
|
|
15970
|
+
* Все три источника — диск, каталог ресурсов и ссылка — те же, что у контейнера вложений
|
|
15971
|
+
* в карточке объекта: файловое api берётся из глобального контекста, диалог каталога выдаёт
|
|
15972
|
+
* виджету приложение, а ссылка разбирается по адресу.
|
|
15973
|
+
*
|
|
15974
|
+
* Папку-приёмник загрузки задаёт сам атрибут: у колонки нет узла-элемента с опциями, зато
|
|
15975
|
+
* колонок вложений в таблице может быть несколько, и складывать их файлы в одно место незачем.
|
|
15976
|
+
*/
|
|
15977
|
+
const useAttachmentsCellEdit = ({ attribute, items, persist }) => {
|
|
15978
|
+
const { api } = useGlobalContext();
|
|
15979
|
+
const { selectAttachmentsFromCatalog } = useWidgetContext();
|
|
15980
|
+
const [isLinkDialogOpen, , setLinkDialogOpen] = useToggle(false);
|
|
15981
|
+
const [uploading, setUploading] = React.useState(false);
|
|
15982
|
+
const { parentResourceId, fileExtensions } = attribute;
|
|
15983
|
+
const onDelete = React.useCallback((link) => persist(items.filter(item => item.link !== link)), [items, persist]);
|
|
15984
|
+
const onUpload = React.useCallback(async (files) => {
|
|
15985
|
+
if (!api?.file?.upload || uploading) {
|
|
15986
|
+
return;
|
|
15987
|
+
}
|
|
15988
|
+
setUploading(true);
|
|
15989
|
+
try {
|
|
15990
|
+
const uploaded = await Promise.all(files.map(file => api.file.upload(file, true, parentResourceId || "", file.name)));
|
|
15991
|
+
persist([
|
|
15992
|
+
...items,
|
|
15993
|
+
...uploaded.map((response, index) => ({
|
|
15994
|
+
link: response.resourceId,
|
|
15995
|
+
name: response.name ?? files[index].name,
|
|
15996
|
+
mimeType: files[index].type,
|
|
15997
|
+
date: new Date().toISOString(),
|
|
15998
|
+
isExternal: false,
|
|
15999
|
+
})),
|
|
16000
|
+
]);
|
|
16001
|
+
}
|
|
16002
|
+
finally {
|
|
16003
|
+
setUploading(false);
|
|
16004
|
+
}
|
|
16005
|
+
}, [api, items, parentResourceId, persist, uploading]);
|
|
16006
|
+
const onAddFromCatalog = React.useCallback((resources) => persist([
|
|
16007
|
+
...items,
|
|
16008
|
+
...resources.map(({ resourceId, name, contentType }) => ({
|
|
16009
|
+
link: resourceId ?? "",
|
|
16010
|
+
name: name ?? "",
|
|
16011
|
+
mimeType: contentType ?? "",
|
|
16012
|
+
date: new Date().toISOString(),
|
|
16013
|
+
isExternal: false,
|
|
16014
|
+
})),
|
|
16015
|
+
]), [items, persist]);
|
|
16016
|
+
const onSelectFromCatalog = React.useMemo(() => (selectAttachmentsFromCatalog ? () => selectAttachmentsFromCatalog(onAddFromCatalog) : undefined), [onAddFromCatalog, selectAttachmentsFromCatalog]);
|
|
16017
|
+
const onOpenLinkDialog = React.useCallback(() => setLinkDialogOpen(true), [setLinkDialogOpen]);
|
|
16018
|
+
const onCloseLinkDialog = React.useCallback(() => setLinkDialogOpen(false), [setLinkDialogOpen]);
|
|
16019
|
+
const onAddByLink = React.useCallback((url) => persist([
|
|
16020
|
+
...items,
|
|
16021
|
+
{
|
|
16022
|
+
link: url,
|
|
16023
|
+
name: getFileNameFromUrl(url),
|
|
16024
|
+
mimeType: getMimeTypeFromUrl(url),
|
|
16025
|
+
date: new Date().toISOString(),
|
|
16026
|
+
isExternal: true,
|
|
16027
|
+
},
|
|
16028
|
+
]), [items, persist]);
|
|
16029
|
+
return {
|
|
16030
|
+
accept: fileExtensions,
|
|
16031
|
+
isLinkDialogOpen,
|
|
16032
|
+
onDelete,
|
|
16033
|
+
onUpload,
|
|
16034
|
+
onSelectFromCatalog,
|
|
16035
|
+
onOpenLinkDialog,
|
|
16036
|
+
onCloseLinkDialog,
|
|
16037
|
+
onAddByLink,
|
|
16038
|
+
};
|
|
16039
|
+
};
|
|
16040
|
+
|
|
16041
|
+
/**
|
|
16042
|
+
* Колонка вложений: разбор значения, свёрнутый вид ячейки и полный список в поп-апе.
|
|
15794
16043
|
*
|
|
15795
16044
|
* Значение атрибута — строка: файлы приезжают в ней списком JSON, поэтому и обратно в черновик
|
|
15796
16045
|
* кладём строку, а не массив — иначе тип ячейки менялся бы от самой правки.
|
|
15797
16046
|
*
|
|
15798
|
-
*
|
|
15799
|
-
*
|
|
16047
|
+
* Ячейка показывает один файл, а несколько схлопывает в счётчик, и весь список с добавлением
|
|
16048
|
+
* и удалением живёт в поп-апе — тот же набор, что у контейнера вложений в карточке объекта.
|
|
15800
16049
|
*/
|
|
15801
|
-
const useAttachmentsCell = ({ attribute, row, canEdit, onChange }) => {
|
|
16050
|
+
const useAttachmentsCell = ({ attribute, row, canEdit, onChange, }) => {
|
|
15802
16051
|
const [previewIndex, setPreviewIndex] = React.useState(null);
|
|
15803
|
-
const [
|
|
16052
|
+
const [isPopupOpen, , setPopupOpen] = useToggle(false);
|
|
15804
16053
|
const { attributeName, isEditable } = attribute;
|
|
15805
16054
|
const value = row.properties[attributeName];
|
|
15806
16055
|
const items = React.useMemo(() => parseAttachments(value), [value]);
|
|
16056
|
+
const view = useAttachmentsView({
|
|
16057
|
+
items,
|
|
16058
|
+
limit: ATTACHMENTS_SHOWN_ITEMS,
|
|
16059
|
+
initialViewMode: ATTACHMENTS_VIEW_MODE,
|
|
16060
|
+
});
|
|
16061
|
+
const { setShowMore } = view;
|
|
15807
16062
|
const previewImages = useAttachmentPreviewImages({ items, active: previewIndex !== null });
|
|
15808
16063
|
const downloadByIndex = useAttachmentDownload(items);
|
|
15809
16064
|
// Те же два условия, что и у обычной ячейки: режим таблицы и разрешение самого атрибута.
|
|
15810
16065
|
const editable = canEdit && isEditable;
|
|
15811
16066
|
const persist = React.useCallback((next) => onChange(row.key, attributeName, JSON.stringify(next)), [attributeName, onChange, row.key]);
|
|
16067
|
+
const edit = useAttachmentsCellEdit({ attribute, items, persist });
|
|
15812
16068
|
const onPreview = React.useCallback((link) => {
|
|
15813
16069
|
const index = items.findIndex(item => item.link === link);
|
|
15814
16070
|
if (index >= 0) {
|
|
@@ -15817,48 +16073,78 @@ const useAttachmentsCell = ({ attribute, row, canEdit, onChange }) => {
|
|
|
15817
16073
|
}, [items]);
|
|
15818
16074
|
const onClosePreview = React.useCallback(() => setPreviewIndex(null), []);
|
|
15819
16075
|
const onDownload = React.useCallback((_image, index) => downloadByIndex(index), [downloadByIndex]);
|
|
15820
|
-
const
|
|
15821
|
-
const
|
|
15822
|
-
|
|
15823
|
-
|
|
15824
|
-
|
|
15825
|
-
|
|
15826
|
-
|
|
15827
|
-
|
|
15828
|
-
|
|
15829
|
-
|
|
15830
|
-
|
|
15831
|
-
}
|
|
15832
|
-
|
|
16076
|
+
const onShowMore = React.useCallback(() => setShowMore(true), [setShowMore]);
|
|
16077
|
+
const onClosePopup = React.useCallback(() => setPopupOpen(false), [setPopupOpen]);
|
|
16078
|
+
/**
|
|
16079
|
+
* На правку поп-ап открывается всегда, даже у пустой ячейки: другого места, откуда добавить
|
|
16080
|
+
* первый файл, у колонки нет. На чтение единственный файл ведёт прямо в галерею, а свёрнутый
|
|
16081
|
+
* счётчик — в тот же поп-ап, только без кнопок.
|
|
16082
|
+
*/
|
|
16083
|
+
const onCellClick = React.useCallback(() => {
|
|
16084
|
+
if (!editable && items.length === ATTACHMENTS_INLINE_LIMIT) {
|
|
16085
|
+
onPreview(items[0].link);
|
|
16086
|
+
return;
|
|
16087
|
+
}
|
|
16088
|
+
if (editable || items.length) {
|
|
16089
|
+
setPopupOpen(true);
|
|
16090
|
+
}
|
|
16091
|
+
}, [editable, items, onPreview, setPopupOpen]);
|
|
15833
16092
|
return {
|
|
16093
|
+
...view,
|
|
16094
|
+
...edit,
|
|
15834
16095
|
items,
|
|
15835
16096
|
editable,
|
|
16097
|
+
onShowMore,
|
|
16098
|
+
isPopupOpen,
|
|
16099
|
+
onClosePopup,
|
|
16100
|
+
onCellClick,
|
|
15836
16101
|
previewIndex,
|
|
15837
16102
|
previewImages,
|
|
15838
|
-
isLinkDialogOpen,
|
|
15839
16103
|
onPreview,
|
|
15840
16104
|
onClosePreview,
|
|
15841
16105
|
onDownload,
|
|
15842
|
-
onDelete,
|
|
15843
|
-
onOpenLinkDialog,
|
|
15844
|
-
onCloseLinkDialog,
|
|
15845
|
-
onAddByLink,
|
|
15846
16106
|
};
|
|
15847
16107
|
};
|
|
15848
16108
|
|
|
15849
16109
|
/**
|
|
15850
|
-
* Колонка со
|
|
16110
|
+
* Колонка со вложениями.
|
|
15851
16111
|
*
|
|
15852
16112
|
* Тип у атрибута строковый, вложениями его делает `subType: "Attachments"` в схеме контейнера —
|
|
15853
16113
|
* поэтому ветка стоит раньше разбора типа и обычных редакторов ячейки.
|
|
16114
|
+
*
|
|
16115
|
+
* Сама ячейка показывает один файл, а несколько схлопывает в строку со значком ссылки
|
|
16116
|
+
* и счётчиком: в ширину колонки список файлов не помещается. Весь список живёт в поп-апе.
|
|
15854
16117
|
*/
|
|
15855
16118
|
const AttachmentsCell = React.memo(({ attribute, row, canEdit, onChange }) => {
|
|
15856
16119
|
const { t } = useGlobalContext();
|
|
15857
|
-
const
|
|
15858
|
-
|
|
16120
|
+
const state = useAttachmentsCell({ attribute, row, canEdit, onChange });
|
|
16121
|
+
const { items, editable, isPopupOpen, onClosePopup, onCellClick } = state;
|
|
16122
|
+
const [single] = items;
|
|
16123
|
+
const isCollapsed = items.length > ATTACHMENTS_INLINE_LIMIT;
|
|
16124
|
+
const fileType = React.useMemo(() => (single ? getFileType(single.mimeType, single.name) : undefined), [single]);
|
|
16125
|
+
const isImage = React.useMemo(() => !!fileType && IMAGE_FILE_TYPES.includes(fileType), [fileType]);
|
|
16126
|
+
// Удаление единственного файла — действие самой ячейки, поп-ап ради него открывать незачем.
|
|
16127
|
+
const handleDelete = React.useCallback((event) => {
|
|
16128
|
+
event.stopPropagation();
|
|
16129
|
+
state.onDelete(single.link);
|
|
16130
|
+
}, [single, state]);
|
|
16131
|
+
const renderCell = () => {
|
|
16132
|
+
if (isCollapsed) {
|
|
16133
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(AttachmentsCellLinkIcon, { kind: "link" }), jsxRuntime.jsx(AttachmentsCellLabel, { children: t("attachments.objectsCount", {
|
|
16134
|
+
ns: "common",
|
|
16135
|
+
total: items.length,
|
|
16136
|
+
defaultValue: "Объектов: {{total}}",
|
|
16137
|
+
}) })] }));
|
|
16138
|
+
}
|
|
16139
|
+
if (!single) {
|
|
16140
|
+
return jsxRuntime.jsx(CellPlaceholder, { children: "\u2014" });
|
|
16141
|
+
}
|
|
16142
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [isImage ? (jsxRuntime.jsx(FileImagePreview, { size: "1rem", isExternal: single.isExternal, link: single.link })) : (jsxRuntime.jsx(AttachmentsCellIcon, { fileType: fileType })), jsxRuntime.jsx(AttachmentsCellLabel, { title: single.name, children: single.name }), editable && jsxRuntime.jsx(uilibGl.IconButton, { kind: "delete", tabIndex: 0, onClick: handleDelete })] }));
|
|
16143
|
+
};
|
|
16144
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(uilibGl.Popup, { zIndex: DASHBOARD_OVERLAY_Z_INDEX, isVisible: isPopupOpen, onRequestClose: onClosePopup, placement: "bottom-start", anchor: ref => (jsxRuntime.jsx(AttachmentsCellBox, { ref: ref, "$interactive": editable || !!items.length, onClick: onCellClick, children: renderCell() })), children: jsxRuntime.jsx(AttachmentsCellPopup, { alias: attribute.alias, state: state }) }), jsxRuntime.jsx(AttachmentLinkDialog, { isOpen: state.isLinkDialogOpen, onClose: state.onCloseLinkDialog, onSubmit: state.onAddByLink }), state.previewIndex !== null && (jsxRuntime.jsx(uilibGl.Preview, { images: state.previewImages, initialIndex: state.previewIndex, isOpen: true, onClose: state.onClosePreview, onDownload: state.onDownload, errorTitleText: t("attachments.resourceUnavailable", {
|
|
15859
16145
|
ns: "common",
|
|
15860
16146
|
defaultValue: "Ресурс недоступен",
|
|
15861
|
-
}) }, previewIndex))] }));
|
|
16147
|
+
}) }, state.previewIndex))] }));
|
|
15862
16148
|
});
|
|
15863
16149
|
|
|
15864
16150
|
/**
|
|
@@ -19971,6 +20257,7 @@ exports.getRenderElement = getRenderElement;
|
|
|
19971
20257
|
exports.getResourceUrl = getResourceUrl;
|
|
19972
20258
|
exports.getRootElementId = getRootElementId;
|
|
19973
20259
|
exports.getSelectedFilterValue = getSelectedFilterValue;
|
|
20260
|
+
exports.getShownItemsLimit = getShownItemsLimit;
|
|
19974
20261
|
exports.getSlideshowImages = getSlideshowImages;
|
|
19975
20262
|
exports.getStyleAttributes = getStyleAttributes;
|
|
19976
20263
|
exports.getSvgUrl = getSvgUrl;
|
|
@@ -20038,6 +20325,7 @@ exports.useAppHeight = useAppHeight;
|
|
|
20038
20325
|
exports.useAttachmentDownload = useAttachmentDownload;
|
|
20039
20326
|
exports.useAttachmentItems = useAttachmentItems;
|
|
20040
20327
|
exports.useAttachmentPreviewImages = useAttachmentPreviewImages;
|
|
20328
|
+
exports.useAttachmentsView = useAttachmentsView;
|
|
20041
20329
|
exports.useAutoCompleteControl = useAutoCompleteControl;
|
|
20042
20330
|
exports.useBeforeSave = useBeforeSave;
|
|
20043
20331
|
exports.useBgImageHost = useBgImageHost;
|