@atlaskit/link-datasource 1.27.4 → 1.28.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.
Files changed (117) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/cjs/services/mocks.js +152 -1
  3. package/dist/cjs/services/useBasicFilterAGG.js +9 -2
  4. package/dist/cjs/services/utils.js +3 -2
  5. package/dist/cjs/ui/common/modal/popup-select/formatOptionLabel.js +6 -3
  6. package/dist/cjs/ui/common/modal/popup-select/index.js +2 -1
  7. package/dist/cjs/ui/common/modal/popup-select/trigger.js +1 -2
  8. package/dist/cjs/ui/confluence-search-modal/basic-filters/filters/date-range-picker/PopupComponent.js +19 -0
  9. package/dist/cjs/ui/confluence-search-modal/basic-filters/filters/date-range-picker/index.js +89 -0
  10. package/dist/cjs/ui/confluence-search-modal/basic-filters/filters/date-range-picker/messages.js +49 -0
  11. package/dist/cjs/ui/confluence-search-modal/basic-filters/filters/date-range-picker/styled.js +75 -0
  12. package/dist/cjs/ui/confluence-search-modal/basic-filters/filters/date-range-picker/trigger.js +32 -0
  13. package/dist/cjs/ui/confluence-search-modal/basic-filters/filters/edited-or-created-by/index.js +110 -0
  14. package/dist/cjs/ui/confluence-search-modal/basic-filters/filters/edited-or-created-by/messages.js +14 -0
  15. package/dist/cjs/ui/confluence-search-modal/basic-filters/hooks/useCurrentUserInfo.js +48 -0
  16. package/dist/cjs/ui/confluence-search-modal/basic-filters/hooks/useRecommendation.js +120 -0
  17. package/dist/cjs/ui/confluence-search-modal/basic-filters/index.js +14 -3
  18. package/dist/cjs/ui/confluence-search-modal/basic-filters/types.js +11 -0
  19. package/dist/cjs/ui/confluence-search-modal/confluence-search-container/index.js +25 -1
  20. package/dist/cjs/ui/confluence-search-modal/modal/index.js +41 -11
  21. package/dist/cjs/ui/datasource-table-view/datasourceTableView.js +1 -0
  22. package/dist/cjs/ui/table-footer/index.js +8 -2
  23. package/dist/cjs/ui/table-footer/messages.js +5 -0
  24. package/dist/cjs/ui/table-footer/powered-by-jsm-assets/index.js +53 -0
  25. package/dist/es2019/services/mocks.js +151 -0
  26. package/dist/es2019/services/useBasicFilterAGG.js +8 -3
  27. package/dist/es2019/services/utils.js +8 -0
  28. package/dist/es2019/ui/common/modal/popup-select/formatOptionLabel.js +6 -3
  29. package/dist/es2019/ui/common/modal/popup-select/index.js +1 -1
  30. package/dist/es2019/ui/common/modal/popup-select/trigger.js +1 -2
  31. package/dist/es2019/ui/confluence-search-modal/basic-filters/filters/date-range-picker/PopupComponent.js +7 -0
  32. package/dist/es2019/ui/confluence-search-modal/basic-filters/filters/date-range-picker/index.js +68 -0
  33. package/dist/es2019/ui/confluence-search-modal/basic-filters/filters/date-range-picker/messages.js +43 -0
  34. package/dist/es2019/ui/confluence-search-modal/basic-filters/filters/date-range-picker/styled.js +66 -0
  35. package/dist/es2019/ui/confluence-search-modal/basic-filters/filters/date-range-picker/trigger.js +26 -0
  36. package/dist/es2019/ui/confluence-search-modal/basic-filters/filters/edited-or-created-by/index.js +82 -0
  37. package/dist/es2019/ui/confluence-search-modal/basic-filters/filters/edited-or-created-by/messages.js +8 -0
  38. package/dist/es2019/ui/confluence-search-modal/basic-filters/hooks/useCurrentUserInfo.js +25 -0
  39. package/dist/es2019/ui/confluence-search-modal/basic-filters/hooks/useRecommendation.js +74 -0
  40. package/dist/es2019/ui/confluence-search-modal/basic-filters/index.js +17 -2
  41. package/dist/es2019/ui/confluence-search-modal/basic-filters/types.js +5 -0
  42. package/dist/es2019/ui/confluence-search-modal/confluence-search-container/index.js +20 -1
  43. package/dist/es2019/ui/confluence-search-modal/modal/index.js +27 -3
  44. package/dist/es2019/ui/datasource-table-view/datasourceTableView.js +1 -0
  45. package/dist/es2019/ui/table-footer/index.js +7 -1
  46. package/dist/es2019/ui/table-footer/messages.js +5 -0
  47. package/dist/es2019/ui/table-footer/powered-by-jsm-assets/index.js +45 -0
  48. package/dist/esm/services/mocks.js +151 -0
  49. package/dist/esm/services/useBasicFilterAGG.js +10 -3
  50. package/dist/esm/services/utils.js +2 -1
  51. package/dist/esm/ui/common/modal/popup-select/formatOptionLabel.js +6 -3
  52. package/dist/esm/ui/common/modal/popup-select/index.js +2 -1
  53. package/dist/esm/ui/common/modal/popup-select/trigger.js +1 -2
  54. package/dist/esm/ui/confluence-search-modal/basic-filters/filters/date-range-picker/PopupComponent.js +9 -0
  55. package/dist/esm/ui/confluence-search-modal/basic-filters/filters/date-range-picker/index.js +79 -0
  56. package/dist/esm/ui/confluence-search-modal/basic-filters/filters/date-range-picker/messages.js +43 -0
  57. package/dist/esm/ui/confluence-search-modal/basic-filters/filters/date-range-picker/styled.js +68 -0
  58. package/dist/esm/ui/confluence-search-modal/basic-filters/filters/date-range-picker/trigger.js +25 -0
  59. package/dist/esm/ui/confluence-search-modal/basic-filters/filters/edited-or-created-by/index.js +100 -0
  60. package/dist/esm/ui/confluence-search-modal/basic-filters/filters/edited-or-created-by/messages.js +8 -0
  61. package/dist/esm/ui/confluence-search-modal/basic-filters/hooks/useCurrentUserInfo.js +41 -0
  62. package/dist/esm/ui/confluence-search-modal/basic-filters/hooks/useRecommendation.js +113 -0
  63. package/dist/esm/ui/confluence-search-modal/basic-filters/index.js +14 -3
  64. package/dist/esm/ui/confluence-search-modal/basic-filters/types.js +5 -0
  65. package/dist/esm/ui/confluence-search-modal/confluence-search-container/index.js +25 -1
  66. package/dist/esm/ui/confluence-search-modal/modal/index.js +41 -11
  67. package/dist/esm/ui/datasource-table-view/datasourceTableView.js +1 -0
  68. package/dist/esm/ui/table-footer/index.js +8 -2
  69. package/dist/esm/ui/table-footer/messages.js +5 -0
  70. package/dist/esm/ui/table-footer/powered-by-jsm-assets/index.js +46 -0
  71. package/dist/types/analytics/generated/analytics.types.d.ts +7 -0
  72. package/dist/types/services/mocks.d.ts +51 -0
  73. package/dist/types/services/useBasicFilterAGG.d.ts +2 -0
  74. package/dist/types/services/utils.d.ts +1 -0
  75. package/dist/types/ui/common/modal/popup-select/index.d.ts +1 -1
  76. package/dist/types/ui/common/modal/popup-select/types.d.ts +6 -1
  77. package/dist/types/ui/confluence-search-modal/basic-filters/filters/date-range-picker/PopupComponent.d.ts +3 -0
  78. package/dist/types/ui/confluence-search-modal/basic-filters/filters/date-range-picker/index.d.ts +8 -0
  79. package/dist/types/ui/confluence-search-modal/basic-filters/filters/date-range-picker/messages.d.ts +42 -0
  80. package/dist/types/ui/confluence-search-modal/basic-filters/filters/date-range-picker/styled.d.ts +31 -0
  81. package/dist/types/ui/confluence-search-modal/basic-filters/filters/date-range-picker/trigger.d.ts +10 -0
  82. package/dist/types/ui/confluence-search-modal/basic-filters/filters/edited-or-created-by/index.d.ts +10 -0
  83. package/dist/types/ui/confluence-search-modal/basic-filters/filters/edited-or-created-by/messages.d.ts +7 -0
  84. package/dist/types/ui/confluence-search-modal/basic-filters/hooks/useCurrentUserInfo.d.ts +7 -0
  85. package/dist/types/ui/confluence-search-modal/basic-filters/hooks/useRecommendation.d.ts +16 -0
  86. package/dist/types/ui/confluence-search-modal/basic-filters/index.d.ts +6 -1
  87. package/dist/types/ui/confluence-search-modal/basic-filters/types.d.ts +20 -0
  88. package/dist/types/ui/confluence-search-modal/confluence-search-container/index.d.ts +2 -1
  89. package/dist/types/ui/confluence-search-modal/types.d.ts +2 -1
  90. package/dist/types/ui/table-footer/index.d.ts +2 -1
  91. package/dist/types/ui/table-footer/messages.d.ts +5 -0
  92. package/dist/types/ui/table-footer/powered-by-jsm-assets/index.d.ts +4 -0
  93. package/dist/types-ts4.5/analytics/generated/analytics.types.d.ts +7 -0
  94. package/dist/types-ts4.5/services/mocks.d.ts +51 -0
  95. package/dist/types-ts4.5/services/useBasicFilterAGG.d.ts +2 -0
  96. package/dist/types-ts4.5/services/utils.d.ts +1 -0
  97. package/dist/types-ts4.5/ui/common/modal/popup-select/index.d.ts +1 -1
  98. package/dist/types-ts4.5/ui/common/modal/popup-select/types.d.ts +6 -1
  99. package/dist/types-ts4.5/ui/confluence-search-modal/basic-filters/filters/date-range-picker/PopupComponent.d.ts +3 -0
  100. package/dist/types-ts4.5/ui/confluence-search-modal/basic-filters/filters/date-range-picker/index.d.ts +8 -0
  101. package/dist/types-ts4.5/ui/confluence-search-modal/basic-filters/filters/date-range-picker/messages.d.ts +42 -0
  102. package/dist/types-ts4.5/ui/confluence-search-modal/basic-filters/filters/date-range-picker/styled.d.ts +31 -0
  103. package/dist/types-ts4.5/ui/confluence-search-modal/basic-filters/filters/date-range-picker/trigger.d.ts +10 -0
  104. package/dist/types-ts4.5/ui/confluence-search-modal/basic-filters/filters/edited-or-created-by/index.d.ts +10 -0
  105. package/dist/types-ts4.5/ui/confluence-search-modal/basic-filters/filters/edited-or-created-by/messages.d.ts +7 -0
  106. package/dist/types-ts4.5/ui/confluence-search-modal/basic-filters/hooks/useCurrentUserInfo.d.ts +7 -0
  107. package/dist/types-ts4.5/ui/confluence-search-modal/basic-filters/hooks/useRecommendation.d.ts +16 -0
  108. package/dist/types-ts4.5/ui/confluence-search-modal/basic-filters/index.d.ts +6 -1
  109. package/dist/types-ts4.5/ui/confluence-search-modal/basic-filters/types.d.ts +20 -0
  110. package/dist/types-ts4.5/ui/confluence-search-modal/confluence-search-container/index.d.ts +2 -1
  111. package/dist/types-ts4.5/ui/confluence-search-modal/types.d.ts +2 -1
  112. package/dist/types-ts4.5/ui/table-footer/index.d.ts +2 -1
  113. package/dist/types-ts4.5/ui/table-footer/messages.d.ts +5 -0
  114. package/dist/types-ts4.5/ui/table-footer/powered-by-jsm-assets/index.d.ts +4 -0
  115. package/examples-helpers/buildAssetsIssuesTable.tsx +71 -0
  116. package/examples-helpers/useAssetsTableProps.tsx +57 -0
  117. package/package.json +8 -2
@@ -117,4 +117,12 @@ export const fieldValuesQuery = `query fieldValues($cloudId: ID!, $first: Int =
117
117
  }
118
118
  }
119
119
  }
120
+ }`;
121
+ export const userQuery = `query userQuery {
122
+ me {
123
+ user {
124
+ id
125
+ accountId
126
+ }
127
+ }
120
128
  }`;
@@ -78,8 +78,11 @@ const formatOptionLabel = data => {
78
78
  data: data
79
79
  });
80
80
  }
81
- return /*#__PURE__*/React.createElement(IconOptionLabel, {
82
- data: data
83
- });
81
+ if (data.optionType === 'iconLabel') {
82
+ return /*#__PURE__*/React.createElement(IconOptionLabel, {
83
+ data: data
84
+ });
85
+ }
86
+ return /*#__PURE__*/React.createElement(React.Fragment, null);
84
87
  };
85
88
  export default formatOptionLabel;
@@ -15,7 +15,7 @@ import PopupTrigger from './trigger';
15
15
  const noFilterOptions = () => true;
16
16
  export const FilterPopupSelect = ({
17
17
  filterName,
18
- totalCount,
18
+ totalCount = 0,
19
19
  status,
20
20
  buttonLabel,
21
21
  showLoading = false,
@@ -7,8 +7,7 @@ import { Box, Flex, xcss } from '@atlaskit/primitives';
7
7
  import Spinner from '@atlaskit/spinner';
8
8
  const triggerButtonLabelStyles = xcss({
9
9
  textOverflow: 'ellipsis',
10
- overflow: 'hidden',
11
- maxWidth: '150px'
10
+ overflow: 'hidden'
12
11
  });
13
12
  const badgeStyles = xcss({
14
13
  marginLeft: 'space.050'
@@ -0,0 +1,7 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ import React, { forwardRef } from 'react';
3
+ import { PopupComponentContainer } from './styled';
4
+ export const PopupComponent = /*#__PURE__*/forwardRef((props, ref) => /*#__PURE__*/React.createElement(PopupComponentContainer, _extends({}, props, {
5
+ "data-testId": 'confluence-search-datasource-popup-container',
6
+ ref: ref
7
+ })));
@@ -0,0 +1,68 @@
1
+ import React, { useCallback, useState } from 'react';
2
+ import { FormattedMessage, useIntl } from 'react-intl-next';
3
+ import Popup from '@atlaskit/popup';
4
+ import { layers } from '@atlaskit/theme/constants';
5
+ import { CLOLBasicFilters } from '../../types';
6
+ import { dateRangeMessages } from './messages';
7
+ import { PopupComponent } from './PopupComponent';
8
+ import { CustomDropdown, CustomDropdownItem } from './styled';
9
+ import { PopupTrigger } from './trigger';
10
+ const lastModifiedValues = ['anyTime', 'today', 'yesterday', 'past7Days', 'past30Days', 'pastYear', 'custom'];
11
+ const defaultOptionValue = 'anyTime';
12
+ const filterName = CLOLBasicFilters.lastModified;
13
+ export const DateRangePicker = ({
14
+ onSelectionChange
15
+ }) => {
16
+ const [currentOption, setCurrentOption] = useState(null);
17
+ const [isPickerOpen, setIsPickerOpen] = useState(false);
18
+ const {
19
+ formatMessage
20
+ } = useIntl();
21
+ const onClickFilterOption = useCallback(option => {
22
+ setCurrentOption(option);
23
+ setIsPickerOpen(false);
24
+ onSelectionChange(filterName, [{
25
+ optionType: 'defaultOption',
26
+ label: option,
27
+ value: option
28
+ }]);
29
+ }, [onSelectionChange]);
30
+ const handleTogglePopup = useCallback(() => {
31
+ setIsPickerOpen(!isPickerOpen);
32
+ }, [isPickerOpen]);
33
+ return /*#__PURE__*/React.createElement(Popup, {
34
+ isOpen: isPickerOpen,
35
+ onClose: handleTogglePopup,
36
+ popupComponent: PopupComponent,
37
+ zIndex: layers.modal(),
38
+ content: () => {
39
+ return /*#__PURE__*/React.createElement(CustomDropdown, null, lastModifiedValues.map(option => /*#__PURE__*/React.createElement(CustomDropdownItem, {
40
+ key: option
41
+ //want to show Anytime as selected if none of the other options are selected
42
+ ,
43
+ isSelected: currentOption ? option === currentOption : option === defaultOptionValue,
44
+ onClick: () => onClickFilterOption(option)
45
+ }, /*#__PURE__*/React.createElement(FormattedMessage, getCurrentOptionLabel(option)))));
46
+ },
47
+ placement: "bottom-start",
48
+ trigger: triggerProps => /*#__PURE__*/React.createElement(PopupTrigger, {
49
+ triggerProps: triggerProps,
50
+ optionSelected: !!currentOption,
51
+ label: formatMessage(dateRangeMessages.dateRangeTitle),
52
+ selectedLabel: formatMessage(getCurrentOptionLabel(currentOption)),
53
+ onClickButton: handleTogglePopup
54
+ })
55
+ });
56
+ };
57
+ const getCurrentOptionLabel = option => {
58
+ const mapping = {
59
+ anyTime: 'dateRangeAnyTime',
60
+ today: 'dateRangeToday',
61
+ yesterday: 'dateRangeYesterday',
62
+ past7Days: 'dateRangeLastWeek',
63
+ past30Days: 'dateRangeLastMonth',
64
+ pastYear: 'dateRangeLastYear',
65
+ custom: 'dateRangeCustom'
66
+ };
67
+ return option ? dateRangeMessages[mapping[option]] : dateRangeMessages[mapping['anyTime']];
68
+ };
@@ -0,0 +1,43 @@
1
+ import { defineMessages } from 'react-intl-next';
2
+ export const dateRangeMessages = defineMessages({
3
+ dateRangeTitle: {
4
+ id: 'linkDataSource.confluence-search.configmodal.date.range.title',
5
+ defaultMessage: 'Last updated',
6
+ description: 'Filter by the date content was modified'
7
+ },
8
+ dateRangeAnyTime: {
9
+ id: 'linkDataSource.confluence-search.configmodal.date.range.any.time',
10
+ defaultMessage: 'Anytime',
11
+ description: 'Option to show content from any time'
12
+ },
13
+ dateRangeToday: {
14
+ id: 'linkDataSource.confluence-search.configmodal.date.range.today',
15
+ defaultMessage: 'Today',
16
+ description: 'Date range of content modified today'
17
+ },
18
+ dateRangeYesterday: {
19
+ id: 'linkDataSource.confluence-search.configmodal.date.range.yesterday',
20
+ defaultMessage: 'Yesterday',
21
+ description: 'Date range of content modified yesterday'
22
+ },
23
+ dateRangeLastWeek: {
24
+ id: 'linkDataSource.confluence-search.configmodal.date.range.last.week',
25
+ defaultMessage: 'Past 7 days',
26
+ description: 'Date range of content modified in the last 7 days'
27
+ },
28
+ dateRangeLastMonth: {
29
+ id: 'linkDataSource.confluence-search.configmodal.date.range.last.month',
30
+ defaultMessage: 'Past 30 days',
31
+ description: 'Date range of content modified in the last 30 days'
32
+ },
33
+ dateRangeLastYear: {
34
+ id: 'linkDataSource.confluence-search.configmodal.date.range.last.year',
35
+ defaultMessage: 'Past year',
36
+ description: 'Date range of content modified in the last 365 days'
37
+ },
38
+ dateRangeCustom: {
39
+ id: 'linkDataSource.confluence-search.configmodal.date.range.custom',
40
+ defaultMessage: 'Custom',
41
+ description: 'Custom date range'
42
+ }
43
+ });
@@ -0,0 +1,66 @@
1
+ import styled from '@emotion/styled';
2
+ import { B400, B50, N0, N20, N30, R400 } from '@atlaskit/theme/colors';
3
+ export const PopupComponentContainer = styled.div({
4
+ boxSizing: 'border-box',
5
+ display: 'block',
6
+ flex: '1 1 auto',
7
+ overflow: 'visible',
8
+ background: `var(--ds-background-input, ${N0})`,
9
+ ':focus': {
10
+ outline: 'none'
11
+ },
12
+ boxShadow: "var(--ds-shadow-overlay, 0px 0px 1px 0px rgba(9, 30, 66, 0.31), 0px 3px 5px 0px rgba(9, 30, 66, 0.20))"
13
+ });
14
+ export const CustomDropdown = styled.div({
15
+ width: '360px',
16
+ background: `var(--ds-background-input, ${N0})`,
17
+ borderRadius: '3px',
18
+ boxShadow: "var(--ds-shadow-overlay, 0px 0px 1px 0px rgba(9, 30, 66, 0.31), 0px 3px 5px 0px rgba(9, 30, 66, 0.20))",
19
+ zIndex: '900'
20
+ });
21
+ export const CustomDropdownItem = styled.div(props => ({
22
+ height: '36px',
23
+ width: '100%',
24
+ display: 'flex',
25
+ justifyContent: 'flex-start',
26
+ alignItems: 'center',
27
+ paddingLeft: props.isSelected ? '15px' : '16px',
28
+ boxSizing: 'border-box',
29
+ color: props.isSelected ? `var(--ds-text-selected, ${B400})` : 'inherit',
30
+ background: props.isSelected ? `var(--ds-background-accent-blue-subtlest, ${B50})` : 'transparent',
31
+ borderLeft: props.isSelected ? `2px solid ${`var(--ds-text-selected, ${B400})`}` : 'none',
32
+ '&:hover': {
33
+ background: props.isSelected ? `var(--ds-background-accent-blue-subtlest, ${B50})` : `var(--ds-background-input-hovered, ${N20})`,
34
+ cursor: 'default'
35
+ }
36
+ }));
37
+ export const CustomDateWrapper = styled.div({
38
+ padding: "var(--ds-space-150, 12px)",
39
+ boxSizing: 'border-box'
40
+ });
41
+ export const DatePickersWrapper = styled.div({
42
+ display: 'flex',
43
+ justifyContent: 'space-between',
44
+ alignItems: 'center',
45
+ width: '100%'
46
+ });
47
+ export const SelectDateRangeButton = styled.button({
48
+ background: `var(--ds-background-accent-gray-subtler, ${N20})`,
49
+ border: 'none',
50
+ font: 'inherit',
51
+ width: '70px',
52
+ height: '40px',
53
+ marginTop: "var(--ds-space-150, 12px)",
54
+ borderRadius: '3px',
55
+ '&:hover': {
56
+ background: `var(--ds-background-accent-gray-subtler, ${N30})`,
57
+ cursor: 'pointer'
58
+ }
59
+ });
60
+ export const DateRangeErrorMessage = styled.div({
61
+ display: 'flex',
62
+ lineHeight: 1.3333,
63
+ marginTop: "var(--ds-space-050, 4px)",
64
+ fontSize: '12px',
65
+ color: `var(--ds-text-danger, ${R400})`
66
+ });
@@ -0,0 +1,26 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ import React from 'react';
3
+ import Button from '@atlaskit/button/standard-button';
4
+ import ChevronDownIcon from '@atlaskit/icon/glyph/chevron-down';
5
+ export const PopupTrigger = ({
6
+ triggerProps,
7
+ optionSelected,
8
+ label,
9
+ selectedLabel,
10
+ onClickButton
11
+ }) => {
12
+ return /*#__PURE__*/React.createElement(Button, _extends({}, triggerProps, {
13
+ testId: 'confluence-search-modal--date-range-button',
14
+ onClick: onClickButton,
15
+ isSelected: optionSelected,
16
+ iconAfter: /*#__PURE__*/React.createElement("span", {
17
+ style: {
18
+ display: 'flex',
19
+ alignItems: 'center'
20
+ }
21
+ }, /*#__PURE__*/React.createElement(ChevronDownIcon, {
22
+ size: "medium",
23
+ label: ""
24
+ }))
25
+ }), label, selectedLabel ? `: ${selectedLabel}` : '');
26
+ };
@@ -0,0 +1,82 @@
1
+ import React, { useCallback, useState } from 'react';
2
+ import { useIntl } from 'react-intl-next';
3
+ import { useDebouncedCallback } from 'use-debounce';
4
+ import { FilterPopupSelect } from '../../../../common/modal/popup-select';
5
+ import { SEARCH_DEBOUNCE_MS } from '../../../../common/modal/popup-select/constants';
6
+ import { useCurrentUserInfo } from '../../hooks/useCurrentUserInfo';
7
+ import useRecommendation from '../../hooks/useRecommendation';
8
+ import { CLOLBasicFilters } from '../../types';
9
+ import { editedOrCreatedByMessage } from './messages';
10
+ const filterName = `clol-basic-filter-${CLOLBasicFilters.editedOrCreatedBy}`;
11
+ const EditedOrCreatedByFilter = ({
12
+ cloudId,
13
+ onSelectionChange,
14
+ selection = []
15
+ }) => {
16
+ const {
17
+ user
18
+ } = useCurrentUserInfo();
19
+ const {
20
+ formatMessage
21
+ } = useIntl();
22
+ const {
23
+ status,
24
+ filterOptions,
25
+ fetchFilterOptions,
26
+ errors
27
+ } = useRecommendation();
28
+ const [searchTerm, setSearchTerm] = useState('');
29
+ const [handleDebouncedFetchFilterOptions] = useDebouncedCallback(searchTerm => {
30
+ if (cloudId && user !== null && user !== void 0 && user.accountId) {
31
+ fetchFilterOptions({
32
+ searchTerm,
33
+ cloudId,
34
+ userId: user.accountId
35
+ });
36
+ }
37
+ }, SEARCH_DEBOUNCE_MS);
38
+ const handleInputChange = useCallback(async newSearchTerm => {
39
+ setSearchTerm(newSearchTerm);
40
+ handleDebouncedFetchFilterOptions(newSearchTerm);
41
+ }, [handleDebouncedFetchFilterOptions]);
42
+ const handleOptionSelection = useCallback(newValue => {
43
+ onSelectionChange(CLOLBasicFilters.editedOrCreatedBy, newValue);
44
+ }, [onSelectionChange]);
45
+ const handleMenuOpen = useCallback(() => {
46
+ if ((status === 'empty' || status === 'rejected') && cloudId && user !== null && user !== void 0 && user.accountId) {
47
+ // if user searches and gets status as rejected, we want the dropdown to try load the request with searchString when the user reopens the dropdown
48
+ fetchFilterOptions({
49
+ cloudId,
50
+ userId: user.accountId,
51
+ searchTerm
52
+ });
53
+ }
54
+ }, [fetchFilterOptions, status, cloudId, user === null || user === void 0 ? void 0 : user.accountId, searchTerm]);
55
+ const filterOptionsLength = filterOptions.length;
56
+ const isError = status === 'rejected';
57
+ const isLoading = status === 'loading' || status === 'empty';
58
+ const isEmpty = status === 'resolved' && filterOptionsLength === 0;
59
+ const isDisabled = !cloudId || !(user !== null && user !== void 0 && user.accountId);
60
+ return /*#__PURE__*/React.createElement(FilterPopupSelect, {
61
+ buttonLabel: formatMessage(editedOrCreatedByMessage.buttonLabel),
62
+ filterName: filterName,
63
+ isDisabled: isDisabled,
64
+ options: filterOptions,
65
+ showLoading: isLoading,
66
+ selectedOptions: selection,
67
+ onSelectionChange: handleOptionSelection,
68
+ onInputChange: handleInputChange,
69
+ showHydrating: false,
70
+ shouldShowFooter: false,
71
+ status: status,
72
+ onMenuOpen: handleMenuOpen,
73
+ menuListProps: {
74
+ filterName: filterName,
75
+ errors,
76
+ isLoading,
77
+ isError,
78
+ isEmpty
79
+ }
80
+ });
81
+ };
82
+ export default EditedOrCreatedByFilter;
@@ -0,0 +1,8 @@
1
+ import { defineMessages } from 'react-intl-next';
2
+ export const editedOrCreatedByMessage = defineMessages({
3
+ buttonLabel: {
4
+ id: 'linkDataSource.clol-basic-filter.editedOrCreatedBy.label',
5
+ description: 'Label to be displayed for "Edited or created by" filter dropdown button.',
6
+ defaultMessage: 'Edited or created by'
7
+ }
8
+ });
@@ -0,0 +1,25 @@
1
+ import { useCallback, useEffect, useState } from 'react';
2
+ import { useBasicFilterAGG } from '../../../../services/useBasicFilterAGG';
3
+ export const useCurrentUserInfo = () => {
4
+ const [user, setUser] = useState();
5
+ const {
6
+ getCurrentUserInfo: getCurrentUserInfoFromAGG
7
+ } = useBasicFilterAGG();
8
+ const getCurrentUserInfo = useCallback(async () => {
9
+ var _user$data;
10
+ const user = await getCurrentUserInfoFromAGG();
11
+ if (user !== null && user !== void 0 && (_user$data = user.data) !== null && _user$data !== void 0 && _user$data.me.user) {
12
+ var _user$data2;
13
+ setUser((_user$data2 = user.data) === null || _user$data2 === void 0 ? void 0 : _user$data2.me.user);
14
+ } else {
15
+ setUser(undefined);
16
+ }
17
+ }, [getCurrentUserInfoFromAGG]);
18
+ useEffect(() => {
19
+ getCurrentUserInfo();
20
+ }, [getCurrentUserInfo]);
21
+ return {
22
+ user,
23
+ getCurrentUserInfo
24
+ };
25
+ };
@@ -0,0 +1,74 @@
1
+ import { useCallback, useRef, useState } from 'react';
2
+ import { useIntl } from 'react-intl-next';
3
+ import { getUserRecommendations } from '@atlaskit/smart-user-picker';
4
+ const useRecommendation = () => {
5
+ const intl = useIntl();
6
+ const [filterOptions, setFilterOptions] = useState([]);
7
+ const [status, setStatus] = useState('empty');
8
+ const [errors, setErrors] = useState([]);
9
+ const initialData = useRef();
10
+ const convertRecommendationsToFilterOptions = recommendations => {
11
+ return recommendations.map(item => ({
12
+ optionType: 'avatarLabel',
13
+ label: item.name,
14
+ value: item.id,
15
+ avatar: item.avatarUrl
16
+ }));
17
+ };
18
+ const fetchFilterOptions = useCallback(async ({
19
+ userId,
20
+ cloudId,
21
+ searchTerm
22
+ }) => {
23
+ setStatus('loading');
24
+ const requestParams = {
25
+ context: {
26
+ contextType: 'contributors',
27
+ principalId: userId || '',
28
+ productAttributes: {
29
+ isEntitledConfluenceExternalCollaborator: true
30
+ },
31
+ productKey: 'confluence',
32
+ siteId: cloudId
33
+ },
34
+ includeGroups: false,
35
+ includeTeams: false,
36
+ includeUsers: true,
37
+ maxNumberOfResults: 10,
38
+ performSearchQueryOnly: false,
39
+ query: searchTerm
40
+ };
41
+ const {
42
+ current: initialResponseData
43
+ } = initialData;
44
+ const isRequestLikeInitialSearch = !searchTerm;
45
+ try {
46
+ const recommendations = isRequestLikeInitialSearch && initialResponseData ? initialResponseData : await getUserRecommendations(requestParams, intl);
47
+ setFilterOptions(convertRecommendationsToFilterOptions(recommendations));
48
+ setStatus('resolved');
49
+ if (!searchTerm) {
50
+ /**
51
+ * The initial dataset is used in couple of paths, eg: when a user searches and clears the search text.
52
+ * During these times, we dont want to fetch data again and again, hence a mini cache setup to store and provide the initial dataset
53
+ */
54
+ initialData.current = recommendations;
55
+ }
56
+ } catch (error) {
57
+ setStatus('rejected');
58
+ setErrors([error]);
59
+ }
60
+ }, [intl]);
61
+ const reset = useCallback(() => {
62
+ setStatus('empty');
63
+ setFilterOptions([]);
64
+ setErrors([]);
65
+ }, []);
66
+ return {
67
+ status,
68
+ errors,
69
+ filterOptions,
70
+ reset,
71
+ fetchFilterOptions
72
+ };
73
+ };
74
+ export default useRecommendation;
@@ -1,13 +1,28 @@
1
1
  import React from 'react';
2
2
  import { Flex, xcss } from '@atlaskit/primitives';
3
+ import { DateRangePicker } from './filters/date-range-picker';
4
+ import EditedOrCreatedByFilter from './filters/edited-or-created-by';
3
5
  const basicFilterContainerStyles = xcss({
4
6
  paddingLeft: 'space.100'
5
7
  });
6
- const BasicFilterContainer = ({}) => {
8
+ const BasicFilterContainer = ({
9
+ cloudId,
10
+ onChange,
11
+ selections = {}
12
+ }) => {
13
+ const {
14
+ editedOrCreatedBy
15
+ } = selections;
7
16
  return /*#__PURE__*/React.createElement(Flex, {
8
17
  xcss: basicFilterContainerStyles,
9
18
  gap: "space.100",
10
19
  testId: "clol-basic-filter-container"
11
- }, /*#__PURE__*/React.createElement(React.Fragment, null), /*#__PURE__*/React.createElement(React.Fragment, null));
20
+ }, /*#__PURE__*/React.createElement(EditedOrCreatedByFilter, {
21
+ cloudId: cloudId,
22
+ onSelectionChange: onChange,
23
+ selection: editedOrCreatedBy || []
24
+ }), /*#__PURE__*/React.createElement(DateRangePicker, {
25
+ onSelectionChange: onChange
26
+ }));
12
27
  };
13
28
  export default BasicFilterContainer;
@@ -0,0 +1,5 @@
1
+ export let CLOLBasicFilters = /*#__PURE__*/function (CLOLBasicFilters) {
2
+ CLOLBasicFilters["editedOrCreatedBy"] = "editedOrCreatedBy";
3
+ CLOLBasicFilters["lastModified"] = "lastModified";
4
+ return CLOLBasicFilters;
5
+ }({});
@@ -1,7 +1,9 @@
1
1
  import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
+ import { useDebouncedCallback } from 'use-debounce';
2
3
  import { getBooleanFF } from '@atlaskit/platform-feature-flags';
3
4
  import { Flex, xcss } from '@atlaskit/primitives';
4
5
  import { BasicSearchInput } from '../../common/modal/basic-search-input';
6
+ import { FILTER_SELECTION_DEBOUNCE_MS } from '../../common/modal/popup-select/constants';
5
7
  import BasicFilters from '../basic-filters';
6
8
  import { searchMessages } from './messages';
7
9
  const basicSearchInputContainerStyles = xcss({
@@ -15,16 +17,29 @@ const ConfluenceSearchContainer = ({
15
17
  }) => {
16
18
  const currentCloudId = useRef(cloudId);
17
19
  const [searchBarSearchString, setSearchBarSearchString] = useState(initialSearchValue !== null && initialSearchValue !== void 0 ? initialSearchValue : '');
20
+ const [filterSelections, setFilterSelections] = useState({});
18
21
  const handleSearchChange = useCallback(e => {
19
22
  const rawSearch = e.currentTarget.value;
20
23
  setSearchBarSearchString(rawSearch);
21
24
  }, []);
25
+ const [debouncedBasicFilterSelectionChange] = useDebouncedCallback(filterValues => {
26
+ onSearch(searchBarSearchString, filterValues);
27
+ }, FILTER_SELECTION_DEBOUNCE_MS);
28
+ const handleBasicFilterSelectionChange = useCallback((filterType, options) => {
29
+ const updatedSelection = {
30
+ ...filterSelections,
31
+ [filterType]: options
32
+ };
33
+ setFilterSelections(updatedSelection);
34
+ debouncedBasicFilterSelectionChange(updatedSelection);
35
+ }, [debouncedBasicFilterSelectionChange, filterSelections]);
22
36
 
23
37
  // TODO: further refactoring in EDM-9573
24
38
  // https://stash.atlassian.com/projects/ATLASSIAN/repos/atlassian-frontend-monorepo/pull-requests/82725/overview?commentId=6827913
25
39
  useEffect(() => {
26
40
  if (currentCloudId.current !== cloudId) {
27
41
  setSearchBarSearchString('');
42
+ setFilterSelections({});
28
43
  currentCloudId.current = cloudId;
29
44
  }
30
45
  }, [cloudId]);
@@ -45,6 +60,10 @@ const ConfluenceSearchContainer = ({
45
60
  searchTerm: searchBarSearchString,
46
61
  placeholder: searchMessages.searchLabel,
47
62
  fullWidth: !showBasicFilters
48
- }), showBasicFilters && /*#__PURE__*/React.createElement(BasicFilters, null));
63
+ }), showBasicFilters && /*#__PURE__*/React.createElement(BasicFilters, {
64
+ cloudId: cloudId,
65
+ selections: filterSelections,
66
+ onChange: handleBasicFilterSelectionChange
67
+ }));
49
68
  };
50
69
  export default ConfluenceSearchContainer;
@@ -78,6 +78,8 @@ export const PlainConfluenceSearchConfigModal = props => {
78
78
  const [cloudId, setCloudId] = useState(initialParameters === null || initialParameters === void 0 ? void 0 : initialParameters.cloudId);
79
79
  const [searchString, setSearchString] = useState(initialParameters === null || initialParameters === void 0 ? void 0 : initialParameters.searchString);
80
80
  const [visibleColumnKeys, setVisibleColumnKeys] = useState(initialVisibleColumnKeys);
81
+ const [lastModified, setLastModified] = useState(initialParameters === null || initialParameters === void 0 ? void 0 : initialParameters.lastModified);
82
+ const [contributorAccountIds, setContributorAccountIds] = useState((initialParameters === null || initialParameters === void 0 ? void 0 : initialParameters.contributorAccountIds) || []);
81
83
 
82
84
  // analytics related parameters
83
85
  const searchCount = useRef(0);
@@ -89,8 +91,14 @@ export const PlainConfluenceSearchConfigModal = props => {
89
91
  const parameters = useMemo(() => ({
90
92
  ...initialParameters,
91
93
  cloudId,
92
- searchString
93
- }), [cloudId, initialParameters, searchString /** Add more parameters when more filters are added */]);
94
+ searchString,
95
+ ...(((initialParameters === null || initialParameters === void 0 ? void 0 : initialParameters.lastModified) || lastModified) && {
96
+ lastModified
97
+ }),
98
+ ...(((initialParameters === null || initialParameters === void 0 ? void 0 : initialParameters.contributorAccountIds) || (contributorAccountIds === null || contributorAccountIds === void 0 ? void 0 : contributorAccountIds.length) > 0) && {
99
+ contributorAccountIds
100
+ })
101
+ }), [cloudId, lastModified, contributorAccountIds, initialParameters, searchString /** Add more parameters when more filters are added */]);
94
102
  const isParametersSet = useMemo(() => !!cloudId && Object.values(parameters !== null && parameters !== void 0 ? parameters : {}).filter(v => v !== undefined).length > 1, [cloudId, parameters]);
95
103
  const parametersToSend = useMemo(() => {
96
104
  if (!isParametersSet) {
@@ -150,6 +158,8 @@ export const PlainConfluenceSearchConfigModal = props => {
150
158
  const onSiteSelection = useCallback(site => {
151
159
  userInteractionActions.current.add(DatasourceAction.INSTANCE_UPDATED);
152
160
  setSearchString(undefined);
161
+ setLastModified(undefined);
162
+ setContributorAccountIds([]);
153
163
  setCloudId(site.cloudId);
154
164
  reset({
155
165
  shouldForceRequest: true
@@ -360,9 +370,23 @@ export const PlainConfluenceSearchConfigModal = props => {
360
370
  userInteractionActions.current.add(DatasourceAction.DISPLAY_VIEW_CHANGED);
361
371
  setCurrentViewMode(selectedMode);
362
372
  };
363
- const onSearch = useCallback(newSearchString => {
373
+ const onSearch = useCallback((newSearchString, filters) => {
364
374
  searchCount.current++;
365
375
  userInteractionActions.current.add(DatasourceAction.QUERY_UPDATED);
376
+ if (filters) {
377
+ const {
378
+ editedOrCreatedBy,
379
+ lastModified
380
+ } = filters;
381
+ if (lastModified) {
382
+ const lastModifiedValue = lastModified.find(range => range.value);
383
+ setLastModified(lastModifiedValue === null || lastModifiedValue === void 0 ? void 0 : lastModifiedValue.value);
384
+ }
385
+ if (editedOrCreatedBy) {
386
+ const accountIds = editedOrCreatedBy.map(user => user.value);
387
+ setContributorAccountIds(accountIds);
388
+ }
389
+ }
366
390
  setSearchString(newSearchString);
367
391
  reset({
368
392
  shouldForceRequest: true
@@ -173,6 +173,7 @@ const DatasourceTableViewWithoutAnalytics = ({
173
173
  testId: "datasource-table-view-skeleton",
174
174
  isCompact: true
175
175
  }), jsx(TableFooter, {
176
+ datasourceId: datasourceId,
176
177
  itemCount: isDataReady ? totalCount : undefined,
177
178
  onRefresh: onRefresh,
178
179
  isLoading: !isDataReady || status === 'loading',
@@ -7,9 +7,12 @@ import { FormattedMessage, FormattedNumber, useIntl } from 'react-intl-next';
7
7
  import Button from '@atlaskit/button';
8
8
  import Heading from '@atlaskit/heading';
9
9
  import RefreshIcon from '@atlaskit/icon/glyph/refresh';
10
+ import { getBooleanFF } from '@atlaskit/platform-feature-flags';
10
11
  import LinkUrl from '@atlaskit/smart-card/link-url';
11
12
  import { N0, N40, N800, N90 } from '@atlaskit/theme/colors';
13
+ import { ASSETS_LIST_OF_LINKS_DATASOURCE_ID } from '../assets-modal';
12
14
  import { footerMessages } from './messages';
15
+ import { PoweredByJSMAssets } from './powered-by-jsm-assets';
13
16
  import { SyncInfo } from './sync-info';
14
17
  const FooterWrapper = styled.div({
15
18
  padding: `${"var(--ds-space-0, 0px)"} ${"var(--ds-space-200, 16px)"}`,
@@ -40,6 +43,7 @@ const SyncTextWrapper = styled.div({
40
43
  fontSize: '12px'
41
44
  });
42
45
  export const TableFooter = ({
46
+ datasourceId,
43
47
  itemCount,
44
48
  onRefresh,
45
49
  isLoading,
@@ -77,7 +81,9 @@ export const TableFooter = ({
77
81
  values: {
78
82
  itemCount
79
83
  }
80
- }))))), jsx(SyncWrapper, null, onRefresh && jsx(Fragment, null, jsx(SyncTextWrapper, {
84
+ }))))), getBooleanFF('platform.linking-platform.datasource-assets_objects_add_jsm_promotional_tag') && datasourceId === ASSETS_LIST_OF_LINKS_DATASOURCE_ID ? jsx(PoweredByJSMAssets, {
85
+ text: intl.formatMessage(footerMessages.powerByJSM)
86
+ }) : null, jsx(SyncWrapper, null, onRefresh && jsx(Fragment, null, jsx(SyncTextWrapper, {
81
87
  "data-testid": "sync-text"
82
88
  }, isLoading ? jsx(FormattedMessage, footerMessages.loadingText) : jsx(SyncInfo, {
83
89
  lastSyncTime: lastSyncTime
@@ -14,5 +14,10 @@ export const footerMessages = defineMessages({
14
14
  id: 'linkDataSource.table-footer.refresh',
15
15
  description: 'Label for refresh icon',
16
16
  defaultMessage: 'Refresh'
17
+ },
18
+ powerByJSM: {
19
+ id: 'linkDataSource.table-footer.power-by-jsm',
20
+ description: 'Displayed on the issue like table footer to increase JSM Assets visibility',
21
+ defaultMessage: 'Powered by Assets in Jira Service Management'
17
22
  }
18
23
  });