@jetbrains/ring-ui-built 8.0.0-beta.4 → 8.0.0-beta.5

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.
Files changed (65) hide show
  1. package/components/_helpers/alert.js +3 -0
  2. package/components/_helpers/caption.js +1 -1
  3. package/components/_helpers/header.js +1 -1
  4. package/components/_helpers/table.js +1 -1
  5. package/components/alert/alert-actions.d.ts +4 -0
  6. package/components/alert/alert-actions.js +51 -0
  7. package/components/alert/alert-heading.d.ts +4 -0
  8. package/components/alert/alert-heading.js +62 -0
  9. package/components/alert/alert.d.ts +14 -1
  10. package/components/alert/alert.js +43 -25
  11. package/components/alert-service/alert-service.d.ts +2 -1
  12. package/components/alert-service/alert-service.js +15 -5
  13. package/components/auth/auth-core.d.ts +5 -9
  14. package/components/auth/auth-core.js +71 -17
  15. package/components/auth/auth.js +7 -1
  16. package/components/auth/down-notification.js +7 -1
  17. package/components/auth/storage.js +7 -1
  18. package/components/clipboard/clipboard.js +7 -1
  19. package/components/date-picker/consts.d.ts +1 -0
  20. package/components/date-picker/date-input.js +3 -2
  21. package/components/header/header.js +7 -1
  22. package/components/header/smart-profile.js +7 -1
  23. package/components/http/http.d.ts +2 -2
  24. package/components/http/http.js +2 -2
  25. package/components/i18n/i18n.d.ts +1 -0
  26. package/components/i18n/i18n.js +2 -0
  27. package/components/internal/reorder-animation-context.js +159 -0
  28. package/components/internal/reorder-handle.js +750 -0
  29. package/components/internal/reorder-layout-context.js +141 -0
  30. package/components/internal/table-header.js +221 -645
  31. package/components/internal/{virtual-items.js → virtualization.js} +29 -14
  32. package/components/old-browsers-message/white-list.js +2 -2
  33. package/components/storage/storage-local.js +7 -1
  34. package/components/storage/storage.js +7 -1
  35. package/components/style.css +1 -1
  36. package/components/table/default-item-renderer.d.ts +7 -1
  37. package/components/table/default-item-renderer.js +119 -67
  38. package/components/table/internal/reorder-animation-context.d.ts +21 -0
  39. package/components/table/internal/reorder-handle.d.ts +9 -0
  40. package/components/table/internal/reorder-layout-context.d.ts +16 -0
  41. package/components/table/internal/table-header.d.ts +1 -4
  42. package/components/table/internal/{virtual-items.d.ts → virtualization.d.ts} +10 -3
  43. package/components/table/item-virtualization.d.ts +5 -3
  44. package/components/table/item-virtualization.js +13 -11
  45. package/components/table/reorder-animation.d.ts +37 -0
  46. package/components/table/reorder-animation.js +18 -0
  47. package/components/table/reorder-item-layout.d.ts +32 -0
  48. package/components/table/reorder-item-layout.js +57 -0
  49. package/components/table/table-const.d.ts +0 -32
  50. package/components/table/table-const.js +1 -8
  51. package/components/table/table-primitives.d.ts +43 -0
  52. package/components/table/table-primitives.js +62 -5
  53. package/components/table/table-props.d.ts +29 -5
  54. package/components/table/table.d.ts +31 -5
  55. package/components/table/table.js +177 -170
  56. package/components/user-agreement/service.js +7 -1
  57. package/components/user-card/card.js +7 -1
  58. package/components/user-card/smart-user-card-tooltip.d.ts +1 -1
  59. package/components/user-card/smart-user-card-tooltip.js +7 -1
  60. package/components/user-card/tooltip.js +7 -1
  61. package/components/user-card/user-card.js +7 -1
  62. package/components/util-stories.d.ts +2 -2
  63. package/package.json +2 -2
  64. package/components/internal/column-animation.js +0 -133
  65. package/components/table/internal/column-animation.d.ts +0 -16
@@ -0,0 +1,3 @@
1
+ var styles = {"alert":"ring-alert-alert","alertInline":"ring-alert-alertInline","error":"ring-alert-error","icon":"ring-alert-icon","success":"ring-alert-success","warning":"ring-alert-warning","info":"ring-alert-info","caption":"ring-alert-caption","afterMessage":"ring-alert-afterMessage","badge":"ring-alert-badge","loader":"ring-alert-loader","close":"ring-alert-close","animationOpen":"ring-alert-animationOpen","show":"ring-alert-show","animationClosing":"ring-alert-animationClosing","animationShaking":"ring-alert-animationShaking","shaking":"ring-alert-shaking","heading":"ring-alert-heading","actions":"ring-alert-actions"};
2
+
3
+ export { styles as s };
@@ -2,7 +2,7 @@ import { PureComponent } from 'react';
2
2
  import classNames from 'classnames';
3
3
  import { jsx } from 'react/jsx-runtime';
4
4
 
5
- var styles = {"button":"ring-button-button","active":"ring-button-active","flat":"ring-button-flat","buttonGroup":"ring-button-group-buttonGroup ring-button-group-common ring-button-toolbar-buttonGroup","common":"ring-button-group-common","disabled":"ring-button-group-disabled","split":"ring-button-group-split ring-button-group-common ring-button-toolbar-buttonGroup","caption":"ring-button-group-caption ring-global-font","help":"ring-button-group-help"};
5
+ var styles = {"button":"ring-button-button","buttonActive":"ring-button-active","flat":"ring-button-flat","buttonGroup":"ring-button-group-buttonGroup ring-button-group-common ring-button-toolbar-buttonGroup","common":"ring-button-group-common","disabled":"ring-button-group-disabled","split":"ring-button-group-split ring-button-group-common ring-button-toolbar-buttonGroup","caption":"ring-button-group-caption ring-global-font","help":"ring-button-group-help"};
6
6
 
7
7
  class Caption extends PureComponent {
8
8
  render() {
@@ -1,3 +1,3 @@
1
- var styles = {"link":"ring-link-link","active":"ring-link-active","header":"ring-header-header","headerSpaced":"ring-header-headerSpaced","headerVertical":"ring-header-headerVertical","logo":"ring-header-logo","links":"ring-header-links","tray":"ring-header-tray","trayItemContent":"ring-header-trayItemContent","icon":"ring-header-icon","main":"ring-header-main","rotatable":"ring-header-rotatable","rotated":"ring-header-rotated","profileEmpty":"ring-header-profileEmpty","profile":"ring-header-profile ring-header-profileEmpty","anchorClassName":"ring-header-anchorClassName ring-global-resetButton","avatarWrapper":"ring-header-avatarWrapper","hasUpdates":"ring-header-hasUpdates"};
1
+ var styles = {"link":"ring-link-link","linkActive":"ring-link-active","header":"ring-header-header","headerSpaced":"ring-header-headerSpaced","headerVertical":"ring-header-headerVertical","logo":"ring-header-logo","links":"ring-header-links","tray":"ring-header-tray","trayItemContent":"ring-header-trayItemContent","icon":"ring-header-icon","main":"ring-header-main","rotatable":"ring-header-rotatable","rotated":"ring-header-rotated","profileEmpty":"ring-header-profileEmpty","profile":"ring-header-profile ring-header-profileEmpty","anchorClassName":"ring-header-anchorClassName ring-global-resetButton","avatarWrapper":"ring-header-avatarWrapper","hasUpdates":"ring-header-hasUpdates"};
2
2
 
3
3
  export { styles as s };
@@ -1,3 +1,3 @@
1
- var styles = {"headerCell":"ring-table-headerCell","columnReorderHandleMirror":"ring-table-columnReorderHandleMirror","columnReorderHandle":"ring-table-columnReorderHandle","table":"ring-table-table","stickyHeader":"ring-table-stickyHeader","animatedColumnInitial":"ring-table-animatedColumnInitial","animatedColumnFadeOut":"ring-table-animatedColumnFadeOut","headerCellInnerWrapper":"ring-table-headerCellInnerWrapper","sortAndHeader":"ring-table-sortAndHeader","rightButtons":"ring-table-rightButtons","headerButton":"ring-table-headerButton","deleteColumnButton":"ring-table-deleteColumnButton","theadColumnEditing":"ring-table-theadColumnEditing","editColumnsButton":"ring-table-editColumnsButton","columnDragFrame":"ring-table-columnDragFrame","columnInsertionIndicator":"ring-table-columnInsertionIndicator","spacerRow":"ring-table-spacerRow","spacerCell":"ring-table-spacerCell","row":"ring-table-row","clickableRow":"ring-table-clickableRow","selectedRow":"ring-table-selectedRow","cell":"ring-table-cell"};
1
+ var styles = {"headerCell":"ring-table-headerCell","columnReorderHandleMirror":"ring-table-columnReorderHandleMirror","columnReorderHandle":"ring-table-columnReorderHandle","table":"ring-table-table","stickyHeader":"ring-table-stickyHeader","reorderAnimationInitial":"ring-table-reorderAnimationInitial","reorderAnimationFadeOut":"ring-table-reorderAnimationFadeOut","headerCellInnerWrapper":"ring-table-headerCellInnerWrapper","sortAndHeader":"ring-table-sortAndHeader","rightButtons":"ring-table-rightButtons","tableButton":"ring-table-tableButton","deleteColumnButton":"ring-table-deleteColumnButton","theadColumnEditing":"ring-table-theadColumnEditing","itemReorderHandle":"ring-table-itemReorderHandle","editColumnsButton":"ring-table-editColumnsButton","dragFrame":"ring-table-dragFrame","insertionIndicator":"ring-table-insertionIndicator","spacerRow":"ring-table-spacerRow","spacerCell":"ring-table-spacerCell","row":"ring-table-row","clickableRow":"ring-table-clickableRow","selectedRow":"ring-table-selectedRow","cell":"ring-table-cell"};
2
2
 
3
3
  export { styles as s };
@@ -0,0 +1,4 @@
1
+ import { type HTMLAttributes } from 'react';
2
+ export interface AlertActionsProps extends HTMLAttributes<HTMLDivElement> {
3
+ }
4
+ export default function AlertActions({ className, ...restProps }: AlertActionsProps): import("react").JSX.Element;
@@ -0,0 +1,51 @@
1
+ import { c } from 'react/compiler-runtime';
2
+ import classNames from 'classnames';
3
+ import { s as styles } from '../_helpers/alert.js';
4
+ import { jsx } from 'react/jsx-runtime';
5
+
6
+ function AlertActions(t0) {
7
+ const $ = c(9);
8
+ if ($[0] !== "f2bf4d74f62c680c534a1b2c09bbecda7a0be402ad8ff52746ab70baf15fa92d") {
9
+ for (let $i = 0; $i < 9; $i += 1) {
10
+ $[$i] = Symbol.for("react.memo_cache_sentinel");
11
+ }
12
+ $[0] = "f2bf4d74f62c680c534a1b2c09bbecda7a0be402ad8ff52746ab70baf15fa92d";
13
+ }
14
+ let className;
15
+ let restProps;
16
+ if ($[1] !== t0) {
17
+ ({
18
+ className,
19
+ ...restProps
20
+ } = t0);
21
+ $[1] = t0;
22
+ $[2] = className;
23
+ $[3] = restProps;
24
+ } else {
25
+ className = $[2];
26
+ restProps = $[3];
27
+ }
28
+ let t1;
29
+ if ($[4] !== className) {
30
+ t1 = classNames(styles.actions, className);
31
+ $[4] = className;
32
+ $[5] = t1;
33
+ } else {
34
+ t1 = $[5];
35
+ }
36
+ let t2;
37
+ if ($[6] !== restProps || $[7] !== t1) {
38
+ t2 = /*#__PURE__*/jsx("div", {
39
+ className: t1,
40
+ ...restProps
41
+ });
42
+ $[6] = restProps;
43
+ $[7] = t1;
44
+ $[8] = t2;
45
+ } else {
46
+ t2 = $[8];
47
+ }
48
+ return t2;
49
+ }
50
+
51
+ export { AlertActions as default };
@@ -0,0 +1,4 @@
1
+ import { type HeadingProps } from '../heading/heading';
2
+ export interface AlertHeadingProps extends HeadingProps {
3
+ }
4
+ export default function AlertHeading({ level, className, ...restProps }: AlertHeadingProps): import("react").JSX.Element;
@@ -0,0 +1,62 @@
1
+ import { c } from 'react/compiler-runtime';
2
+ import classNames from 'classnames';
3
+ import Heading, { Levels } from '../heading/heading.js';
4
+ import { s as styles } from '../_helpers/alert.js';
5
+ import { jsx } from 'react/jsx-runtime';
6
+ import 'react';
7
+ import 'util-deprecate';
8
+ import '../_helpers/heading.js';
9
+
10
+ function AlertHeading(t0) {
11
+ const $ = c(11);
12
+ if ($[0] !== "c9fca3356fdd95bbae28f3096eb908e999b2dc9dec9eca1a04791a4822d1dd43") {
13
+ for (let $i = 0; $i < 11; $i += 1) {
14
+ $[$i] = Symbol.for("react.memo_cache_sentinel");
15
+ }
16
+ $[0] = "c9fca3356fdd95bbae28f3096eb908e999b2dc9dec9eca1a04791a4822d1dd43";
17
+ }
18
+ let className;
19
+ let restProps;
20
+ let t1;
21
+ if ($[1] !== t0) {
22
+ ({
23
+ level: t1,
24
+ className,
25
+ ...restProps
26
+ } = t0);
27
+ $[1] = t0;
28
+ $[2] = className;
29
+ $[3] = restProps;
30
+ $[4] = t1;
31
+ } else {
32
+ className = $[2];
33
+ restProps = $[3];
34
+ t1 = $[4];
35
+ }
36
+ const level = t1 === undefined ? Levels.H3 : t1;
37
+ let t2;
38
+ if ($[5] !== className) {
39
+ t2 = classNames(styles.heading, className);
40
+ $[5] = className;
41
+ $[6] = t2;
42
+ } else {
43
+ t2 = $[6];
44
+ }
45
+ let t3;
46
+ if ($[7] !== level || $[8] !== restProps || $[9] !== t2) {
47
+ t3 = /*#__PURE__*/jsx(Heading, {
48
+ level: level,
49
+ className: t2,
50
+ ...restProps
51
+ });
52
+ $[7] = level;
53
+ $[8] = restProps;
54
+ $[9] = t2;
55
+ $[10] = t3;
56
+ } else {
57
+ t3 = $[10];
58
+ }
59
+ return t3;
60
+ }
61
+
62
+ export { AlertHeading as default };
@@ -1,6 +1,8 @@
1
1
  import { PureComponent, type ReactNode } from 'react';
2
2
  import * as React from 'react';
3
3
  import Theme from '../global/theme';
4
+ import AlertHeading from './alert-heading';
5
+ import AlertActions from './alert-actions';
4
6
  export declare const ANIMATION_TIME = 500;
5
7
  /**
6
8
  * @name Alert
@@ -14,8 +16,16 @@ export declare enum AlertType {
14
16
  MESSAGE = "message",
15
17
  SUCCESS = "success",
16
18
  WARNING = "warning",
17
- LOADING = "loading"
19
+ LOADING = "loading",
20
+ INFO = "info"
18
21
  }
22
+ /**
23
+ * Maps the values React renders as nothing (except empty arrays/fragments,
24
+ * which are not worth chasing here) to undefined, so that they neither create
25
+ * the afterMessage wrapper nor distinguish alerts in the alert-service
26
+ * duplicate check
27
+ */
28
+ export declare function normalizeAfterMessage(afterMessage: ReactNode): ReactNode;
19
29
  export interface AlertProps {
20
30
  theme: Theme;
21
31
  timeout: number;
@@ -39,6 +49,7 @@ export interface AlertProps {
39
49
  captionClassName?: string | null | undefined;
40
50
  closeButtonClassName?: string | null | undefined;
41
51
  'data-test'?: string | null | undefined;
52
+ afterMessage?: ReactNode;
42
53
  }
43
54
  interface State {
44
55
  height: number | null;
@@ -74,6 +85,8 @@ export default class Alert extends PureComponent<AlertProps, State> {
74
85
  node?: HTMLDivElement | null;
75
86
  hideTimeout?: number;
76
87
  static Type: typeof AlertType;
88
+ static Heading: typeof AlertHeading;
89
+ static Actions: typeof AlertActions;
77
90
  closeRequest: (event: React.MouseEvent<HTMLElement>) => void;
78
91
  startCloseAnimation: () => void;
79
92
  private _close;
@@ -1,8 +1,9 @@
1
1
  import { PureComponent } from 'react';
2
2
  import classNames from 'classnames';
3
3
  import exceptionIcon from '@jetbrains/icons/exception';
4
- import checkmarkIcon from '@jetbrains/icons/checkmark';
4
+ import successIcon from '@jetbrains/icons/success';
5
5
  import warningIcon from '@jetbrains/icons/warning';
6
+ import infoIcon from '@jetbrains/icons/info-filled';
6
7
  import closeIcon from '@jetbrains/icons/close';
7
8
  import Icon from '../icon/icon.js';
8
9
  import LoaderInline from '../loader-inline/loader-inline.js';
@@ -10,10 +11,13 @@ import { getRect } from '../global/dom.js';
10
11
  import joinDataTestAttributes from '../global/data-tests.js';
11
12
  import { Button } from '../button/button.js';
12
13
  import { T as Theme, a as ThemeProvider } from '../_helpers/theme.js';
14
+ import AlertHeading from './alert-heading.js';
15
+ import AlertActions from './alert-actions.js';
16
+ import { s as styles } from '../_helpers/alert.js';
13
17
  import { jsx, jsxs } from 'react/jsx-runtime';
14
18
  export { default as Container } from './container.js';
15
- import { Color } from '../icon/icon.constants.js';
16
19
  import 'util-deprecate';
20
+ import '../icon/icon.constants.js';
17
21
  import '../_helpers/icon-svg.js';
18
22
  import 'react/compiler-runtime';
19
23
  import '../global/memoize.js';
@@ -23,10 +27,10 @@ import '../link/clickable-link.js';
23
27
  import '../global/controls-height.js';
24
28
  import '../global/configuration.js';
25
29
  import '../_helpers/button.classes.js';
30
+ import '../heading/heading.js';
31
+ import '../_helpers/heading.js';
26
32
  import 'react-dom';
27
33
 
28
- var styles = {"alert":"ring-alert-alert","alertInline":"ring-alert-alertInline","error":"ring-alert-error","icon":"ring-alert-icon","caption":"ring-alert-caption","withCloseButton":"ring-alert-withCloseButton","badge":"ring-alert-badge","loader":"ring-alert-loader","close":"ring-alert-close","animationOpen":"ring-alert-animationOpen","show":"ring-alert-show","animationClosing":"ring-alert-animationClosing","animationShaking":"ring-alert-animationShaking","shaking":"ring-alert-shaking"};
29
-
30
34
  const ANIMATION_TIME = 500;
31
35
  /**
32
36
  * @name Alert
@@ -42,6 +46,7 @@ var AlertType;
42
46
  AlertType["SUCCESS"] = "success";
43
47
  AlertType["WARNING"] = "warning";
44
48
  AlertType["LOADING"] = "loading";
49
+ AlertType["INFO"] = "info";
45
50
  })(AlertType || (AlertType = {}));
46
51
  /**
47
52
  * Lookup table of alert type to icon modifier.
@@ -49,18 +54,19 @@ var AlertType;
49
54
  */
50
55
  const TypeToIcon = {
51
56
  [AlertType.ERROR]: exceptionIcon,
52
- [AlertType.SUCCESS]: checkmarkIcon,
53
- [AlertType.WARNING]: warningIcon
57
+ [AlertType.SUCCESS]: successIcon,
58
+ [AlertType.WARNING]: warningIcon,
59
+ [AlertType.INFO]: infoIcon
54
60
  };
55
61
  /**
56
- * Lookup table of alert type to icon color.
57
- * @type {Object.<AlertType, Icon.Color>}
62
+ * Maps the values React renders as nothing (except empty arrays/fragments,
63
+ * which are not worth chasing here) to undefined, so that they neither create
64
+ * the afterMessage wrapper nor distinguish alerts in the alert-service
65
+ * duplicate check
58
66
  */
59
- const TypeToIconColor = {
60
- [AlertType.ERROR]: Color.RED,
61
- [AlertType.SUCCESS]: Color.GREEN,
62
- [AlertType.WARNING]: Color.WHITE
63
- };
67
+ function normalizeAfterMessage(afterMessage) {
68
+ return afterMessage == null || typeof afterMessage === 'boolean' || afterMessage === '' ? undefined : afterMessage;
69
+ }
64
70
  /**
65
71
  * @constructor
66
72
  * @name Alert
@@ -102,6 +108,8 @@ class Alert extends PureComponent {
102
108
  node;
103
109
  hideTimeout;
104
110
  static Type = AlertType;
111
+ static Heading = AlertHeading;
112
+ static Actions = AlertActions;
105
113
  closeRequest = event => {
106
114
  this.startCloseAnimation();
107
115
  return this.props.onCloseRequest(event);
@@ -123,7 +131,8 @@ class Alert extends PureComponent {
123
131
  * @private
124
132
  */
125
133
  _handleCaptionsLinksClick = evt => {
126
- if (evt.target instanceof Element && evt.target.matches('a')) {
134
+ const link = evt.target instanceof Element ? evt.target.closest('a') : null;
135
+ if (link != null && evt.currentTarget.contains(link)) {
127
136
  this.closeRequest(evt);
128
137
  }
129
138
  };
@@ -131,10 +140,8 @@ class Alert extends PureComponent {
131
140
  * @private
132
141
  */
133
142
  _getCaption() {
134
- return /*#__PURE__*/jsx("span", {
135
- className: classNames(styles.caption, this.props.captionClassName, {
136
- [styles.withCloseButton]: this.props.closeable
137
- }),
143
+ return /*#__PURE__*/jsx("div", {
144
+ className: classNames(styles.caption, this.props.captionClassName),
138
145
  onClick: this._handleCaptionsLinksClick
139
146
  // We only process clicks on `a` elements, see above
140
147
  ,
@@ -151,8 +158,7 @@ class Alert extends PureComponent {
151
158
  if (glyph) {
152
159
  return /*#__PURE__*/jsx(Icon, {
153
160
  glyph: glyph,
154
- className: styles.icon,
155
- color: TypeToIconColor[this.props.type] || Color.DEFAULT
161
+ className: styles.icon
156
162
  });
157
163
  }
158
164
  if (this.props.type === AlertType.LOADING) {
@@ -175,12 +181,16 @@ class Alert extends PureComponent {
175
181
  showWithAnimation,
176
182
  className,
177
183
  'data-test': dataTest,
178
- theme
184
+ theme,
185
+ afterMessage
179
186
  } = this.props;
180
187
  const classes = classNames(className, {
181
188
  [styles.alert]: true,
182
189
  [styles.animationOpen]: showWithAnimation,
183
- [styles.error]: type === 'error',
190
+ [styles.error]: type === AlertType.ERROR,
191
+ [styles.success]: type === AlertType.SUCCESS,
192
+ [styles.warning]: type === AlertType.WARNING,
193
+ [styles.info]: type === AlertType.INFO,
184
194
  [styles.alertInline]: inline,
185
195
  [styles.animationClosing]: isClosing,
186
196
  [styles.animationShaking]: isShaking
@@ -189,6 +199,7 @@ class Alert extends PureComponent {
189
199
  const style = height ? {
190
200
  marginBottom: -height
191
201
  } : undefined;
202
+ const shownAfterMessage = normalizeAfterMessage(afterMessage);
192
203
  return /*#__PURE__*/jsxs(ThemeProvider, {
193
204
  theme: theme,
194
205
  className: classes,
@@ -196,15 +207,22 @@ class Alert extends PureComponent {
196
207
  "data-test-type": type,
197
208
  style: style,
198
209
  ref: this.storeAlertRef,
199
- children: [this._getIcon(), this._getCaption(), this.props.closeable ? /*#__PURE__*/jsx(Button, {
210
+ children: [this._getIcon(), this._getCaption(), shownAfterMessage != null && /*#__PURE__*/jsx("div", {
211
+ className: styles.afterMessage,
212
+ onClick: this._handleCaptionsLinksClick
213
+ // We only process clicks on `a` elements, see above
214
+ ,
215
+ role: "presentation",
216
+ children: shownAfterMessage
217
+ }), this.props.closeable ? /*#__PURE__*/jsx(Button, {
200
218
  icon: closeIcon,
201
219
  className: classNames(styles.close, closeButtonClassName),
202
220
  "data-test": "alert-close",
203
221
  "aria-label": "close alert",
204
222
  onClick: this.closeRequest
205
- }) : '']
223
+ }) : null]
206
224
  });
207
225
  }
208
226
  }
209
227
 
210
- export { ANIMATION_TIME, AlertType, Alert as default };
228
+ export { ANIMATION_TIME, AlertType, Alert as default, normalizeAfterMessage };
@@ -20,7 +20,7 @@ export declare class AlertService {
20
20
  * Renders alert container into virtual node to skip maintaining container
21
21
  */
22
22
  renderAlerts(): void;
23
- findSameAlert(message: ReactNode, type: AlertType | undefined): AlertItem;
23
+ findSameAlert(message: ReactNode, type: AlertType | undefined, afterMessage?: ReactNode): AlertItem | undefined;
24
24
  startAlertClosing(alert: AlertItem): void;
25
25
  remove(key: string | number | null | undefined): void;
26
26
  removeWithoutAnimation(key: string | number): void;
@@ -31,6 +31,7 @@ export declare class AlertService {
31
31
  message(message: ReactNode, timeout?: number): string | number;
32
32
  warning(message: ReactNode, timeout?: number): string | number;
33
33
  successMessage(message: ReactNode, timeout?: number): string | number;
34
+ infoMessage(message: ReactNode, timeout?: number): string | number;
34
35
  loadingMessage(message: ReactNode, timeout?: number): string | number;
35
36
  }
36
37
  declare const alertService: AlertService;
@@ -1,13 +1,14 @@
1
1
  import { createRoot } from 'react-dom/client';
2
2
  import getUID from '../global/get-uid.js';
3
- import Alert, { ANIMATION_TIME } from '../alert/alert.js';
3
+ import Alert, { normalizeAfterMessage, ANIMATION_TIME } from '../alert/alert.js';
4
4
  import { jsx } from 'react/jsx-runtime';
5
5
  import Alerts from '../alert/container.js';
6
6
  import 'react';
7
7
  import 'classnames';
8
8
  import '@jetbrains/icons/exception';
9
- import '@jetbrains/icons/checkmark';
9
+ import '@jetbrains/icons/success';
10
10
  import '@jetbrains/icons/warning';
11
+ import '@jetbrains/icons/info-filled';
11
12
  import '@jetbrains/icons/close';
12
13
  import '../icon/icon.js';
13
14
  import 'util-deprecate';
@@ -26,6 +27,11 @@ import '../global/controls-height.js';
26
27
  import '../global/configuration.js';
27
28
  import '../_helpers/button.classes.js';
28
29
  import '../_helpers/theme.js';
30
+ import '../alert/alert-heading.js';
31
+ import '../heading/heading.js';
32
+ import '../_helpers/heading.js';
33
+ import '../_helpers/alert.js';
34
+ import '../alert/alert-actions.js';
29
35
  import 'react-dom';
30
36
 
31
37
  const DEFAULT_ALERT_TIMEOUT = 10000; // 10 seconds
@@ -65,8 +71,9 @@ class AlertService {
65
71
  renderAlerts() {
66
72
  this.reactRoot.render(this.renderAlertContainer(this.showingAlerts));
67
73
  }
68
- findSameAlert(message, type) {
69
- return this.showingAlerts.filter(it => it.type === type && it.message === message)[0];
74
+ findSameAlert(message, type, afterMessage) {
75
+ const normalizedAfterMessage = normalizeAfterMessage(afterMessage);
76
+ return this.showingAlerts.find(it => it.type === type && it.message === message && normalizeAfterMessage(it.afterMessage) === normalizedAfterMessage);
70
77
  }
71
78
  startAlertClosing(alert) {
72
79
  alert.isClosing = true;
@@ -96,7 +103,7 @@ class AlertService {
96
103
  onClose,
97
104
  ...restOptions
98
105
  } = options;
99
- const sameAlert = this.findSameAlert(message, type);
106
+ const sameAlert = this.findSameAlert(message, type, options.afterMessage);
100
107
  if (sameAlert) {
101
108
  sameAlert.isShaking = true;
102
109
  this.renderAlerts();
@@ -138,6 +145,9 @@ class AlertService {
138
145
  successMessage(message, timeout) {
139
146
  return this.addAlert(message, Alert.Type.SUCCESS, timeout);
140
147
  }
148
+ infoMessage(message, timeout) {
149
+ return this.addAlert(message, Alert.Type.INFO, timeout);
150
+ }
141
151
  loadingMessage(message, timeout) {
142
152
  return this.addAlert(message, Alert.Type.LOADING, timeout);
143
153
  }
@@ -171,18 +171,13 @@ declare class Auth implements HTTPAuth {
171
171
  requestToken(): Promise<string | null>;
172
172
  /**
173
173
  * Get new token in the background or redirect to the login page.
174
- *
175
- * Retries background token refresh with delays from {@link AuthConfig.tokenRefreshRetryDelays}
176
- * with increasing delays before showing the auth dialog.
177
- * This handles transient failures that commonly occur after network
178
- * recovery (e.g. waking from sleep, switching networks) where the first
179
- * iframe-based auth attempt fails but a subsequent one succeeds once
180
- * the Hub session is re-established.
181
- *
182
174
  * @return {Promise.<string | null>}
183
175
  */
184
- forceTokenUpdate(): Promise<string | null>;
176
+ forceTokenUpdate(failedToken?: string | null): Promise<string | null>;
185
177
  private _doForceTokenUpdate;
178
+ private _refreshTokenUnderWebLock;
179
+ private _refreshTokenOrReuseChanged;
180
+ private _handleTokenRefreshFailure;
186
181
  loadCurrentService(): Promise<void>;
187
182
  getAPIPath(): string;
188
183
  /**
@@ -195,6 +190,7 @@ declare class Auth implements HTTPAuth {
195
190
  requestUser(): Promise<any>;
196
191
  updateUser(): Promise<void>;
197
192
  _detectUserChange(accessToken: string): Promise<void>;
193
+ private _getUserWithTokenRefresh;
198
194
  _beforeLogout(params?: AuthDialogParams): void;
199
195
  _showAuthDialog({ nonInteractive, error, canCancel, onTryAgain }?: AuthDialogParams): void;
200
196
  _showUserChangedDialog({ newUser, onApply, onPostpone }: UserChangedDialogParams): void;
@@ -1,7 +1,7 @@
1
1
  import 'core-js/modules/es.array.includes.js';
2
2
  import { getAbsoluteBaseURL, fixUrl } from '../global/url.js';
3
3
  import Listeners from '../global/listeners.js';
4
- import HTTP from '../http/http.js';
4
+ import HTTP, { HTTPError, CODE } from '../http/http.js';
5
5
  import promiseWithTimeout from '../global/promise-with-timeout.js';
6
6
  import { getTranslationsWithFallback, translate, getTranslations } from '../i18n/i18n.js';
7
7
  import AuthStorage from './storage.js';
@@ -17,8 +17,9 @@ import '../alert/alert.js';
17
17
  import 'react';
18
18
  import 'classnames';
19
19
  import '@jetbrains/icons/exception';
20
- import '@jetbrains/icons/checkmark';
20
+ import '@jetbrains/icons/success';
21
21
  import '@jetbrains/icons/warning';
22
+ import '@jetbrains/icons/info-filled';
22
23
  import '@jetbrains/icons/close';
23
24
  import '../icon/icon.js';
24
25
  import 'util-deprecate';
@@ -38,6 +39,11 @@ import '../global/controls-height.js';
38
39
  import '../global/configuration.js';
39
40
  import '../_helpers/button.classes.js';
40
41
  import '../_helpers/theme.js';
42
+ import '../alert/alert-heading.js';
43
+ import '../heading/heading.js';
44
+ import '../_helpers/heading.js';
45
+ import '../_helpers/alert.js';
46
+ import '../alert/alert-actions.js';
41
47
  import '../alert/container.js';
42
48
  import 'react-dom';
43
49
  import 'simply-uuid';
@@ -49,6 +55,7 @@ const DEFAULT_BACKEND_CHECK_TIMEOUT = 10 * 1000;
49
55
  const BACKGROUND_REDIRECT_TIMEOUT = 20 * 1000;
50
56
  const DEFAULT_WAIT_FOR_REDIRECT_TIMEOUT = 5 * 1000;
51
57
  const TOKEN_REFRESH_RETRY_DELAYS = [0, 2000, 5000];
58
+ const TOKEN_REFRESH_LOCK_TIMEOUT = 15 * 1000;
52
59
  const USER_CHANGED_EVENT = 'userChange';
53
60
  const DOMAIN_USER_CHANGED_EVENT = 'domainUser';
54
61
  const LOGOUT_EVENT = 'logout';
@@ -398,27 +405,20 @@ class Auth {
398
405
  }
399
406
  /**
400
407
  * Get new token in the background or redirect to the login page.
401
- *
402
- * Retries background token refresh with delays from {@link AuthConfig.tokenRefreshRetryDelays}
403
- * with increasing delays before showing the auth dialog.
404
- * This handles transient failures that commonly occur after network
405
- * recovery (e.g. waking from sleep, switching networks) where the first
406
- * iframe-based auth attempt fails but a subsequent one succeeds once
407
- * the Hub session is re-established.
408
- *
409
408
  * @return {Promise.<string | null>}
410
409
  */
411
- forceTokenUpdate() {
410
+ forceTokenUpdate(failedToken) {
412
411
  if (this._forceTokenUpdatePromise) {
413
412
  return this._forceTokenUpdatePromise;
414
413
  }
415
- this._forceTokenUpdatePromise = this._doForceTokenUpdate().finally(() => {
414
+ this._forceTokenUpdatePromise = this._doForceTokenUpdate(failedToken).finally(() => {
416
415
  this._forceTokenUpdatePromise = null;
417
416
  });
418
417
  return this._forceTokenUpdatePromise;
419
418
  }
420
- async _doForceTokenUpdate() {
421
- var _lastError$message;
419
+ async _doForceTokenUpdate(failedToken) {
420
+ var _ref;
421
+ const previousToken = (_ref = failedToken !== null && failedToken !== void 0 ? failedToken : (await this._storage?.getToken())?.accessToken) !== null && _ref !== void 0 ? _ref : null;
422
422
  try {
423
423
  if (!this._backendCheckPromise) {
424
424
  this._backendCheckPromise = this._checkBackendsStatusesIfEnabled();
@@ -431,6 +431,39 @@ class Auth {
431
431
  } finally {
432
432
  this._backendCheckPromise = null;
433
433
  }
434
+ const attempt = await this._refreshTokenUnderWebLock(previousToken);
435
+ if ('token' in attempt) {
436
+ return attempt.token;
437
+ }
438
+ return this._handleTokenRefreshFailure(attempt.error);
439
+ }
440
+ async _refreshTokenUnderWebLock(previousToken) {
441
+ if (navigator.locks == null) {
442
+ return this._refreshTokenOrReuseChanged(previousToken);
443
+ }
444
+ const lockName = `ring-ui-token-refresh-${this.config.clientId}`;
445
+ try {
446
+ return await navigator.locks.request(lockName, {
447
+ signal: AbortSignal.timeout(TOKEN_REFRESH_LOCK_TIMEOUT)
448
+ }, () => this._refreshTokenOrReuseChanged(previousToken));
449
+ } catch {
450
+ return this._refreshTokenOrReuseChanged(previousToken);
451
+ }
452
+ }
453
+ async _refreshTokenOrReuseChanged(previousToken) {
454
+ var _lastError;
455
+ let storedToken = null;
456
+ try {
457
+ var _await$this$_tokenVal2;
458
+ storedToken = (_await$this$_tokenVal2 = await this._tokenValidator?.validateTokenLocally()) !== null && _await$this$_tokenVal2 !== void 0 ? _await$this$_tokenVal2 : null;
459
+ } catch {
460
+ // No valid local token — fall through to refresh.
461
+ }
462
+ if (storedToken != null && storedToken !== previousToken) {
463
+ return {
464
+ token: storedToken
465
+ };
466
+ }
434
467
  let lastError = null;
435
468
  for (const delay of this.config.tokenRefreshRetryDelays) {
436
469
  if (delay > 0) {
@@ -438,11 +471,18 @@ class Auth {
438
471
  }
439
472
  try {
440
473
  var _await$this$_backgrou;
441
- return (_await$this$_backgrou = await this._backgroundFlow?.authorize()) !== null && _await$this$_backgrou !== void 0 ? _await$this$_backgrou : null;
474
+ return {
475
+ token: (_await$this$_backgrou = await this._backgroundFlow?.authorize()) !== null && _await$this$_backgrou !== void 0 ? _await$this$_backgrou : null
476
+ };
442
477
  } catch (error) {
443
478
  lastError = error instanceof Error ? error : new Error(String(error));
444
479
  }
445
480
  }
481
+ return {
482
+ error: (_lastError = lastError) !== null && _lastError !== void 0 ? _lastError : new Error('Failed to refresh token')
483
+ };
484
+ }
485
+ async _handleTokenRefreshFailure(lastError) {
446
486
  if (this._canShowDialogs()) {
447
487
  return new Promise(resolve => {
448
488
  const onTryAgain = async () => {
@@ -471,7 +511,7 @@ class Auth {
471
511
  if (authRequest) {
472
512
  this._redirectCurrentPage(authRequest.url);
473
513
  }
474
- throw new TokenValidator.TokenValidationError((_lastError$message = lastError?.message) !== null && _lastError$message !== void 0 ? _lastError$message : 'Failed to refresh token');
514
+ throw new TokenValidator.TokenValidationError(lastError.message);
475
515
  }
476
516
  async loadCurrentService() {
477
517
  if (this._service.serviceName) {
@@ -528,7 +568,7 @@ class Auth {
528
568
  }
529
569
  async _detectUserChange(accessToken) {
530
570
  const windowWasOpen = this._isLoginWindowOpen;
531
- const user = await this.getUser(accessToken);
571
+ const user = await this._getUserWithTokenRefresh(accessToken);
532
572
  const onApply = () => {
533
573
  this.user = user;
534
574
  this.listeners.trigger(USER_CHANGED_EVENT, user);
@@ -554,6 +594,20 @@ class Auth {
554
594
  });
555
595
  }
556
596
  }
597
+ async _getUserWithTokenRefresh(accessToken) {
598
+ try {
599
+ return await this.getUser(accessToken);
600
+ } catch (error) {
601
+ if (!(error instanceof HTTPError) || error.status !== CODE.UNAUTHORIZED) {
602
+ throw error;
603
+ }
604
+ const attempt = await this._refreshTokenUnderWebLock(accessToken);
605
+ if ('error' in attempt) {
606
+ throw error;
607
+ }
608
+ return this.getUser(attempt.token);
609
+ }
610
+ }
557
611
  _beforeLogout(params) {
558
612
  if (this._canShowDialogs()) {
559
613
  const onTryAgain = async () => {