@atlaskit/editor-plugin-extension 4.1.2 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/cjs/extensionPlugin.js +16 -4
- package/dist/cjs/ui/ConfigPanel/ConfigPanel.js +9 -1
- package/dist/cjs/ui/ConfigPanel/DescriptionSummary.js +50 -0
- package/dist/cjs/ui/ConfigPanel/Header/HeaderAfterIconElement.js +50 -0
- package/dist/cjs/ui/ConfigPanel/Header/HeaderIcon.js +49 -0
- package/dist/cjs/ui/ConfigPanel/Header.js +3 -12
- package/dist/cjs/ui/ConfigPanel/HelpLink.js +22 -0
- package/dist/cjs/ui/ConfigPanel/constants.js +4 -2
- package/dist/cjs/ui/ConfigPanel/withExtensionManifest.js +33 -0
- package/dist/cjs/ui/useConfigPanelPluginHook.js +250 -0
- package/dist/es2019/extensionPlugin.js +16 -4
- package/dist/es2019/ui/ConfigPanel/ConfigPanel.js +9 -1
- package/dist/es2019/ui/ConfigPanel/DescriptionSummary.js +45 -0
- package/dist/es2019/ui/ConfigPanel/Header/HeaderAfterIconElement.js +44 -0
- package/dist/es2019/ui/ConfigPanel/Header/HeaderIcon.js +39 -0
- package/dist/es2019/ui/ConfigPanel/Header.js +1 -11
- package/dist/es2019/ui/ConfigPanel/HelpLink.js +16 -0
- package/dist/es2019/ui/ConfigPanel/constants.js +3 -1
- package/dist/es2019/ui/ConfigPanel/withExtensionManifest.js +21 -0
- package/dist/es2019/ui/useConfigPanelPluginHook.js +201 -0
- package/dist/esm/extensionPlugin.js +15 -4
- package/dist/esm/ui/ConfigPanel/ConfigPanel.js +9 -1
- package/dist/esm/ui/ConfigPanel/DescriptionSummary.js +41 -0
- package/dist/esm/ui/ConfigPanel/Header/HeaderAfterIconElement.js +43 -0
- package/dist/esm/ui/ConfigPanel/Header/HeaderIcon.js +40 -0
- package/dist/esm/ui/ConfigPanel/Header.js +1 -10
- package/dist/esm/ui/ConfigPanel/HelpLink.js +15 -0
- package/dist/esm/ui/ConfigPanel/constants.js +3 -1
- package/dist/esm/ui/ConfigPanel/withExtensionManifest.js +26 -0
- package/dist/esm/ui/useConfigPanelPluginHook.js +236 -0
- package/dist/types/extensionPluginType.d.ts +2 -0
- package/dist/types/ui/ConfigPanel/DescriptionSummary.d.ts +7 -0
- package/dist/types/ui/ConfigPanel/Header/HeaderAfterIconElement.d.ts +7 -0
- package/dist/types/ui/ConfigPanel/Header/HeaderIcon.d.ts +7 -0
- package/dist/types/ui/ConfigPanel/HelpLink.d.ts +7 -0
- package/dist/types/ui/ConfigPanel/constants.d.ts +2 -0
- package/dist/types/ui/ConfigPanel/withExtensionManifest.d.ts +9 -0
- package/dist/types/ui/useConfigPanelPluginHook.d.ts +27 -0
- package/dist/types-ts4.5/extensionPluginType.d.ts +2 -0
- package/dist/types-ts4.5/ui/ConfigPanel/DescriptionSummary.d.ts +7 -0
- package/dist/types-ts4.5/ui/ConfigPanel/Header/HeaderAfterIconElement.d.ts +7 -0
- package/dist/types-ts4.5/ui/ConfigPanel/Header/HeaderIcon.d.ts +7 -0
- package/dist/types-ts4.5/ui/ConfigPanel/HelpLink.d.ts +7 -0
- package/dist/types-ts4.5/ui/ConfigPanel/constants.d.ts +2 -0
- package/dist/types-ts4.5/ui/ConfigPanel/withExtensionManifest.d.ts +9 -0
- package/dist/types-ts4.5/ui/useConfigPanelPluginHook.d.ts +27 -0
- package/package.json +6 -3
|
@@ -12,7 +12,9 @@ import { ACTION, ACTION_SUBJECT, EVENT_TYPE, fireAnalyticsEvent } from '@atlaski
|
|
|
12
12
|
import { isTabGroup, configPanelMessages as messages } from '@atlaskit/editor-common/extensions';
|
|
13
13
|
import { useSharedPluginState } from '@atlaskit/editor-common/hooks';
|
|
14
14
|
import Form, { FormFooter } from '@atlaskit/form';
|
|
15
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
15
16
|
import { ALLOWED_LOGGED_MACRO_PARAMS } from './constants';
|
|
17
|
+
import { DescriptionSummary } from './DescriptionSummary';
|
|
16
18
|
import ErrorMessage from './ErrorMessage';
|
|
17
19
|
import FormContent from './FormContent';
|
|
18
20
|
import { FormErrorBoundary } from './FormErrorBoundary';
|
|
@@ -213,6 +215,10 @@ class ConfigPanel extends React.Component {
|
|
|
213
215
|
});
|
|
214
216
|
// memoized to prevent rerender on new parameters
|
|
215
217
|
_defineProperty(this, "renderHeader", memoizeOne(extensionManifest => {
|
|
218
|
+
// If below FG is true then Header will be rendered separately
|
|
219
|
+
if (fg('platform_editor_ai_object_sidebar_injection')) {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
216
222
|
const {
|
|
217
223
|
onCancel,
|
|
218
224
|
showHeader
|
|
@@ -381,7 +387,9 @@ class ConfigPanel extends React.Component {
|
|
|
381
387
|
noValidate: true,
|
|
382
388
|
onKeyDown: handleKeyDown,
|
|
383
389
|
"data-testid": "extension-config-panel"
|
|
384
|
-
}), this.renderHeader(extensionManifest), /*#__PURE__*/React.createElement(
|
|
390
|
+
}), this.renderHeader(extensionManifest), fg('platform_editor_ai_object_sidebar_injection') && /*#__PURE__*/React.createElement(DescriptionSummary, {
|
|
391
|
+
extensionManifest: extensionManifest
|
|
392
|
+
}), /*#__PURE__*/React.createElement(ConfigFormIntlWithBoundary, {
|
|
385
393
|
api: api,
|
|
386
394
|
canSave: false,
|
|
387
395
|
errorMessage: errorMessage,
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React, { Fragment } from 'react';
|
|
2
|
+
import { useIntl } from 'react-intl-next';
|
|
3
|
+
import { configPanelMessages as messages } from '@atlaskit/editor-common/extensions';
|
|
4
|
+
import { Box, Text, xcss } from '@atlaskit/primitives';
|
|
5
|
+
import { HelpLink } from './HelpLink';
|
|
6
|
+
const descriptionStyles = xcss({
|
|
7
|
+
marginBottom: 'space.300'
|
|
8
|
+
});
|
|
9
|
+
const helpLinkStyles = xcss({
|
|
10
|
+
paddingTop: 'space.150'
|
|
11
|
+
});
|
|
12
|
+
export function DescriptionSummary({
|
|
13
|
+
extensionManifest
|
|
14
|
+
}) {
|
|
15
|
+
const {
|
|
16
|
+
formatMessage
|
|
17
|
+
} = useIntl();
|
|
18
|
+
const {
|
|
19
|
+
description,
|
|
20
|
+
documentationUrl
|
|
21
|
+
} = extensionManifest;
|
|
22
|
+
// Use a temporary allowlist of top 3 macros to test out a new "Documentation" CTA ("Need help?")
|
|
23
|
+
// This will be removed when Top 5 Modernized Macros updates are rolled out
|
|
24
|
+
const modernizedMacrosList = ['children', 'recently-updated', 'excerpt'];
|
|
25
|
+
const enableHelpCTA = modernizedMacrosList.includes(extensionManifest.key);
|
|
26
|
+
return /*#__PURE__*/React.createElement(Fragment, null, (description || documentationUrl) && /*#__PURE__*/React.createElement(Box, {
|
|
27
|
+
xcss: descriptionStyles
|
|
28
|
+
}, /*#__PURE__*/React.createElement(Text, {
|
|
29
|
+
as: "p",
|
|
30
|
+
testId: "config-panel-header-description"
|
|
31
|
+
}, description && /*#__PURE__*/React.createElement(Fragment, null,
|
|
32
|
+
// Ignored via go/ees005
|
|
33
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
34
|
+
description.replace(/([^.])$/, '$1.'), ' '), documentationUrl && (enableHelpCTA ? /*#__PURE__*/React.createElement(Box, {
|
|
35
|
+
xcss: helpLinkStyles
|
|
36
|
+
}, /*#__PURE__*/React.createElement(Text, {
|
|
37
|
+
as: "p"
|
|
38
|
+
}, /*#__PURE__*/React.createElement(HelpLink, {
|
|
39
|
+
documentationUrl: documentationUrl,
|
|
40
|
+
label: formatMessage(messages.help)
|
|
41
|
+
}))) : /*#__PURE__*/React.createElement(HelpLink, {
|
|
42
|
+
documentationUrl: documentationUrl,
|
|
43
|
+
label: formatMessage(messages.documentation)
|
|
44
|
+
})))));
|
|
45
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Box, Flex, xcss } from '@atlaskit/primitives';
|
|
3
|
+
import { withExtensionManifest } from '../withExtensionManifest';
|
|
4
|
+
const itemBodyStyles = xcss({
|
|
5
|
+
display: 'flex',
|
|
6
|
+
flexDirection: 'row',
|
|
7
|
+
flexWrap: 'nowrap',
|
|
8
|
+
justifyContent: 'space-between',
|
|
9
|
+
margin: 'space.200',
|
|
10
|
+
flexGrow: 3
|
|
11
|
+
});
|
|
12
|
+
const itemTextStyles = xcss({
|
|
13
|
+
maxWidth: '100%',
|
|
14
|
+
whiteSpace: 'initial'
|
|
15
|
+
});
|
|
16
|
+
const summaryStyles = xcss({
|
|
17
|
+
font: "var(--ds-font-body-small, normal 400 11px/16px ui-sans-serif, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Ubuntu, \"Helvetica Neue\", sans-serif)",
|
|
18
|
+
color: 'color.text.subtlest',
|
|
19
|
+
marginTop: 'space.050',
|
|
20
|
+
whiteSpace: 'nowrap',
|
|
21
|
+
overflow: 'hidden',
|
|
22
|
+
textOverflow: 'ellipsis'
|
|
23
|
+
});
|
|
24
|
+
function HeaderAfterIconElement({
|
|
25
|
+
extensionManifest
|
|
26
|
+
}) {
|
|
27
|
+
const title = extensionManifest.title;
|
|
28
|
+
const summary = extensionManifest.summary;
|
|
29
|
+
return /*#__PURE__*/React.createElement(Box, {
|
|
30
|
+
xcss: itemBodyStyles
|
|
31
|
+
}, summary ? /*#__PURE__*/React.createElement(Box, {
|
|
32
|
+
xcss: itemTextStyles
|
|
33
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
34
|
+
id: "context-panel-title",
|
|
35
|
+
"data-testid": "context-panel-title"
|
|
36
|
+
}, title), /*#__PURE__*/React.createElement(Box, {
|
|
37
|
+
xcss: summaryStyles
|
|
38
|
+
}, summary)) : /*#__PURE__*/React.createElement(Flex, {
|
|
39
|
+
direction: "column",
|
|
40
|
+
alignItems: "center",
|
|
41
|
+
testId: "context-panel-title"
|
|
42
|
+
}, title));
|
|
43
|
+
}
|
|
44
|
+
export default withExtensionManifest(HeaderAfterIconElement);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React, { Suspense, lazy, useMemo } from 'react';
|
|
2
|
+
import { Box, xcss } from '@atlaskit/primitives';
|
|
3
|
+
import { withExtensionManifest } from '../withExtensionManifest';
|
|
4
|
+
const iconWidth = '40px';
|
|
5
|
+
const itemIconStyles = xcss({
|
|
6
|
+
width: iconWidth,
|
|
7
|
+
height: iconWidth,
|
|
8
|
+
overflow: 'hidden',
|
|
9
|
+
border: `1px solid ${"var(--ds-border, rgba(223, 225, 229, 0.5))"}`,
|
|
10
|
+
borderRadius: "var(--ds-border-radius, 3px)",
|
|
11
|
+
boxSizing: 'border-box',
|
|
12
|
+
display: 'flex',
|
|
13
|
+
justifyContent: 'center',
|
|
14
|
+
alignItems: 'center'
|
|
15
|
+
});
|
|
16
|
+
function HeaderIcon({
|
|
17
|
+
extensionManifest
|
|
18
|
+
}) {
|
|
19
|
+
const icon = extensionManifest.icons['48'];
|
|
20
|
+
const title = extensionManifest.title;
|
|
21
|
+
const ResolvedIcon = useMemo(() => {
|
|
22
|
+
return /*#__PURE__*/lazy(() => icon().then(Cmp => {
|
|
23
|
+
if ('default' in Cmp) {
|
|
24
|
+
return Cmp;
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
default: Cmp
|
|
28
|
+
};
|
|
29
|
+
}));
|
|
30
|
+
}, [icon]);
|
|
31
|
+
return /*#__PURE__*/React.createElement(Box, {
|
|
32
|
+
xcss: itemIconStyles
|
|
33
|
+
}, /*#__PURE__*/React.createElement(Suspense, {
|
|
34
|
+
fallback: null
|
|
35
|
+
}, /*#__PURE__*/React.createElement(ResolvedIcon, {
|
|
36
|
+
label: title
|
|
37
|
+
})));
|
|
38
|
+
}
|
|
39
|
+
export default withExtensionManifest(HeaderIcon);
|
|
@@ -14,6 +14,7 @@ import CrossIcon from '@atlaskit/icon/core/migration/close--cross';
|
|
|
14
14
|
import { Box, Text, xcss } from '@atlaskit/primitives';
|
|
15
15
|
import { N200 } from '@atlaskit/theme/colors';
|
|
16
16
|
import { borderRadius } from '@atlaskit/theme/constants';
|
|
17
|
+
import { HelpLink } from './HelpLink';
|
|
17
18
|
const iconWidth = 40;
|
|
18
19
|
const buttonWidth = 40;
|
|
19
20
|
const margin = 16;
|
|
@@ -151,15 +152,4 @@ const Header = ({
|
|
|
151
152
|
label: intl.formatMessage(messages.documentation)
|
|
152
153
|
})))));
|
|
153
154
|
};
|
|
154
|
-
const HelpLink = ({
|
|
155
|
-
documentationUrl,
|
|
156
|
-
label
|
|
157
|
-
}) => {
|
|
158
|
-
return jsx("a", {
|
|
159
|
-
target: "_blank",
|
|
160
|
-
rel: "noopener noreferrer",
|
|
161
|
-
href: documentationUrl,
|
|
162
|
-
"data-testid": "config-panel-header-documentation-link"
|
|
163
|
-
}, label);
|
|
164
|
-
};
|
|
165
155
|
export default injectIntl(Header);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export const HelpLink = ({
|
|
3
|
+
documentationUrl,
|
|
4
|
+
label
|
|
5
|
+
}) => {
|
|
6
|
+
return (
|
|
7
|
+
/*#__PURE__*/
|
|
8
|
+
// eslint-disable-next-line @atlaskit/design-system/no-html-anchor
|
|
9
|
+
React.createElement("a", {
|
|
10
|
+
target: "_blank",
|
|
11
|
+
rel: "noopener noreferrer",
|
|
12
|
+
href: documentationUrl,
|
|
13
|
+
"data-testid": "config-panel-header-documentation-link"
|
|
14
|
+
}, label)
|
|
15
|
+
);
|
|
16
|
+
};
|
|
@@ -4,4 +4,6 @@ export const ALLOWED_LOGGED_MACRO_PARAMS = {
|
|
|
4
4
|
'recently-updated': ['width', 'types', 'max', 'theme', 'showProfilePic', 'hideHeading'],
|
|
5
5
|
excerpt: ['hidden']
|
|
6
6
|
};
|
|
7
|
-
export const ALLOWED_PARAM_TYPES = ['enum', 'number', 'boolean'];
|
|
7
|
+
export const ALLOWED_PARAM_TYPES = ['enum', 'number', 'boolean'];
|
|
8
|
+
export const CONFIG_PANEL_WIDTH = 320;
|
|
9
|
+
export const CONFIG_PANEL_ID = 'extensions-panel';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { useStateFromPromise } from './use-state-from-promise';
|
|
4
|
+
export function withExtensionManifest(WrappedComponent) {
|
|
5
|
+
return function WithExtensionManifest(props) {
|
|
6
|
+
const {
|
|
7
|
+
extensionKey,
|
|
8
|
+
extensionProvider,
|
|
9
|
+
extensionType,
|
|
10
|
+
...restProps
|
|
11
|
+
} = props;
|
|
12
|
+
const [extensionManifest] = useStateFromPromise(() => extensionProvider.getExtension(extensionType, extensionKey), [extensionProvider, extensionType, extensionKey]);
|
|
13
|
+
return extensionManifest ?
|
|
14
|
+
/*#__PURE__*/
|
|
15
|
+
// Ignored via go/ees005
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, react/jsx-props-no-spreading
|
|
17
|
+
React.createElement(WrappedComponent, _extends({
|
|
18
|
+
extensionManifest: extensionManifest
|
|
19
|
+
}, restProps)) : null;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
|
+
import { configPanelMessages, getExtensionKeyAndNodeKey } from '@atlaskit/editor-common/extensions';
|
|
3
|
+
import { useSharedPluginState } from '@atlaskit/editor-common/hooks';
|
|
4
|
+
import { Box } from '@atlaskit/primitives';
|
|
5
|
+
import { clearEditingContext, forceAutoSave } from '../editor-commands/commands';
|
|
6
|
+
import { getPluginState } from '../pm-plugins/plugin-factory';
|
|
7
|
+
import { getSelectedExtension } from '../pm-plugins/utils';
|
|
8
|
+
import ConfigPanelLoader from './ConfigPanel/ConfigPanelLoader';
|
|
9
|
+
import { CONFIG_PANEL_ID, CONFIG_PANEL_WIDTH } from './ConfigPanel/constants';
|
|
10
|
+
import HeaderAfterIconElement from './ConfigPanel/Header/HeaderAfterIconElement';
|
|
11
|
+
import HeaderIcon from './ConfigPanel/Header/HeaderIcon';
|
|
12
|
+
import { onChangeAction } from './context-panel';
|
|
13
|
+
import { SaveIndicator } from './SaveIndicator/SaveIndicator';
|
|
14
|
+
export function useConfigPanelPluginHook({
|
|
15
|
+
editorView,
|
|
16
|
+
api
|
|
17
|
+
}) {
|
|
18
|
+
const editorState = editorView.state;
|
|
19
|
+
const {
|
|
20
|
+
extensionState
|
|
21
|
+
} = useSharedPluginState(api, ['extension']);
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
const nodeWithPos = getSelectedExtension(editorState, true);
|
|
24
|
+
// Adding checks to bail out early
|
|
25
|
+
if (!nodeWithPos || !extensionState) {
|
|
26
|
+
hideConfigPanel(api);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (extensionState) {
|
|
30
|
+
const {
|
|
31
|
+
showContextPanel,
|
|
32
|
+
extensionProvider,
|
|
33
|
+
processParametersAfter
|
|
34
|
+
} = extensionState;
|
|
35
|
+
if (showContextPanel && extensionProvider && processParametersAfter) {
|
|
36
|
+
showConfigPanel({
|
|
37
|
+
api,
|
|
38
|
+
editorView,
|
|
39
|
+
extensionProvider,
|
|
40
|
+
nodeWithPos
|
|
41
|
+
});
|
|
42
|
+
} else {
|
|
43
|
+
hideConfigPanel(api);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}, [api, editorState, editorView, extensionState]);
|
|
47
|
+
}
|
|
48
|
+
export function hideConfigPanel(api) {
|
|
49
|
+
var _api$contextPanel, _api$contextPanel$act;
|
|
50
|
+
const closePanelById = api === null || api === void 0 ? void 0 : (_api$contextPanel = api.contextPanel) === null || _api$contextPanel === void 0 ? void 0 : (_api$contextPanel$act = _api$contextPanel.actions) === null || _api$contextPanel$act === void 0 ? void 0 : _api$contextPanel$act.closePanelById;
|
|
51
|
+
if (closePanelById) {
|
|
52
|
+
closePanelById(CONFIG_PANEL_ID);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export function showConfigPanel({
|
|
56
|
+
api,
|
|
57
|
+
editorView,
|
|
58
|
+
extensionProvider,
|
|
59
|
+
nodeWithPos
|
|
60
|
+
}) {
|
|
61
|
+
var _api$contextPanel2, _api$contextPanel2$ac;
|
|
62
|
+
const showContextPanel = api === null || api === void 0 ? void 0 : (_api$contextPanel2 = api.contextPanel) === null || _api$contextPanel2 === void 0 ? void 0 : (_api$contextPanel2$ac = _api$contextPanel2.actions) === null || _api$contextPanel2$ac === void 0 ? void 0 : _api$contextPanel2$ac.showPanel;
|
|
63
|
+
if (showContextPanel) {
|
|
64
|
+
const nodeAttrs = nodeWithPos === null || nodeWithPos === void 0 ? void 0 : nodeWithPos.node.attrs;
|
|
65
|
+
const extensionType = nodeAttrs === null || nodeAttrs === void 0 ? void 0 : nodeAttrs.extensionType;
|
|
66
|
+
const extensionKey = nodeAttrs === null || nodeAttrs === void 0 ? void 0 : nodeAttrs.extensionKey;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Loading extension manifest fails when using
|
|
70
|
+
* extensionKey directly from nodeAttrs.
|
|
71
|
+
* Always get extensionKey from getExtensionKeyAndNodeKey to load
|
|
72
|
+
* extension manifest successfully.
|
|
73
|
+
*/
|
|
74
|
+
const [extKey, _] = getExtensionKeyAndNodeKey(extensionKey, extensionType);
|
|
75
|
+
const HeadeIconWrapper = () => {
|
|
76
|
+
return /*#__PURE__*/React.createElement(HeaderIcon, {
|
|
77
|
+
extensionProvider: extensionProvider,
|
|
78
|
+
extensionKey: extKey,
|
|
79
|
+
extensionType: extensionType
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
const HeaderAfterIconElementWrapper = () => {
|
|
83
|
+
return /*#__PURE__*/React.createElement(HeaderAfterIconElement, {
|
|
84
|
+
extensionProvider: extensionProvider,
|
|
85
|
+
extensionKey: extKey,
|
|
86
|
+
extensionType: extensionType
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
const BodyComponent = getContextPanelBodyComponent({
|
|
90
|
+
api,
|
|
91
|
+
editorView,
|
|
92
|
+
extensionProvider,
|
|
93
|
+
nodeWithPos
|
|
94
|
+
});
|
|
95
|
+
showContextPanel({
|
|
96
|
+
id: CONFIG_PANEL_ID,
|
|
97
|
+
headerComponentElements: {
|
|
98
|
+
HeaderIcon: HeadeIconWrapper,
|
|
99
|
+
headerLabel: configPanelMessages.objectSidebarPanelHeaderLabel,
|
|
100
|
+
HeaderAfterIconElement: HeaderAfterIconElementWrapper
|
|
101
|
+
},
|
|
102
|
+
BodyComponent,
|
|
103
|
+
closeOptions: {
|
|
104
|
+
canClosePanel: () => {
|
|
105
|
+
const extensionState = getPluginState(editorView.state);
|
|
106
|
+
/**
|
|
107
|
+
* If context panel is open, then first update extension plugin state.
|
|
108
|
+
* Updating extension plugin state will trigger useEffect in useConfigPanelPluginHook,
|
|
109
|
+
* which will call hideConfigPanel.
|
|
110
|
+
*/
|
|
111
|
+
if (extensionState !== null && extensionState !== void 0 && extensionState.showContextPanel) {
|
|
112
|
+
startClosingConfigPanel({
|
|
113
|
+
api,
|
|
114
|
+
editorView
|
|
115
|
+
});
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Return true if extension plugin state has been updated and hideConfigPanel has been called.
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}, 'push', CONFIG_PANEL_WIDTH);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
export async function startClosingConfigPanel({
|
|
127
|
+
api,
|
|
128
|
+
editorView
|
|
129
|
+
}) {
|
|
130
|
+
var _api$contextPanel3;
|
|
131
|
+
const applyChange = api === null || api === void 0 ? void 0 : (_api$contextPanel3 = api.contextPanel) === null || _api$contextPanel3 === void 0 ? void 0 : _api$contextPanel3.actions.applyChange;
|
|
132
|
+
// Even if the save failed, we should proceed with closing the panel
|
|
133
|
+
clearEditingContext(applyChange)(editorView.state, editorView.dispatch);
|
|
134
|
+
try {
|
|
135
|
+
await new Promise((resolve, reject) => {
|
|
136
|
+
forceAutoSave(applyChange)(resolve, reject)(editorView.state, editorView.dispatch);
|
|
137
|
+
});
|
|
138
|
+
} catch (e) {
|
|
139
|
+
// Even if the save failed, we should proceed with closing the panel
|
|
140
|
+
// eslint-disable-next-line no-console
|
|
141
|
+
console.error(`Autosave failed with error`, e);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
export const getContextPanelBodyComponent = ({
|
|
145
|
+
api,
|
|
146
|
+
editorView,
|
|
147
|
+
extensionProvider,
|
|
148
|
+
nodeWithPos
|
|
149
|
+
}) => {
|
|
150
|
+
var _api$featureFlags;
|
|
151
|
+
const featureFlags = (api === null || api === void 0 ? void 0 : (_api$featureFlags = api.featureFlags) === null || _api$featureFlags === void 0 ? void 0 : _api$featureFlags.sharedState.currentState()) || {};
|
|
152
|
+
const editorState = editorView.state;
|
|
153
|
+
const extensionState = getPluginState(editorState);
|
|
154
|
+
const {
|
|
155
|
+
autoSaveResolve,
|
|
156
|
+
autoSaveReject,
|
|
157
|
+
processParametersBefore
|
|
158
|
+
} = extensionState;
|
|
159
|
+
const {
|
|
160
|
+
extensionType,
|
|
161
|
+
extensionKey,
|
|
162
|
+
parameters
|
|
163
|
+
} = nodeWithPos.node.attrs;
|
|
164
|
+
const [extKey, nodeKey] = getExtensionKeyAndNodeKey(extensionKey, extensionType);
|
|
165
|
+
const configParams = processParametersBefore ? processParametersBefore(parameters || {}) : parameters;
|
|
166
|
+
return () => /*#__PURE__*/React.createElement(Box, {
|
|
167
|
+
padding: "space.200"
|
|
168
|
+
}, /*#__PURE__*/React.createElement(SaveIndicator, {
|
|
169
|
+
duration: 5000,
|
|
170
|
+
visible: true
|
|
171
|
+
}, ({
|
|
172
|
+
onSaveStarted,
|
|
173
|
+
onSaveEnded
|
|
174
|
+
}) => {
|
|
175
|
+
return /*#__PURE__*/React.createElement(ConfigPanelLoader, {
|
|
176
|
+
api: api,
|
|
177
|
+
showHeader: true,
|
|
178
|
+
closeOnEsc: true,
|
|
179
|
+
extensionType: extensionType,
|
|
180
|
+
extensionKey: extKey,
|
|
181
|
+
nodeKey: nodeKey,
|
|
182
|
+
extensionParameters: parameters,
|
|
183
|
+
parameters: configParams,
|
|
184
|
+
extensionProvider: extensionProvider,
|
|
185
|
+
autoSaveTrigger: autoSaveResolve,
|
|
186
|
+
autoSaveReject: autoSaveReject,
|
|
187
|
+
onChange: async updatedParameters => {
|
|
188
|
+
await onChangeAction(editorView, updatedParameters, parameters, nodeWithPos, onSaveStarted);
|
|
189
|
+
onSaveEnded();
|
|
190
|
+
if (autoSaveResolve) {
|
|
191
|
+
autoSaveResolve();
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
onCancel: () => startClosingConfigPanel({
|
|
195
|
+
api,
|
|
196
|
+
editorView
|
|
197
|
+
}),
|
|
198
|
+
featureFlags: featureFlags
|
|
199
|
+
});
|
|
200
|
+
}));
|
|
201
|
+
};
|
|
@@ -12,7 +12,9 @@ import { pluginKey } from './pm-plugins/plugin-key';
|
|
|
12
12
|
import { bodiedExtensionSpecWithFixedToDOM } from './pm-plugins/toDOM-fixes/bodiedExtension';
|
|
13
13
|
import { getToolbarConfig } from './pm-plugins/toolbar';
|
|
14
14
|
import { createPlugin as createUniqueIdPlugin } from './pm-plugins/unique-id';
|
|
15
|
+
// Remove below line when cleaning up platform_editor_ai_object_sidebar_injection feature flag
|
|
15
16
|
import { getContextPanel } from './ui/context-panel';
|
|
17
|
+
import { useConfigPanelPluginHook } from './ui/useConfigPanelPluginHook';
|
|
16
18
|
export var extensionPlugin = function extensionPlugin(_ref) {
|
|
17
19
|
var _api$featureFlags, _api$analytics2, _api$analytics3, _api$contextPanel3, _api$decorations, _api$contextPanel4, _api$analytics4;
|
|
18
20
|
var _ref$config = _ref.config,
|
|
@@ -51,7 +53,9 @@ export var extensionPlugin = function extensionPlugin(_ref) {
|
|
|
51
53
|
}
|
|
52
54
|
var pluginState = pluginKey.getState(state);
|
|
53
55
|
return {
|
|
54
|
-
showContextPanel: pluginState === null || pluginState === void 0 ? void 0 : pluginState.showContextPanel
|
|
56
|
+
showContextPanel: pluginState === null || pluginState === void 0 ? void 0 : pluginState.showContextPanel,
|
|
57
|
+
extensionProvider: pluginState === null || pluginState === void 0 ? void 0 : pluginState.extensionProvider,
|
|
58
|
+
processParametersAfter: pluginState === null || pluginState === void 0 ? void 0 : pluginState.processParametersAfter
|
|
55
59
|
};
|
|
56
60
|
},
|
|
57
61
|
pmPlugins: function pmPlugins() {
|
|
@@ -169,10 +173,17 @@ export var extensionPlugin = function extensionPlugin(_ref) {
|
|
|
169
173
|
applyChangeToContextPanel: _api === null || _api === void 0 || (_api$contextPanel4 = _api.contextPanel) === null || _api$contextPanel4 === void 0 ? void 0 : _api$contextPanel4.actions.applyChange,
|
|
170
174
|
editorAnalyticsAPI: _api === null || _api === void 0 || (_api$analytics4 = _api.analytics) === null || _api$analytics4 === void 0 ? void 0 : _api$analytics4.actions
|
|
171
175
|
}),
|
|
172
|
-
contextPanel: getContextPanel(function () {
|
|
176
|
+
contextPanel: !fg('platform_editor_ai_object_sidebar_injection') ? getContextPanel(function () {
|
|
173
177
|
var _editorViewRef$curren;
|
|
174
178
|
return (_editorViewRef$curren = editorViewRef.current) !== null && _editorViewRef$curren !== void 0 ? _editorViewRef$curren : undefined;
|
|
175
|
-
})(_api, featureFlags)
|
|
176
|
-
}
|
|
179
|
+
})(_api, featureFlags) : undefined
|
|
180
|
+
},
|
|
181
|
+
usePluginHook: fg('platform_editor_ai_object_sidebar_injection') ? function (_ref6) {
|
|
182
|
+
var editorView = _ref6.editorView;
|
|
183
|
+
useConfigPanelPluginHook({
|
|
184
|
+
editorView: editorView,
|
|
185
|
+
api: _api
|
|
186
|
+
});
|
|
187
|
+
} : undefined
|
|
177
188
|
};
|
|
178
189
|
};
|
|
@@ -23,7 +23,9 @@ import { ACTION, ACTION_SUBJECT, EVENT_TYPE, fireAnalyticsEvent } from '@atlaski
|
|
|
23
23
|
import { isTabGroup, configPanelMessages as messages } from '@atlaskit/editor-common/extensions';
|
|
24
24
|
import { useSharedPluginState } from '@atlaskit/editor-common/hooks';
|
|
25
25
|
import Form, { FormFooter } from '@atlaskit/form';
|
|
26
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
26
27
|
import { ALLOWED_LOGGED_MACRO_PARAMS } from './constants';
|
|
28
|
+
import { DescriptionSummary } from './DescriptionSummary';
|
|
27
29
|
import ErrorMessage from './ErrorMessage';
|
|
28
30
|
import FormContent from './FormContent';
|
|
29
31
|
import { FormErrorBoundary } from './FormErrorBoundary';
|
|
@@ -260,6 +262,10 @@ var ConfigPanel = /*#__PURE__*/function (_React$Component) {
|
|
|
260
262
|
}());
|
|
261
263
|
// memoized to prevent rerender on new parameters
|
|
262
264
|
_defineProperty(_this, "renderHeader", memoizeOne(function (extensionManifest) {
|
|
265
|
+
// If below FG is true then Header will be rendered separately
|
|
266
|
+
if (fg('platform_editor_ai_object_sidebar_injection')) {
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
263
269
|
var _this$props2 = _this.props,
|
|
264
270
|
onCancel = _this$props2.onCancel,
|
|
265
271
|
showHeader = _this$props2.showHeader;
|
|
@@ -426,7 +432,9 @@ var ConfigPanel = /*#__PURE__*/function (_React$Component) {
|
|
|
426
432
|
noValidate: true,
|
|
427
433
|
onKeyDown: handleKeyDown,
|
|
428
434
|
"data-testid": "extension-config-panel"
|
|
429
|
-
}), _this2.renderHeader(extensionManifest), /*#__PURE__*/React.createElement(
|
|
435
|
+
}), _this2.renderHeader(extensionManifest), fg('platform_editor_ai_object_sidebar_injection') && /*#__PURE__*/React.createElement(DescriptionSummary, {
|
|
436
|
+
extensionManifest: extensionManifest
|
|
437
|
+
}), /*#__PURE__*/React.createElement(ConfigFormIntlWithBoundary, {
|
|
430
438
|
api: api,
|
|
431
439
|
canSave: false,
|
|
432
440
|
errorMessage: errorMessage,
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React, { Fragment } from 'react';
|
|
2
|
+
import { useIntl } from 'react-intl-next';
|
|
3
|
+
import { configPanelMessages as messages } from '@atlaskit/editor-common/extensions';
|
|
4
|
+
import { Box, Text, xcss } from '@atlaskit/primitives';
|
|
5
|
+
import { HelpLink } from './HelpLink';
|
|
6
|
+
var descriptionStyles = xcss({
|
|
7
|
+
marginBottom: 'space.300'
|
|
8
|
+
});
|
|
9
|
+
var helpLinkStyles = xcss({
|
|
10
|
+
paddingTop: 'space.150'
|
|
11
|
+
});
|
|
12
|
+
export function DescriptionSummary(_ref) {
|
|
13
|
+
var extensionManifest = _ref.extensionManifest;
|
|
14
|
+
var _useIntl = useIntl(),
|
|
15
|
+
formatMessage = _useIntl.formatMessage;
|
|
16
|
+
var description = extensionManifest.description,
|
|
17
|
+
documentationUrl = extensionManifest.documentationUrl;
|
|
18
|
+
// Use a temporary allowlist of top 3 macros to test out a new "Documentation" CTA ("Need help?")
|
|
19
|
+
// This will be removed when Top 5 Modernized Macros updates are rolled out
|
|
20
|
+
var modernizedMacrosList = ['children', 'recently-updated', 'excerpt'];
|
|
21
|
+
var enableHelpCTA = modernizedMacrosList.includes(extensionManifest.key);
|
|
22
|
+
return /*#__PURE__*/React.createElement(Fragment, null, (description || documentationUrl) && /*#__PURE__*/React.createElement(Box, {
|
|
23
|
+
xcss: descriptionStyles
|
|
24
|
+
}, /*#__PURE__*/React.createElement(Text, {
|
|
25
|
+
as: "p",
|
|
26
|
+
testId: "config-panel-header-description"
|
|
27
|
+
}, description && /*#__PURE__*/React.createElement(Fragment, null,
|
|
28
|
+
// Ignored via go/ees005
|
|
29
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
30
|
+
description.replace(/([^.])$/, '$1.'), ' '), documentationUrl && (enableHelpCTA ? /*#__PURE__*/React.createElement(Box, {
|
|
31
|
+
xcss: helpLinkStyles
|
|
32
|
+
}, /*#__PURE__*/React.createElement(Text, {
|
|
33
|
+
as: "p"
|
|
34
|
+
}, /*#__PURE__*/React.createElement(HelpLink, {
|
|
35
|
+
documentationUrl: documentationUrl,
|
|
36
|
+
label: formatMessage(messages.help)
|
|
37
|
+
}))) : /*#__PURE__*/React.createElement(HelpLink, {
|
|
38
|
+
documentationUrl: documentationUrl,
|
|
39
|
+
label: formatMessage(messages.documentation)
|
|
40
|
+
})))));
|
|
41
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Box, Flex, xcss } from '@atlaskit/primitives';
|
|
3
|
+
import { withExtensionManifest } from '../withExtensionManifest';
|
|
4
|
+
var itemBodyStyles = xcss({
|
|
5
|
+
display: 'flex',
|
|
6
|
+
flexDirection: 'row',
|
|
7
|
+
flexWrap: 'nowrap',
|
|
8
|
+
justifyContent: 'space-between',
|
|
9
|
+
margin: 'space.200',
|
|
10
|
+
flexGrow: 3
|
|
11
|
+
});
|
|
12
|
+
var itemTextStyles = xcss({
|
|
13
|
+
maxWidth: '100%',
|
|
14
|
+
whiteSpace: 'initial'
|
|
15
|
+
});
|
|
16
|
+
var summaryStyles = xcss({
|
|
17
|
+
font: "var(--ds-font-body-small, normal 400 11px/16px ui-sans-serif, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Ubuntu, \"Helvetica Neue\", sans-serif)",
|
|
18
|
+
color: 'color.text.subtlest',
|
|
19
|
+
marginTop: 'space.050',
|
|
20
|
+
whiteSpace: 'nowrap',
|
|
21
|
+
overflow: 'hidden',
|
|
22
|
+
textOverflow: 'ellipsis'
|
|
23
|
+
});
|
|
24
|
+
function HeaderAfterIconElement(_ref) {
|
|
25
|
+
var extensionManifest = _ref.extensionManifest;
|
|
26
|
+
var title = extensionManifest.title;
|
|
27
|
+
var summary = extensionManifest.summary;
|
|
28
|
+
return /*#__PURE__*/React.createElement(Box, {
|
|
29
|
+
xcss: itemBodyStyles
|
|
30
|
+
}, summary ? /*#__PURE__*/React.createElement(Box, {
|
|
31
|
+
xcss: itemTextStyles
|
|
32
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
33
|
+
id: "context-panel-title",
|
|
34
|
+
"data-testid": "context-panel-title"
|
|
35
|
+
}, title), /*#__PURE__*/React.createElement(Box, {
|
|
36
|
+
xcss: summaryStyles
|
|
37
|
+
}, summary)) : /*#__PURE__*/React.createElement(Flex, {
|
|
38
|
+
direction: "column",
|
|
39
|
+
alignItems: "center",
|
|
40
|
+
testId: "context-panel-title"
|
|
41
|
+
}, title));
|
|
42
|
+
}
|
|
43
|
+
export default withExtensionManifest(HeaderAfterIconElement);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React, { Suspense, lazy, useMemo } from 'react';
|
|
2
|
+
import { Box, xcss } from '@atlaskit/primitives';
|
|
3
|
+
import { withExtensionManifest } from '../withExtensionManifest';
|
|
4
|
+
var iconWidth = '40px';
|
|
5
|
+
var itemIconStyles = xcss({
|
|
6
|
+
width: iconWidth,
|
|
7
|
+
height: iconWidth,
|
|
8
|
+
overflow: 'hidden',
|
|
9
|
+
border: "1px solid ".concat("var(--ds-border, rgba(223, 225, 229, 0.5))"),
|
|
10
|
+
borderRadius: "var(--ds-border-radius, 3px)",
|
|
11
|
+
boxSizing: 'border-box',
|
|
12
|
+
display: 'flex',
|
|
13
|
+
justifyContent: 'center',
|
|
14
|
+
alignItems: 'center'
|
|
15
|
+
});
|
|
16
|
+
function HeaderIcon(_ref) {
|
|
17
|
+
var extensionManifest = _ref.extensionManifest;
|
|
18
|
+
var icon = extensionManifest.icons['48'];
|
|
19
|
+
var title = extensionManifest.title;
|
|
20
|
+
var ResolvedIcon = useMemo(function () {
|
|
21
|
+
return /*#__PURE__*/lazy(function () {
|
|
22
|
+
return icon().then(function (Cmp) {
|
|
23
|
+
if ('default' in Cmp) {
|
|
24
|
+
return Cmp;
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
default: Cmp
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
}, [icon]);
|
|
32
|
+
return /*#__PURE__*/React.createElement(Box, {
|
|
33
|
+
xcss: itemIconStyles
|
|
34
|
+
}, /*#__PURE__*/React.createElement(Suspense, {
|
|
35
|
+
fallback: null
|
|
36
|
+
}, /*#__PURE__*/React.createElement(ResolvedIcon, {
|
|
37
|
+
label: title
|
|
38
|
+
})));
|
|
39
|
+
}
|
|
40
|
+
export default withExtensionManifest(HeaderIcon);
|
|
@@ -14,6 +14,7 @@ import CrossIcon from '@atlaskit/icon/core/migration/close--cross';
|
|
|
14
14
|
import { Box, Text, xcss } from '@atlaskit/primitives';
|
|
15
15
|
import { N200 } from '@atlaskit/theme/colors';
|
|
16
16
|
import { borderRadius } from '@atlaskit/theme/constants';
|
|
17
|
+
import { HelpLink } from './HelpLink';
|
|
17
18
|
var iconWidth = 40;
|
|
18
19
|
var buttonWidth = 40;
|
|
19
20
|
var margin = 16;
|
|
@@ -152,14 +153,4 @@ var Header = function Header(_ref) {
|
|
|
152
153
|
label: intl.formatMessage(messages.documentation)
|
|
153
154
|
})))));
|
|
154
155
|
};
|
|
155
|
-
var HelpLink = function HelpLink(_ref2) {
|
|
156
|
-
var documentationUrl = _ref2.documentationUrl,
|
|
157
|
-
label = _ref2.label;
|
|
158
|
-
return jsx("a", {
|
|
159
|
-
target: "_blank",
|
|
160
|
-
rel: "noopener noreferrer",
|
|
161
|
-
href: documentationUrl,
|
|
162
|
-
"data-testid": "config-panel-header-documentation-link"
|
|
163
|
-
}, label);
|
|
164
|
-
};
|
|
165
156
|
export default injectIntl(Header);
|