@jetbrains/ring-ui 7.0.0-beta.8 → 7.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/babel.config.js +20 -14
- package/components/alert/alert.css +7 -7
- package/components/alert/alert.d.ts +2 -2
- package/components/alert/alert.js +10 -12
- package/components/alert/container.js +1 -1
- package/components/alert-service/alert-service.js +4 -2
- package/components/analytics/analytics__custom-plugin.js +1 -1
- package/components/auth/auth.js +1 -1
- package/components/auth/auth__core.js +36 -36
- package/components/auth/background-flow.js +2 -2
- package/components/auth/down-notification.js +3 -1
- package/components/auth/iframe-flow.js +4 -2
- package/components/auth/request-builder.js +5 -5
- package/components/auth/storage.js +10 -9
- package/components/auth/token-validator.js +8 -15
- package/components/auth-dialog/auth-dialog.js +8 -8
- package/components/auth-dialog-service/auth-dialog-service.js +4 -4
- package/components/avatar/avatar.js +9 -7
- package/components/avatar/fallback-avatar.js +15 -12
- package/components/button/button.css +36 -25
- package/components/button/button.js +9 -9
- package/components/button/button__classes.d.ts +1 -1
- package/components/button/button__classes.js +3 -4
- package/components/button-group/button-group.css +25 -13
- package/components/button-group/caption.js +1 -1
- package/components/button-toolbar/button-toolbar.d.ts +1 -1
- package/components/button-toolbar/button-toolbar.js +2 -2
- package/components/caret/caret.js +8 -8
- package/components/checkbox/checkbox.css +8 -5
- package/components/checkbox/checkbox.js +1 -1
- package/components/clipboard/clipboard-fallback.js +2 -6
- package/components/clipboard/clipboard.js +5 -5
- package/components/code/code.d.ts +1 -1
- package/components/code/code.js +2 -2
- package/components/code/highlight.css +3 -1
- package/components/collapse/collapse-content.d.ts +1 -2
- package/components/collapse/collapse-content.js +25 -14
- package/components/collapse/collapse-context.js +1 -1
- package/components/collapse/collapse-control.js +5 -3
- package/components/collapse/collapse.css +21 -20
- package/components/collapse/collapse.js +2 -2
- package/components/confirm/confirm.d.ts +2 -2
- package/components/confirm/confirm.js +2 -2
- package/components/confirm-service/confirm-service.d.ts +1 -1
- package/components/confirm-service/confirm-service.js +6 -6
- package/components/content-layout/content-layout.css +6 -5
- package/components/content-layout/content-layout.js +7 -6
- package/components/content-layout/sidebar.js +5 -5
- package/components/contenteditable/contenteditable.d.ts +1 -1
- package/components/contenteditable/contenteditable.js +3 -4
- package/components/control-label/control-label.js +5 -3
- package/components/data-list/data-list.css +3 -3
- package/components/data-list/data-list.d.ts +2 -2
- package/components/data-list/data-list.js +6 -7
- package/components/data-list/data-list.mock.js +57 -47
- package/components/data-list/item.js +14 -16
- package/components/data-list/selection.js +5 -7
- package/components/data-list/title.js +5 -6
- package/components/date-picker/consts.js +2 -2
- package/components/date-picker/date-input.js +4 -4
- package/components/date-picker/date-picker.css +23 -18
- package/components/date-picker/date-picker.d.ts +2 -1
- package/components/date-picker/date-picker.js +13 -19
- package/components/date-picker/date-popup.js +30 -36
- package/components/date-picker/day.js +6 -9
- package/components/date-picker/formats.js +647 -1
- package/components/date-picker/month-names.js +6 -8
- package/components/date-picker/month-slider.js +2 -2
- package/components/date-picker/month.js +1 -3
- package/components/date-picker/months.js +2 -6
- package/components/date-picker/weekdays.js +2 -3
- package/components/date-picker/years.js +3 -3
- package/components/dialog/dialog.d.ts +1 -0
- package/components/dialog/dialog.js +20 -13
- package/components/dialog/dialog__body-scroll-preventer.js +1 -1
- package/components/dropdown/dropdown.css +2 -4
- package/components/dropdown/dropdown.d.ts +2 -2
- package/components/dropdown/dropdown.js +5 -5
- package/components/dropdown-menu/dropdown-menu.js +5 -5
- package/components/editable-heading/editable-heading.css +5 -2
- package/components/editable-heading/editable-heading.js +21 -19
- package/components/error-bubble/error-bubble.js +1 -1
- package/components/error-message/error-message.js +2 -4
- package/components/footer/footer.js +11 -15
- package/components/form/form.stories.js +45 -63
- package/components/global/create-stateful-context.js +2 -4
- package/components/global/data-tests.js +5 -6
- package/components/global/dom.js +8 -11
- package/components/global/focus-sensor-hoc.js +5 -6
- package/components/global/fuzzy-highlight.js +1 -1
- package/components/global/get-event-key.js +2 -2
- package/components/global/global.css +0 -3
- package/components/global/linear-function.js +1 -1
- package/components/global/normalize-indent.js +2 -6
- package/components/global/react-dom-renderer.js +2 -3
- package/components/global/theme.d.ts +4 -2
- package/components/global/theme.js +14 -12
- package/components/global/url.js +8 -8
- package/components/global/variables.css +1 -8
- package/components/global/variables_dark.css +0 -1
- package/components/grid/col.js +6 -6
- package/components/grid/grid.css +174 -173
- package/components/grid/grid.js +1 -1
- package/components/grid/row.js +13 -6
- package/components/group/group.js +1 -1
- package/components/header/header-icon.js +2 -2
- package/components/header/header.css +19 -15
- package/components/header/header.js +3 -5
- package/components/header/links.js +1 -1
- package/components/header/logo.js +1 -1
- package/components/header/profile.d.ts +2 -2
- package/components/header/profile.js +9 -9
- package/components/header/services-link.js +1 -1
- package/components/header/services.js +4 -5
- package/components/header/smart-profile.js +4 -3
- package/components/header/smart-services.js +9 -5
- package/components/header/tray.js +1 -1
- package/components/heading/heading.css +0 -1
- package/components/heading/heading.js +2 -2
- package/components/http/http.d.ts +3 -3
- package/components/http/http.js +25 -29
- package/components/http/http.mock.js +9 -6
- package/components/hub-source/hub-source.js +5 -7
- package/components/hub-source/hub-source__user.js +1 -1
- package/components/hub-source/hub-source__users-groups.js +6 -7
- package/components/i18n/README.md +3 -4
- package/components/i18n/i18n-context.js +2 -4
- package/components/icon/icon.css +1 -1
- package/components/icon/icon.js +7 -9
- package/components/icon/icon__svg.js +6 -6
- package/components/input/input.css +1 -1
- package/components/input/input.js +11 -14
- package/components/input-size/input-size.stories.js +42 -22
- package/components/island/adaptive-island-hoc.js +1 -1
- package/components/island/content.js +4 -6
- package/components/island/header.js +8 -10
- package/components/island/island.css +5 -5
- package/components/island/island.js +1 -1
- package/components/link/clickableLink.js +3 -1
- package/components/link/link.js +5 -3
- package/components/list/consts.js +1 -1
- package/components/list/list.d.ts +1 -1
- package/components/list/list.js +35 -57
- package/components/list/list__custom.js +3 -5
- package/components/list/list__hint.js +3 -1
- package/components/list/list__item.js +11 -9
- package/components/list/list__link.js +1 -1
- package/components/list/list__separator.js +2 -2
- package/components/list/list__title.js +7 -3
- package/components/list/list__users-groups-source.js +6 -8
- package/components/loader/loader.js +1 -1
- package/components/loader/loader__core.js +5 -5
- package/components/loader-inline/loader-inline.css +0 -3
- package/components/loader-inline/loader-inline.js +5 -7
- package/components/loader-screen/loader-screen.js +1 -1
- package/components/login-dialog/login-dialog.js +4 -4
- package/components/login-dialog/service.js +5 -5
- package/components/markdown/markdown.css +6 -6
- package/components/markdown/markdown.d.ts +2 -2
- package/components/markdown/markdown.js +4 -6
- package/components/message/message.css +2 -1
- package/components/message/message.js +30 -21
- package/components/old-browsers-message/old-browsers-message.js +2 -2
- package/components/old-browsers-message/white-list.js +2 -3
- package/components/pager/pager.js +28 -29
- package/components/permissions/permissions.js +8 -13
- package/components/permissions/permissions__cache.js +6 -7
- package/components/popup/popup.consts.js +8 -2
- package/components/popup/popup.js +27 -33
- package/components/popup/popup.target.js +4 -4
- package/components/popup/position.js +21 -28
- package/components/popup-menu/popup-menu.js +1 -1
- package/components/progress-bar/progress-bar.css +10 -8
- package/components/progress-bar/progress-bar.d.ts +2 -2
- package/components/progress-bar/progress-bar.js +2 -2
- package/components/query-assist/query-assist.css +0 -3
- package/components/query-assist/query-assist.js +73 -84
- package/components/query-assist/query-assist__suggestions.js +10 -9
- package/components/radio/radio.css +6 -2
- package/components/radio/radio.js +1 -3
- package/components/scrollable-section/scrollable-section.css +5 -6
- package/components/scrollable-section/scrollable-section.js +1 -1
- package/components/select/select.css +5 -7
- package/components/select/select.d.ts +1 -1
- package/components/select/select.js +96 -110
- package/components/select/select__filter.js +1 -1
- package/components/select/select__popup.js +40 -51
- package/components/shortcuts/core.js +8 -6
- package/components/shortcuts/shortcut-title.js +6 -6
- package/components/shortcuts/shortcuts.js +1 -1
- package/components/sidebar/sidebar.css +3 -1
- package/components/slider/slider.css +14 -14
- package/components/slider/slider.js +7 -7
- package/components/tab-trap/tab-trap.js +7 -9
- package/components/table/cell.js +3 -1
- package/components/table/disable-hover-hoc.js +2 -2
- package/components/table/header-cell.js +5 -3
- package/components/table/header.d.ts +2 -10
- package/components/table/header.js +10 -12
- package/components/table/multitable.js +5 -3
- package/components/table/row.d.ts +0 -1
- package/components/table/row.js +20 -27
- package/components/table/selection-adapter.js +1 -1
- package/components/table/selection-shortcuts-hoc.js +2 -2
- package/components/table/selection.d.ts +2 -3
- package/components/table/selection.js +4 -5
- package/components/table/simple-table.js +4 -4
- package/components/table/smart-table.js +5 -5
- package/components/table/table.css +8 -9
- package/components/table/table.d.ts +0 -1
- package/components/table/table.js +22 -23
- package/components/table/table.stories.json +45 -16
- package/components/tabs/collapsible-more.d.ts +1 -1
- package/components/tabs/collapsible-more.js +13 -16
- package/components/tabs/collapsible-tab.js +2 -2
- package/components/tabs/collapsible-tabs.d.ts +2 -2
- package/components/tabs/collapsible-tabs.js +13 -22
- package/components/tabs/dumb-tabs.js +6 -9
- package/components/tabs/smart-tabs.js +4 -4
- package/components/tabs/tab-link.js +1 -3
- package/components/tabs/tabs.css +7 -9
- package/components/tag/tag.css +7 -7
- package/components/tag/tag.d.ts +1 -1
- package/components/tag/tag.js +9 -12
- package/components/tags-input/tags-input.js +15 -19
- package/components/tags-list/tags-list.d.ts +2 -2
- package/components/tags-list/tags-list.js +6 -5
- package/components/text/text.js +5 -3
- package/components/toggle/toggle.css +12 -10
- package/components/toggle/toggle.d.ts +2 -2
- package/components/toggle/toggle.js +4 -3
- package/components/tooltip/tooltip.d.ts +4 -1
- package/components/tooltip/tooltip.js +19 -10
- package/components/user-agreement/service.js +15 -13
- package/components/user-agreement/user-agreement.js +3 -5
- package/components/user-card/card.js +10 -9
- package/components/user-card/smart-user-card-tooltip.js +5 -7
- package/components/user-card/tooltip.js +4 -4
- package/components/user-card/user-card.css +4 -0
- package/jslint-xml.js +20 -19
- package/package.json +66 -58
- package/postcss.config.js +3 -4
- package/typings.d.ts +2 -4
- package/webpack.config.js +20 -25
- package/components/badge/badge.css +0 -42
- package/components/badge/badge.d.ts +0 -14
- package/components/badge/badge.js +0 -29
- package/components/island-legacy/content-legacy.d.ts +0 -5
- package/components/island-legacy/content-legacy.js +0 -12
- package/components/island-legacy/header-legacy.d.ts +0 -5
- package/components/island-legacy/header-legacy.js +0 -14
- package/components/island-legacy/island-legacy.css +0 -98
- package/components/island-legacy/island-legacy.d.ts +0 -7
- package/components/island-legacy/island-legacy.js +0 -14
- package/components/table-legacy/table-legacy.css +0 -346
- package/components/table-legacy/table-legacy__toolbar.css +0 -25
package/babel.config.js
CHANGED
|
@@ -5,24 +5,30 @@ module.exports = function config(api) {
|
|
|
5
5
|
|
|
6
6
|
return {
|
|
7
7
|
presets: [
|
|
8
|
-
[
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
8
|
+
[
|
|
9
|
+
'@jetbrains/babel-preset-jetbrains',
|
|
10
|
+
{
|
|
11
|
+
typeScript: true,
|
|
12
|
+
useBuiltIns: 'usage',
|
|
13
|
+
corejs: '3',
|
|
14
|
+
react: {
|
|
15
|
+
runtime: 'automatic',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
],
|
|
16
19
|
],
|
|
17
20
|
plugins: [
|
|
18
|
-
[
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
[
|
|
22
|
+
'babel-plugin-transform-define',
|
|
23
|
+
{
|
|
24
|
+
SUPPORTED_BROWSERS: browserslist(),
|
|
25
|
+
},
|
|
26
|
+
],
|
|
21
27
|
],
|
|
22
28
|
env: {
|
|
23
29
|
test: {
|
|
24
|
-
plugins: ['require-context-hook']
|
|
25
|
-
}
|
|
26
|
-
}
|
|
30
|
+
plugins: ['require-context-hook'],
|
|
31
|
+
},
|
|
32
|
+
},
|
|
27
33
|
};
|
|
28
34
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
@import "../global/variables.css";
|
|
2
2
|
|
|
3
|
-
@value animation-duration: 300ms;
|
|
4
|
-
@value animation-easing: ease-out;
|
|
5
|
-
|
|
6
3
|
.alert {
|
|
4
|
+
--ring-alert-animation-duration: 300ms;
|
|
5
|
+
--ring-alert-animation-easing: ease-out;
|
|
6
|
+
|
|
7
7
|
position: relative;
|
|
8
8
|
|
|
9
9
|
display: flex;
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
padding: 0 calc(var(--ring-unit) * 2);
|
|
16
16
|
|
|
17
17
|
transition:
|
|
18
|
-
transform animation-duration animation-easing,
|
|
19
|
-
margin-bottom animation-duration animation-easing,
|
|
20
|
-
opacity animation-duration animation-easing;
|
|
18
|
+
transform var(--ring-alert-animation-duration) var(--ring-alert-animation-easing),
|
|
19
|
+
margin-bottom var(--ring-alert-animation-duration) var(--ring-alert-animation-easing),
|
|
20
|
+
opacity var(--ring-alert-animation-duration) var(--ring-alert-animation-easing);
|
|
21
21
|
white-space: nowrap;
|
|
22
22
|
pointer-events: auto;
|
|
23
23
|
|
|
@@ -124,7 +124,7 @@
|
|
|
124
124
|
|
|
125
125
|
.animationOpen {
|
|
126
126
|
animation-name: show;
|
|
127
|
-
animation-duration: animation-duration;
|
|
127
|
+
animation-duration: var(--ring-alert-animation-duration);
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
.animationClosing {
|
|
@@ -22,8 +22,8 @@ export interface AlertProps {
|
|
|
22
22
|
/**
|
|
23
23
|
* Fires when alert starts closing if timeout is out or user clicks "Close" button
|
|
24
24
|
*/
|
|
25
|
-
onCloseRequest: (
|
|
26
|
-
onClose: (
|
|
25
|
+
onCloseRequest: (event?: React.MouseEvent<HTMLElement>) => void;
|
|
26
|
+
onClose: () => void;
|
|
27
27
|
isShaking: boolean;
|
|
28
28
|
isClosing: boolean;
|
|
29
29
|
/**
|
|
@@ -35,7 +35,7 @@ export var AlertType;
|
|
|
35
35
|
const TypeToIcon = {
|
|
36
36
|
[AlertType.ERROR]: exceptionIcon,
|
|
37
37
|
[AlertType.SUCCESS]: checkmarkIcon,
|
|
38
|
-
[AlertType.WARNING]: warningIcon
|
|
38
|
+
[AlertType.WARNING]: warningIcon,
|
|
39
39
|
};
|
|
40
40
|
/**
|
|
41
41
|
* Lookup table of alert type to icon color.
|
|
@@ -44,7 +44,7 @@ const TypeToIcon = {
|
|
|
44
44
|
const TypeToIconColor = {
|
|
45
45
|
[AlertType.ERROR]: Color.RED,
|
|
46
46
|
[AlertType.SUCCESS]: Color.GREEN,
|
|
47
|
-
[AlertType.WARNING]: Color.WHITE
|
|
47
|
+
[AlertType.WARNING]: Color.WHITE,
|
|
48
48
|
};
|
|
49
49
|
/**
|
|
50
50
|
* @constructor
|
|
@@ -66,10 +66,10 @@ export default class Alert extends PureComponent {
|
|
|
66
66
|
isShaking: false,
|
|
67
67
|
timeout: 0,
|
|
68
68
|
onClose: () => { },
|
|
69
|
-
onCloseRequest: () => { }
|
|
69
|
+
onCloseRequest: () => { },
|
|
70
70
|
};
|
|
71
71
|
state = {
|
|
72
|
-
height: null
|
|
72
|
+
height: null,
|
|
73
73
|
};
|
|
74
74
|
componentDidMount() {
|
|
75
75
|
if (this.props.timeout > 0) {
|
|
@@ -115,7 +115,7 @@ export default class Alert extends PureComponent {
|
|
|
115
115
|
*/
|
|
116
116
|
_getCaption() {
|
|
117
117
|
return (<span className={classNames(styles.caption, this.props.captionClassName, {
|
|
118
|
-
[styles.withCloseButton]: this.props.closeable
|
|
118
|
+
[styles.withCloseButton]: this.props.closeable,
|
|
119
119
|
})} onClick={this._handleCaptionsLinksClick}
|
|
120
120
|
// We only process clicks on `a` elements, see above
|
|
121
121
|
role="presentation">
|
|
@@ -129,10 +129,10 @@ export default class Alert extends PureComponent {
|
|
|
129
129
|
_getIcon() {
|
|
130
130
|
const glyph = TypeToIcon[this.props.type];
|
|
131
131
|
if (glyph) {
|
|
132
|
-
return
|
|
132
|
+
return <Icon glyph={glyph} className={styles.icon} color={TypeToIconColor[this.props.type] || Color.DEFAULT}/>;
|
|
133
133
|
}
|
|
134
134
|
else if (this.props.type === AlertType.LOADING) {
|
|
135
|
-
return
|
|
135
|
+
return <Loader className={styles.loader}/>;
|
|
136
136
|
}
|
|
137
137
|
return '';
|
|
138
138
|
}
|
|
@@ -140,23 +140,21 @@ export default class Alert extends PureComponent {
|
|
|
140
140
|
this.node = node;
|
|
141
141
|
};
|
|
142
142
|
render() {
|
|
143
|
-
const { type, inline, isClosing, isShaking, closeButtonClassName, showWithAnimation, className, 'data-test': dataTest, theme } = this.props;
|
|
143
|
+
const { type, inline, isClosing, isShaking, closeButtonClassName, showWithAnimation, className, 'data-test': dataTest, theme, } = this.props;
|
|
144
144
|
const classes = classNames(className, {
|
|
145
145
|
[styles.alert]: true,
|
|
146
146
|
[styles.animationOpen]: showWithAnimation,
|
|
147
147
|
[styles.error]: type === 'error',
|
|
148
148
|
[styles.alertInline]: inline,
|
|
149
149
|
[styles.animationClosing]: isClosing,
|
|
150
|
-
[styles.animationShaking]: isShaking
|
|
150
|
+
[styles.animationShaking]: isShaking,
|
|
151
151
|
});
|
|
152
152
|
const height = this.state.height;
|
|
153
153
|
const style = height ? { marginBottom: -height } : undefined;
|
|
154
154
|
return (<ThemeProvider theme={theme} className={classes} data-test={dataTests('alert', dataTest)} data-test-type={type} style={style} ref={this.storeAlertRef}>
|
|
155
155
|
{this._getIcon()}
|
|
156
156
|
{this._getCaption()}
|
|
157
|
-
{this.props.closeable
|
|
158
|
-
? (<Button icon={closeIcon} className={classNames(styles.close, closeButtonClassName)} data-test="alert-close" aria-label="close alert" onClick={this.closeRequest}/>)
|
|
159
|
-
: ''}
|
|
157
|
+
{this.props.closeable ? (<Button icon={closeIcon} className={classNames(styles.close, closeButtonClassName)} data-test="alert-close" aria-label="close alert" onClick={this.closeRequest}/>) : ('')}
|
|
160
158
|
</ThemeProvider>);
|
|
161
159
|
}
|
|
162
160
|
}
|
|
@@ -17,7 +17,7 @@ export default class Alerts extends PureComponent {
|
|
|
17
17
|
}
|
|
18
18
|
const alertClassNames = classNames(styles.alertInContainer, child.props.className);
|
|
19
19
|
return cloneElement(child, {
|
|
20
|
-
className: alertClassNames
|
|
20
|
+
className: alertClassNames,
|
|
21
21
|
});
|
|
22
22
|
})}
|
|
23
23
|
</div>, document.body);
|
|
@@ -20,7 +20,9 @@ class AlertService {
|
|
|
20
20
|
return (<AlertContainer>
|
|
21
21
|
{alerts.map(alert => {
|
|
22
22
|
const { message, key, ...rest } = alert;
|
|
23
|
-
return (<Alert key={key} {...rest}>
|
|
23
|
+
return (<Alert key={key} {...rest}>
|
|
24
|
+
{message}
|
|
25
|
+
</Alert>);
|
|
24
26
|
})}
|
|
25
27
|
</AlertContainer>);
|
|
26
28
|
}
|
|
@@ -78,7 +80,7 @@ class AlertService {
|
|
|
78
80
|
onClose?.();
|
|
79
81
|
this.removeWithoutAnimation(alert.key);
|
|
80
82
|
},
|
|
81
|
-
...restOptions
|
|
83
|
+
...restOptions,
|
|
82
84
|
};
|
|
83
85
|
this.showingAlerts = [alert, ...this.showingAlerts];
|
|
84
86
|
this.renderAlerts();
|
package/components/auth/auth.js
CHANGED
|
@@ -36,7 +36,7 @@ import Auth from './auth__core';
|
|
|
36
36
|
Auth.DEFAULT_CONFIG = {
|
|
37
37
|
...Auth.DEFAULT_CONFIG,
|
|
38
38
|
EmbeddedLoginFlow: WindowFlow,
|
|
39
|
-
onBackendDown: defaultOnBackendDown
|
|
39
|
+
onBackendDown: defaultOnBackendDown,
|
|
40
40
|
};
|
|
41
41
|
export * from './auth__core';
|
|
42
42
|
export default Auth;
|
|
@@ -43,7 +43,7 @@ const DEFAULT_CONFIG = {
|
|
|
43
43
|
onBackendDown: () => () => { },
|
|
44
44
|
defaultExpiresIn: DEFAULT_EXPIRES_TIMEOUT,
|
|
45
45
|
waitForRedirectTimeout: DEFAULT_WAIT_FOR_REDIRECT_TIMEOUT,
|
|
46
|
-
translations: null
|
|
46
|
+
translations: null,
|
|
47
47
|
};
|
|
48
48
|
export default class Auth {
|
|
49
49
|
static DEFAULT_CONFIG = DEFAULT_CONFIG;
|
|
@@ -76,7 +76,7 @@ export default class Auth {
|
|
|
76
76
|
throw new Error('Config is required');
|
|
77
77
|
}
|
|
78
78
|
if (config.serverUri == null) {
|
|
79
|
-
throw new Error('
|
|
79
|
+
throw new Error('"serverUri" property is required');
|
|
80
80
|
}
|
|
81
81
|
const unsupportedParams = ['redirect_uri', 'request_credentials', 'client_id'].filter(param => config.hasOwnProperty(param));
|
|
82
82
|
if (unsupportedParams.length !== 0) {
|
|
@@ -91,8 +91,8 @@ export default class Auth {
|
|
|
91
91
|
}
|
|
92
92
|
this.config.userParams = {
|
|
93
93
|
query: {
|
|
94
|
-
fields: [...new Set(Auth.DEFAULT_CONFIG.userFields.concat(config.userFields))].join()
|
|
95
|
-
}
|
|
94
|
+
fields: [...new Set(Auth.DEFAULT_CONFIG.userFields.concat(config.userFields))].join(),
|
|
95
|
+
},
|
|
96
96
|
};
|
|
97
97
|
if (!scope.includes(Auth.DEFAULT_CONFIG.clientId)) {
|
|
98
98
|
scope.push(Auth.DEFAULT_CONFIG.clientId);
|
|
@@ -101,7 +101,7 @@ export default class Auth {
|
|
|
101
101
|
messagePrefix: `${clientId}-message-`,
|
|
102
102
|
stateKeyPrefix: `${clientId}-states-`,
|
|
103
103
|
tokenKey: `${clientId}-token`,
|
|
104
|
-
userKey: `${clientId}-user
|
|
104
|
+
userKey: `${clientId}-user-`,
|
|
105
105
|
});
|
|
106
106
|
this._domainStorage = new AuthStorage({ messagePrefix: 'domain-message-' });
|
|
107
107
|
this._requestBuilder = new AuthRequestBuilder({
|
|
@@ -110,22 +110,18 @@ export default class Auth {
|
|
|
110
110
|
redirect,
|
|
111
111
|
redirectUri,
|
|
112
112
|
requestCredentials,
|
|
113
|
-
scopes: scope
|
|
113
|
+
scopes: scope,
|
|
114
114
|
}, this._storage);
|
|
115
115
|
let { backgroundRefreshTimeout } = this.config;
|
|
116
116
|
if (!backgroundRefreshTimeout) {
|
|
117
|
-
backgroundRefreshTimeout = this.config.embeddedLogin
|
|
118
|
-
? DEFAULT_BACKGROUND_TIMEOUT
|
|
119
|
-
: BACKGROUND_REDIRECT_TIMEOUT;
|
|
117
|
+
backgroundRefreshTimeout = this.config.embeddedLogin ? DEFAULT_BACKGROUND_TIMEOUT : BACKGROUND_REDIRECT_TIMEOUT;
|
|
120
118
|
}
|
|
121
119
|
this._backgroundFlow = new BackgroundFlow(this._requestBuilder, this._storage, backgroundRefreshTimeout);
|
|
122
120
|
if (this.config.EmbeddedLoginFlow) {
|
|
123
121
|
this._embeddedFlow = new this.config.EmbeddedLoginFlow(this._requestBuilder, this._storage, this.config.translations ?? getTranslationsWithFallback());
|
|
124
122
|
}
|
|
125
123
|
const API_BASE = this.config.serverUri + Auth.API_PATH;
|
|
126
|
-
const fetchConfig = config.fetchCredentials
|
|
127
|
-
? { credentials: config.fetchCredentials }
|
|
128
|
-
: undefined;
|
|
124
|
+
const fetchConfig = config.fetchCredentials ? { credentials: config.fetchCredentials } : undefined;
|
|
129
125
|
this.http = new HTTP(this, API_BASE, fetchConfig);
|
|
130
126
|
const getUser = async (token) => {
|
|
131
127
|
const user = await this.getUser(token);
|
|
@@ -163,7 +159,7 @@ export default class Auth {
|
|
|
163
159
|
_updateDomainUser(userID) {
|
|
164
160
|
this._domainStorage.sendMessage(DOMAIN_USER_CHANGED_EVENT, {
|
|
165
161
|
userID,
|
|
166
|
-
serviceID: this.config.clientId
|
|
162
|
+
serviceID: this.config.clientId,
|
|
167
163
|
});
|
|
168
164
|
}
|
|
169
165
|
addListener(event, handler) {
|
|
@@ -333,7 +329,7 @@ export default class Auth {
|
|
|
333
329
|
if (Auth.storageIsUnavailable) {
|
|
334
330
|
return null; // Forever guest if storage is unavailable
|
|
335
331
|
}
|
|
336
|
-
return await this._tokenValidator?.validateTokenLocally() ?? null;
|
|
332
|
+
return (await this._tokenValidator?.validateTokenLocally()) ?? null;
|
|
337
333
|
}
|
|
338
334
|
catch (e) {
|
|
339
335
|
return this.forceTokenUpdate();
|
|
@@ -357,7 +353,7 @@ export default class Auth {
|
|
|
357
353
|
this._backendCheckPromise = null;
|
|
358
354
|
}
|
|
359
355
|
try {
|
|
360
|
-
return await this._backgroundFlow?.authorize() ?? null;
|
|
356
|
+
return (await this._backgroundFlow?.authorize()) ?? null;
|
|
361
357
|
}
|
|
362
358
|
catch (error) {
|
|
363
359
|
if (!(error instanceof Error)) {
|
|
@@ -375,7 +371,7 @@ export default class Auth {
|
|
|
375
371
|
this._showAuthDialog({
|
|
376
372
|
nonInteractive: true,
|
|
377
373
|
error: retryError,
|
|
378
|
-
onTryAgain
|
|
374
|
+
onTryAgain,
|
|
379
375
|
});
|
|
380
376
|
}
|
|
381
377
|
throw retryError;
|
|
@@ -384,7 +380,7 @@ export default class Auth {
|
|
|
384
380
|
this._showAuthDialog({
|
|
385
381
|
nonInteractive: true,
|
|
386
382
|
error: error,
|
|
387
|
-
onTryAgain
|
|
383
|
+
onTryAgain,
|
|
388
384
|
});
|
|
389
385
|
});
|
|
390
386
|
}
|
|
@@ -402,7 +398,7 @@ export default class Auth {
|
|
|
402
398
|
return;
|
|
403
399
|
}
|
|
404
400
|
try {
|
|
405
|
-
const { serviceName, iconUrl: serviceImage } = await this.http.get(`oauth2/interactive/login/settings?client_id=${this.config.clientId}`) || {};
|
|
401
|
+
const { serviceName, iconUrl: serviceImage } = (await this.http.get(`oauth2/interactive/login/settings?client_id=${this.config.clientId}`)) || {};
|
|
406
402
|
this.setCurrentService({ serviceImage, serviceName });
|
|
407
403
|
}
|
|
408
404
|
catch (e) {
|
|
@@ -469,7 +465,7 @@ export default class Auth {
|
|
|
469
465
|
onPostpone: () => {
|
|
470
466
|
this.listeners.trigger(USER_CHANGE_POSTPONED_EVENT);
|
|
471
467
|
this.config.onPostponeChangedUser(this.user, user);
|
|
472
|
-
}
|
|
468
|
+
},
|
|
473
469
|
});
|
|
474
470
|
}
|
|
475
471
|
}
|
|
@@ -531,7 +527,7 @@ export default class Auth {
|
|
|
531
527
|
errorMessage: this._extractErrorMessage(error, true),
|
|
532
528
|
onConfirm,
|
|
533
529
|
onCancel,
|
|
534
|
-
onTryAgain: onTryAgain ? onTryAgainClick : undefined
|
|
530
|
+
onTryAgain: onTryAgain ? onTryAgainClick : undefined,
|
|
535
531
|
});
|
|
536
532
|
const stopTokenListening = this._storage?.onTokenChange(token => {
|
|
537
533
|
if (token) {
|
|
@@ -551,9 +547,10 @@ export default class Auth {
|
|
|
551
547
|
};
|
|
552
548
|
const hide = this._authDialogService?.({
|
|
553
549
|
...this._service,
|
|
554
|
-
title: translations?.youHaveLoggedInAs ??
|
|
555
|
-
|
|
556
|
-
|
|
550
|
+
title: translations?.youHaveLoggedInAs ??
|
|
551
|
+
translate('youHaveLoggedInAs')
|
|
552
|
+
.replace('%userName%', newUser.name ?? '')
|
|
553
|
+
.replace('{{userName}}', newUser.name ?? ''),
|
|
557
554
|
loginCaption: translations?.login ?? translate('login'),
|
|
558
555
|
loginToCaption: translations?.loginTo ?? translate('loginTo'),
|
|
559
556
|
confirmLabel: translations?.applyChange ?? translate('applyChange'),
|
|
@@ -566,7 +563,7 @@ export default class Auth {
|
|
|
566
563
|
onCancel: () => {
|
|
567
564
|
done();
|
|
568
565
|
onPostpone();
|
|
569
|
-
}
|
|
566
|
+
},
|
|
570
567
|
});
|
|
571
568
|
}
|
|
572
569
|
_extractErrorMessage(error, logError = false) {
|
|
@@ -580,7 +577,11 @@ export default class Auth {
|
|
|
580
577
|
try {
|
|
581
578
|
// We've got some error from this list
|
|
582
579
|
// https://www.jetbrains.com/help/youtrack/devportal/OAuth-2.0-Errors.html
|
|
583
|
-
if ('code' in error &&
|
|
580
|
+
if ('code' in error &&
|
|
581
|
+
error.code &&
|
|
582
|
+
typeof error.code === 'object' &&
|
|
583
|
+
'code' in error.code &&
|
|
584
|
+
typeof error.code.code === 'string') {
|
|
584
585
|
const readableCode = error.code.code.split('_').join(' ');
|
|
585
586
|
return `Authorization error: ${readableCode}`;
|
|
586
587
|
}
|
|
@@ -619,8 +620,10 @@ export default class Auth {
|
|
|
619
620
|
reject(new Error('Auth(@jetbrains/ring-ui): postponed by user'));
|
|
620
621
|
};
|
|
621
622
|
const hide = onBackendDown({
|
|
622
|
-
onCheckAgain,
|
|
623
|
-
|
|
623
|
+
onCheckAgain,
|
|
624
|
+
onPostpone,
|
|
625
|
+
backendError,
|
|
626
|
+
translations: translations ?? getTranslationsWithFallback(),
|
|
624
627
|
});
|
|
625
628
|
window.addEventListener('online', onCheckAgain);
|
|
626
629
|
function networkWatchdog() {
|
|
@@ -639,7 +642,7 @@ export default class Auth {
|
|
|
639
642
|
const requestParams = {
|
|
640
643
|
// eslint-disable-next-line camelcase
|
|
641
644
|
request_credentials: 'required',
|
|
642
|
-
...extraParams
|
|
645
|
+
...extraParams,
|
|
643
646
|
};
|
|
644
647
|
await this._checkBackendsStatusesIfEnabled();
|
|
645
648
|
await this.listeners.trigger('logout');
|
|
@@ -713,7 +716,7 @@ export default class Auth {
|
|
|
713
716
|
return {
|
|
714
717
|
restoreLocation: state,
|
|
715
718
|
created: Date.now(),
|
|
716
|
-
scopes: defaultScope
|
|
719
|
+
scopes: defaultScope,
|
|
717
720
|
};
|
|
718
721
|
}
|
|
719
722
|
/**
|
|
@@ -759,7 +762,7 @@ export default class Auth {
|
|
|
759
762
|
this.setHash('');
|
|
760
763
|
}
|
|
761
764
|
const stateId = authResponse?.restoreAuthState;
|
|
762
|
-
return await (stateId && this._storage?.getState(stateId)) || {};
|
|
765
|
+
return (await (stateId && this._storage?.getState(stateId))) || {};
|
|
763
766
|
}
|
|
764
767
|
_checkBackendsAreUp() {
|
|
765
768
|
const abortCtrl = new AbortController();
|
|
@@ -767,9 +770,9 @@ export default class Auth {
|
|
|
767
770
|
return Promise.all([
|
|
768
771
|
promiseWithTimeout(this.http.fetch('settings/public?fields=id', { signal: abortCtrl.signal }), backendCheckTimeout, {
|
|
769
772
|
error: new Error('The authorization server is taking too long to respond. Please try again later.'),
|
|
770
|
-
onTimeout: () => abortCtrl.abort()
|
|
773
|
+
onTimeout: () => abortCtrl.abort(),
|
|
771
774
|
}),
|
|
772
|
-
this.config.checkBackendIsUp()
|
|
775
|
+
this.config.checkBackendIsUp(),
|
|
773
776
|
]).catch(err => {
|
|
774
777
|
if (err instanceof TypeError) {
|
|
775
778
|
throw new TypeError('Could not connect to the server due to network error. Please check your connection and try again.');
|
|
@@ -832,10 +835,7 @@ export default class Auth {
|
|
|
832
835
|
// a record in history.
|
|
833
836
|
// NB! URL to redirect is formed manually because baseURI could be messed up,
|
|
834
837
|
// in which case it's not obvious where redirect will lead.
|
|
835
|
-
const cleanedUrl = [
|
|
836
|
-
window.location.pathname,
|
|
837
|
-
window.location.search
|
|
838
|
-
].join('');
|
|
838
|
+
const cleanedUrl = [window.location.pathname, window.location.search].join('');
|
|
839
839
|
const hashIfExist = hash ? `#${hash}` : '';
|
|
840
840
|
history.replaceState(undefined, '', `${cleanedUrl}${hashIfExist}`);
|
|
841
841
|
}
|
|
@@ -40,9 +40,9 @@ export default class BackgroundFlow {
|
|
|
40
40
|
* promise is rejected if no token was received after {@link BackgroundToken.BACKGROUND_TIMEOUT} ms.
|
|
41
41
|
*/
|
|
42
42
|
async _load() {
|
|
43
|
-
const authRequest = await this._requestBuilder
|
|
43
|
+
const authRequest = await this._requestBuilder
|
|
44
44
|
// eslint-disable-next-line camelcase
|
|
45
|
-
prepareAuthRequest({ request_credentials: 'silent' }, { nonRedirect: true });
|
|
45
|
+
.prepareAuthRequest({ request_credentials: 'silent' }, { nonRedirect: true });
|
|
46
46
|
return new Promise((resolve, reject) => {
|
|
47
47
|
function onMessage(e) {
|
|
48
48
|
if (e.data === HUB_AUTH_PAGE_OPENED) {
|
|
@@ -23,7 +23,9 @@ function Message({ translations, onCheckAgain }) {
|
|
|
23
23
|
<div className={styles.title}>{backendIsNotAvailable}</div>
|
|
24
24
|
</Group>
|
|
25
25
|
<span className={styles.error}>{errorMessage} </span>
|
|
26
|
-
<Link onClick={onCheckAgain} data-test="check-again">
|
|
26
|
+
<Link onClick={onCheckAgain} data-test="check-again">
|
|
27
|
+
{checkAgain}
|
|
28
|
+
</Link>
|
|
27
29
|
</div>);
|
|
28
30
|
}
|
|
29
31
|
export default function onBackendDown({ onCheckAgain, translations }) {
|
|
@@ -22,7 +22,9 @@ export default class IFrameFlow {
|
|
|
22
22
|
const authRequest = await this._requestBuilder.prepareAuthRequest(
|
|
23
23
|
// eslint-disable-next-line camelcase
|
|
24
24
|
{ request_credentials: 'required', auth_mode: 'bypass_to_login' }, { nonRedirect: false });
|
|
25
|
-
const renderFallbackLink = () => (<Link href={authRequest.url} target="_self">
|
|
25
|
+
const renderFallbackLink = () => (<Link href={authRequest.url} target="_self">
|
|
26
|
+
{this._translations.nothingHappensLink}
|
|
27
|
+
</Link>);
|
|
26
28
|
return new Promise((resolve, reject) => {
|
|
27
29
|
this.hideDialog = loginDialogService({
|
|
28
30
|
url: authRequest.url,
|
|
@@ -32,7 +34,7 @@ export default class IFrameFlow {
|
|
|
32
34
|
cleanUp();
|
|
33
35
|
this.stop();
|
|
34
36
|
},
|
|
35
|
-
renderFallbackLink
|
|
37
|
+
renderFallbackLink,
|
|
36
38
|
});
|
|
37
39
|
this.reject = reject;
|
|
38
40
|
const removeTokenListener = this._storage.onTokenChange(token => {
|
|
@@ -38,19 +38,19 @@ export default class AuthRequestBuilder {
|
|
|
38
38
|
redirect_uri: this.config.redirectUri,
|
|
39
39
|
request_credentials: this.config.requestCredentials,
|
|
40
40
|
client_id: this.config.clientId,
|
|
41
|
-
scope: scopes.join(' ')
|
|
41
|
+
scope: scopes.join(' '),
|
|
42
42
|
}, extraParams || {});
|
|
43
43
|
/* eslint-enable camelcase */
|
|
44
44
|
const authURL = encodeURL(this.config.authorization, request);
|
|
45
45
|
const state = Object.assign({
|
|
46
46
|
restoreLocation: window.location.href,
|
|
47
|
-
scopes: this.config.scopes
|
|
47
|
+
scopes: this.config.scopes,
|
|
48
48
|
}, extraState || {});
|
|
49
49
|
await this._saveState(stateId, state);
|
|
50
|
-
return
|
|
50
|
+
return {
|
|
51
51
|
url: authURL,
|
|
52
|
-
stateId
|
|
53
|
-
}
|
|
52
|
+
stateId,
|
|
53
|
+
};
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
56
|
* @param {string} id
|
|
@@ -41,16 +41,16 @@ export default class AuthStorage {
|
|
|
41
41
|
const StorageConstructor = config.storage || Storage;
|
|
42
42
|
this.stateQuota = config.stateQuota || DEFAULT_STATE_QUOTA;
|
|
43
43
|
this._stateStorage = new StorageConstructor({
|
|
44
|
-
cookieName: 'ring-state'
|
|
44
|
+
cookieName: 'ring-state',
|
|
45
45
|
});
|
|
46
46
|
this._tokenStorage = new StorageConstructor({
|
|
47
|
-
cookieName: 'ring-token'
|
|
47
|
+
cookieName: 'ring-token',
|
|
48
48
|
});
|
|
49
49
|
this._messagesStorage = new StorageConstructor({
|
|
50
|
-
cookieName: 'ring-message'
|
|
50
|
+
cookieName: 'ring-message',
|
|
51
51
|
});
|
|
52
52
|
this._currentUserStorage = new StorageConstructor({
|
|
53
|
-
cookieName: 'ring-user'
|
|
53
|
+
cookieName: 'ring-user',
|
|
54
54
|
});
|
|
55
55
|
}
|
|
56
56
|
/**
|
|
@@ -132,23 +132,24 @@ export default class AuthStorage {
|
|
|
132
132
|
return {
|
|
133
133
|
key,
|
|
134
134
|
created,
|
|
135
|
-
size: JSON.stringify(state).length
|
|
135
|
+
size: JSON.stringify(state).length,
|
|
136
136
|
};
|
|
137
137
|
}
|
|
138
138
|
return undefined;
|
|
139
139
|
});
|
|
140
140
|
const currentStates = removalResult.filter((state) => state != null);
|
|
141
|
-
let stateStorageSize = currentStates.
|
|
142
|
-
reduce((overallSize, state) => state.size + overallSize, 0);
|
|
141
|
+
let stateStorageSize = currentStates.reduce((overallSize, state) => state.size + overallSize, 0);
|
|
143
142
|
if (stateStorageSize > this.stateQuota) {
|
|
144
143
|
currentStates.sort((a, b) => a.created - b.created);
|
|
145
|
-
const removalPromises = currentStates
|
|
144
|
+
const removalPromises = currentStates
|
|
145
|
+
.filter(state => {
|
|
146
146
|
if (stateStorageSize > this.stateQuota) {
|
|
147
147
|
stateStorageSize -= state.size;
|
|
148
148
|
return true;
|
|
149
149
|
}
|
|
150
150
|
return false;
|
|
151
|
-
})
|
|
151
|
+
})
|
|
152
|
+
.map(state => this._stateStorage.remove(state.key));
|
|
152
153
|
return removalPromises.length && Promise.all(removalPromises);
|
|
153
154
|
}
|
|
154
155
|
return undefined;
|
|
@@ -48,7 +48,7 @@ export default class TokenValidator {
|
|
|
48
48
|
return this._getValidatedToken([
|
|
49
49
|
TokenValidator._validateExistence,
|
|
50
50
|
TokenValidator._validateExpiration,
|
|
51
|
-
this._validateScopes.bind(this)
|
|
51
|
+
this._validateScopes.bind(this),
|
|
52
52
|
]);
|
|
53
53
|
}
|
|
54
54
|
/**
|
|
@@ -60,7 +60,7 @@ export default class TokenValidator {
|
|
|
60
60
|
TokenValidator._validateExistence,
|
|
61
61
|
TokenValidator._validateExpiration,
|
|
62
62
|
this._validateScopes.bind(this),
|
|
63
|
-
this._validateAgainstUser.bind(this)
|
|
63
|
+
this._validateAgainstUser.bind(this),
|
|
64
64
|
]);
|
|
65
65
|
}
|
|
66
66
|
/**
|
|
@@ -82,10 +82,8 @@ export default class TokenValidator {
|
|
|
82
82
|
*/
|
|
83
83
|
static _validateExpiration({ expires, lifeTime }) {
|
|
84
84
|
const REFRESH_BEFORE_RATIO = 6;
|
|
85
|
-
const refreshBefore = lifeTime
|
|
86
|
-
|
|
87
|
-
: TokenValidator.DEFAULT_REFRESH_BEFORE;
|
|
88
|
-
if (expires && expires < (TokenValidator._epoch() + refreshBefore)) {
|
|
85
|
+
const refreshBefore = lifeTime ? Math.ceil(lifeTime / REFRESH_BEFORE_RATIO) : TokenValidator.DEFAULT_REFRESH_BEFORE;
|
|
86
|
+
if (expires && expires < TokenValidator._epoch() + refreshBefore) {
|
|
89
87
|
throw new TokenValidator.TokenValidationError('Token expired');
|
|
90
88
|
}
|
|
91
89
|
}
|
|
@@ -97,12 +95,10 @@ export default class TokenValidator {
|
|
|
97
95
|
*/
|
|
98
96
|
_validateScopes(storedToken) {
|
|
99
97
|
const { scope, optionalScopes } = this._config;
|
|
100
|
-
const requiredScopes = optionalScopes
|
|
101
|
-
? scope.filter(scopeId => !optionalScopes.includes(scopeId))
|
|
102
|
-
: scope;
|
|
98
|
+
const requiredScopes = optionalScopes ? scope.filter(scopeId => !optionalScopes.includes(scopeId)) : scope;
|
|
103
99
|
const hasAllScopes = requiredScopes.every(scopeId => storedToken.scopes?.includes(scopeId));
|
|
104
100
|
if (!hasAllScopes) {
|
|
105
|
-
throw new TokenValidator.TokenValidationError(
|
|
101
|
+
throw new TokenValidator.TokenValidationError("Token doesn't match required scopes");
|
|
106
102
|
}
|
|
107
103
|
}
|
|
108
104
|
/**
|
|
@@ -111,9 +107,7 @@ export default class TokenValidator {
|
|
|
111
107
|
* @return {boolean}
|
|
112
108
|
*/
|
|
113
109
|
static shouldRefreshToken(error) {
|
|
114
|
-
return error === 'invalid_grant' ||
|
|
115
|
-
error === 'invalid_request' ||
|
|
116
|
-
error === 'invalid_token';
|
|
110
|
+
return error === 'invalid_grant' || error === 'invalid_request' || error === 'invalid_token';
|
|
117
111
|
}
|
|
118
112
|
/**
|
|
119
113
|
* Check scopes
|
|
@@ -134,8 +128,7 @@ export default class TokenValidator {
|
|
|
134
128
|
catch (e) {
|
|
135
129
|
// Skip JSON parsing errors
|
|
136
130
|
}
|
|
137
|
-
if (errorResponse.status === CODE.UNAUTHORIZED ||
|
|
138
|
-
TokenValidator.shouldRefreshToken(response.error)) {
|
|
131
|
+
if (errorResponse.status === CODE.UNAUTHORIZED || TokenValidator.shouldRefreshToken(response.error)) {
|
|
139
132
|
// Token expired
|
|
140
133
|
throw new TokenValidator.TokenValidationError(response.error || errorResponse.message, errorResponse.data?.error ? new Error(errorResponse.data?.error) : undefined);
|
|
141
134
|
}
|