@atlaskit/link-datasource 5.5.1 → 5.6.1
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 +15 -0
- package/dist/cjs/ui/datasource-table-view/datasource-column-sort.js +60 -0
- package/dist/cjs/ui/datasource-table-view/datasourceTableView.js +52 -5
- package/dist/cjs/ui/issue-like-table/index.compiled.css +5 -0
- package/dist/cjs/ui/issue-like-table/index.js +148 -65
- package/dist/cjs/ui/issue-like-table/messages.js +10 -0
- package/dist/es2019/ui/datasource-table-view/datasource-column-sort.js +52 -0
- package/dist/es2019/ui/datasource-table-view/datasourceTableView.js +46 -6
- package/dist/es2019/ui/issue-like-table/index.compiled.css +5 -0
- package/dist/es2019/ui/issue-like-table/index.js +87 -8
- package/dist/es2019/ui/issue-like-table/messages.js +10 -0
- package/dist/esm/ui/datasource-table-view/datasource-column-sort.js +53 -0
- package/dist/esm/ui/datasource-table-view/datasourceTableView.js +53 -6
- package/dist/esm/ui/issue-like-table/index.compiled.css +5 -0
- package/dist/esm/ui/issue-like-table/index.js +148 -65
- package/dist/esm/ui/issue-like-table/messages.js +10 -0
- package/dist/types/ui/datasource-table-view/datasource-column-sort.d.ts +12 -0
- package/dist/types/ui/datasource-table-view/datasourceTableView.d.ts +2 -2
- package/dist/types/ui/datasource-table-view/types.d.ts +1 -1
- package/dist/types/ui/issue-like-table/index.d.ts +1 -1
- package/dist/types/ui/issue-like-table/messages.d.ts +33 -23
- package/dist/types/ui/issue-like-table/types.d.ts +10 -0
- package/dist/types-ts4.5/ui/datasource-table-view/datasource-column-sort.d.ts +12 -0
- package/dist/types-ts4.5/ui/datasource-table-view/datasourceTableView.d.ts +2 -2
- package/dist/types-ts4.5/ui/datasource-table-view/types.d.ts +1 -1
- package/dist/types-ts4.5/ui/issue-like-table/index.d.ts +1 -1
- package/dist/types-ts4.5/ui/issue-like-table/messages.d.ts +33 -23
- package/dist/types-ts4.5/ui/issue-like-table/types.d.ts +10 -0
- package/package.json +14 -11
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { JIRA_LIST_OF_LINKS_DATASOURCE_ID } from '../jira-issues-modal';
|
|
2
|
+
const getNextSortDirection = (columnKey, currentSort) => {
|
|
3
|
+
if ((currentSort === null || currentSort === void 0 ? void 0 : currentSort.key) !== columnKey) {
|
|
4
|
+
return 'ASC';
|
|
5
|
+
}
|
|
6
|
+
if (currentSort.direction === 'ASC') {
|
|
7
|
+
return 'DESC';
|
|
8
|
+
}
|
|
9
|
+
return undefined;
|
|
10
|
+
};
|
|
11
|
+
// Match and remove an existing trailing ORDER BY clause before appending the next sort:
|
|
12
|
+
// - (?:^|\\s+) allows ORDER BY at the start of the JQL or after whitespace.
|
|
13
|
+
// - ORDER\\s+BY matches ORDER BY with flexible spacing and is case-insensitive (/i).
|
|
14
|
+
// - [\\s\\S]*$ consumes everything after ORDER BY to the end of the JQL.
|
|
15
|
+
// Examples:
|
|
16
|
+
// - "project = TEST ORDER BY created DESC" -> "project = TEST"
|
|
17
|
+
// - "ORDER BY priority ASC" -> ""
|
|
18
|
+
const JIRA_ORDER_BY_PATTERN = /(?:^|\s+)ORDER\s+BY\s+[\s\S]*$/i;
|
|
19
|
+
const getJiraColumnSortParameters = ({
|
|
20
|
+
parameters,
|
|
21
|
+
columnKey,
|
|
22
|
+
currentSort
|
|
23
|
+
}) => {
|
|
24
|
+
const direction = getNextSortDirection(columnKey, currentSort);
|
|
25
|
+
if (!direction) {
|
|
26
|
+
return {
|
|
27
|
+
parameters,
|
|
28
|
+
sort: undefined
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
if (typeof parameters.jql !== 'string') {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
const jqlWithoutOrder = parameters.jql.replace(JIRA_ORDER_BY_PATTERN, '').trim();
|
|
35
|
+
const nextOrderByClause = `ORDER BY ${columnKey} ${direction}`;
|
|
36
|
+
return {
|
|
37
|
+
parameters: {
|
|
38
|
+
...parameters,
|
|
39
|
+
jql: [jqlWithoutOrder, nextOrderByClause].filter(Boolean).join(' ')
|
|
40
|
+
},
|
|
41
|
+
sort: {
|
|
42
|
+
key: columnKey,
|
|
43
|
+
direction
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
export const getDatasourceColumnSortGetter = datasourceId => {
|
|
48
|
+
if (datasourceId === JIRA_LIST_OF_LINKS_DATASOURCE_ID) {
|
|
49
|
+
return getJiraColumnSortParameters;
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/* datasourceTableView.tsx generated by @compiled/babel-plugin v0.39.1 */
|
|
2
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
2
3
|
import "./datasourceTableView.compiled.css";
|
|
3
4
|
import * as React from 'react';
|
|
4
5
|
import { ax, ix } from "@compiled/react/runtime";
|
|
5
|
-
import { useCallback, useEffect, useRef } from 'react';
|
|
6
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
7
|
+
import isEqual from 'lodash/isEqual';
|
|
6
8
|
import { withAnalyticsContext } from '@atlaskit/analytics-next';
|
|
7
9
|
import { IntlMessagesProvider } from '@atlaskit/intl-messages-provider';
|
|
8
10
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
@@ -26,6 +28,7 @@ import { ProviderAuthRequired } from '../common/error-state/provider-auth-requir
|
|
|
26
28
|
import { IssueLikeDataTableView } from '../issue-like-table';
|
|
27
29
|
import EmptyState from '../issue-like-table/empty-state';
|
|
28
30
|
import { TableFooter } from '../table-footer';
|
|
31
|
+
import { getDatasourceColumnSortGetter } from './datasource-column-sort';
|
|
29
32
|
const containerStyles = null;
|
|
30
33
|
const DefaultScrollableContainerHeight = 590;
|
|
31
34
|
const DatasourceTableViewWithoutAnalytics = ({
|
|
@@ -40,6 +43,26 @@ const DatasourceTableViewWithoutAnalytics = ({
|
|
|
40
43
|
onWrappedColumnChange,
|
|
41
44
|
scrollableContainerHeight = DefaultScrollableContainerHeight
|
|
42
45
|
}) => {
|
|
46
|
+
// Local copy lets us apply in-session sort mutations without mutating external parameters.
|
|
47
|
+
const [sessionParameters, setSessionParameters] = useState(parameters);
|
|
48
|
+
// Tracks the external parameters that the current session/sort state was derived from.
|
|
49
|
+
const sessionBaseParametersRef = useRef(parameters);
|
|
50
|
+
const [sortState, setSortState] = useState();
|
|
51
|
+
const columnSortGetter = getDatasourceColumnSortGetter(datasourceId);
|
|
52
|
+
// Sorting is only owned by this view when parent callbacks are absent (read-only rendering mode).
|
|
53
|
+
const isReadOnlyDatasourceTable = !onVisibleColumnKeysChange && !onColumnResize && !onWrappedColumnChange;
|
|
54
|
+
// Keep sort UI hidden unless datasource + ownership + feature gate all allow it.
|
|
55
|
+
const shouldEnableColumnSort = !!columnSortGetter && isReadOnlyDatasourceTable && fg('platform_lp_jira_sllv_renderer_column_sorting');
|
|
56
|
+
useDeepEffect(() => {
|
|
57
|
+
// External parameter updates should always reset local sort/session state back to source-of-truth.
|
|
58
|
+
sessionBaseParametersRef.current = parameters;
|
|
59
|
+
setSessionParameters(parameters);
|
|
60
|
+
setSortState(undefined);
|
|
61
|
+
}, [parameters]);
|
|
62
|
+
const isSessionBasedOnCurrentParameters = isEqual(sessionBaseParametersRef.current, parameters);
|
|
63
|
+
// Use session parameters only when they are known to be based on the current external parameters.
|
|
64
|
+
// This avoids a one-render stale read during the deep-effect update cycle above.
|
|
65
|
+
const activeParameters = isSessionBasedOnCurrentParameters && fg('platform_lp_jira_sllv_renderer_column_sorting') ? sessionParameters : parameters;
|
|
43
66
|
const {
|
|
44
67
|
reset,
|
|
45
68
|
status,
|
|
@@ -57,7 +80,7 @@ const DatasourceTableViewWithoutAnalytics = ({
|
|
|
57
80
|
authDetails
|
|
58
81
|
} = useDatasourceTableState({
|
|
59
82
|
datasourceId,
|
|
60
|
-
parameters,
|
|
83
|
+
parameters: activeParameters,
|
|
61
84
|
fieldKeys: visibleColumnKeys
|
|
62
85
|
});
|
|
63
86
|
const isInPDFRender = useIsInPDFRender();
|
|
@@ -95,7 +118,7 @@ const DatasourceTableViewWithoutAnalytics = ({
|
|
|
95
118
|
reset();
|
|
96
119
|
}
|
|
97
120
|
isInitialRender.current = false;
|
|
98
|
-
}, [reset,
|
|
121
|
+
}, [reset, activeParameters]);
|
|
99
122
|
useEffect(() => {
|
|
100
123
|
if (onVisibleColumnKeysChange && (visibleColumnKeys || []).length === 0 && defaultVisibleColumnKeys.length > 0) {
|
|
101
124
|
onVisibleColumnKeysChange(defaultVisibleColumnKeys);
|
|
@@ -141,6 +164,19 @@ const DatasourceTableViewWithoutAnalytics = ({
|
|
|
141
164
|
});
|
|
142
165
|
forcedReset();
|
|
143
166
|
}, [destinationObjectTypes, extensionKey, fireEvent, forcedReset]);
|
|
167
|
+
const onColumnSort = useCallback(columnKey => {
|
|
168
|
+
// Build next params/sort atomically so UI state and query state stay in sync.
|
|
169
|
+
const result = columnSortGetter === null || columnSortGetter === void 0 ? void 0 : columnSortGetter({
|
|
170
|
+
parameters: sessionBaseParametersRef.current,
|
|
171
|
+
columnKey,
|
|
172
|
+
currentSort: sortState
|
|
173
|
+
});
|
|
174
|
+
if (!result) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
setSortState(result.sort);
|
|
178
|
+
setSessionParameters(result.parameters);
|
|
179
|
+
}, [columnSortGetter, sortState]);
|
|
144
180
|
const handleErrorRefresh = useCallback(() => {
|
|
145
181
|
reset({
|
|
146
182
|
shouldForceRequest: true
|
|
@@ -172,7 +208,7 @@ const DatasourceTableViewWithoutAnalytics = ({
|
|
|
172
208
|
loaderFn: fetchMessagesForLocale
|
|
173
209
|
}, /*#__PURE__*/React.createElement("div", {
|
|
174
210
|
className: ax(["_2rko1kw7", "datasource-table"])
|
|
175
|
-
}, hasColumns ? /*#__PURE__*/React.createElement(IssueLikeDataTableView, {
|
|
211
|
+
}, hasColumns ? /*#__PURE__*/React.createElement(IssueLikeDataTableView, _extends({
|
|
176
212
|
testId: 'datasource-table-view',
|
|
177
213
|
hasNextPage: hasNextPage,
|
|
178
214
|
items: responseItems,
|
|
@@ -184,12 +220,16 @@ const DatasourceTableViewWithoutAnalytics = ({
|
|
|
184
220
|
visibleColumnKeys: hasStaleVisibleColumnKeys ? defaultVisibleColumnKeys : visibleColumnKeys || defaultVisibleColumnKeys,
|
|
185
221
|
onVisibleColumnKeysChange: onVisibleColumnKeysChange,
|
|
186
222
|
columnCustomSizes: columnCustomSizes,
|
|
187
|
-
onColumnResize: onColumnResize
|
|
223
|
+
onColumnResize: onColumnResize
|
|
224
|
+
}, shouldEnableColumnSort && fg('platform_lp_jira_sllv_renderer_column_sorting') ? {
|
|
225
|
+
onColumnSort,
|
|
226
|
+
sortState
|
|
227
|
+
} : {}, {
|
|
188
228
|
wrappedColumnKeys: wrappedColumnKeys,
|
|
189
229
|
onWrappedColumnChange: onWrappedColumnChange,
|
|
190
230
|
scrollableContainerHeight: isInPDFRender ? undefined : fg('lp_enable_datasource-table-view_height_override') ? scrollableContainerHeight : DefaultScrollableContainerHeight,
|
|
191
231
|
extensionKey: extensionKey
|
|
192
|
-
}) : /*#__PURE__*/React.createElement(EmptyState, {
|
|
232
|
+
})) : /*#__PURE__*/React.createElement(EmptyState, {
|
|
193
233
|
testId: "datasource-table-view-skeleton",
|
|
194
234
|
isCompact: true
|
|
195
235
|
}), /*#__PURE__*/React.createElement(TableFooter, {
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
.pm-table-wrapper>table thead ._1rmlidpf:last-of-type{border:0}
|
|
15
15
|
.pm-table-wrapper>table thead ._1u3bidpf{border:0}
|
|
16
16
|
.pm-table-wrapper>table thead ._ex0g13hi:last-of-type{background:linear-gradient(90deg,hsla(0,0%,100%,0) 0,var(--ds-elevation-surface-current,#fff) 10%)}
|
|
17
|
+
._1wtnze3t button{padding-block:var(--ds-space-0,0)}
|
|
17
18
|
.ProseMirror .pm-table-wrapper>table tbody ._15lria51{border-bottom:var(--ds-border-width,1px) solid var(--ds-border,#0b120e24)}
|
|
18
19
|
.ProseMirror .pm-table-wrapper>table tbody ._1ho1idpf:last-of-type{border-right:0}
|
|
19
20
|
.ProseMirror .pm-table-wrapper>table tbody ._1xqpia51{border-right:var(--ds-border-width,1px) solid var(--ds-border,#0b120e24)}
|
|
@@ -66,6 +67,7 @@ thead.has-column-picker ._10i2idpf:nth-last-of-type(2){border-right:0}.ProseMirr
|
|
|
66
67
|
.ProseMirror .pm-table-wrapper>table thead ._zjk41if8:last-of-type{position:sticky}
|
|
67
68
|
._11681tcg [data-testid=datasource-header-content--container]{line-height:24px}
|
|
68
69
|
._11j11b66 [data-testid=datasource-header-content--container]{padding-right:var(--ds-space-050,4px)}
|
|
70
|
+
._11lvze3t button{padding-left:var(--ds-space-0,0)}
|
|
69
71
|
._124in7od [data-testid=inline-card-icon-and-title]{white-space:unset}
|
|
70
72
|
._12pn15vq [data-testid=datasource-header-content--container]{overflow-x:hidden}
|
|
71
73
|
._12ruusvi:last-of-type{box-sizing:border-box}
|
|
@@ -108,7 +110,9 @@ thead.has-column-picker ._10i2idpf:nth-last-of-type(2){border-right:0}.ProseMirr
|
|
|
108
110
|
._btyzidpf{border-spacing:0}
|
|
109
111
|
._ca0qv77o{padding-top:var(--ds-space-025,2px)}
|
|
110
112
|
._ca0qze3t{padding-top:var(--ds-space-0,0)}
|
|
113
|
+
._ficf1e5h button{text-align:left}
|
|
111
114
|
._iscccj1k [data-testid=datasource-header-content--container]{display:-webkit-box}
|
|
115
|
+
._jq8g1wug button{height:auto}
|
|
112
116
|
._k48p1wq8{font-weight:var(--ds-font-weight-medium,500)}
|
|
113
117
|
._kqsw1if8{position:sticky}
|
|
114
118
|
._kqswh2mm{position:relative}
|
|
@@ -130,6 +134,7 @@ thead.has-column-picker ._10i2idpf:nth-last-of-type(2){border-right:0}.ProseMirr
|
|
|
130
134
|
._vchh1ntv{box-sizing:content-box}
|
|
131
135
|
._vchhusvi{box-sizing:border-box}
|
|
132
136
|
._vwz41tcg{line-height:24px}
|
|
137
|
+
._yhjm1b66 button{padding-right:var(--ds-space-050,4px)}
|
|
133
138
|
._yq5hus1c{border-collapse:separate}
|
|
134
139
|
.pm-table-wrapper>table tbody ._18a21kw7{vertical-align:inherit}
|
|
135
140
|
.pm-table-wrapper>table tbody ._1h12ze3t{padding-right:var(--ds-space-0,0)}
|
|
@@ -7,9 +7,14 @@ import { ax, ix } from "@compiled/react/runtime";
|
|
|
7
7
|
/* eslint-disable @atlaskit/design-system/use-tokens-typography */
|
|
8
8
|
|
|
9
9
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
10
|
+
import { useIntl } from 'react-intl';
|
|
10
11
|
import invariant from 'tiny-invariant';
|
|
12
|
+
import Button from '@atlaskit/button/new';
|
|
11
13
|
import { FlagsProvider } from '@atlaskit/flag';
|
|
14
|
+
import SortAscendingIcon from '@atlaskit/icon/core/sort-ascending';
|
|
15
|
+
import SortDescendingIcon from '@atlaskit/icon/core/sort-descending';
|
|
12
16
|
import { Skeleton } from '@atlaskit/linking-common';
|
|
17
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
13
18
|
import { extractClosestEdge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';
|
|
14
19
|
import { reorderWithEdge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/util/reorder-with-edge';
|
|
15
20
|
import { autoScroller } from '@atlaskit/pragmatic-drag-and-drop-react-beautiful-dnd-autoscroll';
|
|
@@ -24,6 +29,7 @@ import { ColumnPicker } from './column-picker';
|
|
|
24
29
|
import { DragColumnPreview } from './drag-column-preview';
|
|
25
30
|
import { DraggableTableHeading } from './draggable-table-heading';
|
|
26
31
|
import TableEmptyState from './empty-state';
|
|
32
|
+
import { issueLikeTableMessages } from './messages';
|
|
27
33
|
import { renderType } from './render-type';
|
|
28
34
|
import { TableCellContent } from './table-cell-content';
|
|
29
35
|
import { useIsOnScreen } from './useIsOnScreen';
|
|
@@ -115,6 +121,22 @@ const tableStyles = null;
|
|
|
115
121
|
const noDefaultBorderStyles = null;
|
|
116
122
|
const headerStyles = null;
|
|
117
123
|
const headingHoverEffectStyles = null;
|
|
124
|
+
|
|
125
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-styled -- Matches DraggableTableHeading button normalization.
|
|
126
|
+
const SortableHeaderParent = forwardRef(({
|
|
127
|
+
as: C = "div",
|
|
128
|
+
style: __cmpls,
|
|
129
|
+
...__cmplp
|
|
130
|
+
}, __cmplr) => {
|
|
131
|
+
return /*#__PURE__*/React.createElement(C, _extends({}, __cmplp, {
|
|
132
|
+
style: __cmpls,
|
|
133
|
+
ref: __cmplr,
|
|
134
|
+
className: ax(["_1e0c1txw _4cvr1h6o _o5721q9c _1wtnze3t _ficf1e5h _jq8g1wug _11lvze3t _yhjm1b66", __cmplp.className])
|
|
135
|
+
}));
|
|
136
|
+
});
|
|
137
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
138
|
+
SortableHeaderParent.displayName = 'SortableHeaderParent';
|
|
139
|
+
}
|
|
118
140
|
function extractIndex(data) {
|
|
119
141
|
const {
|
|
120
142
|
index
|
|
@@ -171,14 +193,19 @@ export const IssueLikeDataTableView = ({
|
|
|
171
193
|
onVisibleColumnKeysChange,
|
|
172
194
|
columnCustomSizes,
|
|
173
195
|
onColumnResize,
|
|
196
|
+
onColumnSort,
|
|
174
197
|
wrappedColumnKeys,
|
|
175
198
|
onWrappedColumnChange,
|
|
199
|
+
sortState,
|
|
176
200
|
status,
|
|
177
201
|
hasNextPage,
|
|
178
202
|
scrollableContainerHeight,
|
|
179
203
|
extensionKey
|
|
180
204
|
}) => {
|
|
181
205
|
var _containerRef$current;
|
|
206
|
+
const {
|
|
207
|
+
formatMessage
|
|
208
|
+
} = useIntl();
|
|
182
209
|
const tableId = useMemo(() => Symbol('unique-id'), []);
|
|
183
210
|
const experienceId = useDatasourceExperienceId();
|
|
184
211
|
const tableHeaderRowRef = useRef(null);
|
|
@@ -241,7 +268,8 @@ export const IssueLikeDataTableView = ({
|
|
|
241
268
|
height: 14,
|
|
242
269
|
testId: "issues-table-row-loading"
|
|
243
270
|
})),
|
|
244
|
-
key: column.key
|
|
271
|
+
key: column.key,
|
|
272
|
+
width: column.width
|
|
245
273
|
}))
|
|
246
274
|
}), [headerColumns]);
|
|
247
275
|
useEffect(() => {
|
|
@@ -363,10 +391,25 @@ export const IssueLikeDataTableView = ({
|
|
|
363
391
|
ref: rowIndex === items.length - 1 ? el => setLastRowElement(el) : undefined
|
|
364
392
|
};
|
|
365
393
|
}), [items, itemIds, renderItem, wrappedColumnKeys, visibleSortedColumns, getColumnWidth]);
|
|
394
|
+
const previousRealRowsCountRef = useRef(undefined);
|
|
395
|
+
useEffect(() => {
|
|
396
|
+
if (tableRows.length > 0) {
|
|
397
|
+
previousRealRowsCountRef.current = tableRows.length;
|
|
398
|
+
}
|
|
399
|
+
}, [tableRows.length]);
|
|
366
400
|
const rows = useMemo(() => {
|
|
367
|
-
if (
|
|
368
|
-
|
|
401
|
+
if (fg('platform_lp_jira_sllv_renderer_column_sorting')) {
|
|
402
|
+
const hasPreviousRealRows = !!previousRealRowsCountRef.current;
|
|
403
|
+
const isLoadingState = status === 'loading' || status === 'empty' && hasPreviousRealRows;
|
|
404
|
+
if (!isLoadingState) {
|
|
405
|
+
return tableRows;
|
|
406
|
+
}
|
|
407
|
+
} else {
|
|
408
|
+
if (status !== 'loading') {
|
|
409
|
+
return tableRows;
|
|
410
|
+
}
|
|
369
411
|
}
|
|
412
|
+
|
|
370
413
|
// if there are table rows, only add 1 loading row
|
|
371
414
|
if (tableRows.length > 0) {
|
|
372
415
|
return [...tableRows, {
|
|
@@ -376,7 +419,15 @@ export const IssueLikeDataTableView = ({
|
|
|
376
419
|
}
|
|
377
420
|
// if there are no table rows add 14 rows if it is compact (has scrollableContainerHeight or non-modal)
|
|
378
421
|
// add 10 rows if it is modal (no scrollableContainerHeight)
|
|
379
|
-
|
|
422
|
+
let loadingRowsCount = scrollableContainerHeight ? 14 : 10;
|
|
423
|
+
if (fg('platform_lp_jira_sllv_renderer_column_sorting')) {
|
|
424
|
+
const defaultLoadingRowsCount = scrollableContainerHeight ? 14 : 10;
|
|
425
|
+
const previousRealRowsCount = previousRealRowsCountRef.current;
|
|
426
|
+
loadingRowsCount = defaultLoadingRowsCount;
|
|
427
|
+
if (previousRealRowsCount && previousRealRowsCount < defaultLoadingRowsCount) {
|
|
428
|
+
loadingRowsCount = previousRealRowsCount;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
380
431
|
return [...Array(loadingRowsCount)].map((_, index) => ({
|
|
381
432
|
...loadingRow,
|
|
382
433
|
key: `loading-${index}`
|
|
@@ -405,6 +456,9 @@ export const IssueLikeDataTableView = ({
|
|
|
405
456
|
}
|
|
406
457
|
}, [experienceId, extensionKey, hasFullSchema, onLoadDatasourceDetails]);
|
|
407
458
|
const isEditable = onVisibleColumnKeysChange && hasData;
|
|
459
|
+
// Sorting is enabled only when the table owns the header interaction (read-only mode).
|
|
460
|
+
// Editable tables reserve header interactions for drag/resize/wrap controls.
|
|
461
|
+
const shouldEnableColumnSort = !!onColumnSort && !onVisibleColumnKeysChange && !onColumnResize && !onWrappedColumnChange;
|
|
408
462
|
const orderedColumnsAreUpToDate = orderedColumns.length === columns.length;
|
|
409
463
|
const shouldDisplayColumnsInPicker = hasFullSchema && orderedColumnsAreUpToDate;
|
|
410
464
|
const view = /*#__PURE__*/React.createElement("div", {
|
|
@@ -449,7 +503,30 @@ export const IssueLikeDataTableView = ({
|
|
|
449
503
|
className: ax(["_11c8wadc _k48p1wq8"])
|
|
450
504
|
}, content));
|
|
451
505
|
const isHeadingOutsideButton = !isEditable || !onWrappedColumnChange;
|
|
452
|
-
if (
|
|
506
|
+
if (shouldEnableColumnSort) {
|
|
507
|
+
const sortedDirection = (sortState === null || sortState === void 0 ? void 0 : sortState.key) === key ? sortState.direction : undefined;
|
|
508
|
+
// Use directional icon only for the active sort column; keep width stable otherwise.
|
|
509
|
+
const SortIcon = sortedDirection ? sortedDirection === 'ASC' ? SortAscendingIcon : SortDescendingIcon : null;
|
|
510
|
+
const sortLabel = typeof content === 'string' ? content : key;
|
|
511
|
+
const sortButtonAriaLabel = sortedDirection === 'ASC' ? formatMessage(issueLikeTableMessages.sortByColumnDescendingAction, {
|
|
512
|
+
column: sortLabel
|
|
513
|
+
}) : formatMessage(issueLikeTableMessages.sortByColumnAscendingAction, {
|
|
514
|
+
column: sortLabel
|
|
515
|
+
});
|
|
516
|
+
heading = /*#__PURE__*/React.createElement(SortableHeaderParent, null, /*#__PURE__*/React.createElement(Button, _extends({
|
|
517
|
+
appearance: "subtle",
|
|
518
|
+
spacing: "compact",
|
|
519
|
+
shouldFitContainer: true,
|
|
520
|
+
testId: `${key}-column-sort-button`,
|
|
521
|
+
"aria-label": sortButtonAriaLabel
|
|
522
|
+
}, SortIcon ? {
|
|
523
|
+
iconAfter: iconProps => /*#__PURE__*/React.createElement(SortIcon, _extends({}, iconProps, {
|
|
524
|
+
size: "small"
|
|
525
|
+
}))
|
|
526
|
+
} : {}, {
|
|
527
|
+
onClick: () => onColumnSort === null || onColumnSort === void 0 ? void 0 : onColumnSort(key)
|
|
528
|
+
}), heading));
|
|
529
|
+
} else if (isHeadingOutsideButton) {
|
|
453
530
|
heading = /*#__PURE__*/React.createElement("div", {
|
|
454
531
|
className: ax(["_1e0c1txw _4cvr1h6o _o5721q9c _8vu418qm _irr3l4ek"])
|
|
455
532
|
}, heading);
|
|
@@ -483,16 +560,18 @@ export const IssueLikeDataTableView = ({
|
|
|
483
560
|
onIsWrappedChange: onWrappedColumnChange === null || onWrappedColumnChange === void 0 ? void 0 : onWrappedColumnChange.bind(null, key)
|
|
484
561
|
}, heading);
|
|
485
562
|
} else {
|
|
486
|
-
return /*#__PURE__*/React.createElement(TableHeading, {
|
|
563
|
+
return /*#__PURE__*/React.createElement(TableHeading, _extends({
|
|
487
564
|
key: key,
|
|
488
565
|
"data-testid": `${key}-column-heading`
|
|
566
|
+
}, fg('platform_lp_jira_sllv_renderer_column_sorting') ? {
|
|
567
|
+
'aria-sort': (sortState === null || sortState === void 0 ? void 0 : sortState.key) === key && sortState.direction === 'ASC' ? 'ascending' : (sortState === null || sortState === void 0 ? void 0 : sortState.key) === key && sortState.direction === 'DESC' ? 'descending' : undefined
|
|
568
|
+
} : {}, {
|
|
489
569
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop, @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766
|
|
490
|
-
,
|
|
491
570
|
style: getWidthCss({
|
|
492
571
|
shouldUseWidth,
|
|
493
572
|
width
|
|
494
573
|
})
|
|
495
|
-
}, heading);
|
|
574
|
+
}), heading);
|
|
496
575
|
}
|
|
497
576
|
}), onVisibleColumnKeysChange && /*#__PURE__*/React.createElement(ColumnPickerHeader, null, /*#__PURE__*/React.createElement(ColumnPicker, {
|
|
498
577
|
columns: shouldDisplayColumnsInPicker ? orderedColumns : [],
|
|
@@ -40,6 +40,16 @@ export const issueLikeTableMessages = defineMessages({
|
|
|
40
40
|
description: 'Table header Dropdown item for making whole column to not wrap text',
|
|
41
41
|
defaultMessage: 'Unwrap text'
|
|
42
42
|
},
|
|
43
|
+
sortByColumnAscendingAction: {
|
|
44
|
+
id: 'linkDataSource.issue-line-table.sort-by-column-ascending-action',
|
|
45
|
+
description: 'Accessible label for sorting a table column in ascending order',
|
|
46
|
+
defaultMessage: 'Sort by {column} ascending.'
|
|
47
|
+
},
|
|
48
|
+
sortByColumnDescendingAction: {
|
|
49
|
+
id: 'linkDataSource.issue-line-table.sort-by-column-descending-action',
|
|
50
|
+
description: 'Accessible label for sorting a table column in descending order',
|
|
51
|
+
defaultMessage: 'Sort by {column} descending.'
|
|
52
|
+
},
|
|
43
53
|
fetchActionErrorGenericDescriptionGalaxia: {
|
|
44
54
|
id: 'linkDataSource.issue-line-table.fetch-action-error-generic-description-galaxia',
|
|
45
55
|
description: 'Generic error message description shown when fetching inline edit dropdown field fails',
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
3
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
4
|
+
import { JIRA_LIST_OF_LINKS_DATASOURCE_ID } from '../jira-issues-modal';
|
|
5
|
+
var getNextSortDirection = function getNextSortDirection(columnKey, currentSort) {
|
|
6
|
+
if ((currentSort === null || currentSort === void 0 ? void 0 : currentSort.key) !== columnKey) {
|
|
7
|
+
return 'ASC';
|
|
8
|
+
}
|
|
9
|
+
if (currentSort.direction === 'ASC') {
|
|
10
|
+
return 'DESC';
|
|
11
|
+
}
|
|
12
|
+
return undefined;
|
|
13
|
+
};
|
|
14
|
+
// Match and remove an existing trailing ORDER BY clause before appending the next sort:
|
|
15
|
+
// - (?:^|\\s+) allows ORDER BY at the start of the JQL or after whitespace.
|
|
16
|
+
// - ORDER\\s+BY matches ORDER BY with flexible spacing and is case-insensitive (/i).
|
|
17
|
+
// - [\\s\\S]*$ consumes everything after ORDER BY to the end of the JQL.
|
|
18
|
+
// Examples:
|
|
19
|
+
// - "project = TEST ORDER BY created DESC" -> "project = TEST"
|
|
20
|
+
// - "ORDER BY priority ASC" -> ""
|
|
21
|
+
var JIRA_ORDER_BY_PATTERN = /(?:^|\s+)ORDER\s+BY\s+[\s\S]*$/i;
|
|
22
|
+
var getJiraColumnSortParameters = function getJiraColumnSortParameters(_ref) {
|
|
23
|
+
var parameters = _ref.parameters,
|
|
24
|
+
columnKey = _ref.columnKey,
|
|
25
|
+
currentSort = _ref.currentSort;
|
|
26
|
+
var direction = getNextSortDirection(columnKey, currentSort);
|
|
27
|
+
if (!direction) {
|
|
28
|
+
return {
|
|
29
|
+
parameters: parameters,
|
|
30
|
+
sort: undefined
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
if (typeof parameters.jql !== 'string') {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
var jqlWithoutOrder = parameters.jql.replace(JIRA_ORDER_BY_PATTERN, '').trim();
|
|
37
|
+
var nextOrderByClause = "ORDER BY ".concat(columnKey, " ").concat(direction);
|
|
38
|
+
return {
|
|
39
|
+
parameters: _objectSpread(_objectSpread({}, parameters), {}, {
|
|
40
|
+
jql: [jqlWithoutOrder, nextOrderByClause].filter(Boolean).join(' ')
|
|
41
|
+
}),
|
|
42
|
+
sort: {
|
|
43
|
+
key: columnKey,
|
|
44
|
+
direction: direction
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
export var getDatasourceColumnSortGetter = function getDatasourceColumnSortGetter(datasourceId) {
|
|
49
|
+
if (datasourceId === JIRA_LIST_OF_LINKS_DATASOURCE_ID) {
|
|
50
|
+
return getJiraColumnSortParameters;
|
|
51
|
+
}
|
|
52
|
+
return undefined;
|
|
53
|
+
};
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
/* datasourceTableView.tsx generated by @compiled/babel-plugin v0.39.1 */
|
|
2
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
3
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
4
|
import "./datasourceTableView.compiled.css";
|
|
3
5
|
import * as React from 'react';
|
|
4
6
|
import { ax, ix } from "@compiled/react/runtime";
|
|
5
|
-
import { useCallback, useEffect, useRef } from 'react';
|
|
7
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
8
|
+
import isEqual from 'lodash/isEqual';
|
|
6
9
|
import { withAnalyticsContext } from '@atlaskit/analytics-next';
|
|
7
10
|
import { IntlMessagesProvider } from '@atlaskit/intl-messages-provider';
|
|
8
11
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
@@ -26,6 +29,7 @@ import { ProviderAuthRequired } from '../common/error-state/provider-auth-requir
|
|
|
26
29
|
import { IssueLikeDataTableView } from '../issue-like-table';
|
|
27
30
|
import EmptyState from '../issue-like-table/empty-state';
|
|
28
31
|
import { TableFooter } from '../table-footer';
|
|
32
|
+
import { getDatasourceColumnSortGetter } from './datasource-column-sort';
|
|
29
33
|
var containerStyles = null;
|
|
30
34
|
var DefaultScrollableContainerHeight = 590;
|
|
31
35
|
var DatasourceTableViewWithoutAnalytics = function DatasourceTableViewWithoutAnalytics(_ref) {
|
|
@@ -40,9 +44,35 @@ var DatasourceTableViewWithoutAnalytics = function DatasourceTableViewWithoutAna
|
|
|
40
44
|
onWrappedColumnChange = _ref.onWrappedColumnChange,
|
|
41
45
|
_ref$scrollableContai = _ref.scrollableContainerHeight,
|
|
42
46
|
scrollableContainerHeight = _ref$scrollableContai === void 0 ? DefaultScrollableContainerHeight : _ref$scrollableContai;
|
|
47
|
+
// Local copy lets us apply in-session sort mutations without mutating external parameters.
|
|
48
|
+
var _useState = useState(parameters),
|
|
49
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
50
|
+
sessionParameters = _useState2[0],
|
|
51
|
+
setSessionParameters = _useState2[1];
|
|
52
|
+
// Tracks the external parameters that the current session/sort state was derived from.
|
|
53
|
+
var sessionBaseParametersRef = useRef(parameters);
|
|
54
|
+
var _useState3 = useState(),
|
|
55
|
+
_useState4 = _slicedToArray(_useState3, 2),
|
|
56
|
+
sortState = _useState4[0],
|
|
57
|
+
setSortState = _useState4[1];
|
|
58
|
+
var columnSortGetter = getDatasourceColumnSortGetter(datasourceId);
|
|
59
|
+
// Sorting is only owned by this view when parent callbacks are absent (read-only rendering mode).
|
|
60
|
+
var isReadOnlyDatasourceTable = !onVisibleColumnKeysChange && !onColumnResize && !onWrappedColumnChange;
|
|
61
|
+
// Keep sort UI hidden unless datasource + ownership + feature gate all allow it.
|
|
62
|
+
var shouldEnableColumnSort = !!columnSortGetter && isReadOnlyDatasourceTable && fg('platform_lp_jira_sllv_renderer_column_sorting');
|
|
63
|
+
useDeepEffect(function () {
|
|
64
|
+
// External parameter updates should always reset local sort/session state back to source-of-truth.
|
|
65
|
+
sessionBaseParametersRef.current = parameters;
|
|
66
|
+
setSessionParameters(parameters);
|
|
67
|
+
setSortState(undefined);
|
|
68
|
+
}, [parameters]);
|
|
69
|
+
var isSessionBasedOnCurrentParameters = isEqual(sessionBaseParametersRef.current, parameters);
|
|
70
|
+
// Use session parameters only when they are known to be based on the current external parameters.
|
|
71
|
+
// This avoids a one-render stale read during the deep-effect update cycle above.
|
|
72
|
+
var activeParameters = isSessionBasedOnCurrentParameters && fg('platform_lp_jira_sllv_renderer_column_sorting') ? sessionParameters : parameters;
|
|
43
73
|
var _useDatasourceTableSt = useDatasourceTableState({
|
|
44
74
|
datasourceId: datasourceId,
|
|
45
|
-
parameters:
|
|
75
|
+
parameters: activeParameters,
|
|
46
76
|
fieldKeys: visibleColumnKeys
|
|
47
77
|
}),
|
|
48
78
|
reset = _useDatasourceTableSt.reset,
|
|
@@ -98,7 +128,7 @@ var DatasourceTableViewWithoutAnalytics = function DatasourceTableViewWithoutAna
|
|
|
98
128
|
reset();
|
|
99
129
|
}
|
|
100
130
|
isInitialRender.current = false;
|
|
101
|
-
}, [reset,
|
|
131
|
+
}, [reset, activeParameters]);
|
|
102
132
|
useEffect(function () {
|
|
103
133
|
if (onVisibleColumnKeysChange && (visibleColumnKeys || []).length === 0 && defaultVisibleColumnKeys.length > 0) {
|
|
104
134
|
onVisibleColumnKeysChange(defaultVisibleColumnKeys);
|
|
@@ -144,6 +174,19 @@ var DatasourceTableViewWithoutAnalytics = function DatasourceTableViewWithoutAna
|
|
|
144
174
|
});
|
|
145
175
|
forcedReset();
|
|
146
176
|
}, [destinationObjectTypes, extensionKey, fireEvent, forcedReset]);
|
|
177
|
+
var onColumnSort = useCallback(function (columnKey) {
|
|
178
|
+
// Build next params/sort atomically so UI state and query state stay in sync.
|
|
179
|
+
var result = columnSortGetter === null || columnSortGetter === void 0 ? void 0 : columnSortGetter({
|
|
180
|
+
parameters: sessionBaseParametersRef.current,
|
|
181
|
+
columnKey: columnKey,
|
|
182
|
+
currentSort: sortState
|
|
183
|
+
});
|
|
184
|
+
if (!result) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
setSortState(result.sort);
|
|
188
|
+
setSessionParameters(result.parameters);
|
|
189
|
+
}, [columnSortGetter, sortState]);
|
|
147
190
|
var handleErrorRefresh = useCallback(function () {
|
|
148
191
|
reset({
|
|
149
192
|
shouldForceRequest: true
|
|
@@ -175,7 +218,7 @@ var DatasourceTableViewWithoutAnalytics = function DatasourceTableViewWithoutAna
|
|
|
175
218
|
loaderFn: fetchMessagesForLocale
|
|
176
219
|
}, /*#__PURE__*/React.createElement("div", {
|
|
177
220
|
className: ax(["_2rko1kw7", "datasource-table"])
|
|
178
|
-
}, hasColumns ? /*#__PURE__*/React.createElement(IssueLikeDataTableView, {
|
|
221
|
+
}, hasColumns ? /*#__PURE__*/React.createElement(IssueLikeDataTableView, _extends({
|
|
179
222
|
testId: 'datasource-table-view',
|
|
180
223
|
hasNextPage: hasNextPage,
|
|
181
224
|
items: responseItems,
|
|
@@ -187,12 +230,16 @@ var DatasourceTableViewWithoutAnalytics = function DatasourceTableViewWithoutAna
|
|
|
187
230
|
visibleColumnKeys: hasStaleVisibleColumnKeys ? defaultVisibleColumnKeys : visibleColumnKeys || defaultVisibleColumnKeys,
|
|
188
231
|
onVisibleColumnKeysChange: onVisibleColumnKeysChange,
|
|
189
232
|
columnCustomSizes: columnCustomSizes,
|
|
190
|
-
onColumnResize: onColumnResize
|
|
233
|
+
onColumnResize: onColumnResize
|
|
234
|
+
}, shouldEnableColumnSort && fg('platform_lp_jira_sllv_renderer_column_sorting') ? {
|
|
235
|
+
onColumnSort: onColumnSort,
|
|
236
|
+
sortState: sortState
|
|
237
|
+
} : {}, {
|
|
191
238
|
wrappedColumnKeys: wrappedColumnKeys,
|
|
192
239
|
onWrappedColumnChange: onWrappedColumnChange,
|
|
193
240
|
scrollableContainerHeight: isInPDFRender ? undefined : fg('lp_enable_datasource-table-view_height_override') ? scrollableContainerHeight : DefaultScrollableContainerHeight,
|
|
194
241
|
extensionKey: extensionKey
|
|
195
|
-
}) : /*#__PURE__*/React.createElement(EmptyState, {
|
|
242
|
+
})) : /*#__PURE__*/React.createElement(EmptyState, {
|
|
196
243
|
testId: "datasource-table-view-skeleton",
|
|
197
244
|
isCompact: true
|
|
198
245
|
}), /*#__PURE__*/React.createElement(TableFooter, {
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
.pm-table-wrapper>table thead ._1rmlidpf:last-of-type{border:0}
|
|
15
15
|
.pm-table-wrapper>table thead ._1u3bidpf{border:0}
|
|
16
16
|
.pm-table-wrapper>table thead ._ex0g13hi:last-of-type{background:linear-gradient(90deg,hsla(0,0%,100%,0) 0,var(--ds-elevation-surface-current,#fff) 10%)}
|
|
17
|
+
._1wtnze3t button{padding-block:var(--ds-space-0,0)}
|
|
17
18
|
.ProseMirror .pm-table-wrapper>table tbody ._15lria51{border-bottom:var(--ds-border-width,1px) solid var(--ds-border,#0b120e24)}
|
|
18
19
|
.ProseMirror .pm-table-wrapper>table tbody ._1ho1idpf:last-of-type{border-right:0}
|
|
19
20
|
.ProseMirror .pm-table-wrapper>table tbody ._1xqpia51{border-right:var(--ds-border-width,1px) solid var(--ds-border,#0b120e24)}
|
|
@@ -66,6 +67,7 @@ thead.has-column-picker ._10i2idpf:nth-last-of-type(2){border-right:0}.ProseMirr
|
|
|
66
67
|
.ProseMirror .pm-table-wrapper>table thead ._zjk41if8:last-of-type{position:sticky}
|
|
67
68
|
._11681tcg [data-testid=datasource-header-content--container]{line-height:24px}
|
|
68
69
|
._11j11b66 [data-testid=datasource-header-content--container]{padding-right:var(--ds-space-050,4px)}
|
|
70
|
+
._11lvze3t button{padding-left:var(--ds-space-0,0)}
|
|
69
71
|
._124in7od [data-testid=inline-card-icon-and-title]{white-space:unset}
|
|
70
72
|
._12pn15vq [data-testid=datasource-header-content--container]{overflow-x:hidden}
|
|
71
73
|
._12ruusvi:last-of-type{box-sizing:border-box}
|
|
@@ -108,7 +110,9 @@ thead.has-column-picker ._10i2idpf:nth-last-of-type(2){border-right:0}.ProseMirr
|
|
|
108
110
|
._btyzidpf{border-spacing:0}
|
|
109
111
|
._ca0qv77o{padding-top:var(--ds-space-025,2px)}
|
|
110
112
|
._ca0qze3t{padding-top:var(--ds-space-0,0)}
|
|
113
|
+
._ficf1e5h button{text-align:left}
|
|
111
114
|
._iscccj1k [data-testid=datasource-header-content--container]{display:-webkit-box}
|
|
115
|
+
._jq8g1wug button{height:auto}
|
|
112
116
|
._k48p1wq8{font-weight:var(--ds-font-weight-medium,500)}
|
|
113
117
|
._kqsw1if8{position:sticky}
|
|
114
118
|
._kqswh2mm{position:relative}
|
|
@@ -130,6 +134,7 @@ thead.has-column-picker ._10i2idpf:nth-last-of-type(2){border-right:0}.ProseMirr
|
|
|
130
134
|
._vchh1ntv{box-sizing:content-box}
|
|
131
135
|
._vchhusvi{box-sizing:border-box}
|
|
132
136
|
._vwz41tcg{line-height:24px}
|
|
137
|
+
._yhjm1b66 button{padding-right:var(--ds-space-050,4px)}
|
|
133
138
|
._yq5hus1c{border-collapse:separate}
|
|
134
139
|
.pm-table-wrapper>table tbody ._18a21kw7{vertical-align:inherit}
|
|
135
140
|
.pm-table-wrapper>table tbody ._1h12ze3t{padding-right:var(--ds-space-0,0)}
|