@evergis/react 4.0.167 → 4.0.169
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/actions/types.d.ts +2 -0
- package/dist/components/Dashboard/componentTypes.d.ts +3 -4
- package/dist/components/Dashboard/components/ContainerButton/index.d.ts +4 -0
- package/dist/components/Dashboard/containers/VoteContainer/components/VoteScreen.d.ts +2 -2
- package/dist/components/Dashboard/containers/VoteContainer/types.d.ts +10 -3
- package/dist/components/Dashboard/types.d.ts +2 -0
- package/dist/components/Dashboard/utils/getButtonSlot.d.ts +4 -0
- package/dist/dashboardActions/index.js +6 -0
- package/dist/dashboardActions/index.js.map +1 -1
- package/dist/hooks/task/runtime/getPythonTaskConfiguration.d.ts +2 -0
- package/dist/index.js +76 -37
- package/dist/index.js.map +1 -1
- package/dist/react.esm.js +77 -38
- package/dist/react.esm.js.map +1 -1
- package/package.json +2 -2
package/dist/react.esm.js
CHANGED
|
@@ -3,7 +3,7 @@ import { Icon, IconButtonInnerChild, IconButton, Flex, CircularProgress, transit
|
|
|
3
3
|
import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
|
|
4
4
|
import { memo, forwardRef, isValidElement, Fragment, createContext, useContext, useId, useMemo, useRef, useCallback, useLayoutEffect, useSyncExternalStore, useEffect, useState, createElement } from 'react';
|
|
5
5
|
import { barChartClassNames, lineChartClassNames, BarChart as BarChart$1, LineChart, PieChart } from '@evergis/charts';
|
|
6
|
-
import { AttributeType, AttributeIconType, StringSubType, RemoteTaskStatus, generateId, STORAGE_TOKEN_KEY, parseJwt, STORAGE_REFRESH_TOKEN_KEY, AttributeConfigurationType, LayerServiceType, OgcGeometryType } from '@evergis/api';
|
|
6
|
+
import { AttributeType, AttributeIconType, StringSubType, RemoteTaskStatus, HTTPError, TaskResourceSubType, generateId, STORAGE_TOKEN_KEY, parseJwt, STORAGE_REFRESH_TOKEN_KEY, AttributeConfigurationType, LayerServiceType, OgcGeometryType } from '@evergis/api';
|
|
7
7
|
import { Color as Color$1, ColorScale } from '@evergis/color';
|
|
8
8
|
import { isValid, format, parseJSON, parseISO, toDate } from 'date-fns';
|
|
9
9
|
import { isNil, isUndefined, isEqual, cloneDeep, isEmpty, uniqueId, uniqBy, unescape } from 'lodash';
|
|
@@ -5152,7 +5152,7 @@ const FeatureControls = styled(Flex).withConfig({ displayName: "FeatureControls"
|
|
|
5152
5152
|
const FiltersContainerWrapper = styled(Flex).withConfig({ displayName: "FiltersContainerWrapper", componentId: "sc-1a6ru74" }) `
|
|
5153
5153
|
flex-direction: column;
|
|
5154
5154
|
padding: ${({ $padding }) => $padding ?? `${DEFAULT_FILTER_PADDING}px`};
|
|
5155
|
-
background
|
|
5155
|
+
background: ${({ $bgColor, $fontColor, theme: { palette } }) => $bgColor || ($fontColor ? transparentizeColor($fontColor, 6) : palette.element)};
|
|
5156
5156
|
border-radius: ${({ theme: { borderRadius } }) => borderRadius.medium};
|
|
5157
5157
|
|
|
5158
5158
|
${DropdownField}, input {
|
|
@@ -6467,6 +6467,12 @@ function getActionOptionsError(type, value) {
|
|
|
6467
6467
|
return "Options must be an object";
|
|
6468
6468
|
if (type === "runTask" && (typeof value.taskName !== "string" || !value.taskName))
|
|
6469
6469
|
return "runTask requires taskName";
|
|
6470
|
+
if (type === "runTask") {
|
|
6471
|
+
for (const field of ["fileName", "methodName"]) {
|
|
6472
|
+
if (value[field] !== undefined && (typeof value[field] !== "string" || !value[field].trim()))
|
|
6473
|
+
return `runTask ${field} must be a non-empty string`;
|
|
6474
|
+
}
|
|
6475
|
+
}
|
|
6470
6476
|
if (type === "openModal" && (typeof value.modalId !== "string" || !value.modalId))
|
|
6471
6477
|
return "openModal requires modalId";
|
|
6472
6478
|
if (type === "openUrl" && (typeof value.url !== "string" || !value.url))
|
|
@@ -8946,7 +8952,7 @@ const POLL_SUBTASK_INTERVAL_MS = 500;
|
|
|
8946
8952
|
const POLL_SUBTASK_TIMEOUT_MS = 15_000;
|
|
8947
8953
|
|
|
8948
8954
|
const StatusBadge = styled(Chip).withConfig({ displayName: "StatusBadge", componentId: "sc-1xmfl10" }) `
|
|
8949
|
-
background
|
|
8955
|
+
background: ${({ bgColor }) => bgColor};
|
|
8950
8956
|
color: ${({ theme }) => theme.palette.iconContrast};
|
|
8951
8957
|
`;
|
|
8952
8958
|
|
|
@@ -9035,6 +9041,22 @@ class PythonExecutionError extends Error {
|
|
|
9035
9041
|
const RUN_ID_RADIX = 36;
|
|
9036
9042
|
const TASK_OBSERVATION_TIMEOUT_MS = 86_400_000;
|
|
9037
9043
|
|
|
9044
|
+
const BAD_REQUEST_STATUS = 400;
|
|
9045
|
+
const getPythonTaskConfiguration = async (resourceId, manager, hasExplicitTarget) => {
|
|
9046
|
+
try {
|
|
9047
|
+
return await manager.getTaskResource({ id: resourceId });
|
|
9048
|
+
}
|
|
9049
|
+
catch (error) {
|
|
9050
|
+
if (!hasExplicitTarget || !(error instanceof HTTPError) || error.response.status !== BAD_REQUEST_STATUS)
|
|
9051
|
+
throw error;
|
|
9052
|
+
// Clone the response so a propagated error retains its body for the caller.
|
|
9053
|
+
const body = await error.response.clone().text().catch(() => "");
|
|
9054
|
+
if (!body.includes("Python importMethod is required"))
|
|
9055
|
+
throw error;
|
|
9056
|
+
return undefined;
|
|
9057
|
+
}
|
|
9058
|
+
};
|
|
9059
|
+
|
|
9038
9060
|
const resolvePythonTaskDefinition = async (request, manager) => {
|
|
9039
9061
|
const task = request.taskName ? request.tasks?.find(({ name }) => name === request.taskName) : undefined;
|
|
9040
9062
|
if (request.taskName && !task)
|
|
@@ -9042,20 +9064,23 @@ const resolvePythonTaskDefinition = async (request, manager) => {
|
|
|
9042
9064
|
const resourceId = task?.resourceId ?? request.resourceId;
|
|
9043
9065
|
if (!resourceId)
|
|
9044
9066
|
throw new Error(`Task resourceId is missing: ${request.taskName ?? ""}`);
|
|
9045
|
-
const
|
|
9046
|
-
|
|
9067
|
+
const fileName = request.fileName ?? task?.fileName;
|
|
9068
|
+
const methodName = request.methodName ?? task?.methodName;
|
|
9069
|
+
const hasExplicitTarget = typeof fileName === "string" && !!fileName.trim() && typeof methodName === "string" && !!methodName.trim();
|
|
9070
|
+
const configuration = await getPythonTaskConfiguration(resourceId, manager, hasExplicitTarget);
|
|
9071
|
+
if (configuration && configuration.taskResourceSubType !== TaskResourceSubType.PythonTask && !["pythonService", "PythonTask"].includes(configuration.taskType)) {
|
|
9047
9072
|
throw new Error(`Task ${request.taskName ?? resourceId} is not a Python task`);
|
|
9048
9073
|
}
|
|
9049
|
-
const schema = configuration
|
|
9074
|
+
const schema = configuration?.defaultConfiguration ?? {};
|
|
9050
9075
|
const defaults = buildDefaultForSchema(new SchemaResolver(schema), schema);
|
|
9051
|
-
const parameters = [defaults, configuration
|
|
9076
|
+
const parameters = [defaults, configuration?.userConfiguration, task?.params, request.parameters]
|
|
9052
9077
|
.filter(isObject)
|
|
9053
9078
|
.reduce((base, override) => mergeActionParameters(base, override), {});
|
|
9054
9079
|
return {
|
|
9055
9080
|
resourceId,
|
|
9056
9081
|
parameters,
|
|
9057
|
-
fileName:
|
|
9058
|
-
methodName:
|
|
9082
|
+
fileName: fileName ?? schema.fileName,
|
|
9083
|
+
methodName: methodName ?? schema.methodName,
|
|
9059
9084
|
script: request.script,
|
|
9060
9085
|
};
|
|
9061
9086
|
};
|
|
@@ -11291,7 +11316,7 @@ const FilterChip = styled.div.withConfig({ displayName: "FilterChip", componentI
|
|
|
11291
11316
|
padding: 0.3125rem 0.5rem;
|
|
11292
11317
|
height: 1.5rem;
|
|
11293
11318
|
border-radius: 0.25rem;
|
|
11294
|
-
background
|
|
11319
|
+
background: ${({ $isActive, $bgColor, theme }) => $bgColor
|
|
11295
11320
|
? $bgColor
|
|
11296
11321
|
: $isActive
|
|
11297
11322
|
? theme.palette?.primary
|
|
@@ -11311,7 +11336,7 @@ const FilterChip = styled.div.withConfig({ displayName: "FilterChip", componentI
|
|
|
11311
11336
|
box-sizing: border-box;
|
|
11312
11337
|
|
|
11313
11338
|
&:hover {
|
|
11314
|
-
background
|
|
11339
|
+
background: ${({ $isActive, $bgColor, theme }) => $isActive
|
|
11315
11340
|
? $bgColor || 'inherit'
|
|
11316
11341
|
: $bgColor || theme.palette?.elementDark};
|
|
11317
11342
|
}
|
|
@@ -14556,12 +14581,21 @@ const ContainerBackground = memo(({ elementConfig, renderElement }) => {
|
|
|
14556
14581
|
return (jsx(ContainerBackgroundLayer, { "$outflow": elementConfig?.options?.outflow, children: renderElement({ id: BG_IMAGE_SLOT_ID, wrap: false }) }));
|
|
14557
14582
|
});
|
|
14558
14583
|
|
|
14559
|
-
|
|
14584
|
+
/** Кнопка нативного действия контейнера со стандартными подстановками дочернего конфига. */
|
|
14585
|
+
const ContainerButton = memo(({ type = WidgetType.Dashboard, elementConfig, ...props }) => {
|
|
14586
|
+
const sources = useConfigStringSources(type);
|
|
14587
|
+
const node = useActionNode();
|
|
14588
|
+
const attributes = props.attributes ?? node.attributes ?? sources.attributes;
|
|
14589
|
+
const resolvedConfig = useMemo(() => resolveElementStrings(elementConfig, { ...sources, attributes }), [elementConfig, sources, attributes]);
|
|
14590
|
+
return jsx(ElementButton, { ...props, type: type, attributes: attributes, elementConfig: resolvedConfig });
|
|
14591
|
+
});
|
|
14592
|
+
|
|
14593
|
+
const AddFeatureContainer = memo(({ type, elementConfig, renderElement }) => {
|
|
14560
14594
|
const { id, children, style } = elementConfig || {};
|
|
14561
14595
|
const bgHost = useBgImageHost(elementConfig);
|
|
14562
|
-
|
|
14563
|
-
|
|
14564
|
-
.map((
|
|
14596
|
+
const handleAddFeature = useCallback(() => undefined, []);
|
|
14597
|
+
return (jsxs(Container, { id: id, style: style, ...bgHost, children: [jsx(ContainerBackground, { elementConfig: elementConfig, renderElement: renderElement }), children?.filter(({ type: childType }) => childType === "button")
|
|
14598
|
+
.map((button, index) => (jsx(ContainerButton, { type: type, elementConfig: button, onClick: handleAddFeature }, button.id ?? index)))] }));
|
|
14565
14599
|
});
|
|
14566
14600
|
|
|
14567
14601
|
/**
|
|
@@ -16495,7 +16529,7 @@ const RoundedBackgroundContainerWrapper = styled(Flex).withConfig({ displayName:
|
|
|
16495
16529
|
* иначе фон тонируется цветом иконки, а без неё — цветом текста (colorAttribute/fontColor);
|
|
16496
16530
|
* если не задан ни один цвет, остаётся токен темы.
|
|
16497
16531
|
*/
|
|
16498
|
-
background
|
|
16532
|
+
background: ${({ $bgColor, $iconColor, $color, theme: { palette } }) => $bgColor || tintedBackground($iconColor || $color) || palette.element};
|
|
16499
16533
|
border-radius: ${({ theme: { borderRadius } }) => borderRadius.large};
|
|
16500
16534
|
flex-wrap: nowrap;
|
|
16501
16535
|
|
|
@@ -16566,11 +16600,6 @@ const RoundedBackgroundContainerWrapper = styled(Flex).withConfig({ displayName:
|
|
|
16566
16600
|
> * {
|
|
16567
16601
|
text-align: left;
|
|
16568
16602
|
}
|
|
16569
|
-
|
|
16570
|
-
/* Зазор наружу даёт обёртка иконки, здесь — отступ внутри её бокса. */
|
|
16571
|
-
span[kind] {
|
|
16572
|
-
margin-right: 0.5rem;
|
|
16573
|
-
}
|
|
16574
16603
|
|
|
16575
16604
|
${ContainerValue} {
|
|
16576
16605
|
width: auto;
|
|
@@ -17284,7 +17313,7 @@ const TabContainer = styled.a.withConfig({ displayName: "TabContainer", componen
|
|
|
17284
17313
|
justify-content: center;
|
|
17285
17314
|
flex-wrap: nowrap;
|
|
17286
17315
|
padding: ${({ onlyIcon }) => (onlyIcon ? 1 : 0.5)}rem 1rem;
|
|
17287
|
-
background
|
|
17316
|
+
background: ${({ active, bgColor, theme: { palette } }) => active ? bgColor || palette.primary : palette.element};
|
|
17288
17317
|
border-radius: ${({ column, radius, theme: { borderRadius } }) => radius ? `${radius}px` : column ? borderRadius.medium : borderRadius.xLarge};
|
|
17289
17318
|
text-decoration: none;
|
|
17290
17319
|
|
|
@@ -17750,22 +17779,22 @@ const useVoteForm = (initialValues) => {
|
|
|
17750
17779
|
};
|
|
17751
17780
|
};
|
|
17752
17781
|
|
|
17753
|
-
const VoteCreateForm = ({ categories, initialValues, isEditing, canDelete, submitting, onSubmit, onDelete, onCancel, }) => {
|
|
17782
|
+
const VoteCreateForm = ({ type, buttonConfigs, categories, initialValues, isEditing, canDelete, submitting, onSubmit, onDelete, onCancel, }) => {
|
|
17754
17783
|
const { t } = useGlobalContext();
|
|
17755
17784
|
const form = useVoteForm(initialValues);
|
|
17756
17785
|
const { categoryId, setCategoryId, text, setText, multiSelect, setMultiSelect, variants, addVariant, removeVariant, draft, setDraft, isValid, values, } = form;
|
|
17757
17786
|
const categoryOptions = useMemo(() => categories.map(({ id, name }) => ({ text: name, value: id })), [categories]);
|
|
17787
|
+
const submitButton = useMemo(() => isEditing ? buttonConfigs.saveButton : buttonConfigs.createButton, [buttonConfigs, isEditing]);
|
|
17788
|
+
const handleSubmit = useCallback(() => onSubmit(values), [onSubmit, values]);
|
|
17758
17789
|
return (jsxs(VoteWrapper, { children: [!isEditing && jsx(VoteHeading, { children: t("vote.newVote", { ns: VOTE_NS, defaultValue: "Новое голосование" }) }), jsx(Dropdown, { zIndex: 110000, label: t("vote.category", { ns: VOTE_NS, defaultValue: "Категория" }), width: "100%", placeholder: t("vote.categoryPlaceholder", { ns: VOTE_NS, defaultValue: "Выберите категорию" }), options: categoryOptions, value: categoryId, onChange: items => setCategoryId(String(items[0]?.value ?? "")) }), jsx(Input, { label: t("vote.question", { ns: VOTE_NS, defaultValue: "Вопрос" }), width: "100%", placeholder: t("vote.questionPlaceholder", { ns: VOTE_NS, defaultValue: "Текст вопроса" }), value: text, onChange: ({ target }) => setText(target.value) }), jsx(VoteSectionLabel, { children: t("vote.variants", { ns: VOTE_NS, defaultValue: "Варианты ответов" }) }), !!variants.length && (jsx(VoteChipList, { children: variants.map(({ text: variantText }, index) => (jsxs(VoteChip, { children: [jsx(VoteVariantText, { children: variantText }), jsx(IconButton, { kind: "close", onClick: () => removeVariant(index) })] }, `${variantText}:${index}`))) })), jsx(Input, { width: "100%", placeholder: t("vote.variantPlaceholder", { ns: VOTE_NS, defaultValue: "Введите вариант и нажмите Enter" }), value: draft, onChange: ({ target }) => setDraft(target.value), onKeyDown: event => {
|
|
17759
17790
|
if (event.key === "Enter") {
|
|
17760
17791
|
event.preventDefault();
|
|
17761
17792
|
addVariant();
|
|
17762
17793
|
}
|
|
17763
|
-
} }), jsxs(Flex, { alignItems: "center", justifyContent: "space-between", children: [jsx(VoteSectionLabel, { children: t("vote.multiSelect", { ns: VOTE_NS, defaultValue: "Множественный выбор" }) }), jsx(Switch, { checked: multiSelect, onChange: () => setMultiSelect(prev => !prev) })] }), jsx(
|
|
17764
|
-
? t("vote.save", { ns: VOTE_NS, defaultValue: "Сохранить" })
|
|
17765
|
-
: t("vote.create", { ns: VOTE_NS, defaultValue: "Создать голосование" }) }), !isValid && (jsx(VoteHint, { children: t("vote.formHint", {
|
|
17794
|
+
} }), jsxs(Flex, { alignItems: "center", justifyContent: "space-between", children: [jsx(VoteSectionLabel, { children: t("vote.multiSelect", { ns: VOTE_NS, defaultValue: "Множественный выбор" }) }), jsx(Switch, { checked: multiSelect, onChange: () => setMultiSelect(prev => !prev) })] }), submitButton && (jsx(ContainerButton, { type: type, elementConfig: submitButton, disabled: !isValid || submitting, onClick: handleSubmit })), !isValid && (jsx(VoteHint, { children: t("vote.formHint", {
|
|
17766
17795
|
ns: VOTE_NS,
|
|
17767
17796
|
defaultValue: "Нужны категория, вопрос и минимум два варианта ответа",
|
|
17768
|
-
}) })), isEditing && (jsxs(Flex, { alignItems: "center", justifyContent: "space-between", children: [onCancel && (jsx(VoteEditLink, { onClick: onCancel, children: t("vote.cancel", { ns: VOTE_NS, defaultValue: "Отмена" }) })), canDelete && onDelete && (jsx(
|
|
17797
|
+
}) })), isEditing && (jsxs(Flex, { alignItems: "center", justifyContent: "space-between", children: [onCancel && (jsx(VoteEditLink, { onClick: onCancel, children: t("vote.cancel", { ns: VOTE_NS, defaultValue: "Отмена" }) })), canDelete && onDelete && buttonConfigs.deleteButton && (jsx(ContainerButton, { type: type, elementConfig: buttonConfigs.deleteButton, disabled: submitting, onClick: onDelete }))] }))] }));
|
|
17769
17798
|
};
|
|
17770
17799
|
|
|
17771
17800
|
/** Блок «Поделиться в соцсетях» — пока только вёрстка, без рабочих ссылок. */
|
|
@@ -17774,7 +17803,7 @@ const VoteShare = () => {
|
|
|
17774
17803
|
return (jsxs(VoteShareBlock, { children: [jsx(VoteSectionLabel, { children: t("vote.share", { ns: VOTE_NS, defaultValue: "Поделиться в соцсетях" }) }), jsx(VoteShareChips, { children: VOTE_SOCIALS.map(name => (jsx(VoteShareChip, { children: name }, name))) })] }));
|
|
17775
17804
|
};
|
|
17776
17805
|
|
|
17777
|
-
const VoteResults = ({ question, category, results, screen, isOwner, hasAnswers, submitting, onSubmit, onEdit, }) => {
|
|
17806
|
+
const VoteResults = ({ type, buttonConfigs, question, category, results, screen, isOwner, hasAnswers, submitting, onSubmit, onEdit, }) => {
|
|
17778
17807
|
const { t } = useGlobalContext();
|
|
17779
17808
|
const [selected, setSelected] = useState([]);
|
|
17780
17809
|
const showControls = screen === "voting";
|
|
@@ -17788,8 +17817,9 @@ const VoteResults = ({ question, category, results, screen, isOwner, hasAnswers,
|
|
|
17788
17817
|
});
|
|
17789
17818
|
}, [question.multiSelect]);
|
|
17790
17819
|
const canSubmit = useMemo(() => selected.length > 0 && !submitting, [selected.length, submitting]);
|
|
17820
|
+
const handleSubmit = useCallback(() => onSubmit(selected), [onSubmit, selected]);
|
|
17791
17821
|
return (jsxs(VoteWrapper, { children: [category && jsx(VoteCategoryLabel, { children: category.name }), jsx(VoteQuestionText, { children: question.text }), jsx(VoteVariantList, { column: true, value: selected[0] ?? "", children: results.map(({ id, text, count, percent }) => (jsxs(VoteVariantRow, { children: [jsxs(VoteVariantHead, { children: [showControls &&
|
|
17792
|
-
(question.multiSelect ? (jsx(Checkbox, { checked: selected.includes(id), onChange: () => toggle(id) })) : (jsx(Radio, { value: id, checked: selected.includes(id), onChange: () => toggle(id) }))), jsx(VoteVariantText, { children: text }), jsx(VoteVariantCount, { children: count })] }), jsx(LinearProgress, { done: percent })] }, id))) }), screen === "unauthenticated" && (jsx(VoteHint, { children: t("vote.authHint", { ns: VOTE_NS, defaultValue: "Чтобы проголосовать, пожалуйста, авторизуйтесь" }) })), screen === "voted" && (jsxs(VoteAcceptedBadge, { children: [jsx(Icon, { kind: "success" }), t("vote.accepted", { ns: VOTE_NS, defaultValue: "Ваш ответ принят" })] })), showControls && (jsx(
|
|
17822
|
+
(question.multiSelect ? (jsx(Checkbox, { checked: selected.includes(id), onChange: () => toggle(id) })) : (jsx(Radio, { value: id, checked: selected.includes(id), onChange: () => toggle(id) }))), jsx(VoteVariantText, { children: text }), jsx(VoteVariantCount, { children: count })] }), jsx(LinearProgress, { done: percent })] }, id))) }), screen === "unauthenticated" && (jsx(VoteHint, { children: t("vote.authHint", { ns: VOTE_NS, defaultValue: "Чтобы проголосовать, пожалуйста, авторизуйтесь" }) })), screen === "voted" && (jsxs(VoteAcceptedBadge, { children: [jsx(Icon, { kind: "success" }), t("vote.accepted", { ns: VOTE_NS, defaultValue: "Ваш ответ принят" })] })), showControls && buttonConfigs.submitButton && (jsx(ContainerButton, { type: type, elementConfig: buttonConfigs.submitButton, disabled: !canSubmit, onClick: handleSubmit })), canEdit && onEdit && (jsx(Flex, { children: jsx(VoteEditLink, { onClick: onEdit, children: t("vote.edit", { ns: VOTE_NS, defaultValue: "Редактировать" }) }) })), showShare && jsx(VoteShare, {})] }));
|
|
17793
17823
|
};
|
|
17794
17824
|
|
|
17795
17825
|
/**
|
|
@@ -17798,7 +17828,7 @@ const VoteResults = ({ question, category, results, screen, isOwner, hasAnswers,
|
|
|
17798
17828
|
* Живёт отдельно от `VoteContainer`, потому что тот отвечает за корень контейнера — размеры,
|
|
17799
17829
|
* фон и заголовок — и не должен раздуваться ветвлением по состояниям.
|
|
17800
17830
|
*/
|
|
17801
|
-
const VoteScreen = ({ screen, categories, question, category, results, totalVotes, isOwner, hasAnswers, isEditing, setIsEditing, editInitialValues, submitting, createVote, submitAnswer, editVote, deleteVote, }) => {
|
|
17831
|
+
const VoteScreen = ({ type, buttonConfigs, screen, categories, question, category, results, totalVotes, isOwner, hasAnswers, isEditing, setIsEditing, editInitialValues, submitting, createVote, submitAnswer, editVote, deleteVote, }) => {
|
|
17802
17832
|
const handleCreate = useCallback((values) => void createVote(values), [createVote]);
|
|
17803
17833
|
const handleEdit = useCallback((values) => void editVote(values).then(() => setIsEditing(false)), [editVote, setIsEditing]);
|
|
17804
17834
|
const handleDelete = useCallback(() => void deleteVote().then(() => setIsEditing(false)), [deleteVote, setIsEditing]);
|
|
@@ -17808,14 +17838,14 @@ const VoteScreen = ({ screen, categories, question, category, results, totalVote
|
|
|
17808
17838
|
if (screen === "loading")
|
|
17809
17839
|
return jsx(ContainerLoading, {});
|
|
17810
17840
|
if (isEditing && question) {
|
|
17811
|
-
return (jsx(VoteCreateForm, { categories: categories, initialValues: editInitialValues, isEditing: true, canDelete: !hasAnswers, submitting: submitting, onSubmit: handleEdit, onDelete: handleDelete, onCancel: handleCancel }));
|
|
17841
|
+
return (jsx(VoteCreateForm, { type: type, buttonConfigs: buttonConfigs, categories: categories, initialValues: editInitialValues, isEditing: true, canDelete: !hasAnswers, submitting: submitting, onSubmit: handleEdit, onDelete: handleDelete, onCancel: handleCancel }));
|
|
17812
17842
|
}
|
|
17813
17843
|
if (screen === "create") {
|
|
17814
|
-
return (jsx(VoteCreateForm, { categories: categories, isEditing: false, canDelete: false, submitting: submitting, onSubmit: handleCreate }));
|
|
17844
|
+
return (jsx(VoteCreateForm, { type: type, buttonConfigs: buttonConfigs, categories: categories, isEditing: false, canDelete: false, submitting: submitting, onSubmit: handleCreate }));
|
|
17815
17845
|
}
|
|
17816
17846
|
if (!question)
|
|
17817
17847
|
return null;
|
|
17818
|
-
return (jsx(VoteResults, { question: question, category: category, results: results, totalVotes: totalVotes, screen: screen, isOwner: isOwner, hasAnswers: hasAnswers, submitting: submitting, onSubmit: handleSubmitAnswer, onEdit: handleEditOpen }));
|
|
17848
|
+
return (jsx(VoteResults, { type: type, buttonConfigs: buttonConfigs, question: question, category: category, results: results, totalVotes: totalVotes, screen: screen, isOwner: isOwner, hasAnswers: hasAnswers, submitting: submitting, onSubmit: handleSubmitAnswer, onEdit: handleEditOpen }));
|
|
17819
17849
|
};
|
|
17820
17850
|
|
|
17821
17851
|
/** Приводит значение атрибута к строке-идентификатору (id приходят числами/строками). */
|
|
@@ -18242,6 +18272,9 @@ const useVoteContainer = (elementConfig) => {
|
|
|
18242
18272
|
};
|
|
18243
18273
|
};
|
|
18244
18274
|
|
|
18275
|
+
/** Слот кнопки существует только при совпадении id и явном type: "button". */
|
|
18276
|
+
const getButtonSlot = (children, id) => children?.find((child) => child.id === id && child.type === "button");
|
|
18277
|
+
|
|
18245
18278
|
/**
|
|
18246
18279
|
* Контейнер «Голосование»: привязывает опрос к объекту карты через `attributeName`
|
|
18247
18280
|
* и показывает один из экранов — создание, голосование, после голосования
|
|
@@ -18253,6 +18286,13 @@ const useVoteContainer = (elementConfig) => {
|
|
|
18253
18286
|
const VoteContainer = memo(({ type, elementConfig, isVisible, renderElement }) => {
|
|
18254
18287
|
const { root, body } = useContainerRoot({ elementConfig });
|
|
18255
18288
|
const { configured, ...vote } = useVoteContainer(elementConfig);
|
|
18289
|
+
const children = elementConfig?.children;
|
|
18290
|
+
const buttonConfigs = useMemo(() => ({
|
|
18291
|
+
submitButton: getButtonSlot(children, "submitButton"),
|
|
18292
|
+
createButton: getButtonSlot(children, "createButton"),
|
|
18293
|
+
saveButton: getButtonSlot(children, "saveButton"),
|
|
18294
|
+
deleteButton: getButtonSlot(children, "deleteButton"),
|
|
18295
|
+
}), [children]);
|
|
18256
18296
|
// Без имени атрибута или хотя бы одного источника контейнеру не с чем работать. Ошибка вместо
|
|
18257
18297
|
// пустоты: молчаливый `null` выдавал бы опечатку в конфиге за «блока просто нет».
|
|
18258
18298
|
if (!configured) {
|
|
@@ -18262,7 +18302,7 @@ const VoteContainer = memo(({ type, elementConfig, isVisible, renderElement }) =
|
|
|
18262
18302
|
// в карточке в этом случае тоже не нужен, поэтому не рисуем и корень.
|
|
18263
18303
|
if (!vote.screen)
|
|
18264
18304
|
return null;
|
|
18265
|
-
return (jsxs(ContainerRoot, { ...root, children: [jsx(ContainerBackground, { elementConfig: elementConfig, renderElement: renderElement }), jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), isVisible && (jsx(Container, { ...body, isColumn: true, children: jsx(VoteScreen, { ...vote, screen: vote.screen }) }))] }));
|
|
18305
|
+
return (jsxs(ContainerRoot, { ...root, children: [jsx(ContainerBackground, { elementConfig: elementConfig, renderElement: renderElement }), jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), isVisible && (jsx(Container, { ...body, isColumn: true, children: jsx(VoteScreen, { ...vote, screen: vote.screen, type: type, buttonConfigs: buttonConfigs }) }))] }));
|
|
18266
18306
|
});
|
|
18267
18307
|
|
|
18268
18308
|
const ExpandableTitle = memo(({ elementConfig, type, renderElement }) => {
|
|
@@ -18878,12 +18918,11 @@ const ContainersGroupContainer = memo(props => {
|
|
|
18878
18918
|
});
|
|
18879
18919
|
|
|
18880
18920
|
const ExportPdfContainer = memo(({ type, elementConfig, renderElement }) => {
|
|
18881
|
-
const { t } = useGlobalContext();
|
|
18882
18921
|
const { loading, onExport } = useExportPdf(getRootElementId(type));
|
|
18883
|
-
const { id, style,
|
|
18884
|
-
const
|
|
18922
|
+
const { id, style, children } = elementConfig || {};
|
|
18923
|
+
const buttonConfig = useMemo(() => getButtonSlot(children, "button"), [children]);
|
|
18885
18924
|
const bgHost = useBgImageHost(elementConfig);
|
|
18886
|
-
return (jsxs(Container, { id: id, style: style, ...bgHost, children: [jsx(ContainerBackground, { elementConfig: elementConfig, renderElement: renderElement }), jsx(
|
|
18925
|
+
return (jsxs(Container, { id: id, style: style, ...bgHost, children: [jsx(ContainerBackground, { elementConfig: elementConfig, renderElement: renderElement }), buttonConfig && jsx(ContainerButton, { type: type, elementConfig: buttonConfig, disabled: loading, onClick: onExport })] }));
|
|
18887
18926
|
});
|
|
18888
18927
|
|
|
18889
18928
|
var ThemeName;
|