@evergis/react 4.0.64 → 4.0.66
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/hooks/index.d.ts +5 -0
- package/dist/components/Dashboard/hooks/useAfterSave.d.ts +3 -0
- package/dist/components/Dashboard/hooks/useBeforeSave.d.ts +3 -0
- package/dist/components/Dashboard/hooks/useFeatureSaveHooks.d.ts +16 -0
- package/dist/components/Dashboard/hooks/useFeatureSaveHooks.utils.d.ts +4 -0
- package/dist/components/Dashboard/hooks/useSavePrototypeBuilder.d.ts +3 -0
- package/dist/components/Dashboard/types.d.ts +22 -0
- package/dist/hooks/task/index.d.ts +1 -0
- package/dist/hooks/task/useRemoteTask.d.ts +16 -0
- package/dist/index.js +357 -117
- package/dist/index.js.map +1 -1
- package/dist/react.esm.js +350 -118
- package/dist/react.esm.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -5747,6 +5747,49 @@ const usePythonTask = () => {
|
|
|
5747
5747
|
};
|
|
5748
5748
|
};
|
|
5749
5749
|
|
|
5750
|
+
const useRemoteTask = ({ onUpdate } = {}) => {
|
|
5751
|
+
const { api: api$1 } = useGlobalContext();
|
|
5752
|
+
const { addSubscription, connection, unsubscribeById } = useServerNotificationsContext();
|
|
5753
|
+
const runTask = React.useCallback((prototype) => new Promise((resolve, reject) => {
|
|
5754
|
+
const start = async () => {
|
|
5755
|
+
const resourceId = prototype.subTaskSettings?.[0]?.startParameters?.resourceId;
|
|
5756
|
+
let prototypeId = await api$1.remoteTaskManager.createTaskPrototype(prototype);
|
|
5757
|
+
prototypeId = prototypeId.replace(/["']+/g, "");
|
|
5758
|
+
const { id: taskId, success } = await api$1.remoteTaskManager.startTask1(prototypeId);
|
|
5759
|
+
if (!success || !taskId) {
|
|
5760
|
+
reject(new Error("startTask returned no taskId"));
|
|
5761
|
+
return;
|
|
5762
|
+
}
|
|
5763
|
+
const subscriptionId = await addSubscription({
|
|
5764
|
+
tag: "python_task_progress_event",
|
|
5765
|
+
resourceId,
|
|
5766
|
+
});
|
|
5767
|
+
const onNotification = ({ data }) => {
|
|
5768
|
+
if (data?.taskId !== taskId) {
|
|
5769
|
+
return;
|
|
5770
|
+
}
|
|
5771
|
+
onUpdate?.({ status: data.status, log: data.log });
|
|
5772
|
+
const isCompleted = data.status === api.RemoteTaskStatus.Completed;
|
|
5773
|
+
const isError = data.status === api.RemoteTaskStatus.Error;
|
|
5774
|
+
if (isCompleted || isError) {
|
|
5775
|
+
connection?.off(SERVER_NOTIFICATION_EVENT.PythonProgressNotification, onNotification);
|
|
5776
|
+
if (subscriptionId) {
|
|
5777
|
+
unsubscribeById(subscriptionId);
|
|
5778
|
+
}
|
|
5779
|
+
resolve({
|
|
5780
|
+
taskId,
|
|
5781
|
+
status: isCompleted ? api.RemoteTaskStatus.Completed : api.RemoteTaskStatus.Error,
|
|
5782
|
+
log: data.log,
|
|
5783
|
+
});
|
|
5784
|
+
}
|
|
5785
|
+
};
|
|
5786
|
+
connection?.on(SERVER_NOTIFICATION_EVENT.PythonProgressNotification, onNotification);
|
|
5787
|
+
};
|
|
5788
|
+
start().catch(reject);
|
|
5789
|
+
}), [api$1, addSubscription, connection, unsubscribeById, onUpdate]);
|
|
5790
|
+
return { runTask };
|
|
5791
|
+
};
|
|
5792
|
+
|
|
5750
5793
|
const useAppHeight = () => {
|
|
5751
5794
|
React.useEffect(() => {
|
|
5752
5795
|
const setAppHeight = () => {
|
|
@@ -6214,6 +6257,8 @@ const getAttributeByName = (name, attributes) => {
|
|
|
6214
6257
|
: null;
|
|
6215
6258
|
};
|
|
6216
6259
|
|
|
6260
|
+
const isEmptyElementValue = (value) => value === "" || value === null || value === undefined;
|
|
6261
|
+
|
|
6217
6262
|
/**
|
|
6218
6263
|
* Returns a value safe to render as a React child.
|
|
6219
6264
|
*
|
|
@@ -6238,7 +6283,7 @@ const formatElementValue = ({ t, value, elementConfig, attributes, wrap, }) => {
|
|
|
6238
6283
|
? getAttributeByName(attributeName, attributes)
|
|
6239
6284
|
: null;
|
|
6240
6285
|
const { fontColor, fontSize, noUnits, tagView, bgColor, withDivider, radius, noMargin, } = options || {};
|
|
6241
|
-
const valueOrDefault = value
|
|
6286
|
+
const valueOrDefault = isEmptyElementValue(value) ? defaultValue : value;
|
|
6242
6287
|
const resultValue = type === "attributeValue" && attribute?.type && attribute?.stringFormat
|
|
6243
6288
|
? formatAttributeValue({
|
|
6244
6289
|
t,
|
|
@@ -6262,14 +6307,14 @@ const getAttributeValue = (element, attributes) => {
|
|
|
6262
6307
|
return jsxRuntime.jsx(DashboardCheckbox, { title: attribute.alias || attribute.attributeName, checked: attribute.value });
|
|
6263
6308
|
}
|
|
6264
6309
|
if (Array.isArray(element?.attributeName)) {
|
|
6265
|
-
const concatAttributes = element.attributeName.map((name) => attributes?.find(({ attributeName }) => attributeName === name)?.value
|
|
6310
|
+
const concatAttributes = element.attributeName.map((name) => attributes?.find(({ attributeName }) => attributeName === name)?.value ?? "");
|
|
6266
6311
|
value = concatAttributes.join(separator || ", ");
|
|
6267
6312
|
}
|
|
6268
6313
|
else {
|
|
6269
6314
|
const rawValue = attribute?.value;
|
|
6270
|
-
value = rawValue && typeof rawValue === "object"
|
|
6315
|
+
value = rawValue !== null && rawValue !== undefined && typeof rawValue === "object"
|
|
6271
6316
|
? JSON.stringify(rawValue)
|
|
6272
|
-
: (rawValue
|
|
6317
|
+
: (rawValue ?? "");
|
|
6273
6318
|
}
|
|
6274
6319
|
return typeof value === "string" && maxLength && maxLength < value.length ? (jsxRuntime.jsx(TextTrim, { maxLength: maxLength, wordBreak: wordBreak, expandable: expandable, lineBreak: lineBreak, children: value })) : (value);
|
|
6275
6320
|
};
|
|
@@ -6478,7 +6523,7 @@ const useRenderContainer = ({ elementConfig, type, renderElement, renderBody, })
|
|
|
6478
6523
|
return (jsxRuntime.jsx(OverrideContainer, { type: type, elementConfig: itemConfig, renderElement: item.render }, attribute));
|
|
6479
6524
|
}
|
|
6480
6525
|
}
|
|
6481
|
-
if (
|
|
6526
|
+
if (isEmptyElementValue(item.value) && item.hideEmpty)
|
|
6482
6527
|
return null;
|
|
6483
6528
|
return renderBody(item, attribute);
|
|
6484
6529
|
}, [getRenderContainerItem, elementConfig, attributes, type, renderBody]);
|
|
@@ -7647,7 +7692,7 @@ const LogDialog = ({ isOpen, onClose, onMinimize, logs, status, statusColors })
|
|
|
7647
7692
|
const getStatusColor = React.useCallback((currentStatus) => {
|
|
7648
7693
|
return statusColors?.[currentStatus] || STATUS_COLORS[currentStatus] || STATUS_COLORS[api.RemoteTaskStatus.Unknown];
|
|
7649
7694
|
}, [statusColors]);
|
|
7650
|
-
return (jsxRuntime.jsxs(uilibGl.Dialog, { isOpen: isOpen, onCloseRequest: onClose, modal: true, maxWidth: "800px", minWidth: "600px", minHeight: "600px", children: [jsxRuntime.jsx(uilibGl.DialogTitle, { children: jsxRuntime.jsxs(uilibGl.Flex, { justifyContent: "space-between", alignItems: "center", children: [jsxRuntime.jsxs(uilibGl.Flex, { alignItems: "center", children: [jsxRuntime.jsx(uilibGl.FlexSpan, { marginRight: "1rem", children: t("taskLogs", { ns: "dashboard", defaultValue: "Логи выполнения задачи" }) }), jsxRuntime.jsx(uilibGl.ThemeProvider, { theme: uilibGl.darkTheme, children: jsxRuntime.jsx(StatusBadge, { text: getStatusTitle(status), bgColor: getStatusColor(status) }) })] }), jsxRuntime.jsxs(uilibGl.Flex, { alignItems: "center", width: "auto", children: [onMinimize && jsxRuntime.jsx(uilibGl.IconButton, { kind: "
|
|
7695
|
+
return (jsxRuntime.jsxs(uilibGl.Dialog, { isOpen: isOpen, onCloseRequest: onClose, modal: true, maxWidth: "800px", minWidth: "600px", minHeight: "600px", children: [jsxRuntime.jsx(uilibGl.DialogTitle, { children: jsxRuntime.jsxs(uilibGl.Flex, { justifyContent: "space-between", alignItems: "center", children: [jsxRuntime.jsxs(uilibGl.Flex, { alignItems: "center", children: [jsxRuntime.jsx(uilibGl.FlexSpan, { marginRight: "1rem", children: t("taskLogs", { ns: "dashboard", defaultValue: "Логи выполнения задачи" }) }), jsxRuntime.jsx(uilibGl.ThemeProvider, { theme: uilibGl.darkTheme, children: jsxRuntime.jsx(StatusBadge, { text: getStatusTitle(status), bgColor: getStatusColor(status) }) })] }), jsxRuntime.jsxs(uilibGl.Flex, { alignItems: "center", width: "auto", children: [onMinimize && jsxRuntime.jsx(uilibGl.IconButton, { kind: "rollup", onClick: onMinimize }), jsxRuntime.jsx(uilibGl.IconButton, { kind: "close", onClick: onClose })] })] }) }), jsxRuntime.jsx(uilibGl.DialogContent, { children: jsxRuntime.jsx(uilibGl.Flex, { flexDirection: "column", height: "100%", marginBottom: "2rem", children: jsxRuntime.jsx(LogTerminal, { log: logs || t("taskLogsEmpty", { ns: "dashboard", defaultValue: "Логи отсутствуют" }) }) }) })] }));
|
|
7651
7696
|
};
|
|
7652
7697
|
|
|
7653
7698
|
exports.ThemeName = void 0;
|
|
@@ -9038,115 +9083,6 @@ const FeatureCardDefaultHeader = ({ noFeature }) => {
|
|
|
9038
9083
|
return (jsxRuntime.jsx(DefaultHeaderWrapper, { withPadding: withPadding, height: height, children: jsxRuntime.jsx(uilibGl.ThemeProvider, { theme: getThemeByName(themeName), children: jsxRuntime.jsx(Header, { "$overlay": overlay, "$isRow": !column, children: jsxRuntime.jsxs(HeaderFrontView, { isDefault: !column, children: [jsxRuntime.jsxs(HeaderContainer, { children: [jsxRuntime.jsx(HeaderLayerIcon, {}), jsxRuntime.jsx(HeaderTitle, { noFeature: noFeature })] }), jsxRuntime.jsx(FeatureCardButtons, {})] }) }) }) }));
|
|
9039
9084
|
};
|
|
9040
9085
|
|
|
9041
|
-
const HeaderWrapperMixin = styled.css `
|
|
9042
|
-
${Header} {
|
|
9043
|
-
min-height: 5.25rem;
|
|
9044
|
-
}
|
|
9045
|
-
|
|
9046
|
-
${HeaderContainer} {
|
|
9047
|
-
max-width: 100%;
|
|
9048
|
-
width: 100%;
|
|
9049
|
-
}
|
|
9050
|
-
|
|
9051
|
-
${FeatureControls} {
|
|
9052
|
-
max-width: calc(100% - 2rem);
|
|
9053
|
-
width: calc(100% - 2rem);
|
|
9054
|
-
margin-top: -0.5rem;
|
|
9055
|
-
padding-top: 1rem;
|
|
9056
|
-
border-radius: ${({ theme: { borderRadius } }) => borderRadius.medium};
|
|
9057
|
-
}
|
|
9058
|
-
|
|
9059
|
-
${({ $fontColor }) => !!$fontColor && HeaderFontColorMixin};
|
|
9060
|
-
`;
|
|
9061
|
-
const HeaderIcon = styled(uilibGl.Flex) `
|
|
9062
|
-
position: absolute;
|
|
9063
|
-
top: 0;
|
|
9064
|
-
right: 0;
|
|
9065
|
-
align-items: center;
|
|
9066
|
-
justify-content: center;
|
|
9067
|
-
width: 7.625rem;
|
|
9068
|
-
height: 100%;
|
|
9069
|
-
|
|
9070
|
-
span[kind] {
|
|
9071
|
-
width: 4rem;
|
|
9072
|
-
|
|
9073
|
-
:after {
|
|
9074
|
-
font-size: 4rem;
|
|
9075
|
-
color: rgba(255, 255, 255, 0.36);
|
|
9076
|
-
}
|
|
9077
|
-
}
|
|
9078
|
-
|
|
9079
|
-
span[kind]:after,
|
|
9080
|
-
path,
|
|
9081
|
-
line,
|
|
9082
|
-
circle {
|
|
9083
|
-
fill: rgba(255, 255, 255, 0.36);
|
|
9084
|
-
}
|
|
9085
|
-
|
|
9086
|
-
&& > * {
|
|
9087
|
-
display: flex;
|
|
9088
|
-
align-items: center;
|
|
9089
|
-
height: 100%;
|
|
9090
|
-
}
|
|
9091
|
-
`;
|
|
9092
|
-
const BigIconHeaderMixin = styled.css `
|
|
9093
|
-
${HeaderIcon} {
|
|
9094
|
-
min-width: 14rem;
|
|
9095
|
-
right: -3rem;
|
|
9096
|
-
|
|
9097
|
-
span[kind]:after {
|
|
9098
|
-
font-size: 14rem;
|
|
9099
|
-
}
|
|
9100
|
-
}
|
|
9101
|
-
`;
|
|
9102
|
-
const WithPaddingHeaderMixin = styled.css `
|
|
9103
|
-
${Header} {
|
|
9104
|
-
width: 100%;
|
|
9105
|
-
margin: -0.5rem -0.5rem 0.5rem -0.5rem;
|
|
9106
|
-
}
|
|
9107
|
-
`;
|
|
9108
|
-
const BottomBlurHeaderMixin = styled.css `
|
|
9109
|
-
${Header} {
|
|
9110
|
-
margin-bottom: 0;
|
|
9111
|
-
|
|
9112
|
-
&::after {
|
|
9113
|
-
content: "";
|
|
9114
|
-
position: absolute;
|
|
9115
|
-
top: 0;
|
|
9116
|
-
right: 0;
|
|
9117
|
-
bottom: 0;
|
|
9118
|
-
left: 0;
|
|
9119
|
-
z-index: 11;
|
|
9120
|
-
pointer-events: none;
|
|
9121
|
-
background: ${({ theme: { palette } }) => palette.background};
|
|
9122
|
-
mask-image: linear-gradient(to top, #000 0%, transparent 100%);
|
|
9123
|
-
-webkit-mask-image: linear-gradient(to top, #000 0%, transparent 100%);
|
|
9124
|
-
}
|
|
9125
|
-
}
|
|
9126
|
-
|
|
9127
|
-
${HeaderFrontView} {
|
|
9128
|
-
z-index: 12;
|
|
9129
|
-
}
|
|
9130
|
-
`;
|
|
9131
|
-
const BackgroundHeaderWrapper = styled.div `
|
|
9132
|
-
${Header} {
|
|
9133
|
-
width: calc(100% + 1rem);
|
|
9134
|
-
height: ${({ $height }) => $height ? `${$height}px` : "auto"};
|
|
9135
|
-
margin: -1rem -1rem 1rem -1rem;
|
|
9136
|
-
border-radius: 0.5rem;
|
|
9137
|
-
background: ${({ $bgColor }) => $bgColor || "linear-gradient(96.55deg, #FFFCD3 0%, #B4DC47 100%)"};
|
|
9138
|
-
overflow: hidden;
|
|
9139
|
-
}
|
|
9140
|
-
|
|
9141
|
-
${HeaderWrapperMixin};
|
|
9142
|
-
|
|
9143
|
-
${({ $bigIcon }) => $bigIcon && BigIconHeaderMixin};
|
|
9144
|
-
|
|
9145
|
-
${({ $withPadding }) => $withPadding && WithPaddingHeaderMixin};
|
|
9146
|
-
|
|
9147
|
-
${({ $bottomBlur }) => $bottomBlur && BottomBlurHeaderMixin};
|
|
9148
|
-
`;
|
|
9149
|
-
|
|
9150
9086
|
const ImageContainerButton = styled(uilibGl.FlatButton) `
|
|
9151
9087
|
min-height: 1.5rem;
|
|
9152
9088
|
border-radius: ${({ theme: { borderRadius } }) => borderRadius.large};
|
|
@@ -10065,6 +10001,121 @@ const HeaderSlideshow = styled.div `
|
|
|
10065
10001
|
}
|
|
10066
10002
|
`;
|
|
10067
10003
|
|
|
10004
|
+
const HeaderWrapperMixin = styled.css `
|
|
10005
|
+
${Header} {
|
|
10006
|
+
min-height: 5.25rem;
|
|
10007
|
+
}
|
|
10008
|
+
|
|
10009
|
+
${HeaderContainer} {
|
|
10010
|
+
max-width: 100%;
|
|
10011
|
+
width: 100%;
|
|
10012
|
+
}
|
|
10013
|
+
|
|
10014
|
+
${FeatureControls} {
|
|
10015
|
+
max-width: calc(100% - 2rem);
|
|
10016
|
+
width: calc(100% - 2rem);
|
|
10017
|
+
margin-top: -0.5rem;
|
|
10018
|
+
padding-top: 1rem;
|
|
10019
|
+
border-radius: ${({ theme: { borderRadius } }) => borderRadius.medium};
|
|
10020
|
+
}
|
|
10021
|
+
|
|
10022
|
+
${({ $fontColor }) => !!$fontColor && HeaderFontColorMixin};
|
|
10023
|
+
`;
|
|
10024
|
+
const HeaderIcon = styled(uilibGl.Flex) `
|
|
10025
|
+
position: absolute;
|
|
10026
|
+
top: 0;
|
|
10027
|
+
right: 0;
|
|
10028
|
+
align-items: center;
|
|
10029
|
+
justify-content: center;
|
|
10030
|
+
width: 7.625rem;
|
|
10031
|
+
height: 100%;
|
|
10032
|
+
|
|
10033
|
+
span[kind] {
|
|
10034
|
+
width: 4rem;
|
|
10035
|
+
|
|
10036
|
+
:after {
|
|
10037
|
+
font-size: 4rem;
|
|
10038
|
+
color: rgba(255, 255, 255, 0.36);
|
|
10039
|
+
}
|
|
10040
|
+
}
|
|
10041
|
+
|
|
10042
|
+
span[kind]:after,
|
|
10043
|
+
path,
|
|
10044
|
+
line,
|
|
10045
|
+
circle {
|
|
10046
|
+
fill: rgba(255, 255, 255, 0.36);
|
|
10047
|
+
}
|
|
10048
|
+
|
|
10049
|
+
&& > * {
|
|
10050
|
+
display: flex;
|
|
10051
|
+
align-items: center;
|
|
10052
|
+
height: 100%;
|
|
10053
|
+
}
|
|
10054
|
+
`;
|
|
10055
|
+
const BigIconHeaderMixin = styled.css `
|
|
10056
|
+
${HeaderIcon} {
|
|
10057
|
+
min-width: 14rem;
|
|
10058
|
+
right: -3rem;
|
|
10059
|
+
|
|
10060
|
+
span[kind]:after {
|
|
10061
|
+
font-size: 14rem;
|
|
10062
|
+
}
|
|
10063
|
+
}
|
|
10064
|
+
`;
|
|
10065
|
+
const WithPaddingHeaderMixin = styled.css `
|
|
10066
|
+
${Header} {
|
|
10067
|
+
width: 100%;
|
|
10068
|
+
margin: -0.5rem -0.5rem 0.5rem -0.5rem;
|
|
10069
|
+
}
|
|
10070
|
+
`;
|
|
10071
|
+
const BottomBlurHeaderMixin = styled.css `
|
|
10072
|
+
${Header} {
|
|
10073
|
+
margin-bottom: 0;
|
|
10074
|
+
|
|
10075
|
+
&::before {
|
|
10076
|
+
-webkit-mask-image: linear-gradient(to bottom, #000 0%, transparent 100%);
|
|
10077
|
+
mask-image: linear-gradient(to bottom, #000 0%, transparent 100%);
|
|
10078
|
+
}
|
|
10079
|
+
}
|
|
10080
|
+
|
|
10081
|
+
${ImageContainerBg} {
|
|
10082
|
+
-webkit-mask-image: linear-gradient(to bottom, #000 0%, transparent 100%);
|
|
10083
|
+
mask-image: linear-gradient(to bottom, #000 0%, transparent 100%);
|
|
10084
|
+
}
|
|
10085
|
+
|
|
10086
|
+
${HeaderFrontView} {
|
|
10087
|
+
z-index: 12;
|
|
10088
|
+
}
|
|
10089
|
+
`;
|
|
10090
|
+
const BackgroundHeaderWrapper = styled.div `
|
|
10091
|
+
${Header} {
|
|
10092
|
+
position: relative;
|
|
10093
|
+
width: calc(100% + 1rem);
|
|
10094
|
+
height: ${({ $height }) => $height ? `${$height}px` : "auto"};
|
|
10095
|
+
margin: -1rem -1rem 1rem -1rem;
|
|
10096
|
+
border-radius: 0.5rem;
|
|
10097
|
+
background: transparent;
|
|
10098
|
+
overflow: hidden;
|
|
10099
|
+
|
|
10100
|
+
&::before {
|
|
10101
|
+
content: "";
|
|
10102
|
+
position: absolute;
|
|
10103
|
+
inset: 0;
|
|
10104
|
+
z-index: 0;
|
|
10105
|
+
pointer-events: none;
|
|
10106
|
+
background: ${({ $bgColor }) => $bgColor || "linear-gradient(96.55deg, #FFFCD3 0%, #B4DC47 100%)"};
|
|
10107
|
+
}
|
|
10108
|
+
}
|
|
10109
|
+
|
|
10110
|
+
${HeaderWrapperMixin};
|
|
10111
|
+
|
|
10112
|
+
${({ $bigIcon }) => $bigIcon && BigIconHeaderMixin};
|
|
10113
|
+
|
|
10114
|
+
${({ $withPadding }) => $withPadding && WithPaddingHeaderMixin};
|
|
10115
|
+
|
|
10116
|
+
${({ $bottomBlur }) => $bottomBlur && BottomBlurHeaderMixin};
|
|
10117
|
+
`;
|
|
10118
|
+
|
|
10068
10119
|
const FeatureCardBackgroundHeader = () => {
|
|
10069
10120
|
const { themeName: pageThemeName } = useGlobalContext();
|
|
10070
10121
|
const { config } = useWidgetConfig(exports.WidgetType.FeatureCard);
|
|
@@ -10320,8 +10371,6 @@ const ModalIcon = styled(uilibGl.IconButton) `
|
|
|
10320
10371
|
}
|
|
10321
10372
|
`;
|
|
10322
10373
|
|
|
10323
|
-
const isEmptyElementValue = (value) => value === "" || value === null || value === undefined;
|
|
10324
|
-
|
|
10325
10374
|
const isHiddenEmptyValue = ({ value, children, hideEmpty, renderElement, }) => {
|
|
10326
10375
|
const valueElement = children?.find(item => item.id === "value");
|
|
10327
10376
|
const renderedValue = valueElement ? renderElement({ id: "value" }) : null;
|
|
@@ -12407,6 +12456,112 @@ const useDiffPage = (type) => {
|
|
|
12407
12456
|
return React.useMemo(() => isDiffPage, [isDiffPage]);
|
|
12408
12457
|
};
|
|
12409
12458
|
|
|
12459
|
+
const SAVE_HOOK_RESULT_DURATION = 4000;
|
|
12460
|
+
const NOTIFICATION_ID_RADIX = 36;
|
|
12461
|
+
const NOTIFICATION_ID_LENGTH = 8;
|
|
12462
|
+
const isHookActive = (hook) => !!hook && (!!hook.resourceId || !!hook.fileName);
|
|
12463
|
+
const createSaveNotificationId = () => `save-hook-${Date.now()}-${Math.random().toString(NOTIFICATION_ID_RADIX).slice(2, NOTIFICATION_ID_LENGTH)}`;
|
|
12464
|
+
|
|
12465
|
+
const useAfterSave = (hook, buildPrototype) => {
|
|
12466
|
+
const { t, notification } = useGlobalContext();
|
|
12467
|
+
const { runTask } = useRemoteTask();
|
|
12468
|
+
return React.useCallback(async (input) => {
|
|
12469
|
+
if (!isHookActive(hook)) {
|
|
12470
|
+
return;
|
|
12471
|
+
}
|
|
12472
|
+
const notificationId = createSaveNotificationId();
|
|
12473
|
+
notification?.add({
|
|
12474
|
+
id: notificationId,
|
|
12475
|
+
title: t("afterSaveProgress", { ns: "dashboard", defaultValue: "Выполняется действие после сохранения" }),
|
|
12476
|
+
progress: true,
|
|
12477
|
+
duration: Number.MAX_SAFE_INTEGER,
|
|
12478
|
+
});
|
|
12479
|
+
try {
|
|
12480
|
+
const { status, log } = await runTask(buildPrototype(hook, input));
|
|
12481
|
+
if (status === api.RemoteTaskStatus.Completed) {
|
|
12482
|
+
notification?.update({
|
|
12483
|
+
id: notificationId,
|
|
12484
|
+
title: t("afterSaveSuccess", { ns: "dashboard", defaultValue: "Действие после сохранения выполнено" }),
|
|
12485
|
+
success: true,
|
|
12486
|
+
progress: false,
|
|
12487
|
+
duration: SAVE_HOOK_RESULT_DURATION,
|
|
12488
|
+
});
|
|
12489
|
+
return;
|
|
12490
|
+
}
|
|
12491
|
+
notification?.update({
|
|
12492
|
+
id: notificationId,
|
|
12493
|
+
title: t("afterSaveError", { ns: "dashboard", defaultValue: "Не удалось выполнить действие после сохранения" }),
|
|
12494
|
+
description: log,
|
|
12495
|
+
error: true,
|
|
12496
|
+
progress: false,
|
|
12497
|
+
duration: SAVE_HOOK_RESULT_DURATION,
|
|
12498
|
+
});
|
|
12499
|
+
}
|
|
12500
|
+
catch (error) {
|
|
12501
|
+
const description = error instanceof Error ? error.message : undefined;
|
|
12502
|
+
notification?.update({
|
|
12503
|
+
id: notificationId,
|
|
12504
|
+
title: t("afterSaveError", { ns: "dashboard", defaultValue: "Не удалось выполнить действие после сохранения" }),
|
|
12505
|
+
description,
|
|
12506
|
+
error: true,
|
|
12507
|
+
progress: false,
|
|
12508
|
+
duration: SAVE_HOOK_RESULT_DURATION,
|
|
12509
|
+
});
|
|
12510
|
+
}
|
|
12511
|
+
}, [hook, buildPrototype, runTask, notification, t]);
|
|
12512
|
+
};
|
|
12513
|
+
|
|
12514
|
+
const useBeforeSave = (hook, buildPrototype) => {
|
|
12515
|
+
const { t, notification } = useGlobalContext();
|
|
12516
|
+
const { runTask } = useRemoteTask();
|
|
12517
|
+
return React.useCallback(async (input) => {
|
|
12518
|
+
if (!isHookActive(hook)) {
|
|
12519
|
+
return true;
|
|
12520
|
+
}
|
|
12521
|
+
const notificationId = createSaveNotificationId();
|
|
12522
|
+
notification?.add({
|
|
12523
|
+
id: notificationId,
|
|
12524
|
+
title: t("beforeSaveProgress", { ns: "dashboard", defaultValue: "Выполняется проверка перед сохранением" }),
|
|
12525
|
+
progress: true,
|
|
12526
|
+
duration: Number.MAX_SAFE_INTEGER,
|
|
12527
|
+
});
|
|
12528
|
+
try {
|
|
12529
|
+
const { status, log } = await runTask(buildPrototype(hook, input));
|
|
12530
|
+
if (status === api.RemoteTaskStatus.Completed) {
|
|
12531
|
+
notification?.update({
|
|
12532
|
+
id: notificationId,
|
|
12533
|
+
title: t("beforeSaveSuccess", { ns: "dashboard", defaultValue: "Проверка перед сохранением пройдена" }),
|
|
12534
|
+
success: true,
|
|
12535
|
+
progress: false,
|
|
12536
|
+
duration: SAVE_HOOK_RESULT_DURATION,
|
|
12537
|
+
});
|
|
12538
|
+
return true;
|
|
12539
|
+
}
|
|
12540
|
+
notification?.update({
|
|
12541
|
+
id: notificationId,
|
|
12542
|
+
title: t("beforeSaveError", { ns: "dashboard", defaultValue: "Не удалось выполнить проверку перед сохранением" }),
|
|
12543
|
+
description: log,
|
|
12544
|
+
error: true,
|
|
12545
|
+
progress: false,
|
|
12546
|
+
duration: SAVE_HOOK_RESULT_DURATION,
|
|
12547
|
+
});
|
|
12548
|
+
return false;
|
|
12549
|
+
}
|
|
12550
|
+
catch (error) {
|
|
12551
|
+
const description = error instanceof Error ? error.message : undefined;
|
|
12552
|
+
notification?.update({
|
|
12553
|
+
id: notificationId,
|
|
12554
|
+
title: t("beforeSaveError", { ns: "dashboard", defaultValue: "Не удалось выполнить проверку перед сохранением" }),
|
|
12555
|
+
description,
|
|
12556
|
+
error: true,
|
|
12557
|
+
progress: false,
|
|
12558
|
+
duration: SAVE_HOOK_RESULT_DURATION,
|
|
12559
|
+
});
|
|
12560
|
+
return false;
|
|
12561
|
+
}
|
|
12562
|
+
}, [hook, buildPrototype, runTask, notification, t]);
|
|
12563
|
+
};
|
|
12564
|
+
|
|
12410
12565
|
const useExpandableContainers = () => {
|
|
12411
12566
|
const [expandedContainers, setExpandedContainers] = React.useState({});
|
|
12412
12567
|
const expandContainer = React.useCallback((id, expanded) => {
|
|
@@ -12514,6 +12669,83 @@ const useExportPdf = (id, margin = 20) => {
|
|
|
12514
12669
|
return { loading, onExport };
|
|
12515
12670
|
};
|
|
12516
12671
|
|
|
12672
|
+
const useSavePrototypeBuilder = () => {
|
|
12673
|
+
const { ewktGeometry } = useGlobalContext();
|
|
12674
|
+
const { layerInfo, attributes, dataSources, filters: selectedFilters, } = useWidgetContext(exports.WidgetType.FeatureCard);
|
|
12675
|
+
const { projectInfo, dataSources: projectDataSources } = useWidgetContext(exports.WidgetType.Dashboard);
|
|
12676
|
+
const { currentPage } = useWidgetPage(exports.WidgetType.FeatureCard);
|
|
12677
|
+
return React.useCallback((hook, input) => {
|
|
12678
|
+
const resolvedParameters = applyQueryFilters({
|
|
12679
|
+
parameters: hook.parameters ?? {},
|
|
12680
|
+
filters: currentPage?.filters ?? [],
|
|
12681
|
+
selectedFilters,
|
|
12682
|
+
geometry: ewktGeometry,
|
|
12683
|
+
attributes,
|
|
12684
|
+
layerInfo,
|
|
12685
|
+
dataSources,
|
|
12686
|
+
projectDataSources,
|
|
12687
|
+
});
|
|
12688
|
+
const scriptParameters = {
|
|
12689
|
+
projectName: projectInfo?.name,
|
|
12690
|
+
layerName: layerInfo?.name,
|
|
12691
|
+
featureId: input.featureId,
|
|
12692
|
+
properties: input.changedProperties,
|
|
12693
|
+
...resolvedParameters,
|
|
12694
|
+
};
|
|
12695
|
+
return {
|
|
12696
|
+
enabled: true,
|
|
12697
|
+
startIfPreviousError: true,
|
|
12698
|
+
startIfPreviousNotFinished: true,
|
|
12699
|
+
subTaskSettings: [
|
|
12700
|
+
{
|
|
12701
|
+
type: "pythonService",
|
|
12702
|
+
startParameters: {
|
|
12703
|
+
resourceId: hook.resourceId,
|
|
12704
|
+
fileName: hook.fileName,
|
|
12705
|
+
methodName: hook.methodName,
|
|
12706
|
+
parameters: scriptParameters,
|
|
12707
|
+
method: "pythonrunner/run",
|
|
12708
|
+
},
|
|
12709
|
+
},
|
|
12710
|
+
],
|
|
12711
|
+
};
|
|
12712
|
+
}, [
|
|
12713
|
+
attributes,
|
|
12714
|
+
currentPage?.filters,
|
|
12715
|
+
dataSources,
|
|
12716
|
+
ewktGeometry,
|
|
12717
|
+
layerInfo,
|
|
12718
|
+
projectDataSources,
|
|
12719
|
+
projectInfo?.name,
|
|
12720
|
+
selectedFilters,
|
|
12721
|
+
]);
|
|
12722
|
+
};
|
|
12723
|
+
|
|
12724
|
+
/**
|
|
12725
|
+
* Орchestrator-хук для серверных `beforeSave` / `afterSave` python-скриптов,
|
|
12726
|
+
* описанных в `layerInfo.configuration.editConfiguration.options` слоя.
|
|
12727
|
+
*
|
|
12728
|
+
* - `runBeforeSave(input)` — `Promise<boolean>`, resolves `false` если
|
|
12729
|
+
* серверная проверка не прошла; сохранение должно быть отменено.
|
|
12730
|
+
* - `runAfterSave(input)` — fire-and-forget после успешного save.
|
|
12731
|
+
*
|
|
12732
|
+
* Активируется только если у потребителя в GlobalProvider переданы
|
|
12733
|
+
* `api`, `notification` и `t`, а приложение обёрнуто в
|
|
12734
|
+
* `<ServerNotificationsProvider>` (для SignalR-подписки на прогресс).
|
|
12735
|
+
*/
|
|
12736
|
+
const useFeatureSaveHooks = () => {
|
|
12737
|
+
const { layerInfo } = useWidgetContext(exports.WidgetType.FeatureCard);
|
|
12738
|
+
const options = React.useMemo(() => layerInfo?.configuration
|
|
12739
|
+
?.editConfiguration?.options, [layerInfo?.configuration]);
|
|
12740
|
+
const buildPrototype = useSavePrototypeBuilder();
|
|
12741
|
+
const runBeforeSave = useBeforeSave(options?.beforeSave, buildPrototype);
|
|
12742
|
+
const runAfterSave = useAfterSave(options?.afterSave, buildPrototype);
|
|
12743
|
+
return {
|
|
12744
|
+
runBeforeSave,
|
|
12745
|
+
runAfterSave,
|
|
12746
|
+
};
|
|
12747
|
+
};
|
|
12748
|
+
|
|
12517
12749
|
const getMinMaxFromStringValue = (items, value, current, type) => {
|
|
12518
12750
|
const valueIndex = items.findIndex(item => item.value === (type === "min" ? value.min : value.max));
|
|
12519
12751
|
const currentIndex = items.findIndex(item => item.value === (type === "min" ? value.min : value.max));
|
|
@@ -13793,6 +14025,7 @@ exports.PresentationPanelWrapper = PresentationPanelWrapper;
|
|
|
13793
14025
|
exports.PresentationWrapper = PresentationWrapper;
|
|
13794
14026
|
exports.ProgressContainer = ProgressContainer;
|
|
13795
14027
|
exports.RoundedBackgroundContainer = RoundedBackgroundContainer;
|
|
14028
|
+
exports.SAVE_HOOK_RESULT_DURATION = SAVE_HOOK_RESULT_DURATION;
|
|
13796
14029
|
exports.SERVER_NOTIFICATION_EVENT = SERVER_NOTIFICATION_EVENT;
|
|
13797
14030
|
exports.STACK_BAR_TOTAL_HEIGHT = STACK_BAR_TOTAL_HEIGHT;
|
|
13798
14031
|
exports.ServerNotificationsContext = ServerNotificationsContext;
|
|
@@ -13835,6 +14068,7 @@ exports.checkIsLoading = checkIsLoading;
|
|
|
13835
14068
|
exports.createConfigLayer = createConfigLayer;
|
|
13836
14069
|
exports.createConfigPage = createConfigPage;
|
|
13837
14070
|
exports.createNewPageId = createNewPageId;
|
|
14071
|
+
exports.createSaveNotificationId = createSaveNotificationId;
|
|
13838
14072
|
exports.createTreeNode = createTreeNode;
|
|
13839
14073
|
exports.dateOptions = dateOptions;
|
|
13840
14074
|
exports.debounce = debounce;
|
|
@@ -13896,6 +14130,7 @@ exports.hexToRgba = hexToRgba;
|
|
|
13896
14130
|
exports.isEmptyElementValue = isEmptyElementValue;
|
|
13897
14131
|
exports.isEmptyValue = isEmptyValue;
|
|
13898
14132
|
exports.isHiddenEmptyValue = isHiddenEmptyValue;
|
|
14133
|
+
exports.isHookActive = isHookActive;
|
|
13899
14134
|
exports.isLayerService = isLayerService;
|
|
13900
14135
|
exports.isNotValidSelectedTab = isNotValidSelectedTab;
|
|
13901
14136
|
exports.isNumeric = isNumeric;
|
|
@@ -13922,10 +14157,12 @@ exports.tooltipValueFromRelatedFeatures = tooltipValueFromRelatedFeatures;
|
|
|
13922
14157
|
exports.transparentizeColor = transparentizeColor;
|
|
13923
14158
|
exports.treeNodesToProjectItems = treeNodesToProjectItems;
|
|
13924
14159
|
exports.updateDataSource = updateDataSource;
|
|
14160
|
+
exports.useAfterSave = useAfterSave;
|
|
13925
14161
|
exports.useAppHeight = useAppHeight;
|
|
13926
14162
|
exports.useAttachmentItems = useAttachmentItems;
|
|
13927
14163
|
exports.useAttachmentPreviewImages = useAttachmentPreviewImages;
|
|
13928
14164
|
exports.useAutoCompleteControl = useAutoCompleteControl;
|
|
14165
|
+
exports.useBeforeSave = useBeforeSave;
|
|
13929
14166
|
exports.useChartChange = useChartChange;
|
|
13930
14167
|
exports.useChartData = useChartData;
|
|
13931
14168
|
exports.useContainerAttributes = useContainerAttributes;
|
|
@@ -13938,6 +14175,7 @@ exports.useDiffPage = useDiffPage;
|
|
|
13938
14175
|
exports.useEditGroupAttributes = useEditGroupAttributes;
|
|
13939
14176
|
exports.useExpandableContainers = useExpandableContainers;
|
|
13940
14177
|
exports.useExportPdf = useExportPdf;
|
|
14178
|
+
exports.useFeatureSaveHooks = useFeatureSaveHooks;
|
|
13941
14179
|
exports.useFetchImageWithAuth = useFetchImageWithAuth;
|
|
13942
14180
|
exports.useFetchWithAuth = useFetchWithAuth;
|
|
13943
14181
|
exports.useGetConfigLayer = useGetConfigLayer;
|
|
@@ -13956,7 +14194,9 @@ exports.usePythonSandbox = usePythonSandbox;
|
|
|
13956
14194
|
exports.usePythonTask = usePythonTask;
|
|
13957
14195
|
exports.useRedrawLayer = useRedrawLayer;
|
|
13958
14196
|
exports.useRelatedDataSourceAttributes = useRelatedDataSourceAttributes;
|
|
14197
|
+
exports.useRemoteTask = useRemoteTask;
|
|
13959
14198
|
exports.useRenderElement = useRenderElement;
|
|
14199
|
+
exports.useSavePrototypeBuilder = useSavePrototypeBuilder;
|
|
13960
14200
|
exports.useServerNotificationsContext = useServerNotificationsContext;
|
|
13961
14201
|
exports.useShownOtherItems = useShownOtherItems;
|
|
13962
14202
|
exports.useToggle = useToggle;
|