@atlaskit/link-datasource 1.11.1 → 1.12.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 +20 -0
- package/dist/cjs/analytics/constants.js +1 -1
- package/dist/cjs/services/mocks.js +134 -0
- package/dist/cjs/services/useBasicFilterAGG.js +119 -0
- package/dist/cjs/services/utils.js +8 -0
- package/dist/cjs/ui/assets-modal/modal/index.js +2 -2
- package/dist/cjs/ui/datasource-table-view/datasourceTableView.js +5 -1
- package/dist/cjs/ui/issue-like-table/draggable-table-heading.js +109 -5
- package/dist/cjs/ui/issue-like-table/index.js +109 -95
- package/dist/cjs/ui/jira-issues-modal/basic-filters/mocks/fieldValuesEmptyResponse.js +20 -0
- package/dist/cjs/ui/jira-issues-modal/basic-filters/mocks/fieldValuesExpectedResponseForAssignees.js +155 -0
- package/dist/cjs/ui/jira-issues-modal/basic-filters/mocks/fieldValuesStandardResponseForProjects.js +82 -0
- package/dist/cjs/ui/jira-issues-modal/basic-filters/mocks/fieldValuesStandardResponseForStatuses.js +87 -0
- package/dist/cjs/ui/jira-issues-modal/basic-filters/mocks/fieldValuesStandardResponseForTypes.js +97 -0
- package/dist/cjs/ui/jira-issues-modal/basic-filters/mocks/hydrateJqlEmptyResponse.js +18 -0
- package/dist/cjs/ui/jira-issues-modal/basic-filters/mocks/hydrateJqlStandardResponse.js +111 -0
- package/dist/cjs/ui/jira-issues-modal/basic-filters/types.js +15 -0
- package/dist/cjs/ui/jira-issues-modal/basic-filters/ui/async-popup-select/formatOptionLabel.js +0 -1
- package/dist/cjs/ui/jira-issues-modal/basic-filters/utils/transformers.js +97 -0
- package/dist/cjs/ui/jira-issues-modal/modal/index.js +16 -5
- package/dist/es2019/analytics/constants.js +1 -1
- package/dist/es2019/services/mocks.js +128 -0
- package/dist/es2019/services/useBasicFilterAGG.js +72 -0
- package/dist/es2019/services/utils.js +113 -0
- package/dist/es2019/ui/assets-modal/modal/index.js +2 -2
- package/dist/es2019/ui/datasource-table-view/datasourceTableView.js +5 -1
- package/dist/es2019/ui/issue-like-table/draggable-table-heading.js +113 -5
- package/dist/es2019/ui/issue-like-table/index.js +82 -72
- package/dist/es2019/ui/jira-issues-modal/basic-filters/mocks/fieldValuesEmptyResponse.js +14 -0
- package/dist/es2019/ui/jira-issues-modal/basic-filters/mocks/fieldValuesExpectedResponseForAssignees.js +149 -0
- package/dist/es2019/ui/jira-issues-modal/basic-filters/mocks/fieldValuesStandardResponseForProjects.js +76 -0
- package/dist/es2019/ui/jira-issues-modal/basic-filters/mocks/fieldValuesStandardResponseForStatuses.js +81 -0
- package/dist/es2019/ui/jira-issues-modal/basic-filters/mocks/fieldValuesStandardResponseForTypes.js +91 -0
- package/dist/es2019/ui/jira-issues-modal/basic-filters/mocks/hydrateJqlEmptyResponse.js +12 -0
- package/dist/es2019/ui/jira-issues-modal/basic-filters/mocks/hydrateJqlStandardResponse.js +105 -0
- package/dist/es2019/ui/jira-issues-modal/basic-filters/types.js +9 -0
- package/dist/es2019/ui/jira-issues-modal/basic-filters/ui/async-popup-select/formatOptionLabel.js +0 -1
- package/dist/es2019/ui/jira-issues-modal/basic-filters/utils/transformers.js +91 -0
- package/dist/es2019/ui/jira-issues-modal/modal/index.js +15 -4
- package/dist/esm/analytics/constants.js +1 -1
- package/dist/esm/services/mocks.js +128 -0
- package/dist/esm/services/useBasicFilterAGG.js +112 -0
- package/dist/esm/services/utils.js +2 -0
- package/dist/esm/ui/assets-modal/modal/index.js +2 -2
- package/dist/esm/ui/datasource-table-view/datasourceTableView.js +5 -1
- package/dist/esm/ui/issue-like-table/draggable-table-heading.js +109 -5
- package/dist/esm/ui/issue-like-table/index.js +108 -94
- package/dist/esm/ui/jira-issues-modal/basic-filters/mocks/fieldValuesEmptyResponse.js +14 -0
- package/dist/esm/ui/jira-issues-modal/basic-filters/mocks/fieldValuesExpectedResponseForAssignees.js +149 -0
- package/dist/esm/ui/jira-issues-modal/basic-filters/mocks/fieldValuesStandardResponseForProjects.js +76 -0
- package/dist/esm/ui/jira-issues-modal/basic-filters/mocks/fieldValuesStandardResponseForStatuses.js +81 -0
- package/dist/esm/ui/jira-issues-modal/basic-filters/mocks/fieldValuesStandardResponseForTypes.js +91 -0
- package/dist/esm/ui/jira-issues-modal/basic-filters/mocks/hydrateJqlEmptyResponse.js +12 -0
- package/dist/esm/ui/jira-issues-modal/basic-filters/mocks/hydrateJqlStandardResponse.js +105 -0
- package/dist/esm/ui/jira-issues-modal/basic-filters/types.js +9 -0
- package/dist/esm/ui/jira-issues-modal/basic-filters/ui/async-popup-select/formatOptionLabel.js +0 -1
- package/dist/esm/ui/jira-issues-modal/basic-filters/utils/transformers.js +89 -0
- package/dist/esm/ui/jira-issues-modal/modal/index.js +17 -6
- package/dist/types/services/mocks.d.ts +3 -0
- package/dist/types/services/useBasicFilterAGG.d.ts +5 -0
- package/dist/types/services/utils.d.ts +2 -0
- package/dist/types/ui/datasource-table-view/types.d.ts +4 -0
- package/dist/types/ui/issue-like-table/draggable-table-heading.d.ts +3 -2
- package/dist/types/ui/issue-like-table/index.d.ts +5 -3
- package/dist/types/ui/issue-like-table/types.d.ts +5 -0
- package/dist/types/ui/jira-issues-modal/basic-filters/hooks/useFieldValues.d.ts +1 -1
- package/dist/types/ui/jira-issues-modal/basic-filters/mocks/fieldValuesEmptyResponse.d.ts +3 -0
- package/dist/types/ui/jira-issues-modal/basic-filters/mocks/fieldValuesExpectedResponseForAssignees.d.ts +17 -0
- package/dist/types/ui/jira-issues-modal/basic-filters/mocks/fieldValuesStandardResponseForProjects.d.ts +8 -0
- package/dist/types/ui/jira-issues-modal/basic-filters/mocks/fieldValuesStandardResponseForStatuses.d.ts +8 -0
- package/dist/types/ui/jira-issues-modal/basic-filters/mocks/fieldValuesStandardResponseForTypes.d.ts +8 -0
- package/dist/types/ui/jira-issues-modal/basic-filters/mocks/hydrateJqlEmptyResponse.d.ts +3 -0
- package/dist/types/ui/jira-issues-modal/basic-filters/mocks/hydrateJqlStandardResponse.d.ts +29 -0
- package/dist/types/ui/jira-issues-modal/basic-filters/types.d.ts +93 -0
- package/dist/types/ui/jira-issues-modal/basic-filters/ui/async-popup-select/control.d.ts +1 -1
- package/dist/types/ui/jira-issues-modal/basic-filters/ui/async-popup-select/formatOptionLabel.d.ts +1 -1
- package/dist/types/ui/jira-issues-modal/basic-filters/ui/async-popup-select/index.d.ts +1 -1
- package/dist/types/ui/jira-issues-modal/basic-filters/ui/async-popup-select/trigger.d.ts +1 -1
- package/dist/types/ui/jira-issues-modal/basic-filters/utils/transformers.d.ts +8 -0
- package/dist/types/ui/jira-issues-modal/jira-search-container/buildJQL.d.ts +1 -1
- package/dist/types/ui/jira-issues-modal/types.d.ts +4 -0
- package/dist/types-ts4.5/services/mocks.d.ts +3 -0
- package/dist/types-ts4.5/services/useBasicFilterAGG.d.ts +5 -0
- package/dist/types-ts4.5/services/utils.d.ts +2 -0
- package/dist/types-ts4.5/ui/datasource-table-view/types.d.ts +4 -0
- package/dist/types-ts4.5/ui/issue-like-table/draggable-table-heading.d.ts +3 -2
- package/dist/types-ts4.5/ui/issue-like-table/index.d.ts +5 -3
- package/dist/types-ts4.5/ui/issue-like-table/types.d.ts +5 -0
- package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/hooks/useFieldValues.d.ts +1 -1
- package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/mocks/fieldValuesEmptyResponse.d.ts +3 -0
- package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/mocks/fieldValuesExpectedResponseForAssignees.d.ts +17 -0
- package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/mocks/fieldValuesStandardResponseForProjects.d.ts +8 -0
- package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/mocks/fieldValuesStandardResponseForStatuses.d.ts +8 -0
- package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/mocks/fieldValuesStandardResponseForTypes.d.ts +8 -0
- package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/mocks/hydrateJqlEmptyResponse.d.ts +3 -0
- package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/mocks/hydrateJqlStandardResponse.d.ts +29 -0
- package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/types.d.ts +93 -0
- package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/ui/async-popup-select/control.d.ts +1 -1
- package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/ui/async-popup-select/formatOptionLabel.d.ts +1 -1
- package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/ui/async-popup-select/index.d.ts +1 -1
- package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/ui/async-popup-select/trigger.d.ts +1 -1
- package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/utils/transformers.d.ts +8 -0
- package/dist/types-ts4.5/ui/jira-issues-modal/jira-search-container/buildJQL.d.ts +1 -1
- package/dist/types-ts4.5/ui/jira-issues-modal/types.d.ts +4 -0
- package/examples-helpers/buildIssueLikeTable.tsx +15 -1
- package/examples-helpers/buildJiraIssuesTable.tsx +15 -1
- package/package.json +6 -6
- package/report.api.md +11 -0
- package/tmp/api-report-tmp.d.ts +11 -0
- package/dist/cjs/ui/jira-issues-modal/basic-filters/ui/async-popup-select/types.js +0 -5
- package/dist/es2019/ui/jira-issues-modal/basic-filters/ui/async-popup-select/types.js +0 -1
- package/dist/esm/ui/jira-issues-modal/basic-filters/ui/async-popup-select/types.js +0 -1
- package/dist/types/ui/jira-issues-modal/basic-filters/ui/async-popup-select/types.d.ts +0 -23
- package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/ui/async-popup-select/types.d.ts +0 -23
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { useCallback, useMemo } from 'react';
|
|
2
|
+
import { useSmartLinkContext } from '@atlaskit/link-provider';
|
|
3
|
+
import { getBaseUrl } from '@atlaskit/linking-common';
|
|
4
|
+
import { fieldValuesQuery, hydrateJQLQuery } from './utils';
|
|
5
|
+
const getGraphqlUrl = (envKey, baseUrlOverride) => {
|
|
6
|
+
const baseUrl = baseUrlOverride || getBaseUrl(envKey);
|
|
7
|
+
return baseUrl ? `${baseUrl}/graphql` : '/gateway/api/graphql';
|
|
8
|
+
};
|
|
9
|
+
export const useBasicFilterAGG = () => {
|
|
10
|
+
const {
|
|
11
|
+
connections: {
|
|
12
|
+
client
|
|
13
|
+
}
|
|
14
|
+
} = useSmartLinkContext();
|
|
15
|
+
const gatewayGraphqlUrl = getGraphqlUrl(client.envKey, client.baseUrlOverride);
|
|
16
|
+
const aggHeaders = useMemo(() => {
|
|
17
|
+
return new Headers({
|
|
18
|
+
'Content-Type': 'application/json',
|
|
19
|
+
'X-ExperimentalApi': 'JiraJqlBuilder'
|
|
20
|
+
});
|
|
21
|
+
}, []);
|
|
22
|
+
const getHydratedJQL = useCallback(async (cloudId, jql) => {
|
|
23
|
+
const body = JSON.stringify({
|
|
24
|
+
variables: {
|
|
25
|
+
cloudId,
|
|
26
|
+
jql
|
|
27
|
+
},
|
|
28
|
+
operationName: 'hydrate',
|
|
29
|
+
query: hydrateJQLQuery
|
|
30
|
+
});
|
|
31
|
+
const request = new Request(gatewayGraphqlUrl, {
|
|
32
|
+
method: 'POST',
|
|
33
|
+
headers: aggHeaders,
|
|
34
|
+
body
|
|
35
|
+
});
|
|
36
|
+
try {
|
|
37
|
+
const response = await fetch(request);
|
|
38
|
+
return response.json();
|
|
39
|
+
} catch (e) {
|
|
40
|
+
throw new Error(e);
|
|
41
|
+
}
|
|
42
|
+
}, [gatewayGraphqlUrl, aggHeaders]);
|
|
43
|
+
const getFieldValues = useCallback(async (cloudId, jql, jqlTerm, searchString, pageCursor) => {
|
|
44
|
+
const body = JSON.stringify({
|
|
45
|
+
variables: {
|
|
46
|
+
cloudId,
|
|
47
|
+
jql,
|
|
48
|
+
first: 10,
|
|
49
|
+
jqlTerm,
|
|
50
|
+
searchString,
|
|
51
|
+
after: pageCursor
|
|
52
|
+
},
|
|
53
|
+
operationName: 'fieldValues',
|
|
54
|
+
query: fieldValuesQuery
|
|
55
|
+
});
|
|
56
|
+
const request = new Request(gatewayGraphqlUrl, {
|
|
57
|
+
method: 'POST',
|
|
58
|
+
headers: aggHeaders,
|
|
59
|
+
body
|
|
60
|
+
});
|
|
61
|
+
try {
|
|
62
|
+
const response = await fetch(request);
|
|
63
|
+
return await response.json();
|
|
64
|
+
} catch (e) {
|
|
65
|
+
throw new Error(e);
|
|
66
|
+
}
|
|
67
|
+
}, [gatewayGraphqlUrl, aggHeaders]);
|
|
68
|
+
return useMemo(() => ({
|
|
69
|
+
getHydratedJQL,
|
|
70
|
+
getFieldValues
|
|
71
|
+
}), [getHydratedJQL, getFieldValues]);
|
|
72
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
export const hydrateJQLQuery = `query hydrate($cloudId: ID!, $jql: String!) {
|
|
2
|
+
jira {
|
|
3
|
+
jqlBuilder(cloudId: $cloudId) {
|
|
4
|
+
hydrateJqlQuery(query: $jql) {
|
|
5
|
+
... on JiraJqlHydratedQuery {
|
|
6
|
+
fields {
|
|
7
|
+
... on JiraJqlQueryHydratedField {
|
|
8
|
+
jqlTerm
|
|
9
|
+
values {
|
|
10
|
+
... on JiraJqlQueryHydratedValue {
|
|
11
|
+
values {
|
|
12
|
+
... on JiraJqlProjectFieldValue {
|
|
13
|
+
jqlTerm
|
|
14
|
+
displayName
|
|
15
|
+
project {
|
|
16
|
+
avatar {
|
|
17
|
+
small
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
... on JiraJqlStatusFieldValue {
|
|
22
|
+
jqlTerm
|
|
23
|
+
displayName
|
|
24
|
+
statusCategory {
|
|
25
|
+
colorName
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
... on JiraJqlIssueTypeFieldValue {
|
|
29
|
+
jqlTerm
|
|
30
|
+
displayName
|
|
31
|
+
issueTypes {
|
|
32
|
+
avatar {
|
|
33
|
+
small
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
... on JiraJqlUserFieldValue {
|
|
38
|
+
jqlTerm
|
|
39
|
+
displayName
|
|
40
|
+
user {
|
|
41
|
+
picture
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
... on JiraJqlGroupFieldValue {
|
|
45
|
+
jqlTerm
|
|
46
|
+
displayName
|
|
47
|
+
group {
|
|
48
|
+
name
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}`;
|
|
61
|
+
export const fieldValuesQuery = `query fieldValues($cloudId: ID!, $first: Int = 10, $jqlTerm: String!, $jql: String!, $searchString: String!, $after: String, $projectOptions: JiraProjectOptions) {
|
|
62
|
+
jira {
|
|
63
|
+
jqlBuilder(cloudId: $cloudId) {
|
|
64
|
+
fieldValues(
|
|
65
|
+
first: $first
|
|
66
|
+
jqlTerm: $jqlTerm
|
|
67
|
+
jqlContext: $jql
|
|
68
|
+
searchString: $searchString
|
|
69
|
+
after: $after
|
|
70
|
+
) {
|
|
71
|
+
totalCount
|
|
72
|
+
pageInfo {
|
|
73
|
+
endCursor
|
|
74
|
+
}
|
|
75
|
+
edges {
|
|
76
|
+
node {
|
|
77
|
+
jqlTerm
|
|
78
|
+
displayName
|
|
79
|
+
... on JiraJqlProjectFieldValue {
|
|
80
|
+
project {
|
|
81
|
+
avatar {
|
|
82
|
+
small
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
... on JiraJqlIssueTypeFieldValue {
|
|
87
|
+
issueTypes {
|
|
88
|
+
avatar {
|
|
89
|
+
small
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
... on JiraJqlStatusFieldValue {
|
|
94
|
+
statusCategory {
|
|
95
|
+
colorName
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
... on JiraJqlUserFieldValue {
|
|
99
|
+
user {
|
|
100
|
+
picture
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
... on JiraJqlGroupFieldValue {
|
|
104
|
+
group {
|
|
105
|
+
name
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}`;
|
|
@@ -216,7 +216,7 @@ const PlainAssetsConfigModal = props => {
|
|
|
216
216
|
onCancel();
|
|
217
217
|
}, [analyticsPayload, onCancel]);
|
|
218
218
|
const handleOnSearch = useCallback(async (searchAql, searchSchemaId) => {
|
|
219
|
-
if (schemaId !== searchSchemaId || aql !== searchAql) {
|
|
219
|
+
if (schemaId !== searchSchemaId || aql !== searchAql || status === 'rejected') {
|
|
220
220
|
searchCount.current++;
|
|
221
221
|
if (schemaId !== searchSchemaId) {
|
|
222
222
|
userInteractionActions.current.add(DatasourceAction.SCHEMA_UPDATED);
|
|
@@ -231,7 +231,7 @@ const PlainAssetsConfigModal = props => {
|
|
|
231
231
|
setSchemaId(searchSchemaId);
|
|
232
232
|
setIsNewSearch(true);
|
|
233
233
|
}
|
|
234
|
-
}, [aql, reset, schemaId]);
|
|
234
|
+
}, [aql, reset, schemaId, status]);
|
|
235
235
|
const renderModalTitleContent = useCallback(() => {
|
|
236
236
|
if (workspaceError) {
|
|
237
237
|
return undefined;
|
|
@@ -21,7 +21,9 @@ const DatasourceTableViewWithoutAnalytics = ({
|
|
|
21
21
|
parameters,
|
|
22
22
|
visibleColumnKeys,
|
|
23
23
|
onVisibleColumnKeysChange,
|
|
24
|
-
url
|
|
24
|
+
url,
|
|
25
|
+
columnCustomSizes,
|
|
26
|
+
onColumnResize
|
|
25
27
|
}) => {
|
|
26
28
|
const {
|
|
27
29
|
reset,
|
|
@@ -132,6 +134,8 @@ const DatasourceTableViewWithoutAnalytics = ({
|
|
|
132
134
|
columns: columns,
|
|
133
135
|
visibleColumnKeys: visibleColumnKeys || defaultVisibleColumnKeys,
|
|
134
136
|
onVisibleColumnKeysChange: onVisibleColumnKeysChange,
|
|
137
|
+
columnCustomSizes: columnCustomSizes,
|
|
138
|
+
onColumnResize: onColumnResize,
|
|
135
139
|
scrollableContainerHeight: ScrollableContainerHeight,
|
|
136
140
|
parentContainerRenderInstanceId: tableRenderInstanceId,
|
|
137
141
|
extensionKey: extensionKey
|
|
@@ -6,10 +6,13 @@ import invariant from 'tiny-invariant';
|
|
|
6
6
|
import { attachClosestEdge, extractClosestEdge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/addon/closest-edge';
|
|
7
7
|
import { DropIndicator } from '@atlaskit/pragmatic-drag-and-drop-react-indicator/box-without-terminal';
|
|
8
8
|
import { draggable, dropTargetForElements, monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/adapter/element';
|
|
9
|
+
import { cancelUnhandled } from '@atlaskit/pragmatic-drag-and-drop/addon/cancel-unhandled';
|
|
9
10
|
import { combine } from '@atlaskit/pragmatic-drag-and-drop/util/combine';
|
|
11
|
+
import { disableNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/util/disable-native-drag-preview';
|
|
10
12
|
import { offsetFromPointer } from '@atlaskit/pragmatic-drag-and-drop/util/offset-from-pointer';
|
|
11
13
|
import { setCustomNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/util/set-custom-native-drag-preview';
|
|
12
14
|
import { TableHeading } from './styled';
|
|
15
|
+
import { COLUMN_MIN_WIDTH } from './index';
|
|
13
16
|
const tableHeadingStatusStyles = {
|
|
14
17
|
idle: css({
|
|
15
18
|
':hover': {
|
|
@@ -35,6 +38,40 @@ const dropTargetStyles = css({
|
|
|
35
38
|
const noPointerEventsStyles = css({
|
|
36
39
|
pointerEvents: 'none'
|
|
37
40
|
});
|
|
41
|
+
const resizerStyles = css({
|
|
42
|
+
'--local-hitbox-width': "var(--ds-space-300, 24px)",
|
|
43
|
+
width: 'var(--local-hitbox-width)',
|
|
44
|
+
cursor: 'col-resize',
|
|
45
|
+
flexGrow: '0',
|
|
46
|
+
position: 'absolute',
|
|
47
|
+
zIndex: 1,
|
|
48
|
+
// we want this to sit on top of adjacent column headers
|
|
49
|
+
right: 'calc(-1 * calc(var(--local-hitbox-width) / 2))',
|
|
50
|
+
top: 0,
|
|
51
|
+
'::before': {
|
|
52
|
+
opacity: 0,
|
|
53
|
+
'--local-line-width': "var(--ds-border-width, 2px)",
|
|
54
|
+
content: '""',
|
|
55
|
+
position: 'absolute',
|
|
56
|
+
background: "var(--ds-border-brand, #0052CC)",
|
|
57
|
+
width: 'var(--local-line-width)',
|
|
58
|
+
inset: 0,
|
|
59
|
+
left: `calc(50% - calc(var(--local-line-width) / 2))`,
|
|
60
|
+
transition: 'opacity 0.2s ease'
|
|
61
|
+
},
|
|
62
|
+
':hover::before': {
|
|
63
|
+
opacity: 1
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
const resizingStyles = css({
|
|
67
|
+
// turning off the resizing cursor as sometimes it can cause the cursor to flicker
|
|
68
|
+
// while resizing. The browser controls the cursor while dragging, but the browser
|
|
69
|
+
// can sometimes bug out.
|
|
70
|
+
cursor: 'unset',
|
|
71
|
+
'::before': {
|
|
72
|
+
opacity: 1
|
|
73
|
+
}
|
|
74
|
+
});
|
|
38
75
|
const idleState = {
|
|
39
76
|
type: 'idle'
|
|
40
77
|
};
|
|
@@ -48,15 +85,17 @@ export const DraggableTableHeading = ({
|
|
|
48
85
|
tableId,
|
|
49
86
|
dndPreviewHeight,
|
|
50
87
|
dragPreview,
|
|
51
|
-
|
|
88
|
+
width,
|
|
89
|
+
onWidthChange
|
|
52
90
|
}) => {
|
|
53
|
-
const
|
|
91
|
+
const mainHeaderCellRef = useRef(null);
|
|
92
|
+
const columnResizeHandleRef = useRef(null);
|
|
54
93
|
const [state, setState] = useState(idleState);
|
|
55
94
|
const [isDraggingAnyColumn, setIsDraggingAnyColumn] = useState(false);
|
|
56
95
|
const [closestEdge, setClosestEdge] = useState(null);
|
|
57
96
|
const dropTargetRef = useRef(null);
|
|
58
97
|
useEffect(() => {
|
|
59
|
-
const cell =
|
|
98
|
+
const cell = mainHeaderCellRef.current;
|
|
60
99
|
invariant(cell);
|
|
61
100
|
return combine(draggable({
|
|
62
101
|
element: cell,
|
|
@@ -161,15 +200,84 @@ export const DraggableTableHeading = ({
|
|
|
161
200
|
}
|
|
162
201
|
});
|
|
163
202
|
}, [tableId]);
|
|
203
|
+
|
|
204
|
+
// Handling column resizing
|
|
205
|
+
useEffect(() => {
|
|
206
|
+
const resizeHandle = columnResizeHandleRef.current;
|
|
207
|
+
invariant(resizeHandle);
|
|
208
|
+
const mainHeaderCell = mainHeaderCellRef.current;
|
|
209
|
+
invariant(mainHeaderCell);
|
|
210
|
+
return draggable({
|
|
211
|
+
element: resizeHandle,
|
|
212
|
+
getInitialData() {
|
|
213
|
+
// metadata related to currently dragging item (can be read by drop events etc)
|
|
214
|
+
return {
|
|
215
|
+
type: 'column-resize',
|
|
216
|
+
id,
|
|
217
|
+
index,
|
|
218
|
+
tableId
|
|
219
|
+
};
|
|
220
|
+
},
|
|
221
|
+
// Is called when dragging started
|
|
222
|
+
onGenerateDragPreview({
|
|
223
|
+
nativeSetDragImage
|
|
224
|
+
}) {
|
|
225
|
+
// We don't show any preview, since column separator (handle) is moving with the cursor
|
|
226
|
+
disableNativeDragPreview({
|
|
227
|
+
nativeSetDragImage
|
|
228
|
+
});
|
|
229
|
+
// Block drag operations outside `@atlaskit/pragmatic-drag-and-drop`
|
|
230
|
+
cancelUnhandled.start();
|
|
231
|
+
setState({
|
|
232
|
+
type: 'resizing',
|
|
233
|
+
initialWidth: width
|
|
234
|
+
});
|
|
235
|
+
},
|
|
236
|
+
onDrag({
|
|
237
|
+
location
|
|
238
|
+
}) {
|
|
239
|
+
const relativeDistanceX = location.current.input.clientX - location.initial.input.clientX;
|
|
240
|
+
invariant(state.type === 'resizing');
|
|
241
|
+
const {
|
|
242
|
+
initialWidth
|
|
243
|
+
} = state;
|
|
244
|
+
|
|
245
|
+
// Set the width of our header being resized
|
|
246
|
+
let proposedWidth = initialWidth + relativeDistanceX;
|
|
247
|
+
if (initialWidth >= COLUMN_MIN_WIDTH && proposedWidth < COLUMN_MIN_WIDTH) {
|
|
248
|
+
proposedWidth = COLUMN_MIN_WIDTH;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// We update width css directly live
|
|
252
|
+
mainHeaderCell.style.setProperty('width', `${proposedWidth}px`);
|
|
253
|
+
},
|
|
254
|
+
onDrop() {
|
|
255
|
+
cancelUnhandled.stop();
|
|
256
|
+
setState(idleState);
|
|
257
|
+
if (onWidthChange) {
|
|
258
|
+
// We use element's css value as a source of truth (compare to another Ref)
|
|
259
|
+
const currentWidthPx = mainHeaderCell.style.getPropertyValue('width');
|
|
260
|
+
onWidthChange(+currentWidthPx.slice(0, -2));
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
}, [id, index, onWidthChange, state, tableId, width]);
|
|
164
265
|
return jsx(TableHeading, {
|
|
165
|
-
ref:
|
|
266
|
+
ref: mainHeaderCellRef,
|
|
166
267
|
css: [tableHeadingStatusStyles[state.type]],
|
|
167
268
|
"data-testid": `${id}-column-heading`,
|
|
168
269
|
style: {
|
|
169
|
-
|
|
270
|
+
width,
|
|
170
271
|
cursor: 'grab'
|
|
171
272
|
}
|
|
172
273
|
}, jsx("div", {
|
|
274
|
+
ref: columnResizeHandleRef,
|
|
275
|
+
css: [resizerStyles, state.type === 'resizing' && resizingStyles],
|
|
276
|
+
style: {
|
|
277
|
+
height: `${dndPreviewHeight}px`
|
|
278
|
+
},
|
|
279
|
+
"data-testid": "column-resize-handle"
|
|
280
|
+
}), jsx("div", {
|
|
173
281
|
ref: dropTargetRef,
|
|
174
282
|
css: [dropTargetStyles, isDraggingAnyColumn ? null : noPointerEventsStyles],
|
|
175
283
|
style: {
|
|
@@ -29,7 +29,8 @@ const tableHeadStyles = css({
|
|
|
29
29
|
zIndex: stickyTableHeadersIndex
|
|
30
30
|
});
|
|
31
31
|
const ColumnPickerHeader = styled.th`
|
|
32
|
-
width:
|
|
32
|
+
width: 56px;
|
|
33
|
+
z-index: 10;
|
|
33
34
|
position: sticky;
|
|
34
35
|
right: calc(-1 * ${tableSidePadding});
|
|
35
36
|
background-color: ${"var(--ds-surface, #FFF)"};
|
|
@@ -43,6 +44,7 @@ const ColumnPickerHeader = styled.th`
|
|
|
43
44
|
&:last-of-type {
|
|
44
45
|
padding-right: ${tableSidePadding};
|
|
45
46
|
}
|
|
47
|
+
text-align: right; /* In case when TH itself is bigger we want to keep picker at the right side */
|
|
46
48
|
`;
|
|
47
49
|
const truncatedCellStyles = css({
|
|
48
50
|
overflow: 'hidden',
|
|
@@ -56,6 +58,7 @@ const scrollableContainerStyles = css({
|
|
|
56
58
|
borderRadius: "var(--ds-border-radius-100, 3px)"
|
|
57
59
|
});
|
|
58
60
|
const tableStyles = css({
|
|
61
|
+
tableLayout: 'fixed',
|
|
59
62
|
// These styles are needed to prevent thead bottom border from scrolling away.
|
|
60
63
|
// This happens because it is sticky. https://stackoverflow.com/questions/50361698/border-style-do-not-work-with-sticky-position-element
|
|
61
64
|
borderCollapse: 'separate',
|
|
@@ -74,7 +77,7 @@ function extractIndex(data) {
|
|
|
74
77
|
invariant(typeof index === 'number');
|
|
75
78
|
return index;
|
|
76
79
|
}
|
|
77
|
-
export const
|
|
80
|
+
export const getOrderedColumns = (columns, visibleColumnKeys) => {
|
|
78
81
|
const visibleColumns = columns.filter(column => visibleColumnKeys.includes(column.key)).sort((a, b) => {
|
|
79
82
|
const indexB = visibleColumnKeys.indexOf(b.key);
|
|
80
83
|
const indexA = visibleColumnKeys.indexOf(a.key);
|
|
@@ -84,25 +87,28 @@ export const orderColumns = (columns, visibleColumnKeys) => {
|
|
|
84
87
|
return [...visibleColumns, ...invisibleColumns];
|
|
85
88
|
};
|
|
86
89
|
const BASE_WIDTH = 8;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
90
|
+
const DEFAULT_WIDTH = BASE_WIDTH * 22;
|
|
91
|
+
export const COLUMN_MIN_WIDTH = BASE_WIDTH * 3;
|
|
92
|
+
const keyBasedWidthMap = {
|
|
93
|
+
priority: BASE_WIDTH * 4,
|
|
94
|
+
status: BASE_WIDTH * 18,
|
|
95
|
+
summary: BASE_WIDTH * 45,
|
|
96
|
+
description: BASE_WIDTH * 31.25,
|
|
97
|
+
type: BASE_WIDTH * 4,
|
|
98
|
+
key: BASE_WIDTH * 13
|
|
99
|
+
};
|
|
100
|
+
function getDefaultColumnWidth(key, type) {
|
|
101
|
+
const keyBasedWidth = keyBasedWidthMap[key];
|
|
102
|
+
if (keyBasedWidth) {
|
|
103
|
+
return keyBasedWidth;
|
|
98
104
|
}
|
|
99
105
|
switch (type) {
|
|
100
106
|
case 'date':
|
|
101
107
|
return BASE_WIDTH * 14;
|
|
102
|
-
case '
|
|
103
|
-
return BASE_WIDTH *
|
|
108
|
+
case 'icon':
|
|
109
|
+
return BASE_WIDTH * 4;
|
|
104
110
|
default:
|
|
105
|
-
return
|
|
111
|
+
return DEFAULT_WIDTH;
|
|
106
112
|
}
|
|
107
113
|
}
|
|
108
114
|
export const IssueLikeDataTableView = ({
|
|
@@ -114,6 +120,8 @@ export const IssueLikeDataTableView = ({
|
|
|
114
120
|
renderItem = fallbackRenderType,
|
|
115
121
|
visibleColumnKeys,
|
|
116
122
|
onVisibleColumnKeysChange,
|
|
123
|
+
columnCustomSizes,
|
|
124
|
+
onColumnResize,
|
|
117
125
|
status,
|
|
118
126
|
hasNextPage,
|
|
119
127
|
scrollableContainerHeight,
|
|
@@ -121,14 +129,15 @@ export const IssueLikeDataTableView = ({
|
|
|
121
129
|
extensionKey
|
|
122
130
|
}) => {
|
|
123
131
|
const tableId = useMemo(() => Symbol('unique-id'), []);
|
|
132
|
+
const tableHeaderRowRef = useRef(null);
|
|
124
133
|
const [lastRowElement, setLastRowElement] = useState(null);
|
|
125
134
|
const [hasFullSchema, setHasFullSchema] = useState(false);
|
|
126
135
|
const isBottomOfTableVisibleRaw = useIsOnScreen(lastRowElement);
|
|
127
136
|
const containerRef = useRef(null);
|
|
128
|
-
const [orderedColumns, setOrderedColumns] = useState(() =>
|
|
137
|
+
const [orderedColumns, setOrderedColumns] = useState(() => getOrderedColumns([...columns], [...visibleColumnKeys]));
|
|
129
138
|
useEffect(() => {
|
|
130
139
|
if (!hasFullSchema) {
|
|
131
|
-
setOrderedColumns(
|
|
140
|
+
setOrderedColumns(getOrderedColumns([...columns], [...visibleColumnKeys]));
|
|
132
141
|
}
|
|
133
142
|
}, [columns, visibleColumnKeys, hasFullSchema]);
|
|
134
143
|
useEffect(() => {
|
|
@@ -147,24 +156,8 @@ export const IssueLikeDataTableView = ({
|
|
|
147
156
|
// or some other combination.
|
|
148
157
|
|
|
149
158
|
const identityColumnKey = 'id';
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
cells: visibleSortedColumns.map(({
|
|
153
|
-
key
|
|
154
|
-
}) => {
|
|
155
|
-
const content = jsx(Skeleton, {
|
|
156
|
-
borderRadius: 8,
|
|
157
|
-
width: "100%",
|
|
158
|
-
height: 14,
|
|
159
|
-
testId: "issues-table-row-loading"
|
|
160
|
-
});
|
|
161
|
-
return {
|
|
162
|
-
key,
|
|
163
|
-
content
|
|
164
|
-
};
|
|
165
|
-
})
|
|
166
|
-
}), [visibleSortedColumns]);
|
|
167
|
-
const headColumns = useMemo(() => visibleSortedColumns.map(({
|
|
159
|
+
const getColumnWidth = useCallback((key, type) => (columnCustomSizes === null || columnCustomSizes === void 0 ? void 0 : columnCustomSizes[key]) || getDefaultColumnWidth(key, type), [columnCustomSizes]);
|
|
160
|
+
const headerColumns = useMemo(() => visibleSortedColumns.map(({
|
|
168
161
|
key,
|
|
169
162
|
title,
|
|
170
163
|
type
|
|
@@ -172,8 +165,20 @@ export const IssueLikeDataTableView = ({
|
|
|
172
165
|
key,
|
|
173
166
|
content: title,
|
|
174
167
|
shouldTruncate: true,
|
|
175
|
-
|
|
176
|
-
})), [visibleSortedColumns]);
|
|
168
|
+
width: getColumnWidth(key, type)
|
|
169
|
+
})), [getColumnWidth, visibleSortedColumns]);
|
|
170
|
+
const loadingRow = useMemo(() => ({
|
|
171
|
+
key: 'loading',
|
|
172
|
+
cells: headerColumns.map(column => ({
|
|
173
|
+
...column,
|
|
174
|
+
content: jsx(Skeleton, {
|
|
175
|
+
borderRadius: 8,
|
|
176
|
+
width: "100%",
|
|
177
|
+
height: 14,
|
|
178
|
+
testId: "issues-table-row-loading"
|
|
179
|
+
})
|
|
180
|
+
}))
|
|
181
|
+
}), [headerColumns]);
|
|
177
182
|
useEffect(() => {
|
|
178
183
|
if (isBottomOfTableVisibleRaw && hasNextPage && status === 'resolved') {
|
|
179
184
|
void onNextPage({
|
|
@@ -193,32 +198,38 @@ export const IssueLikeDataTableView = ({
|
|
|
193
198
|
}
|
|
194
199
|
return combine(monitorForElements({
|
|
195
200
|
onDragStart: ({
|
|
196
|
-
location
|
|
201
|
+
location,
|
|
202
|
+
source
|
|
197
203
|
}) => {
|
|
198
|
-
var _containerRef$current;
|
|
199
204
|
initialAutoScrollerClientY.current = location.current.input.clientY;
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
205
|
+
if (source.data.type === 'table-header') {
|
|
206
|
+
var _containerRef$current;
|
|
207
|
+
autoScroller.start({
|
|
208
|
+
input: {
|
|
209
|
+
...location.current.input,
|
|
210
|
+
clientY:
|
|
211
|
+
// The goal is to have clientY the same and in the middle of the scrollable area
|
|
212
|
+
// Since clientY is taken from to of the viewport we need to plus that in order to get
|
|
213
|
+
// middle of the scrollable area in reference to the viewport
|
|
214
|
+
(initialAutoScrollerClientY.current || 0) + (((_containerRef$current = containerRef.current) === null || _containerRef$current === void 0 ? void 0 : _containerRef$current.offsetHeight) || 0) / 2
|
|
215
|
+
},
|
|
216
|
+
behavior: 'container-only'
|
|
217
|
+
});
|
|
218
|
+
}
|
|
211
219
|
},
|
|
212
220
|
onDrag: ({
|
|
213
|
-
location
|
|
221
|
+
location,
|
|
222
|
+
source
|
|
214
223
|
}) => {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
224
|
+
if (source.data.type === 'table-header') {
|
|
225
|
+
var _containerRef$current2;
|
|
226
|
+
autoScroller.updateInput({
|
|
227
|
+
input: {
|
|
228
|
+
...location.current.input,
|
|
229
|
+
clientY: (initialAutoScrollerClientY.current || 0) + (((_containerRef$current2 = containerRef.current) === null || _containerRef$current2 === void 0 ? void 0 : _containerRef$current2.offsetHeight) || 0) / 2
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
}
|
|
222
233
|
},
|
|
223
234
|
onDrop({
|
|
224
235
|
source,
|
|
@@ -247,9 +258,7 @@ export const IssueLikeDataTableView = ({
|
|
|
247
258
|
onVisibleColumnKeysChange === null || onVisibleColumnKeysChange === void 0 ? void 0 : onVisibleColumnKeysChange([...newColumnKeyOrder]);
|
|
248
259
|
|
|
249
260
|
// We sort columns (whole objects) according to their key order presented in newColumnKeyOrder
|
|
250
|
-
setOrderedColumns(columns =>
|
|
251
|
-
return orderColumns([...columns], [...newColumnKeyOrder]);
|
|
252
|
-
});
|
|
261
|
+
setOrderedColumns(columns => getOrderedColumns([...columns], [...newColumnKeyOrder]));
|
|
253
262
|
}
|
|
254
263
|
}
|
|
255
264
|
}));
|
|
@@ -270,11 +279,11 @@ export const IssueLikeDataTableView = ({
|
|
|
270
279
|
return {
|
|
271
280
|
key,
|
|
272
281
|
content: content.length === 1 ? content[0] : content,
|
|
273
|
-
|
|
282
|
+
width: getColumnWidth(key, type)
|
|
274
283
|
};
|
|
275
284
|
}),
|
|
276
285
|
ref: rowIndex === items.length - 1 ? el => setLastRowElement(el) : undefined
|
|
277
|
-
})), [
|
|
286
|
+
})), [items, visibleSortedColumns, getColumnWidth, renderItem]);
|
|
278
287
|
const rows = useMemo(() => {
|
|
279
288
|
if (status !== 'loading') {
|
|
280
289
|
return tableRows;
|
|
@@ -328,10 +337,12 @@ export const IssueLikeDataTableView = ({
|
|
|
328
337
|
}, jsx("thead", {
|
|
329
338
|
"data-testid": testId && `${testId}--head`,
|
|
330
339
|
css: [noDefaultBorderStyles, tableHeadStyles]
|
|
331
|
-
}, jsx("tr",
|
|
340
|
+
}, jsx("tr", {
|
|
341
|
+
ref: tableHeaderRowRef
|
|
342
|
+
}, headerColumns.map(({
|
|
332
343
|
key,
|
|
333
344
|
content,
|
|
334
|
-
|
|
345
|
+
width
|
|
335
346
|
}, cellIndex) => {
|
|
336
347
|
const heading = jsx(Tooltip, {
|
|
337
348
|
content: content,
|
|
@@ -362,7 +373,8 @@ export const IssueLikeDataTableView = ({
|
|
|
362
373
|
key: key,
|
|
363
374
|
id: key,
|
|
364
375
|
index: cellIndex,
|
|
365
|
-
|
|
376
|
+
width: width,
|
|
377
|
+
onWidthChange: onColumnResize === null || onColumnResize === void 0 ? void 0 : onColumnResize.bind(null, key),
|
|
366
378
|
dndPreviewHeight: ((_containerRef$current3 = containerRef.current) === null || _containerRef$current3 === void 0 ? void 0 : _containerRef$current3.offsetHeight) || 0,
|
|
367
379
|
dragPreview: dragPreview
|
|
368
380
|
}, heading);
|
|
@@ -371,9 +383,7 @@ export const IssueLikeDataTableView = ({
|
|
|
371
383
|
key: key,
|
|
372
384
|
"data-testid": `${key}-column-heading`,
|
|
373
385
|
style: {
|
|
374
|
-
|
|
375
|
-
minWidth: maxWidth,
|
|
376
|
-
maxWidth
|
|
386
|
+
width
|
|
377
387
|
}
|
|
378
388
|
}, heading);
|
|
379
389
|
}
|
|
@@ -397,10 +407,10 @@ export const IssueLikeDataTableView = ({
|
|
|
397
407
|
}, cells.map(({
|
|
398
408
|
key: cellKey,
|
|
399
409
|
content,
|
|
400
|
-
|
|
410
|
+
width
|
|
401
411
|
}, cellIndex) => {
|
|
402
412
|
let loadingRowStyle = {
|
|
403
|
-
|
|
413
|
+
width
|
|
404
414
|
};
|
|
405
415
|
// extra padding is required around skeleton loader to avoid vertical jumps when data loads
|
|
406
416
|
if (key !== null && key !== void 0 && key.includes('loading')) {
|