@atlaskit/jql-editor 6.4.7 → 6.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/cjs/analytics/util.js +1 -1
  3. package/dist/cjs/plugins/rich-inline-nodes/nodes/index.js +2 -0
  4. package/dist/cjs/plugins/rich-inline-nodes/nodes/lozenge-with-avatar/index.js +41 -0
  5. package/dist/cjs/plugins/rich-inline-nodes/nodes/lozenge-with-avatar/styled.js +105 -0
  6. package/dist/cjs/plugins/rich-inline-nodes/util/replace-nodes-transaction.js +86 -33
  7. package/dist/cjs/state/hydration/util.js +6 -6
  8. package/dist/cjs/state/index.js +40 -31
  9. package/dist/es2019/analytics/util.js +1 -1
  10. package/dist/es2019/plugins/rich-inline-nodes/nodes/index.js +2 -0
  11. package/dist/es2019/plugins/rich-inline-nodes/nodes/lozenge-with-avatar/index.js +32 -0
  12. package/dist/es2019/plugins/rich-inline-nodes/nodes/lozenge-with-avatar/styled.js +97 -0
  13. package/dist/es2019/plugins/rich-inline-nodes/util/replace-nodes-transaction.js +63 -15
  14. package/dist/es2019/state/hydration/util.js +6 -6
  15. package/dist/es2019/state/index.js +12 -2
  16. package/dist/esm/analytics/util.js +1 -1
  17. package/dist/esm/plugins/rich-inline-nodes/nodes/index.js +2 -0
  18. package/dist/esm/plugins/rich-inline-nodes/nodes/lozenge-with-avatar/index.js +34 -0
  19. package/dist/esm/plugins/rich-inline-nodes/nodes/lozenge-with-avatar/styled.js +96 -0
  20. package/dist/esm/plugins/rich-inline-nodes/util/replace-nodes-transaction.js +86 -33
  21. package/dist/esm/state/hydration/util.js +6 -6
  22. package/dist/esm/state/index.js +39 -30
  23. package/dist/types/plugins/rich-inline-nodes/nodes/index.d.ts +2 -0
  24. package/dist/types/plugins/rich-inline-nodes/nodes/lozenge-with-avatar/index.d.ts +7 -0
  25. package/dist/types/plugins/rich-inline-nodes/nodes/lozenge-with-avatar/styled.d.ts +18 -0
  26. package/dist/types/state/index.d.ts +5 -1
  27. package/dist/types/types.d.ts +1 -1
  28. package/dist/types/ui/jql-editor/types.d.ts +7 -1
  29. package/dist/types/ui/types.d.ts +1 -1
  30. package/dist/types-ts4.5/plugins/rich-inline-nodes/nodes/index.d.ts +2 -0
  31. package/dist/types-ts4.5/plugins/rich-inline-nodes/nodes/lozenge-with-avatar/index.d.ts +7 -0
  32. package/dist/types-ts4.5/plugins/rich-inline-nodes/nodes/lozenge-with-avatar/styled.d.ts +18 -0
  33. package/dist/types-ts4.5/state/index.d.ts +5 -1
  34. package/dist/types-ts4.5/types.d.ts +1 -1
  35. package/dist/types-ts4.5/ui/jql-editor/types.d.ts +7 -1
  36. package/dist/types-ts4.5/ui/types.d.ts +1 -1
  37. package/package.json +10 -7
@@ -0,0 +1,97 @@
1
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
2
+
3
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
4
+ import { css } from '@emotion/react';
5
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
6
+ import styled from '@emotion/styled';
7
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-exported-styles -- Ignored via go/DSP-18766
8
+ export const LozengeWithAvatarContainer =
9
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-styled -- Ignored via go/DSP-18766
10
+ styled.span({
11
+ display: 'inline-flex',
12
+ alignItems: 'baseline',
13
+ paddingLeft: `${"var(--ds-space-025, 2px)"}`,
14
+ borderRadius: "var(--ds-radius-xlarge, 12px)",
15
+ cursor: 'pointer',
16
+ userSelect: 'none'
17
+ },
18
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-dynamic-styles -- Ignored via go/DSP-18766
19
+ ({
20
+ selected,
21
+ error
22
+ }) => {
23
+ if (selected) {
24
+ if (error) {
25
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766
26
+ return css({
27
+ color: "var(--ds-text-inverse, #FFFFFF)",
28
+ backgroundColor: "var(--ds-background-danger-bold, #C9372C)",
29
+ textDecoration: 'wavy underline',
30
+ textDecorationThickness: '1px',
31
+ textDecorationSkipInk: 'none',
32
+ textDecorationColor: "var(--ds-text-inverse, #FFFFFF)"
33
+ });
34
+ } else {
35
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766
36
+ return css({
37
+ color: "var(--ds-text, #292A2E)",
38
+ backgroundColor: "var(--ds-background-selected, #E9F2FE)",
39
+ boxShadow: `0 0 0 1px ${"var(--ds-border-selected, #1868DB)"}`
40
+ });
41
+ }
42
+ } else {
43
+ if (error) {
44
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766
45
+ return css({
46
+ color: "var(--ds-text-subtle, #505258)",
47
+ backgroundColor: "var(--ds-background-neutral, #0515240F)",
48
+ textDecoration: 'wavy underline',
49
+ textDecorationThickness: '1px',
50
+ textDecorationSkipInk: 'none',
51
+ textDecorationColor: "var(--ds-text-danger, #AE2E24)",
52
+ '&:hover': {
53
+ backgroundColor: "var(--ds-background-neutral-hovered, #0B120E24)"
54
+ }
55
+ });
56
+ } else {
57
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766
58
+ return css({
59
+ color: "var(--ds-text-subtle, #505258)",
60
+ backgroundColor: "var(--ds-background-neutral, #0515240F)",
61
+ '&:hover': {
62
+ backgroundColor: "var(--ds-background-neutral-hovered, #0B120E24)"
63
+ }
64
+ });
65
+ }
66
+ }
67
+ });
68
+
69
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-exported-styles -- Ignored via go/DSP-18766
70
+ export const NameContainer =
71
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-styled -- Ignored via go/DSP-18766
72
+ styled.span({
73
+ marginLeft: "var(--ds-space-075, 6px)",
74
+ marginRight: "var(--ds-space-100, 8px)",
75
+ // eslint-disable-next-line -- Ignored via go/DSP-18766
76
+ lineHeight: "var(--ds-space-250, 20px)"
77
+ });
78
+
79
+ /* Override Avatar styles to match design spec */
80
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-exported-styles -- Ignored via go/DSP-18766
81
+ export const AvatarWrapper =
82
+ // eslint-disable-next-line @atlaskit/design-system/ensure-design-token-usage, @atlaskit/ui-styling-standard/no-styled -- Ignored via go/DSP-18766
83
+ styled.div({
84
+ height: "var(--ds-space-200, 16px)",
85
+ width: "var(--ds-space-200, 16px)",
86
+ alignSelf: 'center',
87
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors -- Ignored via go/DSP-18766
88
+ '> div span': {
89
+ margin: "var(--ds-space-0, 0px)"
90
+ },
91
+ // Fix fallback avatar icon vertical alignment.
92
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors -- Ignored via go/DSP-18766
93
+ '> div > span:has(> span)': {
94
+ position: 'relative',
95
+ top: '-2px'
96
+ }
97
+ });
@@ -13,30 +13,40 @@ export const replaceRichInlineNodes = (editorState, hydratedValues) => {
13
13
  transaction.setMeta('addToHistory', false);
14
14
  Object.entries(hydratedValues).forEach(([fieldName, values]) => {
15
15
  values.forEach(value => {
16
- if (value.type === 'user' || value.type === 'team' || value.type === 'goal' && FeatureGates.getExperimentValue('anip-1095-goals-in-harmonised-filter', 'isEnabled', false) || value.type === 'project' && FeatureGates.getExperimentValue('atlassian_projects_-_native_integration', 'releaseVersion', -1) >= 1) {
17
- // First try to find as direct value operand (e.g., Team[Team] = uuid)
16
+ if (fg('jql-function-arg-hydration')) {
17
+ // Skip deprecated fields
18
+ if (value.type === 'deprecated-field') {
19
+ return;
20
+ }
21
+ // When the gate is on, collect both direct value operands and function argument
22
+ // operands for all node types
23
+ const astNodes = [...getValueNodes(ast, fieldName, value.id), ...getFunctionArgumentNodes(ast, fieldName, value.id)];
24
+ replaceAstNodesWithRichInlineNodes(transaction, astNodes, fieldName, value);
25
+ } else if (value.type === 'user' || value.type === 'team' || value.type === 'goal' && FeatureGates.getExperimentValue('anip-1095-goals-in-harmonised-filter', 'isEnabled', false) || value.type === 'project' && FeatureGates.getExperimentValue('atlassian_projects_-_native_integration', 'releaseVersion', -1) >= 1) {
26
+ // Legacy path: direct value operands only, with membersOf fallback for teams.
18
27
  let astNodes = getValueNodes(ast, fieldName, value.id);
19
-
20
- // If not found as direct value and it's a team, try to find in membersOf function arguments
21
28
  if (astNodes.length === 0 && value.type === 'team' && fg('jira-membersof-team-support')) {
22
29
  astNodes = getMembersOfArgumentNodes(ast, value.id);
23
30
  }
24
- astNodes.forEach(astNode => {
25
- if (astNode.position) {
26
- const [from, to] = astNode.position;
27
- const documentFrom = getDocumentPosition(transaction.doc, from);
28
- if (!isRichInlineNode(transaction.doc, documentFrom)) {
29
- const documentTo = getDocumentPosition(transaction.doc, to);
30
- const node = getRichInlineNode(fieldName, value, astNode.text);
31
- transaction.replaceWith(documentFrom, documentTo, node);
32
- }
33
- }
34
- });
31
+ replaceAstNodesWithRichInlineNodes(transaction, astNodes, fieldName, value);
35
32
  }
36
33
  });
37
34
  });
38
35
  return transaction;
39
36
  };
37
+ const replaceAstNodesWithRichInlineNodes = (transaction, astNodes, fieldName, value) => {
38
+ astNodes.forEach(astNode => {
39
+ if (astNode.position) {
40
+ const [from, to] = astNode.position;
41
+ const documentFrom = getDocumentPosition(transaction.doc, from);
42
+ if (!isRichInlineNode(transaction.doc, documentFrom)) {
43
+ const documentTo = getDocumentPosition(transaction.doc, to);
44
+ const node = getRichInlineNode(fieldName, value, astNode.text);
45
+ transaction.replaceWith(documentFrom, documentTo, node);
46
+ }
47
+ }
48
+ });
49
+ };
40
50
  const getRichInlineNode = (fieldName, value, text) => {
41
51
  switch (value.type) {
42
52
  case 'user':
@@ -71,6 +81,14 @@ const getRichInlineNode = (fieldName, value, text) => {
71
81
  fieldName
72
82
  }, textContent);
73
83
  }
84
+ case 'lozengeWithAvatar':
85
+ {
86
+ const textContent = JQLEditorSchema.text(text);
87
+ return JQLEditorSchema.nodes.lozengeWithAvatar.create({
88
+ ...value,
89
+ fieldName
90
+ }, textContent);
91
+ }
74
92
  default:
75
93
  {
76
94
  throw new Error(`Unsupported hydrated value type ${value.type}`);
@@ -93,6 +111,12 @@ const getMembersOfArgumentNodes = (ast, teamId) => {
93
111
  }
94
112
  return ast.query.accept(new FindMembersOfArgumentsVisitor(teamId));
95
113
  };
114
+ const getFunctionArgumentNodes = (ast, fieldName, valueId) => {
115
+ if (!ast.query) {
116
+ return [];
117
+ }
118
+ return ast.query.accept(new FindFunctionArgumentsVisitor(fieldName, valueId));
119
+ };
96
120
 
97
121
  /**
98
122
  * Base visitor class for traversing JQL AST to find specific nodes.
@@ -161,6 +185,30 @@ class FindValuesVisitor extends BaseAstNodeFinder {
161
185
  }
162
186
  }
163
187
 
188
+ /**
189
+ * Visitor that finds function arguments for a specific field matching a target value id.
190
+ * This visitor is field-aware: it processes clauses for the given field and matches arguments by their raw value.
191
+ */
192
+ class FindFunctionArgumentsVisitor extends BaseAstNodeFinder {
193
+ constructor(fieldName, targetValueId) {
194
+ super();
195
+ _defineProperty(this, "visitTerminalClause", terminalClause => {
196
+ if (!this.equalsIgnoreCase(terminalClause.field.value, this.fieldName)) {
197
+ return [];
198
+ }
199
+ if (terminalClause.operand === undefined) {
200
+ return [];
201
+ }
202
+ return terminalClause.operand.accept(this);
203
+ });
204
+ _defineProperty(this, "visitFunctionOperand", functionOperand => {
205
+ return functionOperand.arguments.filter(arg => this.equalsIgnoreCase(arg.value.trim(), this.targetValueId));
206
+ });
207
+ this.fieldName = fieldName;
208
+ this.targetValueId = targetValueId.trim();
209
+ }
210
+ }
211
+
164
212
  /**
165
213
  * Visitor that finds membersOf function arguments matching a specific team ID.
166
214
  * Used for queries like "assignee in membersOf("id: <uuid>")".
@@ -59,14 +59,14 @@ export class ValidQueryVisitor extends AbstractJastVisitor {
59
59
  return `(${listOperand.values.map(value => value.accept(this)).filter(value => !!value).join(', ')})`;
60
60
  });
61
61
  _defineProperty(this, "visitFunctionOperand", functionOperand => {
62
- // Only include membersOf function as it has arguments that need hydration
63
- // Other functions like currentUser() don't have hydratable arguments
64
62
  const functionName = functionOperand.function.value.toLowerCase();
65
- if (functionName !== 'membersof' || !fg('jira-membersof-team-support')) {
66
- return '';
67
- }
68
63
  const args = functionOperand.arguments.map(arg => arg.text).join(', ');
69
- return `${functionOperand.function.text}(${args})`;
64
+
65
+ // The generic gate supersedes the legacy membersOf-specific gate: when
66
+ // jql-function-arg-hydration is on, any function with arguments is included (covering
67
+ // membersOf and all others). Otherwise fall back to the legacy membersOf-only path.
68
+ const shouldIncludeFunction = fg('jql-function-arg-hydration') ? functionOperand.arguments.length > 0 : functionName === 'membersof' && fg('jira-membersof-team-support');
69
+ return shouldIncludeFunction ? `${functionOperand.function.text}(${args})` : '';
70
70
  });
71
71
  }
72
72
  defaultResult() {
@@ -927,14 +927,24 @@ export const useHydratedGoal = createHook(Store, {
927
927
  return goal && goal.type === 'goal' ? goal : undefined;
928
928
  }
929
929
  });
930
+ export const useHydratedLozengeWithAvatar = createHook(Store, {
931
+ selector: (state, {
932
+ id,
933
+ fieldName
934
+ }) => {
935
+ var _state$hydratedValues0;
936
+ const value = (_state$hydratedValues0 = state.hydratedValues[normaliseHydrationKey(fieldName)]) === null || _state$hydratedValues0 === void 0 ? void 0 : _state$hydratedValues0.get(normaliseJqlString(id));
937
+ return value && value.type === 'lozengeWithAvatar' ? value : undefined;
938
+ }
939
+ });
930
940
  export const useHydratedDeprecations = createHook(Store, {
931
941
  selector: state => {
932
942
  const ast = getJastFromState(state.editorState);
933
943
  const fieldsInQuery = getFieldNodes(ast);
934
944
  const toReturn = [];
935
945
  Object.entries(state.hydratedValues).forEach(([fieldName]) => {
936
- var _state$hydratedValues0;
937
- (_state$hydratedValues0 = state.hydratedValues[fieldName]) === null || _state$hydratedValues0 === void 0 ? void 0 : _state$hydratedValues0.forEach(value => {
946
+ var _state$hydratedValues1;
947
+ (_state$hydratedValues1 = state.hydratedValues[fieldName]) === null || _state$hydratedValues1 === void 0 ? void 0 : _state$hydratedValues1.forEach(value => {
938
948
  if (value.type === 'deprecated-field') {
939
949
  if (fieldsInQuery.has(value.id.toLowerCase())) {
940
950
  toReturn.push(value);
@@ -1,4 +1,4 @@
1
1
  import { ANALYTICS_CHANNEL, useJqlPackageAnalytics } from '@atlaskit/jql-editor-common';
2
2
  export var useJqlEditorAnalytics = function useJqlEditorAnalytics(analyticsSource) {
3
- return useJqlPackageAnalytics(analyticsSource, "@atlaskit/jql-editor", "6.4.6", ANALYTICS_CHANNEL);
3
+ return useJqlPackageAnalytics(analyticsSource, "@atlaskit/jql-editor", "6.4.7", ANALYTICS_CHANNEL);
4
4
  };
@@ -1,8 +1,10 @@
1
1
  import { goal } from './goal';
2
+ import { lozengeWithAvatar } from './lozenge-with-avatar';
2
3
  import { project } from './project';
3
4
  import { team } from './team';
4
5
  import { user } from './user';
5
6
  export var richInlineNodes = {
7
+ lozengeWithAvatar: lozengeWithAvatar,
6
8
  user: user,
7
9
  team: team,
8
10
  project: project,
@@ -0,0 +1,34 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
+ import React from 'react';
3
+ import Avatar from '@atlaskit/avatar';
4
+ import { useHydratedLozengeWithAvatar } from '../../../../state';
5
+ import { AvatarWrapper, LozengeWithAvatarContainer, NameContainer } from './styled';
6
+ var LozengeWithAvatar = function LozengeWithAvatar(_ref) {
7
+ var id = _ref.id,
8
+ name = _ref.name,
9
+ fieldName = _ref.fieldName,
10
+ selected = _ref.selected,
11
+ error = _ref.error;
12
+ var _useHydratedLozengeWi = useHydratedLozengeWithAvatar({
13
+ id: id,
14
+ fieldName: fieldName
15
+ }),
16
+ _useHydratedLozengeWi2 = _slicedToArray(_useHydratedLozengeWi, 1),
17
+ lozengeWithAvatar = _useHydratedLozengeWi2[0];
18
+ return /*#__PURE__*/React.createElement(LozengeWithAvatarContainer, {
19
+ selected: selected,
20
+ error: error
21
+ }, /*#__PURE__*/React.createElement(AvatarWrapper, null, /*#__PURE__*/React.createElement(Avatar, {
22
+ src: lozengeWithAvatar === null || lozengeWithAvatar === void 0 ? void 0 : lozengeWithAvatar.avatarUrl,
23
+ borderColor: "transparent",
24
+ size: "xsmall"
25
+ })), /*#__PURE__*/React.createElement(NameContainer, null, name));
26
+ };
27
+ export var lozengeWithAvatar = {
28
+ component: LozengeWithAvatar,
29
+ attrs: {
30
+ id: {},
31
+ name: {},
32
+ fieldName: {}
33
+ }
34
+ };
@@ -0,0 +1,96 @@
1
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
2
+
3
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
4
+ import { css } from '@emotion/react';
5
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
6
+ import styled from '@emotion/styled';
7
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-exported-styles -- Ignored via go/DSP-18766
8
+ export var LozengeWithAvatarContainer =
9
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-styled -- Ignored via go/DSP-18766
10
+ styled.span({
11
+ display: 'inline-flex',
12
+ alignItems: 'baseline',
13
+ paddingLeft: "var(--ds-space-025, 2px)",
14
+ borderRadius: "var(--ds-radius-xlarge, 12px)",
15
+ cursor: 'pointer',
16
+ userSelect: 'none'
17
+ },
18
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-dynamic-styles -- Ignored via go/DSP-18766
19
+ function (_ref) {
20
+ var selected = _ref.selected,
21
+ error = _ref.error;
22
+ if (selected) {
23
+ if (error) {
24
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766
25
+ return css({
26
+ color: "var(--ds-text-inverse, #FFFFFF)",
27
+ backgroundColor: "var(--ds-background-danger-bold, #C9372C)",
28
+ textDecoration: 'wavy underline',
29
+ textDecorationThickness: '1px',
30
+ textDecorationSkipInk: 'none',
31
+ textDecorationColor: "var(--ds-text-inverse, #FFFFFF)"
32
+ });
33
+ } else {
34
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766
35
+ return css({
36
+ color: "var(--ds-text, #292A2E)",
37
+ backgroundColor: "var(--ds-background-selected, #E9F2FE)",
38
+ boxShadow: "0 0 0 1px ".concat("var(--ds-border-selected, #1868DB)")
39
+ });
40
+ }
41
+ } else {
42
+ if (error) {
43
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766
44
+ return css({
45
+ color: "var(--ds-text-subtle, #505258)",
46
+ backgroundColor: "var(--ds-background-neutral, #0515240F)",
47
+ textDecoration: 'wavy underline',
48
+ textDecorationThickness: '1px',
49
+ textDecorationSkipInk: 'none',
50
+ textDecorationColor: "var(--ds-text-danger, #AE2E24)",
51
+ '&:hover': {
52
+ backgroundColor: "var(--ds-background-neutral-hovered, #0B120E24)"
53
+ }
54
+ });
55
+ } else {
56
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766
57
+ return css({
58
+ color: "var(--ds-text-subtle, #505258)",
59
+ backgroundColor: "var(--ds-background-neutral, #0515240F)",
60
+ '&:hover': {
61
+ backgroundColor: "var(--ds-background-neutral-hovered, #0B120E24)"
62
+ }
63
+ });
64
+ }
65
+ }
66
+ });
67
+
68
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-exported-styles -- Ignored via go/DSP-18766
69
+ export var NameContainer =
70
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-styled -- Ignored via go/DSP-18766
71
+ styled.span({
72
+ marginLeft: "var(--ds-space-075, 6px)",
73
+ marginRight: "var(--ds-space-100, 8px)",
74
+ // eslint-disable-next-line -- Ignored via go/DSP-18766
75
+ lineHeight: "var(--ds-space-250, 20px)"
76
+ });
77
+
78
+ /* Override Avatar styles to match design spec */
79
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-exported-styles -- Ignored via go/DSP-18766
80
+ export var AvatarWrapper =
81
+ // eslint-disable-next-line @atlaskit/design-system/ensure-design-token-usage, @atlaskit/ui-styling-standard/no-styled -- Ignored via go/DSP-18766
82
+ styled.div({
83
+ height: "var(--ds-space-200, 16px)",
84
+ width: "var(--ds-space-200, 16px)",
85
+ alignSelf: 'center',
86
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors -- Ignored via go/DSP-18766
87
+ '> div span': {
88
+ margin: "var(--ds-space-0, 0px)"
89
+ },
90
+ // Fix fallback avatar icon vertical alignment.
91
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors -- Ignored via go/DSP-18766
92
+ '> div > span:has(> span)': {
93
+ position: 'relative',
94
+ top: '-2px'
95
+ }
96
+ });
@@ -1,10 +1,10 @@
1
- import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
1
  import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
3
2
  import _createClass from "@babel/runtime/helpers/createClass";
4
3
  import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
5
4
  import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
6
5
  import _inherits from "@babel/runtime/helpers/inherits";
7
6
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
7
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
8
8
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
9
9
  function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
10
10
  function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
@@ -27,32 +27,42 @@ export var replaceRichInlineNodes = function replaceRichInlineNodes(editorState,
27
27
  fieldName = _ref2[0],
28
28
  values = _ref2[1];
29
29
  values.forEach(function (value) {
30
- if (value.type === 'user' || value.type === 'team' || value.type === 'goal' && FeatureGates.getExperimentValue('anip-1095-goals-in-harmonised-filter', 'isEnabled', false) || value.type === 'project' && FeatureGates.getExperimentValue('atlassian_projects_-_native_integration', 'releaseVersion', -1) >= 1) {
31
- // First try to find as direct value operand (e.g., Team[Team] = uuid)
32
- var astNodes = getValueNodes(ast, fieldName, value.id);
33
-
34
- // If not found as direct value and it's a team, try to find in membersOf function arguments
35
- if (astNodes.length === 0 && value.type === 'team' && fg('jira-membersof-team-support')) {
36
- astNodes = getMembersOfArgumentNodes(ast, value.id);
30
+ if (fg('jql-function-arg-hydration')) {
31
+ // Skip deprecated fields
32
+ if (value.type === 'deprecated-field') {
33
+ return;
37
34
  }
38
- astNodes.forEach(function (astNode) {
39
- if (astNode.position) {
40
- var _astNode$position = _slicedToArray(astNode.position, 2),
41
- from = _astNode$position[0],
42
- to = _astNode$position[1];
43
- var documentFrom = getDocumentPosition(transaction.doc, from);
44
- if (!isRichInlineNode(transaction.doc, documentFrom)) {
45
- var documentTo = getDocumentPosition(transaction.doc, to);
46
- var node = getRichInlineNode(fieldName, value, astNode.text);
47
- transaction.replaceWith(documentFrom, documentTo, node);
48
- }
49
- }
50
- });
35
+ // When the gate is on, collect both direct value operands and function argument
36
+ // operands for all node types
37
+ var astNodes = [].concat(_toConsumableArray(getValueNodes(ast, fieldName, value.id)), _toConsumableArray(getFunctionArgumentNodes(ast, fieldName, value.id)));
38
+ replaceAstNodesWithRichInlineNodes(transaction, astNodes, fieldName, value);
39
+ } else if (value.type === 'user' || value.type === 'team' || value.type === 'goal' && FeatureGates.getExperimentValue('anip-1095-goals-in-harmonised-filter', 'isEnabled', false) || value.type === 'project' && FeatureGates.getExperimentValue('atlassian_projects_-_native_integration', 'releaseVersion', -1) >= 1) {
40
+ // Legacy path: direct value operands only, with membersOf fallback for teams.
41
+ var _astNodes = getValueNodes(ast, fieldName, value.id);
42
+ if (_astNodes.length === 0 && value.type === 'team' && fg('jira-membersof-team-support')) {
43
+ _astNodes = getMembersOfArgumentNodes(ast, value.id);
44
+ }
45
+ replaceAstNodesWithRichInlineNodes(transaction, _astNodes, fieldName, value);
51
46
  }
52
47
  });
53
48
  });
54
49
  return transaction;
55
50
  };
51
+ var replaceAstNodesWithRichInlineNodes = function replaceAstNodesWithRichInlineNodes(transaction, astNodes, fieldName, value) {
52
+ astNodes.forEach(function (astNode) {
53
+ if (astNode.position) {
54
+ var _astNode$position = _slicedToArray(astNode.position, 2),
55
+ from = _astNode$position[0],
56
+ to = _astNode$position[1];
57
+ var documentFrom = getDocumentPosition(transaction.doc, from);
58
+ if (!isRichInlineNode(transaction.doc, documentFrom)) {
59
+ var documentTo = getDocumentPosition(transaction.doc, to);
60
+ var node = getRichInlineNode(fieldName, value, astNode.text);
61
+ transaction.replaceWith(documentFrom, documentTo, node);
62
+ }
63
+ }
64
+ });
65
+ };
56
66
  var getRichInlineNode = function getRichInlineNode(fieldName, value, text) {
57
67
  switch (value.type) {
58
68
  case 'user':
@@ -83,6 +93,13 @@ var getRichInlineNode = function getRichInlineNode(fieldName, value, text) {
83
93
  fieldName: fieldName
84
94
  }), _textContent3);
85
95
  }
96
+ case 'lozengeWithAvatar':
97
+ {
98
+ var _textContent4 = JQLEditorSchema.text(text);
99
+ return JQLEditorSchema.nodes.lozengeWithAvatar.create(_objectSpread(_objectSpread({}, value), {}, {
100
+ fieldName: fieldName
101
+ }), _textContent4);
102
+ }
86
103
  default:
87
104
  {
88
105
  throw new Error("Unsupported hydrated value type ".concat(value.type));
@@ -105,6 +122,12 @@ var getMembersOfArgumentNodes = function getMembersOfArgumentNodes(ast, teamId)
105
122
  }
106
123
  return ast.query.accept(new FindMembersOfArgumentsVisitor(teamId));
107
124
  };
125
+ var getFunctionArgumentNodes = function getFunctionArgumentNodes(ast, fieldName, valueId) {
126
+ if (!ast.query) {
127
+ return [];
128
+ }
129
+ return ast.query.accept(new FindFunctionArgumentsVisitor(fieldName, valueId));
130
+ };
108
131
 
109
132
  /**
110
133
  * Base visitor class for traversing JQL AST to find specific nodes.
@@ -191,21 +214,51 @@ var FindValuesVisitor = /*#__PURE__*/function (_BaseAstNodeFinder2) {
191
214
  return _createClass(FindValuesVisitor);
192
215
  }(BaseAstNodeFinder);
193
216
  /**
194
- * Visitor that finds membersOf function arguments matching a specific team ID.
195
- * Used for queries like "assignee in membersOf("id: <uuid>")".
217
+ * Visitor that finds function arguments for a specific field matching a target value id.
218
+ * This visitor is field-aware: it processes clauses for the given field and matches arguments by their raw value.
196
219
  */
197
- var FindMembersOfArgumentsVisitor = /*#__PURE__*/function (_BaseAstNodeFinder3) {
198
- function FindMembersOfArgumentsVisitor(teamId) {
220
+ var FindFunctionArgumentsVisitor = /*#__PURE__*/function (_BaseAstNodeFinder3) {
221
+ function FindFunctionArgumentsVisitor(fieldName, targetValueId) {
199
222
  var _this3;
200
- _classCallCheck(this, FindMembersOfArgumentsVisitor);
201
- _this3 = _callSuper(this, FindMembersOfArgumentsVisitor);
223
+ _classCallCheck(this, FindFunctionArgumentsVisitor);
224
+ _this3 = _callSuper(this, FindFunctionArgumentsVisitor);
202
225
  _defineProperty(_this3, "visitTerminalClause", function (terminalClause) {
226
+ if (!_this3.equalsIgnoreCase(terminalClause.field.value, _this3.fieldName)) {
227
+ return [];
228
+ }
203
229
  if (terminalClause.operand === undefined) {
204
230
  return [];
205
231
  }
206
232
  return terminalClause.operand.accept(_this3);
207
233
  });
208
234
  _defineProperty(_this3, "visitFunctionOperand", function (functionOperand) {
235
+ return functionOperand.arguments.filter(function (arg) {
236
+ return _this3.equalsIgnoreCase(arg.value.trim(), _this3.targetValueId);
237
+ });
238
+ });
239
+ _this3.fieldName = fieldName;
240
+ _this3.targetValueId = targetValueId.trim();
241
+ return _this3;
242
+ }
243
+ _inherits(FindFunctionArgumentsVisitor, _BaseAstNodeFinder3);
244
+ return _createClass(FindFunctionArgumentsVisitor);
245
+ }(BaseAstNodeFinder);
246
+ /**
247
+ * Visitor that finds membersOf function arguments matching a specific team ID.
248
+ * Used for queries like "assignee in membersOf("id: <uuid>")".
249
+ */
250
+ var FindMembersOfArgumentsVisitor = /*#__PURE__*/function (_BaseAstNodeFinder4) {
251
+ function FindMembersOfArgumentsVisitor(teamId) {
252
+ var _this4;
253
+ _classCallCheck(this, FindMembersOfArgumentsVisitor);
254
+ _this4 = _callSuper(this, FindMembersOfArgumentsVisitor);
255
+ _defineProperty(_this4, "visitTerminalClause", function (terminalClause) {
256
+ if (terminalClause.operand === undefined) {
257
+ return [];
258
+ }
259
+ return terminalClause.operand.accept(_this4);
260
+ });
261
+ _defineProperty(_this4, "visitFunctionOperand", function (functionOperand) {
209
262
  var functionName = functionOperand.function.value.toLowerCase();
210
263
 
211
264
  // Only process membersOf function
@@ -216,18 +269,18 @@ var FindMembersOfArgumentsVisitor = /*#__PURE__*/function (_BaseAstNodeFinder3)
216
269
  functionOperand.arguments.forEach(function (arg) {
217
270
  // Normalize both values by removing extra whitespace for comparison
218
271
  // This handles both "id: uuid" and "id:uuid" formats
219
- var normalizedArgValue = _this3.normalizeValue(arg.value);
220
- var normalizedTeamId = _this3.normalizeValue(_this3.teamId);
221
- if (_this3.equalsIgnoreCase(normalizedArgValue, normalizedTeamId)) {
272
+ var normalizedArgValue = _this4.normalizeValue(arg.value);
273
+ var normalizedTeamId = _this4.normalizeValue(_this4.teamId);
274
+ if (_this4.equalsIgnoreCase(normalizedArgValue, normalizedTeamId)) {
222
275
  matchingArgs.push(arg);
223
276
  }
224
277
  });
225
278
  return matchingArgs;
226
279
  });
227
- _this3.teamId = teamId;
228
- return _this3;
280
+ _this4.teamId = teamId;
281
+ return _this4;
229
282
  }
230
- _inherits(FindMembersOfArgumentsVisitor, _BaseAstNodeFinder3);
283
+ _inherits(FindMembersOfArgumentsVisitor, _BaseAstNodeFinder4);
231
284
  return _createClass(FindMembersOfArgumentsVisitor, [{
232
285
  key: "normalizeValue",
233
286
  value:
@@ -79,16 +79,16 @@ export var ValidQueryVisitor = /*#__PURE__*/function (_AbstractJastVisitor) {
79
79
  }).join(', '), ")");
80
80
  });
81
81
  _defineProperty(_this, "visitFunctionOperand", function (functionOperand) {
82
- // Only include membersOf function as it has arguments that need hydration
83
- // Other functions like currentUser() don't have hydratable arguments
84
82
  var functionName = functionOperand.function.value.toLowerCase();
85
- if (functionName !== 'membersof' || !fg('jira-membersof-team-support')) {
86
- return '';
87
- }
88
83
  var args = functionOperand.arguments.map(function (arg) {
89
84
  return arg.text;
90
85
  }).join(', ');
91
- return "".concat(functionOperand.function.text, "(").concat(args, ")");
86
+
87
+ // The generic gate supersedes the legacy membersOf-specific gate: when
88
+ // jql-function-arg-hydration is on, any function with arguments is included (covering
89
+ // membersOf and all others). Otherwise fall back to the legacy membersOf-only path.
90
+ var shouldIncludeFunction = fg('jql-function-arg-hydration') ? functionOperand.arguments.length > 0 : functionName === 'membersof' && fg('jira-membersof-team-support');
91
+ return shouldIncludeFunction ? "".concat(functionOperand.function.text, "(").concat(args, ")") : '';
92
92
  });
93
93
  return _this;
94
94
  }