@ynput/ayon-frontend-shared 0.2.1 → 0.2.3

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 (170) hide show
  1. package/dist/_virtual/index.cjs4.js +4 -4
  2. package/dist/_virtual/index.cjs5.js +4 -4
  3. package/dist/_virtual/index.cjs6.js +2 -2
  4. package/dist/_virtual/index.cjs7.js +2 -2
  5. package/dist/_virtual/index.es4.js +4 -4
  6. package/dist/_virtual/index.es5.js +4 -4
  7. package/dist/_virtual/index.es6.js +2 -2
  8. package/dist/_virtual/index.es7.js +2 -2
  9. package/dist/hooks.cjs.js +2 -0
  10. package/dist/hooks.cjs.js.map +1 -1
  11. package/dist/hooks.es.js +2 -0
  12. package/dist/hooks.es.js.map +1 -1
  13. package/dist/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.modern.cjs.js +19 -10
  14. package/dist/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.modern.cjs.js.map +1 -1
  15. package/dist/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.modern.es.js +21 -12
  16. package/dist/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.modern.es.js.map +1 -1
  17. package/dist/node_modules/@reduxjs/toolkit/dist/query/rtk-query.modern.cjs.js +174 -68
  18. package/dist/node_modules/@reduxjs/toolkit/dist/query/rtk-query.modern.cjs.js.map +1 -1
  19. package/dist/node_modules/@reduxjs/toolkit/dist/query/rtk-query.modern.es.js +174 -68
  20. package/dist/node_modules/@reduxjs/toolkit/dist/query/rtk-query.modern.es.js.map +1 -1
  21. package/dist/node_modules/@standard-schema/utils/dist/index.cjs.js +23 -0
  22. package/dist/node_modules/@standard-schema/utils/dist/index.cjs.js.map +1 -0
  23. package/dist/node_modules/@standard-schema/utils/dist/index.es.js +23 -0
  24. package/dist/node_modules/@standard-schema/utils/dist/index.es.js.map +1 -0
  25. package/dist/node_modules/match-sorter/dist/match-sorter.esm.cjs.js +1 -1
  26. package/dist/node_modules/match-sorter/dist/match-sorter.esm.es.js +1 -1
  27. package/dist/node_modules/parse-numeric-range/index.cjs.js +1 -1
  28. package/dist/node_modules/parse-numeric-range/index.es.js +1 -1
  29. package/dist/node_modules/rehype-prism-plus/dist/index.es.cjs.js +1 -1
  30. package/dist/node_modules/rehype-prism-plus/dist/index.es.es.js +1 -1
  31. package/dist/node_modules/remove-accents/index.cjs.js +1 -1
  32. package/dist/node_modules/remove-accents/index.es.js +1 -1
  33. package/dist/shared/src/api/generated/anatomy.cjs.js +13 -0
  34. package/dist/shared/src/api/generated/anatomy.cjs.js.map +1 -1
  35. package/dist/shared/src/api/generated/anatomy.es.js +13 -0
  36. package/dist/shared/src/api/generated/anatomy.es.js.map +1 -1
  37. package/dist/shared/src/api/queries/entities/transformDetailsPanelData.cjs.js +4 -0
  38. package/dist/shared/src/api/queries/entities/transformDetailsPanelData.cjs.js.map +1 -1
  39. package/dist/shared/src/api/queries/entities/transformDetailsPanelData.es.js +4 -0
  40. package/dist/shared/src/api/queries/entities/transformDetailsPanelData.es.js.map +1 -1
  41. package/dist/shared/src/components/EntityPath/EntityPath.cjs.js +11 -1
  42. package/dist/shared/src/components/EntityPath/EntityPath.cjs.js.map +1 -1
  43. package/dist/shared/src/components/EntityPath/EntityPath.es.js +12 -2
  44. package/dist/shared/src/components/EntityPath/EntityPath.es.js.map +1 -1
  45. package/dist/shared/src/components/EntityPath/EntityPath.styled.cjs.js +10 -1
  46. package/dist/shared/src/components/EntityPath/EntityPath.styled.cjs.js.map +1 -1
  47. package/dist/shared/src/components/EntityPath/EntityPath.styled.es.js +10 -1
  48. package/dist/shared/src/components/EntityPath/EntityPath.styled.es.js.map +1 -1
  49. package/dist/shared/src/containers/Actions/Actions.cjs.js +10 -6
  50. package/dist/shared/src/containers/Actions/Actions.cjs.js.map +1 -1
  51. package/dist/shared/src/containers/Actions/Actions.es.js +10 -6
  52. package/dist/shared/src/containers/Actions/Actions.es.js.map +1 -1
  53. package/dist/shared/src/containers/Feed/components/CommentInput/CommentInput.cjs.js +5 -3
  54. package/dist/shared/src/containers/Feed/components/CommentInput/CommentInput.cjs.js.map +1 -1
  55. package/dist/shared/src/containers/Feed/components/CommentInput/CommentInput.es.js +5 -3
  56. package/dist/shared/src/containers/Feed/components/CommentInput/CommentInput.es.js.map +1 -1
  57. package/dist/shared/src/containers/ProjectTreeTable/ProjectTreeTableColumns.cjs.js +13 -1
  58. package/dist/shared/src/containers/ProjectTreeTable/ProjectTreeTableColumns.cjs.js.map +1 -1
  59. package/dist/shared/src/containers/ProjectTreeTable/ProjectTreeTableColumns.es.js +13 -1
  60. package/dist/shared/src/containers/ProjectTreeTable/ProjectTreeTableColumns.es.js.map +1 -1
  61. package/dist/shared/src/containers/ProjectTreeTable/context/ClipboardContext.cjs.js +0 -1
  62. package/dist/shared/src/containers/ProjectTreeTable/context/ClipboardContext.cjs.js.map +1 -1
  63. package/dist/shared/src/containers/ProjectTreeTable/context/ClipboardContext.es.js +0 -1
  64. package/dist/shared/src/containers/ProjectTreeTable/context/ClipboardContext.es.js.map +1 -1
  65. package/dist/shared/src/containers/ProjectTreeTable/context/clipboard/clipboardUtils.cjs.js +3 -0
  66. package/dist/shared/src/containers/ProjectTreeTable/context/clipboard/clipboardUtils.cjs.js.map +1 -1
  67. package/dist/shared/src/containers/ProjectTreeTable/context/clipboard/clipboardUtils.es.js +3 -0
  68. package/dist/shared/src/containers/ProjectTreeTable/context/clipboard/clipboardUtils.es.js.map +1 -1
  69. package/dist/shared/src/containers/ProjectTreeTable/widgets/BooleanWidget.cjs.js.map +1 -1
  70. package/dist/shared/src/containers/ProjectTreeTable/widgets/BooleanWidget.es.js.map +1 -1
  71. package/dist/shared/src/containers/ProjectTreeTable/widgets/CellWidget.cjs.js +24 -6
  72. package/dist/shared/src/containers/ProjectTreeTable/widgets/CellWidget.cjs.js.map +1 -1
  73. package/dist/shared/src/containers/ProjectTreeTable/widgets/CellWidget.es.js +24 -6
  74. package/dist/shared/src/containers/ProjectTreeTable/widgets/CellWidget.es.js.map +1 -1
  75. package/dist/shared/src/containers/ProjectTreeTable/widgets/DateWidget.cjs.js +7 -5
  76. package/dist/shared/src/containers/ProjectTreeTable/widgets/DateWidget.cjs.js.map +1 -1
  77. package/dist/shared/src/containers/ProjectTreeTable/widgets/DateWidget.es.js +7 -5
  78. package/dist/shared/src/containers/ProjectTreeTable/widgets/DateWidget.es.js.map +1 -1
  79. package/dist/shared/src/containers/ProjectTreeTable/widgets/EnumWidget.cjs.js +8 -0
  80. package/dist/shared/src/containers/ProjectTreeTable/widgets/EnumWidget.cjs.js.map +1 -1
  81. package/dist/shared/src/containers/ProjectTreeTable/widgets/EnumWidget.es.js +8 -0
  82. package/dist/shared/src/containers/ProjectTreeTable/widgets/EnumWidget.es.js.map +1 -1
  83. package/dist/shared/src/containers/ProjectTreeTable/widgets/TextWidget.cjs.js.map +1 -1
  84. package/dist/shared/src/containers/ProjectTreeTable/widgets/TextWidget.es.js.map +1 -1
  85. package/dist/shared/src/containers/RepresentationsList/RepresentationsList.cjs.js +1 -2
  86. package/dist/shared/src/containers/RepresentationsList/RepresentationsList.cjs.js.map +1 -1
  87. package/dist/shared/src/containers/RepresentationsList/RepresentationsList.es.js +1 -2
  88. package/dist/shared/src/containers/RepresentationsList/RepresentationsList.es.js.map +1 -1
  89. package/dist/shared/src/context/RemoteModulesContext.cjs.js +1 -1
  90. package/dist/shared/src/context/RemoteModulesContext.cjs.js.map +1 -1
  91. package/dist/shared/src/context/RemoteModulesContext.es.js +1 -1
  92. package/dist/shared/src/context/RemoteModulesContext.es.js.map +1 -1
  93. package/dist/shared/src/hooks/useLoadModules.cjs.js +136 -0
  94. package/dist/shared/src/hooks/useLoadModules.cjs.js.map +1 -0
  95. package/dist/shared/src/hooks/useLoadModules.es.js +136 -0
  96. package/dist/shared/src/hooks/useLoadModules.es.js.map +1 -0
  97. package/dist/shared/src/hooks/useScopedStatuses.cjs.js +4 -1
  98. package/dist/shared/src/hooks/useScopedStatuses.cjs.js.map +1 -1
  99. package/dist/shared/src/hooks/useScopedStatuses.es.js +4 -1
  100. package/dist/shared/src/hooks/useScopedStatuses.es.js.map +1 -1
  101. package/dist/types/api/generated/access.d.ts +6 -6
  102. package/dist/types/api/generated/actions.d.ts +6 -6
  103. package/dist/types/api/generated/activityFeed.d.ts +8 -8
  104. package/dist/types/api/generated/addons.d.ts +28 -28
  105. package/dist/types/api/generated/anatomy.d.ts +36 -6
  106. package/dist/types/api/generated/attributes.d.ts +5 -5
  107. package/dist/types/api/generated/authentication.d.ts +5 -5
  108. package/dist/types/api/generated/bundles.d.ts +7 -7
  109. package/dist/types/api/generated/configuration.d.ts +7 -7
  110. package/dist/types/api/generated/desktop.d.ts +12 -12
  111. package/dist/types/api/generated/entityLists.d.ts +12 -12
  112. package/dist/types/api/generated/events.d.ts +8 -8
  113. package/dist/types/api/generated/files.d.ts +7 -7
  114. package/dist/types/api/generated/folders.d.ts +8 -8
  115. package/dist/types/api/generated/graphql.d.ts +25 -25
  116. package/dist/types/api/generated/inbox.d.ts +1 -1
  117. package/dist/types/api/generated/links.d.ts +5 -5
  118. package/dist/types/api/generated/market.d.ts +6 -6
  119. package/dist/types/api/generated/onboarding.d.ts +3 -3
  120. package/dist/types/api/generated/operations.d.ts +3 -3
  121. package/dist/types/api/generated/products.d.ts +5 -5
  122. package/dist/types/api/generated/projectDashboard.d.ts +4 -4
  123. package/dist/types/api/generated/projects.d.ts +27 -27
  124. package/dist/types/api/generated/representations.d.ts +5 -5
  125. package/dist/types/api/generated/reviewables.d.ts +7 -7
  126. package/dist/types/api/generated/services.d.ts +6 -6
  127. package/dist/types/api/generated/system.d.ts +12 -12
  128. package/dist/types/api/generated/tasks.d.ts +8 -8
  129. package/dist/types/api/generated/teams.d.ts +6 -6
  130. package/dist/types/api/generated/thumbnails.d.ts +11 -11
  131. package/dist/types/api/generated/uRIs.d.ts +2 -2
  132. package/dist/types/api/generated/users.d.ts +26 -26
  133. package/dist/types/api/generated/versions.d.ts +6 -6
  134. package/dist/types/api/generated/workfiles.d.ts +6 -6
  135. package/dist/types/api/generated/ynputCloud.d.ts +5 -5
  136. package/dist/types/api/queries/actions/getActions.d.ts +29 -29
  137. package/dist/types/api/queries/activities/getActivities.d.ts +72 -71
  138. package/dist/types/api/queries/activities/getMentions.d.ts +18 -18
  139. package/dist/types/api/queries/activities/updateActivities.d.ts +62 -62
  140. package/dist/types/api/queries/activities/updateReaction.d.ts +10 -10
  141. package/dist/types/api/queries/addons/getAddons.d.ts +67 -67
  142. package/dist/types/api/queries/addons/updateAddons.d.ts +35 -35
  143. package/dist/types/api/queries/attributes/getAttributes.d.ts +23 -23
  144. package/dist/types/api/queries/attributes/updateAttributes.d.ts +12 -12
  145. package/dist/types/api/queries/authentication/getAuthentication.d.ts +15 -15
  146. package/dist/types/api/queries/entities/getEntity.d.ts +73 -73
  147. package/dist/types/api/queries/entities/getEntityPanel.d.ts +44 -44
  148. package/dist/types/api/queries/entities/transformDetailsPanelData.d.ts +1 -0
  149. package/dist/types/api/queries/entities/updateEntity.d.ts +32 -32
  150. package/dist/types/api/queries/folders/getFolders.d.ts +26 -26
  151. package/dist/types/api/queries/overview/getOverview.d.ts +72 -72
  152. package/dist/types/api/queries/overview/updateOverview.d.ts +5 -5
  153. package/dist/types/api/queries/project/getProject.d.ts +103 -103
  154. package/dist/types/api/queries/review/getReview.d.ts +36 -36
  155. package/dist/types/api/queries/review/updateReview.d.ts +13 -13
  156. package/dist/types/api/queries/system/getSystem.d.ts +39 -39
  157. package/dist/types/api/queries/userDashboard/getUserDashboard.d.ts +53 -53
  158. package/dist/types/api/queries/users/getUsers.d.ts +110 -110
  159. package/dist/types/api/queries/watchers/getWatchers.d.ts +20 -20
  160. package/dist/types/components/EntityPath/EntityPath.styled.d.ts +1 -0
  161. package/dist/types/containers/Actions/Actions.d.ts +5 -1
  162. package/dist/types/containers/ProjectTreeTable/widgets/BooleanWidget.d.ts +1 -2
  163. package/dist/types/containers/ProjectTreeTable/widgets/CellWidget.d.ts +10 -0
  164. package/dist/types/containers/ProjectTreeTable/widgets/DateWidget.d.ts +2 -3
  165. package/dist/types/containers/ProjectTreeTable/widgets/EnumWidget.d.ts +1 -1
  166. package/dist/types/containers/ProjectTreeTable/widgets/TextWidget.d.ts +1 -1
  167. package/dist/types/containers/RepresentationsList/RepresentationsList.d.ts +1 -1
  168. package/dist/types/hooks/index.d.ts +1 -0
  169. package/dist/types/hooks/useLoadModules.d.ts +28 -0
  170. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"EntityPath.es.js","sources":["../../../../../src/components/EntityPath/EntityPath.tsx"],"sourcesContent":["import { FC, Fragment, MouseEvent, useLayoutEffect, useRef, useState } from 'react'\nimport * as Styled from './EntityPath.styled'\nimport clsx from 'clsx'\nimport SegmentProvider from './SegmentProvider'\nimport { Icon } from '@ynput/ayon-react-components'\nimport { DetailsPanelEntityType } from '@shared/api'\n\nconst Slash = () => <span className=\"slash\">/</span>\n\nexport type PathSegment = {\n type: DetailsPanelEntityType | 'product' | 'project'\n label: string\n id: string\n}\n\nconst dropdownStates = ['more', 'versions']\ntype DropdownState = (typeof dropdownStates)[number]\n\ntype DropdownMouseEvent = MouseEvent<HTMLSpanElement>\nconst getDropdownElements = (e: DropdownMouseEvent): [HTMLElement, string] => {\n const target = e.target as HTMLElement\n const dropdownId = target.closest('.dropdown')?.id || ''\n return [target, dropdownId]\n}\n\nexport interface EntityPathProps {\n projectName: string\n hideProjectName: boolean\n segments: PathSegment[]\n isLoading: boolean\n entityType: string\n versions: PathSegment[]\n scope: string\n}\n\nexport const EntityPath: FC<EntityPathProps> = ({\n projectName,\n hideProjectName,\n segments,\n versions = [],\n isLoading,\n entityType,\n scope,\n}) => {\n const containerRef = useRef<HTMLDivElement>(null)\n const [dropdownOpen, setDropdownOpen] = useState<null | DropdownState>(null)\n // defaults to whole path\n const [maxSegments, setMaxSegments] = useState<null | number>(null)\n const [calcMaxWidth, setCalcMaxWidth] = useState(false)\n\n useLayoutEffect(() => {\n setMaxSegments(null)\n setCalcMaxWidth(true)\n }, [segments])\n\n useLayoutEffect(() => {\n if (!containerRef.current) {\n setCalcMaxWidth(false)\n return\n }\n // find max width the path can be\n const container = containerRef.current\n const pathWidth = container.clientWidth\n const maxWidth = getPathMaxWidth(container)\n\n if (!maxWidth) return\n\n // we need to reduce the number of segments shown\n // but maybe even then it is still longer than the max width\n // so we need to reduce the number of segments until the total width is less than the max width\n const children = container.children\n let totalWidth = pathWidth\n // number of segments to keep\n const fullCount = container.childElementCount\n let segmentsCount = fullCount\n // while loop that removes segments until the total width is less than the max width\n while (totalWidth > maxWidth && segmentsCount > 0) {\n // remove 2 segments at a time (because of slashes)\n segmentsCount -= 2\n totalWidth = totalUpSegmentsWidth(children, segmentsCount, fullCount)\n }\n\n // count number of \"full\" segments left\n // if something goes wrong, removing 1 (2) is probably enough\n let newMaxSegments =\n Array.from(children)\n .slice(0, segmentsCount)\n .filter(\n (segment) => segment.nodeType === Node.ELEMENT_NODE && segment.className.includes('full'),\n )?.length || 2\n\n // cap at 1\n newMaxSegments = Math.max(newMaxSegments, 1)\n\n setMaxSegments(newMaxSegments)\n setCalcMaxWidth(false)\n }, [containerRef.current, calcMaxWidth])\n\n // Check if there are fewer than or equal to maxSegments segments\n const segmentsToShow =\n maxSegments && segments.length > maxSegments ? segments.slice(-maxSegments) : segments\n const hiddenSegments =\n maxSegments && segments.length > maxSegments ? segments.slice(0, -maxSegments) : []\n\n // if there is no project name, add to hidden segments\n if (hideProjectName)\n hiddenSegments.unshift({ type: 'project', label: projectName, id: projectName })\n\n // if the entityType is a version, separate the version\n let versionSegment\n let finalSegmentsToShow = segmentsToShow\n\n if (entityType === 'version' && segments.length > 0) {\n versionSegment = segments[segments.length - 1]\n finalSegmentsToShow = segmentsToShow.slice(0, -1)\n }\n\n const handleMouseEnter = (e: DropdownMouseEvent) => {\n const [, id] = getDropdownElements(e)\n if (id && !dropdownOpen) setDropdownOpen(id)\n }\n const handleMouseLeave = () => setDropdownOpen(null)\n\n const handleDropdownClick = (e: DropdownMouseEvent) => {\n const [target, id] = getDropdownElements(e)\n\n if (!dropdownStates.includes(id)) return\n const isListItem = !!target.closest('li')\n\n if (isListItem) setDropdownOpen(null)\n else if (dropdownOpen !== id) setDropdownOpen(id)\n }\n\n const segmentProps = { scope, projectName }\n\n return (\n <Styled.Path className={clsx({ loading: isLoading })} id=\"entity-path\" ref={containerRef}>\n {!hideProjectName && <Styled.Segment>{projectName}</Styled.Segment>}\n\n {!!hiddenSegments.length && (\n <>\n {!hideProjectName && <Slash />}\n <Styled.Segment\n className=\"dropdown more\"\n id=\"more\"\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n onClick={handleDropdownClick}\n >\n ...\n {dropdownOpen === 'more' && (\n <Styled.MoreModal>\n <Styled.MoreList>\n {hiddenSegments.map((segment) => (\n <SegmentProvider {...segmentProps} segment={segment} key={segment.id}>\n <Styled.MoreItem>{segment.label}</Styled.MoreItem>\n </SegmentProvider>\n ))}\n </Styled.MoreList>\n </Styled.MoreModal>\n )}\n </Styled.Segment>\n </>\n )}\n\n {finalSegmentsToShow.map((segment) => (\n <Fragment key={segment.id}>\n <Slash />\n\n <SegmentProvider {...segmentProps} segment={segment} className=\"full\">\n <Styled.Segment>\n <span className=\"label\">{segment.label}</span>\n </Styled.Segment>\n </SegmentProvider>\n </Fragment>\n ))}\n\n {versionSegment && (\n <>\n <Slash />\n <Styled.SegmentWrapper\n className=\"full dropdown\"\n id=\"versions\"\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n onClick={handleDropdownClick}\n >\n <SegmentProvider\n {...segmentProps}\n segment={versionSegment}\n isOpen={dropdownOpen === 'versions'}\n >\n <Styled.Segment>\n <span className=\"label\">{versionSegment.label}</span>\n <Icon icon=\"expand_more\" />\n </Styled.Segment>\n </SegmentProvider>\n {dropdownOpen === 'versions' && (\n <Styled.MoreModal>\n <Styled.MoreList>\n {versions.map((version) => (\n <SegmentProvider {...segmentProps} segment={version} key={version.id}>\n <Styled.MoreItem>{version.label}</Styled.MoreItem>\n </SegmentProvider>\n ))}\n </Styled.MoreList>\n </Styled.MoreModal>\n )}\n </Styled.SegmentWrapper>\n </>\n )}\n </Styled.Path>\n )\n}\n\nconst getPathMaxWidth = (pathEl: HTMLDivElement) => {\n const toolbar = pathEl.parentElement\n if (!toolbar) return\n // get width of toolbar without padding\n const toolbarStyle = getComputedStyle(toolbar)\n const paddingLeft = parseInt(toolbarStyle.paddingLeft) || 0\n const paddingRight = parseInt(toolbarStyle.paddingRight) || 0\n const gap = parseInt(toolbarStyle.gap) || 0\n const toolbarWidth = toolbar.clientWidth - paddingLeft - paddingRight\n\n // get child elements that are not path\n const children = Array.from(toolbar.children).filter((child) => child.id !== 'entity-path')\n // find total width of children including the gap between them\n const childrenWidth = Array.from(children).reduce(\n (acc, child) => acc + (child as HTMLElement).clientWidth,\n 0,\n )\n\n return toolbarWidth - childrenWidth - gap * (children.length - 1)\n}\n\nconst totalUpSegmentsWidth = (children: HTMLCollection, count: number, full: number) => {\n const skip = full - count\n let total = 0\n for (let i = 0; i < full - skip; i++) {\n const index = i > 1 ? i + skip : i\n const width = (children[index] as Element)?.clientWidth\n if (isNaN(width)) continue\n total += width\n }\n const gap = 4\n const moreWidth = 40\n return total + (gap * count - 1) + moreWidth\n}\n"],"names":["jsx","jsxs","Styled.Path","Styled.Segment","Fragment","Styled.MoreModal","Styled.MoreList","Styled.MoreItem","Styled.SegmentWrapper"],"mappings":"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"}
1
+ {"version":3,"file":"EntityPath.es.js","sources":["../../../../../src/components/EntityPath/EntityPath.tsx"],"sourcesContent":["import { FC, Fragment, MouseEvent, useLayoutEffect, useRef, useState } from 'react'\nimport * as Styled from './EntityPath.styled'\nimport clsx from 'clsx'\nimport SegmentProvider from './SegmentProvider'\nimport { Icon } from '@ynput/ayon-react-components'\nimport { DetailsPanelEntityType } from '@shared/api'\n\nconst Slash = () => <span className=\"slash\">/</span>\n\nexport type PathSegment = {\n type: DetailsPanelEntityType | 'product' | 'project'\n label: string\n id: string\n}\n\nconst dropdownStates = ['more', 'versions']\ntype DropdownState = (typeof dropdownStates)[number]\n\ntype DropdownMouseEvent = MouseEvent<HTMLSpanElement>\nconst getDropdownElements = (e: DropdownMouseEvent): [HTMLElement, string] => {\n const target = e.target as HTMLElement\n const dropdownId = target.closest('.dropdown')?.id || ''\n return [target, dropdownId]\n}\n\nexport interface EntityPathProps {\n projectName: string\n hideProjectName: boolean\n segments: PathSegment[]\n isLoading: boolean\n entityType: string\n versions: PathSegment[]\n scope: string\n}\n\nexport const EntityPath: FC<EntityPathProps> = ({\n projectName,\n hideProjectName,\n segments,\n versions = [],\n isLoading,\n entityType,\n scope,\n}) => {\n const containerRef = useRef<HTMLDivElement>(null)\n const [dropdownOpen, setDropdownOpen] = useState<null | DropdownState>(null)\n // defaults to whole path\n const [maxSegments, setMaxSegments] = useState<null | number>(null)\n const [calcMaxWidth, setCalcMaxWidth] = useState(false)\n const finalSegmentRef = useRef<HTMLSpanElement>(null)\n\n useLayoutEffect(() => {\n setMaxSegments(null)\n setCalcMaxWidth(true)\n }, [segments])\n\n useLayoutEffect(() => {\n if (!containerRef.current) {\n setCalcMaxWidth(false)\n return\n }\n // find max width the path can be\n const container = containerRef.current\n const pathWidth = container.clientWidth\n const maxWidth = getPathMaxWidth(container)\n\n if (!maxWidth) return\n\n // we need to reduce the number of segments shown\n // but maybe even then it is still longer than the max width\n // so we need to reduce the number of segments until the total width is less than the max width\n const children = container.children\n let totalWidth = pathWidth\n // number of segments to keep\n const fullCount = container.childElementCount\n let segmentsCount = fullCount\n // while loop that removes segments until the total width is less than the max width\n while (totalWidth > maxWidth && segmentsCount > 0) {\n // remove 2 segments at a time (because of slashes)\n segmentsCount -= 2\n totalWidth = totalUpSegmentsWidth(children, segmentsCount, fullCount)\n }\n\n // count number of \"full\" segments left\n // if something goes wrong, removing 1 (2) is probably enough\n let newMaxSegments =\n Array.from(children)\n .slice(0, segmentsCount)\n .filter(\n (segment) => segment.nodeType === Node.ELEMENT_NODE && segment.className.includes('full'),\n )?.length || 2\n\n // cap at 1\n newMaxSegments = Math.max(newMaxSegments, 1)\n\n setMaxSegments(newMaxSegments)\n setCalcMaxWidth(false)\n }, [containerRef.current, calcMaxWidth])\n\n // Ensure that, even if the collapsed segments still aren't\n // enough to fit the path within the available space,\n // we fit everything in by truncating the last segment's label.\n // This segment is typically the product + version name,\n // which is typically also shown in much larger font below,\n // so there's no reason to always show it in full.\n useLayoutEffect(() => {\n if (!containerRef.current || !finalSegmentRef.current || !maxSegments) return\n const container = containerRef.current\n\n // The amount of truncation is exactly the difference between the container's width\n // and the maximum available width.\n const maxWidth = getPathMaxWidth(container) ?? Infinity\n const diff = container.clientWidth - maxWidth\n if (diff <= 0) return\n\n // Reduce the segment's width by the difference\n const newWidth = `${finalSegmentRef.current.clientWidth - diff}px`\n finalSegmentRef.current.style.width = newWidth\n }, [maxSegments])\n\n // Check if there are fewer than or equal to maxSegments segments\n const segmentsToShow =\n maxSegments && segments.length > maxSegments ? segments.slice(-maxSegments) : segments\n const hiddenSegments =\n maxSegments && segments.length > maxSegments ? segments.slice(0, -maxSegments) : []\n\n // if there is no project name, add to hidden segments\n if (hideProjectName)\n hiddenSegments.unshift({ type: 'project', label: projectName, id: projectName })\n\n // if the entityType is a version, separate the version\n let versionSegment\n let finalSegmentsToShow = segmentsToShow\n\n if (entityType === 'version' && segments.length > 0) {\n versionSegment = segments[segments.length - 1]\n finalSegmentsToShow = segmentsToShow.slice(0, -1)\n }\n\n const handleMouseEnter = (e: DropdownMouseEvent) => {\n const [, id] = getDropdownElements(e)\n if (id && !dropdownOpen) setDropdownOpen(id)\n }\n const handleMouseLeave = () => setDropdownOpen(null)\n\n const handleDropdownClick = (e: DropdownMouseEvent) => {\n const [target, id] = getDropdownElements(e)\n\n if (!dropdownStates.includes(id)) return\n const isListItem = !!target.closest('li')\n\n if (isListItem) setDropdownOpen(null)\n else if (dropdownOpen !== id) setDropdownOpen(id)\n }\n\n const segmentProps = { scope, projectName }\n\n return (\n <Styled.Path className={clsx({ loading: isLoading })} id=\"entity-path\" ref={containerRef}>\n {!hideProjectName && <Styled.Segment>{projectName}</Styled.Segment>}\n\n {!!hiddenSegments.length && (\n <>\n {!hideProjectName && <Slash />}\n <Styled.Segment\n className=\"dropdown more\"\n id=\"more\"\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n onClick={handleDropdownClick}\n >\n ...\n {dropdownOpen === 'more' && (\n <Styled.MoreModal>\n <Styled.MoreList>\n {hiddenSegments.map((segment) => (\n <SegmentProvider {...segmentProps} segment={segment} key={segment.id}>\n <Styled.MoreItem>{segment.label}</Styled.MoreItem>\n </SegmentProvider>\n ))}\n </Styled.MoreList>\n </Styled.MoreModal>\n )}\n </Styled.Segment>\n </>\n )}\n\n {finalSegmentsToShow.map((segment) => (\n <Fragment key={segment.id}>\n <Slash />\n\n <SegmentProvider {...segmentProps} segment={segment} className=\"full\">\n <Styled.Segment>\n <span className=\"label\">{segment.label}</span>\n </Styled.Segment>\n </SegmentProvider>\n </Fragment>\n ))}\n\n {versionSegment && (\n <>\n <Slash />\n <Styled.SegmentWrapper\n className=\"full dropdown\"\n id=\"versions\"\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n onClick={handleDropdownClick}\n >\n <SegmentProvider\n {...segmentProps}\n segment={versionSegment}\n isOpen={dropdownOpen === 'versions'}\n >\n <Styled.Segment>\n <Styled.FinalSegmentLabel ref={finalSegmentRef} className=\"label\">\n {versionSegment.label}\n </Styled.FinalSegmentLabel>\n <Icon icon=\"expand_more\" />\n </Styled.Segment>\n </SegmentProvider>\n {dropdownOpen === 'versions' && (\n <Styled.MoreModal>\n <Styled.MoreList>\n {versions.map((version) => (\n <SegmentProvider {...segmentProps} segment={version} key={version.id}>\n <Styled.MoreItem>{version.label}</Styled.MoreItem>\n </SegmentProvider>\n ))}\n </Styled.MoreList>\n </Styled.MoreModal>\n )}\n </Styled.SegmentWrapper>\n </>\n )}\n </Styled.Path>\n )\n}\n\nconst getPathMaxWidth = (pathEl: HTMLDivElement) => {\n const toolbar = pathEl.parentElement\n if (!toolbar) return\n // get width of toolbar without padding\n const toolbarStyle = getComputedStyle(toolbar)\n const paddingLeft = parseInt(toolbarStyle.paddingLeft) || 0\n const paddingRight = parseInt(toolbarStyle.paddingRight) || 0\n const gap = parseInt(toolbarStyle.gap) || 0\n const toolbarWidth = toolbar.clientWidth - paddingLeft - paddingRight\n\n // get child elements that are not path\n const children = Array.from(toolbar.children).filter((child) => child.id !== 'entity-path')\n // find total width of children including the gap between them\n const childrenWidth = Array.from(children).reduce(\n (acc, child) => acc + (child as HTMLElement).clientWidth,\n 0,\n )\n\n return toolbarWidth - childrenWidth - gap * (children.length - 1)\n}\n\nconst totalUpSegmentsWidth = (children: HTMLCollection, count: number, full: number) => {\n const skip = full - count\n let total = 0\n for (let i = 0; i < full - skip; i++) {\n const index = i > 1 ? i + skip : i\n const width = (children[index] as Element)?.clientWidth\n if (isNaN(width)) continue\n total += width\n }\n const gap = 4\n const moreWidth = 40\n return total + (gap * count - 1) + moreWidth\n}\n"],"names":["jsx","jsxs","Styled.Path","Styled.Segment","Fragment","Styled.MoreModal","Styled.MoreList","Styled.MoreItem","Styled.SegmentWrapper","Styled.FinalSegmentLabel"],"mappings":"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"}
@@ -24,7 +24,9 @@ const Segment = styled.span`
24
24
  position: relative;
25
25
  padding: 0px 2px;
26
26
  border-radius: var(--border-radius-m);
27
- transition: color 0.2s, background-color 0.2s;
27
+ transition:
28
+ color 0.2s,
29
+ background-color 0.2s;
28
30
  min-width: max-content;
29
31
 
30
32
  display: flex;
@@ -41,6 +43,12 @@ const Segment = styled.span`
41
43
  }
42
44
  }
43
45
  `;
46
+ const FinalSegmentLabel = styled.span`
47
+ text-overflow: ellipsis;
48
+ overflow: hidden;
49
+ display: inline-block;
50
+ white-space: nowrap;
51
+ `;
44
52
  const NotClickableHover = styled.css`
45
53
  background-color: var(--md-sys-color-surface-container);
46
54
  &,
@@ -106,6 +114,7 @@ const MoreItem = styled.li`
106
114
  width: 100%;
107
115
  `;
108
116
  exports.ActiveSegment = ActiveSegment;
117
+ exports.FinalSegmentLabel = FinalSegmentLabel;
109
118
  exports.MoreItem = MoreItem;
110
119
  exports.MoreList = MoreList;
111
120
  exports.MoreModal = MoreModal;
@@ -1 +1 @@
1
- {"version":3,"file":"EntityPath.styled.cjs.js","sources":["../../../../../src/components/EntityPath/EntityPath.styled.ts"],"sourcesContent":["import styled, { css } from 'styled-components'\n\nexport const Path = styled.div`\n position: relative;\n border-radius: var(--border-radius-m);\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--base-gap-small);\n user-select: none;\n height: 100%;\n &,\n .icon {\n color: var(--md-sys-color-outline);\n }\n\n flex: 1;\n`\n\nexport const SegmentWrapper = styled.div`\n position: relative;\n`\n\nexport const Segment = styled.span`\n position: relative;\n padding: 0px 2px;\n border-radius: var(--border-radius-m);\n transition: color 0.2s, background-color 0.2s;\n min-width: max-content;\n\n display: flex;\n align-items: center;\n\n /* ... styles */\n &.more {\n cursor: pointer;\n\n padding: 0px 6px;\n &:hover {\n background-color: var(--md-sys-color-surface-container);\n color: var(--md-sys-color-on-surface);\n }\n }\n`\n\nconst NotClickableHover = css`\n background-color: var(--md-sys-color-surface-container);\n &,\n .icon {\n color: var(--md-sys-color-on-surface);\n }\n`\n\nexport const ActiveSegment = styled.div`\n & > span,\n & > li {\n cursor: pointer;\n &:hover {\n ${NotClickableHover}\n }\n }\n\n &.open {\n & > span {\n ${NotClickableHover}\n }\n }\n\n &.link {\n & > span,\n & > li {\n &:hover {\n background-color: var(--md-sys-color-surface-container-highest-hover);\n }\n }\n }\n`\n\nexport const MoreModal = styled.div`\n position: absolute;\n top: 100%;\n left: 0px;\n width: 100%;\n min-width: fit-content;\n\n z-index: 200;\n padding-top: 4px;\n`\n\nexport const MoreList = styled.ul`\n display: flex;\n flex-direction: column;\n gap: var(--base-gap-small);\n\n background-color: var(--md-sys-color-surface-container-high);\n border-radius: var(--border-radius-m);\n box-shadow: var(--md-sys-shadow-elevation-4);\n padding: var(--padding-s);\n\n margin: 0;\n list-style: none;\n\n max-height: 500px;\n overflow: auto;\n`\n\nexport const MoreItem = styled.li`\n padding: var(--base-gap-small);\n border-radius: var(--border-radius-m);\n color: var(--md-sys-color-on-surface);\n min-width: max-content;\n width: 100%;\n`\n"],"names":["css"],"mappings":";;;AAEO,MAAM,OAAO,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBpB,MAAM,iBAAiB,OAAO;AAAA;AAAA;AAI9B,MAAM,UAAU,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsB9B,MAAM,oBAAoBA,OAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQnB,MAAM,gBAAgB,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,QAK5B,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAMjB,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAclB,MAAM,YAAY,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWzB,MAAM,WAAW,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBxB,MAAM,WAAW,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;;;"}
1
+ {"version":3,"file":"EntityPath.styled.cjs.js","sources":["../../../../../src/components/EntityPath/EntityPath.styled.ts"],"sourcesContent":["import styled, { css } from 'styled-components'\n\nexport const Path = styled.div`\n position: relative;\n border-radius: var(--border-radius-m);\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--base-gap-small);\n user-select: none;\n height: 100%;\n &,\n .icon {\n color: var(--md-sys-color-outline);\n }\n\n flex: 1;\n`\n\nexport const SegmentWrapper = styled.div`\n position: relative;\n`\n\nexport const Segment = styled.span`\n position: relative;\n padding: 0px 2px;\n border-radius: var(--border-radius-m);\n transition:\n color 0.2s,\n background-color 0.2s;\n min-width: max-content;\n\n display: flex;\n align-items: center;\n\n /* ... styles */\n &.more {\n cursor: pointer;\n\n padding: 0px 6px;\n &:hover {\n background-color: var(--md-sys-color-surface-container);\n color: var(--md-sys-color-on-surface);\n }\n }\n`\n\nexport const FinalSegmentLabel = styled.span`\n text-overflow: ellipsis;\n overflow: hidden;\n display: inline-block;\n white-space: nowrap;\n`\n\nconst NotClickableHover = css`\n background-color: var(--md-sys-color-surface-container);\n &,\n .icon {\n color: var(--md-sys-color-on-surface);\n }\n`\n\nexport const ActiveSegment = styled.div`\n & > span,\n & > li {\n cursor: pointer;\n &:hover {\n ${NotClickableHover}\n }\n }\n\n &.open {\n & > span {\n ${NotClickableHover}\n }\n }\n\n &.link {\n & > span,\n & > li {\n &:hover {\n background-color: var(--md-sys-color-surface-container-highest-hover);\n }\n }\n }\n`\n\nexport const MoreModal = styled.div`\n position: absolute;\n top: 100%;\n left: 0px;\n width: 100%;\n min-width: fit-content;\n\n z-index: 200;\n padding-top: 4px;\n`\n\nexport const MoreList = styled.ul`\n display: flex;\n flex-direction: column;\n gap: var(--base-gap-small);\n\n background-color: var(--md-sys-color-surface-container-high);\n border-radius: var(--border-radius-m);\n box-shadow: var(--md-sys-shadow-elevation-4);\n padding: var(--padding-s);\n\n margin: 0;\n list-style: none;\n\n max-height: 500px;\n overflow: auto;\n`\n\nexport const MoreItem = styled.li`\n padding: var(--base-gap-small);\n border-radius: var(--border-radius-m);\n color: var(--md-sys-color-on-surface);\n min-width: max-content;\n width: 100%;\n`\n"],"names":["css"],"mappings":";;;AAEO,MAAM,OAAO,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBpB,MAAM,iBAAiB,OAAO;AAAA;AAAA;AAI9B,MAAM,UAAU,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBvB,MAAM,oBAAoB,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAOxC,MAAM,oBAAoBA,OAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQnB,MAAM,gBAAgB,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,QAK5B,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAMjB,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAclB,MAAM,YAAY,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWzB,MAAM,WAAW,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBxB,MAAM,WAAW,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;;;;"}
@@ -22,7 +22,9 @@ const Segment = styled.span`
22
22
  position: relative;
23
23
  padding: 0px 2px;
24
24
  border-radius: var(--border-radius-m);
25
- transition: color 0.2s, background-color 0.2s;
25
+ transition:
26
+ color 0.2s,
27
+ background-color 0.2s;
26
28
  min-width: max-content;
27
29
 
28
30
  display: flex;
@@ -39,6 +41,12 @@ const Segment = styled.span`
39
41
  }
40
42
  }
41
43
  `;
44
+ const FinalSegmentLabel = styled.span`
45
+ text-overflow: ellipsis;
46
+ overflow: hidden;
47
+ display: inline-block;
48
+ white-space: nowrap;
49
+ `;
42
50
  const NotClickableHover = css`
43
51
  background-color: var(--md-sys-color-surface-container);
44
52
  &,
@@ -105,6 +113,7 @@ const MoreItem = styled.li`
105
113
  `;
106
114
  export {
107
115
  ActiveSegment,
116
+ FinalSegmentLabel,
108
117
  MoreItem,
109
118
  MoreList,
110
119
  MoreModal,
@@ -1 +1 @@
1
- {"version":3,"file":"EntityPath.styled.es.js","sources":["../../../../../src/components/EntityPath/EntityPath.styled.ts"],"sourcesContent":["import styled, { css } from 'styled-components'\n\nexport const Path = styled.div`\n position: relative;\n border-radius: var(--border-radius-m);\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--base-gap-small);\n user-select: none;\n height: 100%;\n &,\n .icon {\n color: var(--md-sys-color-outline);\n }\n\n flex: 1;\n`\n\nexport const SegmentWrapper = styled.div`\n position: relative;\n`\n\nexport const Segment = styled.span`\n position: relative;\n padding: 0px 2px;\n border-radius: var(--border-radius-m);\n transition: color 0.2s, background-color 0.2s;\n min-width: max-content;\n\n display: flex;\n align-items: center;\n\n /* ... styles */\n &.more {\n cursor: pointer;\n\n padding: 0px 6px;\n &:hover {\n background-color: var(--md-sys-color-surface-container);\n color: var(--md-sys-color-on-surface);\n }\n }\n`\n\nconst NotClickableHover = css`\n background-color: var(--md-sys-color-surface-container);\n &,\n .icon {\n color: var(--md-sys-color-on-surface);\n }\n`\n\nexport const ActiveSegment = styled.div`\n & > span,\n & > li {\n cursor: pointer;\n &:hover {\n ${NotClickableHover}\n }\n }\n\n &.open {\n & > span {\n ${NotClickableHover}\n }\n }\n\n &.link {\n & > span,\n & > li {\n &:hover {\n background-color: var(--md-sys-color-surface-container-highest-hover);\n }\n }\n }\n`\n\nexport const MoreModal = styled.div`\n position: absolute;\n top: 100%;\n left: 0px;\n width: 100%;\n min-width: fit-content;\n\n z-index: 200;\n padding-top: 4px;\n`\n\nexport const MoreList = styled.ul`\n display: flex;\n flex-direction: column;\n gap: var(--base-gap-small);\n\n background-color: var(--md-sys-color-surface-container-high);\n border-radius: var(--border-radius-m);\n box-shadow: var(--md-sys-shadow-elevation-4);\n padding: var(--padding-s);\n\n margin: 0;\n list-style: none;\n\n max-height: 500px;\n overflow: auto;\n`\n\nexport const MoreItem = styled.li`\n padding: var(--base-gap-small);\n border-radius: var(--border-radius-m);\n color: var(--md-sys-color-on-surface);\n min-width: max-content;\n width: 100%;\n`\n"],"names":[],"mappings":";AAEO,MAAM,OAAO,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBpB,MAAM,iBAAiB,OAAO;AAAA;AAAA;AAI9B,MAAM,UAAU,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsB9B,MAAM,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQnB,MAAM,gBAAgB,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,QAK5B,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAMjB,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAclB,MAAM,YAAY,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWzB,MAAM,WAAW,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBxB,MAAM,WAAW,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;"}
1
+ {"version":3,"file":"EntityPath.styled.es.js","sources":["../../../../../src/components/EntityPath/EntityPath.styled.ts"],"sourcesContent":["import styled, { css } from 'styled-components'\n\nexport const Path = styled.div`\n position: relative;\n border-radius: var(--border-radius-m);\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--base-gap-small);\n user-select: none;\n height: 100%;\n &,\n .icon {\n color: var(--md-sys-color-outline);\n }\n\n flex: 1;\n`\n\nexport const SegmentWrapper = styled.div`\n position: relative;\n`\n\nexport const Segment = styled.span`\n position: relative;\n padding: 0px 2px;\n border-radius: var(--border-radius-m);\n transition:\n color 0.2s,\n background-color 0.2s;\n min-width: max-content;\n\n display: flex;\n align-items: center;\n\n /* ... styles */\n &.more {\n cursor: pointer;\n\n padding: 0px 6px;\n &:hover {\n background-color: var(--md-sys-color-surface-container);\n color: var(--md-sys-color-on-surface);\n }\n }\n`\n\nexport const FinalSegmentLabel = styled.span`\n text-overflow: ellipsis;\n overflow: hidden;\n display: inline-block;\n white-space: nowrap;\n`\n\nconst NotClickableHover = css`\n background-color: var(--md-sys-color-surface-container);\n &,\n .icon {\n color: var(--md-sys-color-on-surface);\n }\n`\n\nexport const ActiveSegment = styled.div`\n & > span,\n & > li {\n cursor: pointer;\n &:hover {\n ${NotClickableHover}\n }\n }\n\n &.open {\n & > span {\n ${NotClickableHover}\n }\n }\n\n &.link {\n & > span,\n & > li {\n &:hover {\n background-color: var(--md-sys-color-surface-container-highest-hover);\n }\n }\n }\n`\n\nexport const MoreModal = styled.div`\n position: absolute;\n top: 100%;\n left: 0px;\n width: 100%;\n min-width: fit-content;\n\n z-index: 200;\n padding-top: 4px;\n`\n\nexport const MoreList = styled.ul`\n display: flex;\n flex-direction: column;\n gap: var(--base-gap-small);\n\n background-color: var(--md-sys-color-surface-container-high);\n border-radius: var(--border-radius-m);\n box-shadow: var(--md-sys-shadow-elevation-4);\n padding: var(--padding-s);\n\n margin: 0;\n list-style: none;\n\n max-height: 500px;\n overflow: auto;\n`\n\nexport const MoreItem = styled.li`\n padding: var(--base-gap-small);\n border-radius: var(--border-radius-m);\n color: var(--md-sys-color-on-surface);\n min-width: max-content;\n width: 100%;\n`\n"],"names":[],"mappings":";AAEO,MAAM,OAAO,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBpB,MAAM,iBAAiB,OAAO;AAAA;AAAA;AAI9B,MAAM,UAAU,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBvB,MAAM,oBAAoB,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAOxC,MAAM,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQnB,MAAM,gBAAgB,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,QAK5B,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAMjB,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAclB,MAAM,YAAY,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWzB,MAAM,WAAW,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBxB,MAAM,WAAW,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;"}
@@ -83,7 +83,8 @@ const placeholder = {
83
83
  identifier: "placeholder",
84
84
  label: "Featured action slot",
85
85
  isPlaceholder: true,
86
- icon: { type: "material-symbols", name: "sync" }
86
+ icon: { type: "material-symbols", name: "sync" },
87
+ groupLabel: ""
87
88
  };
88
89
  const Actions = ({
89
90
  entities,
@@ -97,9 +98,12 @@ const Actions = ({
97
98
  const context = React.useMemo(() => {
98
99
  if (!entities.length) return null;
99
100
  if (!entities[0].projectName) return null;
100
- const entitySubtypesLoaded = entities.map((entity) => entity.entitySubType).filter((value, index, self) => self.indexOf(value) === index && value);
101
- const entitySubTypesToUse = entitySubTypes || entitySubtypesLoaded || [];
102
- if (!(entitySubTypesToUse == null ? void 0 : entitySubTypesToUse.length) && entityType !== "version") return null;
101
+ const entitySubtypesLoaded = entities.filter((entity) => entity.entitySubType).map((entity) => entity.entitySubType).filter((value, index, self) => self.indexOf(value) === index && value);
102
+ const entitySubTypesToUse = (entitySubTypes == null ? void 0 : entitySubTypes.length) ? entitySubTypes : entitySubtypesLoaded;
103
+ if (!(entitySubTypesToUse == null ? void 0 : entitySubTypesToUse.length) && entityType !== "version" && entityType !== "representation") {
104
+ console.warn("No entity subtypes found");
105
+ return null;
106
+ }
103
107
  return {
104
108
  projectName: entities[0].projectName,
105
109
  entityType,
@@ -148,7 +152,7 @@ const Actions = ({
148
152
  });
149
153
  const groupOptions = groupedActions[category].map((action) => ({
150
154
  value: action.identifier,
151
- label: action.label,
155
+ label: action.groupLabel ? action.groupLabel + " " + action.label : action.label,
152
156
  icon: action.icon,
153
157
  hasConfig: !!action.configFields
154
158
  }));
@@ -266,7 +270,7 @@ const Actions = ({
266
270
  // @ts-expect-error
267
271
  isPlaceholder: action.isPlaceholder
268
272
  }),
269
- "data-tooltip": action.label,
273
+ "data-tooltip": action.groupLabel ? action.groupLabel + " " + action.label : action.label,
270
274
  disabled: action.isPlaceholder,
271
275
  onClick: (e) => handleExecuteAction(action.identifier, e),
272
276
  children: /* @__PURE__ */ jsxRuntime.jsxRuntimeExports.jsx(ActionIcon, { icon: action.icon, isExecuting: executingAction === action.identifier })
@@ -1 +1 @@
1
- {"version":3,"file":"Actions.cjs.js","sources":["../../../../../src/containers/Actions/Actions.tsx"],"sourcesContent":["import * as Styled from './Actions.styled'\nimport { MouseEvent, useState } from 'react'\nimport clsx from 'clsx'\nimport { toast } from 'react-toastify'\nimport { useMemo, useEffect } from 'react'\nimport { ActionContext, useExecuteActionMutation, useGetActionsFromContextQuery } from '@shared/api'\nimport { ActionsDropdown } from './ActionsDropdown'\nimport ActionIcon from './ActionIcon'\nimport { useActionTriggers } from '@shared/hooks'\nimport { ActionConfigDialog } from './ActionConfigDialog'\nimport { InteractiveActionDialog, InteractiveForm } from './InteractiveActionDialog'\n\nconst placeholder = {\n identifier: 'placeholder',\n label: 'Featured action slot',\n isPlaceholder: true,\n icon: { type: 'material-symbols', name: 'sync' },\n}\n\ntype ActionsProps = {\n entities: any[]\n entityType: ActionContext['entityType']\n entitySubTypes?: string[]\n isLoadingEntity: boolean\n}\n\nexport const Actions = ({\n entities,\n entityType,\n entitySubTypes,\n isLoadingEntity,\n}: ActionsProps) => {\n // special triggers the actions can make to perform stuff on the client\n const { handleActionPayload } = useActionTriggers()\n const [actionBeingConfigured, setActionBeingConfigured] = useState<any>(null)\n const [interactiveForm, setInteractiveForm] = useState<any>(null)\n\n const context: ActionContext | null = useMemo(() => {\n if (!entities.length) return null\n if (!entities[0].projectName) return null\n\n // get a list of unique entity subtypes from loaded data\n const entitySubtypesLoaded = entities\n .map((entity) => entity.entitySubType)\n .filter((value, index, self) => self.indexOf(value) === index && value)\n\n // try and use the passed in entitySubTypes, if not use the loaded ones\n const entitySubTypesToUse = entitySubTypes || entitySubtypesLoaded || []\n\n // all types except version should have subtypes\n if (!entitySubTypesToUse?.length && entityType !== 'version') return null\n\n return {\n projectName: entities[0].projectName,\n entityType: entityType,\n entityIds: entities.map((entity) => entity.id),\n entitySubtypes: entitySubTypesToUse,\n }\n }, [entities, entityType])\n\n useEffect(() => {\n setInteractiveForm(null)\n }, [context])\n\n const { data, isFetching: isFetchingActions } = useGetActionsFromContextQuery(\n { mode: 'simple', actionContext: context as ActionContext },\n { skip: !context },\n )\n const actions = data?.actions || []\n\n const categoryOrder = ['application', 'admin', 'workflow']\n // group actions by category\n // sort by hardcoded category, this will changing the future\n const groupedActions = useMemo(() => {\n // Step 1: Group actions by category\n const grouped = actions.reduce((acc: { [key: string]: any[] }, action) => {\n const category = action.category || 'uncategorized'\n if (!acc[category]) {\n acc[category] = []\n }\n acc[category].push(action)\n return acc\n }, {})\n\n // Step 5: Return the ordered groups\n return grouped\n }, [actions])\n\n // get categories that don't have a specific order (not in categoryOrder)\n // then sort them alphabetically\n const unorderedCategories = useMemo(\n () => [\n ...new Set(\n Object.keys(groupedActions)\n .filter((category) => !categoryOrder.includes(category))\n .sort((a, b) => a.localeCompare(b)),\n ),\n ],\n [groupedActions],\n )\n\n const categories = [...categoryOrder, ...unorderedCategories]\n\n // create the options for the dropdown, each category is separated by a divider and a title\n // for the divider we will use a custom dropdown item template\n const dropdownOptions = useMemo(() => {\n const options = []\n\n categories.forEach((category) => {\n if (!groupedActions[category] || !groupedActions[category].length) return\n\n options.push({\n label: category,\n header: true,\n value: category,\n disabled: true,\n })\n\n const groupOptions = groupedActions[category].map((action) => ({\n value: action.identifier,\n label: action.label,\n icon: action.icon,\n hasConfig: !!action.configFields,\n }))\n\n options.push(...groupOptions)\n })\n\n // if no actions, add placeholder\n if (!options.length) {\n options.push({\n label: 'No actions available',\n value: 'no-actions',\n disabled: true,\n header: true,\n })\n }\n\n return options\n }, [groupedActions, unorderedCategories, categoryOrder])\n\n const featuredNumber = 2\n\n const featuredActions = useMemo(() => {\n // Filter and sort to get initial featured actions\n let tempFeaturedActions = actions\n .filter((action) => action.featured)\n .sort((a, b) => (a.order || 0) - (b.order || 0))\n .slice(0, featuredNumber)\n\n // Check if we need to add more actions to reach featuredNumber\n if (tempFeaturedActions.length < featuredNumber) {\n categories.forEach((category) => {\n if (tempFeaturedActions.length >= featuredNumber) return\n const actions = groupedActions[category]\n if (!actions || !actions.length) return\n\n for (let i = tempFeaturedActions.length; i < featuredNumber; i++) {\n const action = actions[i]\n if (!action) break\n if (!action.icon) continue\n tempFeaturedActions.push(action)\n }\n })\n }\n\n return tempFeaturedActions\n }, [actions, groupedActions, placeholder])\n\n const [executeAction, { isLoading: isLoadingExecution, originalArgs }] =\n useExecuteActionMutation()\n const executingAction = isLoadingExecution && originalArgs?.identifier\n\n const handleExecuteAction = async (\n identifier: string,\n e?: MouseEvent<HTMLElement> | null,\n formData?: InteractiveForm,\n ) => {\n e?.preventDefault()\n const action = actions.find((option) => option.identifier === identifier)\n\n if (!action) {\n toast.error('Action not found')\n console.warn('Action not found', identifier)\n return\n }\n\n const params = {\n addonName: action.addonName as string,\n addonVersion: action.addonVersion as string,\n variant: action.variant,\n identifier: action.identifier,\n }\n\n const actionContext = { ...context }\n if (formData) {\n actionContext.formData = formData\n }\n\n let response = null\n\n try {\n response = await executeAction({ actionContext, ...params }).unwrap()\n } catch (error: any) {\n console.error('Error executing action', error)\n toast.error(error?.data?.detail || 'Error executing action')\n return\n }\n\n try {\n // Toast the message if it is available\n if (response?.message) {\n if (response?.success) {\n toast.success(response.message, { autoClose: 2000 })\n } else {\n toast.error(response.message, { autoClose: 2000 })\n }\n }\n\n // Even if response?.success is false, we still want to handle the payload\n // as it may contain useful information - complex error messages in form,\n // redirect to another page etc. If the action just needs to abort,\n // it raises exception instead of returning a response with success: false\n\n // Use the new hook to handle payload\n if (response?.payload) {\n if (response.type === 'form') {\n // action requests additional information from the user.\n // we show a dialog with the form and when the user submits it we call the action again\n\n // It probably does not make sense to move to the useActionTriggers hook\n // as it need contexts and the dialog\n const intf = {\n identifier,\n // @ts-expect-error\n title: response.payload['title'],\n // @ts-expect-error\n fields: response.payload['fields'],\n // @ts-expect-error\n submitLabel: response.payload['submit_label'],\n // @ts-expect-error\n cancelLabel: response.payload['cancel_label'],\n // @ts-expect-error\n submitIcon: response.payload['submit_icon'],\n // @ts-expect-error\n cancelIcon: response.payload['cancel_icon'],\n }\n setInteractiveForm(intf)\n } else {\n handleActionPayload(response.type as string, response.payload)\n }\n }\n } catch (error) {\n // got response, but failed to process it\n console.warn('Error during action response processing', error)\n toast.error('Error occured during action processing')\n }\n }\n\n const handleConfigureAction = (identifier: string) => {\n const action = actions.find((data) => data.identifier === identifier)\n if (!action) return\n setActionBeingConfigured(action)\n }\n\n const handleSubmitInteractiveForm = async (identifier: string, formData: InteractiveForm) => {\n handleExecuteAction(identifier, null, formData)\n }\n\n const loadingActions = [placeholder, placeholder, placeholder]\n\n const isLoading = isFetchingActions || isLoadingEntity\n const featuredActionsToDisplay = isLoading ? loadingActions : featuredActions\n\n return (\n <Styled.Actions className=\"actions\">\n {featuredActionsToDisplay.map((action, i) => (\n <Styled.FeaturedAction\n key={action.identifier + '-' + i}\n className={clsx('action', {\n loading: isLoading,\n // @ts-expect-error\n isPlaceholder: action.isPlaceholder,\n })}\n data-tooltip={action.label}\n // @ts-expect-error\n disabled={action.isPlaceholder}\n onClick={(e) => handleExecuteAction(action.identifier, e)}\n >\n {/* @ts-ignore */}\n <ActionIcon icon={action.icon} isExecuting={executingAction === action.identifier} />\n </Styled.FeaturedAction>\n ))}\n <ActionsDropdown\n options={dropdownOptions}\n isLoading={isLoading}\n onAction={handleExecuteAction}\n onConfig={handleConfigureAction}\n />\n <ActionConfigDialog\n action={actionBeingConfigured}\n // @ts-expect-error\n context={context}\n onClose={() => setActionBeingConfigured(null)}\n />\n <InteractiveActionDialog\n interactiveForm={interactiveForm}\n onClose={() => setInteractiveForm(null)}\n // @ts-expect-error\n onSubmit={handleSubmitInteractiveForm}\n />\n </Styled.Actions>\n )\n}\n"],"names":["useActionTriggers","useState","useMemo","useEffect","useGetActionsFromContextQuery","actions","useExecuteActionMutation","toast","data","jsxs","Styled.Actions","jsx","Styled.FeaturedAction","ActionsDropdown","ActionConfigDialog","InteractiveActionDialog"],"mappings":"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"}
1
+ {"version":3,"file":"Actions.cjs.js","sources":["../../../../../src/containers/Actions/Actions.tsx"],"sourcesContent":["import * as Styled from './Actions.styled'\nimport { MouseEvent, useState } from 'react'\nimport clsx from 'clsx'\nimport { toast } from 'react-toastify'\nimport { useMemo, useEffect } from 'react'\nimport { ActionContext, useExecuteActionMutation, useGetActionsFromContextQuery } from '@shared/api'\nimport { ActionsDropdown } from './ActionsDropdown'\nimport ActionIcon from './ActionIcon'\nimport { useActionTriggers } from '@shared/hooks'\nimport { ActionConfigDialog } from './ActionConfigDialog'\nimport { InteractiveActionDialog, InteractiveForm } from './InteractiveActionDialog'\n\nconst placeholder = {\n identifier: 'placeholder',\n label: 'Featured action slot',\n isPlaceholder: true,\n icon: { type: 'material-symbols', name: 'sync' },\n groupLabel: '',\n}\n\ntype ActionsProps = {\n entities: { id: string; projectName: string; entitySubType?: string }[]\n entityType: ActionContext['entityType']\n entitySubTypes?: string[]\n isLoadingEntity: boolean\n}\n\nexport const Actions = ({\n entities,\n entityType,\n entitySubTypes,\n isLoadingEntity,\n}: ActionsProps) => {\n // special triggers the actions can make to perform stuff on the client\n const { handleActionPayload } = useActionTriggers()\n const [actionBeingConfigured, setActionBeingConfigured] = useState<any>(null)\n const [interactiveForm, setInteractiveForm] = useState<any>(null)\n\n const context: ActionContext | null = useMemo(() => {\n if (!entities.length) return null\n if (!entities[0].projectName) return null\n\n // get a list of unique entity subtypes from loaded data\n const entitySubtypesLoaded = entities\n .filter((entity) => entity.entitySubType)\n .map((entity) => entity.entitySubType as string)\n .filter((value, index, self) => self.indexOf(value) === index && value)\n\n // try and use the passed in entitySubTypes, if not use the loaded ones\n const entitySubTypesToUse = entitySubTypes?.length ? entitySubTypes : entitySubtypesLoaded\n\n // all types except version/representation should have subtypes\n if (\n !entitySubTypesToUse?.length &&\n entityType !== 'version' &&\n entityType !== 'representation'\n ) {\n console.warn('No entity subtypes found')\n return null\n }\n\n return {\n projectName: entities[0].projectName,\n entityType: entityType,\n entityIds: entities.map((entity) => entity.id),\n entitySubtypes: entitySubTypesToUse,\n }\n }, [entities, entityType])\n\n useEffect(() => {\n setInteractiveForm(null)\n }, [context])\n\n const { data, isFetching: isFetchingActions } = useGetActionsFromContextQuery(\n { mode: 'simple', actionContext: context as ActionContext },\n { skip: !context },\n )\n\n const actions = data?.actions || []\n\n const categoryOrder = ['application', 'admin', 'workflow']\n // group actions by category\n // sort by hardcoded category, this will changing the future\n const groupedActions = useMemo(() => {\n // Step 1: Group actions by category\n const grouped = actions.reduce((acc: { [key: string]: any[] }, action) => {\n const category = action.category || 'uncategorized'\n if (!acc[category]) {\n acc[category] = []\n }\n acc[category].push(action)\n return acc\n }, {})\n\n // Step 5: Return the ordered groups\n return grouped\n }, [actions])\n\n // get categories that don't have a specific order (not in categoryOrder)\n // then sort them alphabetically\n const unorderedCategories = useMemo(\n () => [\n ...new Set(\n Object.keys(groupedActions)\n .filter((category) => !categoryOrder.includes(category))\n .sort((a, b) => a.localeCompare(b)),\n ),\n ],\n [groupedActions],\n )\n\n const categories = [...categoryOrder, ...unorderedCategories]\n\n // create the options for the dropdown, each category is separated by a divider and a title\n // for the divider we will use a custom dropdown item template\n const dropdownOptions = useMemo(() => {\n const options = []\n\n categories.forEach((category) => {\n if (!groupedActions[category] || !groupedActions[category].length) return\n\n options.push({\n label: category,\n header: true,\n value: category,\n disabled: true,\n })\n\n const groupOptions = groupedActions[category].map((action) => ({\n value: action.identifier,\n label: action.groupLabel ? action.groupLabel + ' ' + action.label : action.label,\n icon: action.icon,\n hasConfig: !!action.configFields,\n }))\n\n options.push(...groupOptions)\n })\n\n // if no actions, add placeholder\n if (!options.length) {\n options.push({\n label: 'No actions available',\n value: 'no-actions',\n disabled: true,\n header: true,\n })\n }\n\n return options\n }, [groupedActions, unorderedCategories, categoryOrder])\n\n const featuredNumber = 2\n\n const featuredActions = useMemo(() => {\n // Filter and sort to get initial featured actions\n let tempFeaturedActions = actions\n .filter((action) => action.featured)\n .sort((a, b) => (a.order || 0) - (b.order || 0))\n .slice(0, featuredNumber)\n\n // Check if we need to add more actions to reach featuredNumber\n if (tempFeaturedActions.length < featuredNumber) {\n categories.forEach((category) => {\n if (tempFeaturedActions.length >= featuredNumber) return\n const actions = groupedActions[category]\n if (!actions || !actions.length) return\n\n for (let i = tempFeaturedActions.length; i < featuredNumber; i++) {\n const action = actions[i]\n if (!action) break\n if (!action.icon) continue\n tempFeaturedActions.push(action)\n }\n })\n }\n\n return tempFeaturedActions\n }, [actions, groupedActions, placeholder])\n\n const [executeAction, { isLoading: isLoadingExecution, originalArgs }] =\n useExecuteActionMutation()\n const executingAction = isLoadingExecution && originalArgs?.identifier\n\n const handleExecuteAction = async (\n identifier: string,\n e?: MouseEvent<HTMLElement> | null,\n formData?: InteractiveForm,\n ) => {\n e?.preventDefault()\n const action = actions.find((option) => option.identifier === identifier)\n\n if (!action) {\n toast.error('Action not found')\n console.warn('Action not found', identifier)\n return\n }\n\n const params = {\n addonName: action.addonName as string,\n addonVersion: action.addonVersion as string,\n variant: action.variant,\n identifier: action.identifier,\n }\n\n const actionContext = { ...context }\n if (formData) {\n actionContext.formData = formData\n }\n\n let response = null\n\n try {\n response = await executeAction({ actionContext, ...params }).unwrap()\n } catch (error: any) {\n console.error('Error executing action', error)\n toast.error(error?.data?.detail || 'Error executing action')\n return\n }\n\n try {\n // Toast the message if it is available\n if (response?.message) {\n if (response?.success) {\n toast.success(response.message, { autoClose: 2000 })\n } else {\n toast.error(response.message, { autoClose: 2000 })\n }\n }\n\n // Even if response?.success is false, we still want to handle the payload\n // as it may contain useful information - complex error messages in form,\n // redirect to another page etc. If the action just needs to abort,\n // it raises exception instead of returning a response with success: false\n\n // Use the new hook to handle payload\n if (response?.payload) {\n if (response.type === 'form') {\n // action requests additional information from the user.\n // we show a dialog with the form and when the user submits it we call the action again\n\n // It probably does not make sense to move to the useActionTriggers hook\n // as it need contexts and the dialog\n const intf = {\n identifier,\n // @ts-expect-error\n title: response.payload['title'],\n // @ts-expect-error\n fields: response.payload['fields'],\n // @ts-expect-error\n submitLabel: response.payload['submit_label'],\n // @ts-expect-error\n cancelLabel: response.payload['cancel_label'],\n // @ts-expect-error\n submitIcon: response.payload['submit_icon'],\n // @ts-expect-error\n cancelIcon: response.payload['cancel_icon'],\n }\n setInteractiveForm(intf)\n } else {\n handleActionPayload(response.type as string, response.payload)\n }\n }\n } catch (error) {\n // got response, but failed to process it\n console.warn('Error during action response processing', error)\n toast.error('Error occured during action processing')\n }\n }\n\n const handleConfigureAction = (identifier: string) => {\n const action = actions.find((data) => data.identifier === identifier)\n if (!action) return\n setActionBeingConfigured(action)\n }\n\n const handleSubmitInteractiveForm = async (identifier: string, formData: InteractiveForm) => {\n handleExecuteAction(identifier, null, formData)\n }\n\n const loadingActions = [placeholder, placeholder, placeholder]\n\n const isLoading = isFetchingActions || isLoadingEntity\n const featuredActionsToDisplay = isLoading ? loadingActions : featuredActions\n\n return (\n <Styled.Actions className=\"actions\">\n {featuredActionsToDisplay.map((action, i) => (\n <Styled.FeaturedAction\n key={action.identifier + '-' + i}\n className={clsx('action', {\n loading: isLoading,\n // @ts-expect-error\n isPlaceholder: action.isPlaceholder,\n })}\n data-tooltip={action.groupLabel ? action.groupLabel + ' ' + action.label : action.label}\n // @ts-expect-error\n disabled={action.isPlaceholder}\n onClick={(e) => handleExecuteAction(action.identifier, e)}\n >\n {/* @ts-ignore */}\n <ActionIcon icon={action.icon} isExecuting={executingAction === action.identifier} />\n </Styled.FeaturedAction>\n ))}\n <ActionsDropdown\n options={dropdownOptions}\n isLoading={isLoading}\n onAction={handleExecuteAction}\n onConfig={handleConfigureAction}\n />\n <ActionConfigDialog\n action={actionBeingConfigured}\n // @ts-expect-error\n context={context}\n onClose={() => setActionBeingConfigured(null)}\n />\n <InteractiveActionDialog\n interactiveForm={interactiveForm}\n onClose={() => setInteractiveForm(null)}\n // @ts-expect-error\n onSubmit={handleSubmitInteractiveForm}\n />\n </Styled.Actions>\n )\n}\n"],"names":["useActionTriggers","useState","useMemo","useEffect","useGetActionsFromContextQuery","actions","useExecuteActionMutation","toast","data","jsxs","Styled.Actions","jsx","Styled.FeaturedAction","ActionsDropdown","ActionConfigDialog","InteractiveActionDialog"],"mappings":"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"}
@@ -81,7 +81,8 @@ const placeholder = {
81
81
  identifier: "placeholder",
82
82
  label: "Featured action slot",
83
83
  isPlaceholder: true,
84
- icon: { type: "material-symbols", name: "sync" }
84
+ icon: { type: "material-symbols", name: "sync" },
85
+ groupLabel: ""
85
86
  };
86
87
  const Actions = ({
87
88
  entities,
@@ -95,9 +96,12 @@ const Actions = ({
95
96
  const context = useMemo(() => {
96
97
  if (!entities.length) return null;
97
98
  if (!entities[0].projectName) return null;
98
- const entitySubtypesLoaded = entities.map((entity) => entity.entitySubType).filter((value, index, self) => self.indexOf(value) === index && value);
99
- const entitySubTypesToUse = entitySubTypes || entitySubtypesLoaded || [];
100
- if (!(entitySubTypesToUse == null ? void 0 : entitySubTypesToUse.length) && entityType !== "version") return null;
99
+ const entitySubtypesLoaded = entities.filter((entity) => entity.entitySubType).map((entity) => entity.entitySubType).filter((value, index, self) => self.indexOf(value) === index && value);
100
+ const entitySubTypesToUse = (entitySubTypes == null ? void 0 : entitySubTypes.length) ? entitySubTypes : entitySubtypesLoaded;
101
+ if (!(entitySubTypesToUse == null ? void 0 : entitySubTypesToUse.length) && entityType !== "version" && entityType !== "representation") {
102
+ console.warn("No entity subtypes found");
103
+ return null;
104
+ }
101
105
  return {
102
106
  projectName: entities[0].projectName,
103
107
  entityType,
@@ -146,7 +150,7 @@ const Actions = ({
146
150
  });
147
151
  const groupOptions = groupedActions[category].map((action) => ({
148
152
  value: action.identifier,
149
- label: action.label,
153
+ label: action.groupLabel ? action.groupLabel + " " + action.label : action.label,
150
154
  icon: action.icon,
151
155
  hasConfig: !!action.configFields
152
156
  }));
@@ -264,7 +268,7 @@ const Actions = ({
264
268
  // @ts-expect-error
265
269
  isPlaceholder: action.isPlaceholder
266
270
  }),
267
- "data-tooltip": action.label,
271
+ "data-tooltip": action.groupLabel ? action.groupLabel + " " + action.label : action.label,
268
272
  disabled: action.isPlaceholder,
269
273
  onClick: (e) => handleExecuteAction(action.identifier, e),
270
274
  children: /* @__PURE__ */ jsxRuntimeExports.jsx(ActionIcon, { icon: action.icon, isExecuting: executingAction === action.identifier })
@@ -1 +1 @@
1
- {"version":3,"file":"Actions.es.js","sources":["../../../../../src/containers/Actions/Actions.tsx"],"sourcesContent":["import * as Styled from './Actions.styled'\nimport { MouseEvent, useState } from 'react'\nimport clsx from 'clsx'\nimport { toast } from 'react-toastify'\nimport { useMemo, useEffect } from 'react'\nimport { ActionContext, useExecuteActionMutation, useGetActionsFromContextQuery } from '@shared/api'\nimport { ActionsDropdown } from './ActionsDropdown'\nimport ActionIcon from './ActionIcon'\nimport { useActionTriggers } from '@shared/hooks'\nimport { ActionConfigDialog } from './ActionConfigDialog'\nimport { InteractiveActionDialog, InteractiveForm } from './InteractiveActionDialog'\n\nconst placeholder = {\n identifier: 'placeholder',\n label: 'Featured action slot',\n isPlaceholder: true,\n icon: { type: 'material-symbols', name: 'sync' },\n}\n\ntype ActionsProps = {\n entities: any[]\n entityType: ActionContext['entityType']\n entitySubTypes?: string[]\n isLoadingEntity: boolean\n}\n\nexport const Actions = ({\n entities,\n entityType,\n entitySubTypes,\n isLoadingEntity,\n}: ActionsProps) => {\n // special triggers the actions can make to perform stuff on the client\n const { handleActionPayload } = useActionTriggers()\n const [actionBeingConfigured, setActionBeingConfigured] = useState<any>(null)\n const [interactiveForm, setInteractiveForm] = useState<any>(null)\n\n const context: ActionContext | null = useMemo(() => {\n if (!entities.length) return null\n if (!entities[0].projectName) return null\n\n // get a list of unique entity subtypes from loaded data\n const entitySubtypesLoaded = entities\n .map((entity) => entity.entitySubType)\n .filter((value, index, self) => self.indexOf(value) === index && value)\n\n // try and use the passed in entitySubTypes, if not use the loaded ones\n const entitySubTypesToUse = entitySubTypes || entitySubtypesLoaded || []\n\n // all types except version should have subtypes\n if (!entitySubTypesToUse?.length && entityType !== 'version') return null\n\n return {\n projectName: entities[0].projectName,\n entityType: entityType,\n entityIds: entities.map((entity) => entity.id),\n entitySubtypes: entitySubTypesToUse,\n }\n }, [entities, entityType])\n\n useEffect(() => {\n setInteractiveForm(null)\n }, [context])\n\n const { data, isFetching: isFetchingActions } = useGetActionsFromContextQuery(\n { mode: 'simple', actionContext: context as ActionContext },\n { skip: !context },\n )\n const actions = data?.actions || []\n\n const categoryOrder = ['application', 'admin', 'workflow']\n // group actions by category\n // sort by hardcoded category, this will changing the future\n const groupedActions = useMemo(() => {\n // Step 1: Group actions by category\n const grouped = actions.reduce((acc: { [key: string]: any[] }, action) => {\n const category = action.category || 'uncategorized'\n if (!acc[category]) {\n acc[category] = []\n }\n acc[category].push(action)\n return acc\n }, {})\n\n // Step 5: Return the ordered groups\n return grouped\n }, [actions])\n\n // get categories that don't have a specific order (not in categoryOrder)\n // then sort them alphabetically\n const unorderedCategories = useMemo(\n () => [\n ...new Set(\n Object.keys(groupedActions)\n .filter((category) => !categoryOrder.includes(category))\n .sort((a, b) => a.localeCompare(b)),\n ),\n ],\n [groupedActions],\n )\n\n const categories = [...categoryOrder, ...unorderedCategories]\n\n // create the options for the dropdown, each category is separated by a divider and a title\n // for the divider we will use a custom dropdown item template\n const dropdownOptions = useMemo(() => {\n const options = []\n\n categories.forEach((category) => {\n if (!groupedActions[category] || !groupedActions[category].length) return\n\n options.push({\n label: category,\n header: true,\n value: category,\n disabled: true,\n })\n\n const groupOptions = groupedActions[category].map((action) => ({\n value: action.identifier,\n label: action.label,\n icon: action.icon,\n hasConfig: !!action.configFields,\n }))\n\n options.push(...groupOptions)\n })\n\n // if no actions, add placeholder\n if (!options.length) {\n options.push({\n label: 'No actions available',\n value: 'no-actions',\n disabled: true,\n header: true,\n })\n }\n\n return options\n }, [groupedActions, unorderedCategories, categoryOrder])\n\n const featuredNumber = 2\n\n const featuredActions = useMemo(() => {\n // Filter and sort to get initial featured actions\n let tempFeaturedActions = actions\n .filter((action) => action.featured)\n .sort((a, b) => (a.order || 0) - (b.order || 0))\n .slice(0, featuredNumber)\n\n // Check if we need to add more actions to reach featuredNumber\n if (tempFeaturedActions.length < featuredNumber) {\n categories.forEach((category) => {\n if (tempFeaturedActions.length >= featuredNumber) return\n const actions = groupedActions[category]\n if (!actions || !actions.length) return\n\n for (let i = tempFeaturedActions.length; i < featuredNumber; i++) {\n const action = actions[i]\n if (!action) break\n if (!action.icon) continue\n tempFeaturedActions.push(action)\n }\n })\n }\n\n return tempFeaturedActions\n }, [actions, groupedActions, placeholder])\n\n const [executeAction, { isLoading: isLoadingExecution, originalArgs }] =\n useExecuteActionMutation()\n const executingAction = isLoadingExecution && originalArgs?.identifier\n\n const handleExecuteAction = async (\n identifier: string,\n e?: MouseEvent<HTMLElement> | null,\n formData?: InteractiveForm,\n ) => {\n e?.preventDefault()\n const action = actions.find((option) => option.identifier === identifier)\n\n if (!action) {\n toast.error('Action not found')\n console.warn('Action not found', identifier)\n return\n }\n\n const params = {\n addonName: action.addonName as string,\n addonVersion: action.addonVersion as string,\n variant: action.variant,\n identifier: action.identifier,\n }\n\n const actionContext = { ...context }\n if (formData) {\n actionContext.formData = formData\n }\n\n let response = null\n\n try {\n response = await executeAction({ actionContext, ...params }).unwrap()\n } catch (error: any) {\n console.error('Error executing action', error)\n toast.error(error?.data?.detail || 'Error executing action')\n return\n }\n\n try {\n // Toast the message if it is available\n if (response?.message) {\n if (response?.success) {\n toast.success(response.message, { autoClose: 2000 })\n } else {\n toast.error(response.message, { autoClose: 2000 })\n }\n }\n\n // Even if response?.success is false, we still want to handle the payload\n // as it may contain useful information - complex error messages in form,\n // redirect to another page etc. If the action just needs to abort,\n // it raises exception instead of returning a response with success: false\n\n // Use the new hook to handle payload\n if (response?.payload) {\n if (response.type === 'form') {\n // action requests additional information from the user.\n // we show a dialog with the form and when the user submits it we call the action again\n\n // It probably does not make sense to move to the useActionTriggers hook\n // as it need contexts and the dialog\n const intf = {\n identifier,\n // @ts-expect-error\n title: response.payload['title'],\n // @ts-expect-error\n fields: response.payload['fields'],\n // @ts-expect-error\n submitLabel: response.payload['submit_label'],\n // @ts-expect-error\n cancelLabel: response.payload['cancel_label'],\n // @ts-expect-error\n submitIcon: response.payload['submit_icon'],\n // @ts-expect-error\n cancelIcon: response.payload['cancel_icon'],\n }\n setInteractiveForm(intf)\n } else {\n handleActionPayload(response.type as string, response.payload)\n }\n }\n } catch (error) {\n // got response, but failed to process it\n console.warn('Error during action response processing', error)\n toast.error('Error occured during action processing')\n }\n }\n\n const handleConfigureAction = (identifier: string) => {\n const action = actions.find((data) => data.identifier === identifier)\n if (!action) return\n setActionBeingConfigured(action)\n }\n\n const handleSubmitInteractiveForm = async (identifier: string, formData: InteractiveForm) => {\n handleExecuteAction(identifier, null, formData)\n }\n\n const loadingActions = [placeholder, placeholder, placeholder]\n\n const isLoading = isFetchingActions || isLoadingEntity\n const featuredActionsToDisplay = isLoading ? loadingActions : featuredActions\n\n return (\n <Styled.Actions className=\"actions\">\n {featuredActionsToDisplay.map((action, i) => (\n <Styled.FeaturedAction\n key={action.identifier + '-' + i}\n className={clsx('action', {\n loading: isLoading,\n // @ts-expect-error\n isPlaceholder: action.isPlaceholder,\n })}\n data-tooltip={action.label}\n // @ts-expect-error\n disabled={action.isPlaceholder}\n onClick={(e) => handleExecuteAction(action.identifier, e)}\n >\n {/* @ts-ignore */}\n <ActionIcon icon={action.icon} isExecuting={executingAction === action.identifier} />\n </Styled.FeaturedAction>\n ))}\n <ActionsDropdown\n options={dropdownOptions}\n isLoading={isLoading}\n onAction={handleExecuteAction}\n onConfig={handleConfigureAction}\n />\n <ActionConfigDialog\n action={actionBeingConfigured}\n // @ts-expect-error\n context={context}\n onClose={() => setActionBeingConfigured(null)}\n />\n <InteractiveActionDialog\n interactiveForm={interactiveForm}\n onClose={() => setInteractiveForm(null)}\n // @ts-expect-error\n onSubmit={handleSubmitInteractiveForm}\n />\n </Styled.Actions>\n )\n}\n"],"names":["actions","data","jsxs","Styled.Actions","jsx","Styled.FeaturedAction"],"mappings":"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"}
1
+ {"version":3,"file":"Actions.es.js","sources":["../../../../../src/containers/Actions/Actions.tsx"],"sourcesContent":["import * as Styled from './Actions.styled'\nimport { MouseEvent, useState } from 'react'\nimport clsx from 'clsx'\nimport { toast } from 'react-toastify'\nimport { useMemo, useEffect } from 'react'\nimport { ActionContext, useExecuteActionMutation, useGetActionsFromContextQuery } from '@shared/api'\nimport { ActionsDropdown } from './ActionsDropdown'\nimport ActionIcon from './ActionIcon'\nimport { useActionTriggers } from '@shared/hooks'\nimport { ActionConfigDialog } from './ActionConfigDialog'\nimport { InteractiveActionDialog, InteractiveForm } from './InteractiveActionDialog'\n\nconst placeholder = {\n identifier: 'placeholder',\n label: 'Featured action slot',\n isPlaceholder: true,\n icon: { type: 'material-symbols', name: 'sync' },\n groupLabel: '',\n}\n\ntype ActionsProps = {\n entities: { id: string; projectName: string; entitySubType?: string }[]\n entityType: ActionContext['entityType']\n entitySubTypes?: string[]\n isLoadingEntity: boolean\n}\n\nexport const Actions = ({\n entities,\n entityType,\n entitySubTypes,\n isLoadingEntity,\n}: ActionsProps) => {\n // special triggers the actions can make to perform stuff on the client\n const { handleActionPayload } = useActionTriggers()\n const [actionBeingConfigured, setActionBeingConfigured] = useState<any>(null)\n const [interactiveForm, setInteractiveForm] = useState<any>(null)\n\n const context: ActionContext | null = useMemo(() => {\n if (!entities.length) return null\n if (!entities[0].projectName) return null\n\n // get a list of unique entity subtypes from loaded data\n const entitySubtypesLoaded = entities\n .filter((entity) => entity.entitySubType)\n .map((entity) => entity.entitySubType as string)\n .filter((value, index, self) => self.indexOf(value) === index && value)\n\n // try and use the passed in entitySubTypes, if not use the loaded ones\n const entitySubTypesToUse = entitySubTypes?.length ? entitySubTypes : entitySubtypesLoaded\n\n // all types except version/representation should have subtypes\n if (\n !entitySubTypesToUse?.length &&\n entityType !== 'version' &&\n entityType !== 'representation'\n ) {\n console.warn('No entity subtypes found')\n return null\n }\n\n return {\n projectName: entities[0].projectName,\n entityType: entityType,\n entityIds: entities.map((entity) => entity.id),\n entitySubtypes: entitySubTypesToUse,\n }\n }, [entities, entityType])\n\n useEffect(() => {\n setInteractiveForm(null)\n }, [context])\n\n const { data, isFetching: isFetchingActions } = useGetActionsFromContextQuery(\n { mode: 'simple', actionContext: context as ActionContext },\n { skip: !context },\n )\n\n const actions = data?.actions || []\n\n const categoryOrder = ['application', 'admin', 'workflow']\n // group actions by category\n // sort by hardcoded category, this will changing the future\n const groupedActions = useMemo(() => {\n // Step 1: Group actions by category\n const grouped = actions.reduce((acc: { [key: string]: any[] }, action) => {\n const category = action.category || 'uncategorized'\n if (!acc[category]) {\n acc[category] = []\n }\n acc[category].push(action)\n return acc\n }, {})\n\n // Step 5: Return the ordered groups\n return grouped\n }, [actions])\n\n // get categories that don't have a specific order (not in categoryOrder)\n // then sort them alphabetically\n const unorderedCategories = useMemo(\n () => [\n ...new Set(\n Object.keys(groupedActions)\n .filter((category) => !categoryOrder.includes(category))\n .sort((a, b) => a.localeCompare(b)),\n ),\n ],\n [groupedActions],\n )\n\n const categories = [...categoryOrder, ...unorderedCategories]\n\n // create the options for the dropdown, each category is separated by a divider and a title\n // for the divider we will use a custom dropdown item template\n const dropdownOptions = useMemo(() => {\n const options = []\n\n categories.forEach((category) => {\n if (!groupedActions[category] || !groupedActions[category].length) return\n\n options.push({\n label: category,\n header: true,\n value: category,\n disabled: true,\n })\n\n const groupOptions = groupedActions[category].map((action) => ({\n value: action.identifier,\n label: action.groupLabel ? action.groupLabel + ' ' + action.label : action.label,\n icon: action.icon,\n hasConfig: !!action.configFields,\n }))\n\n options.push(...groupOptions)\n })\n\n // if no actions, add placeholder\n if (!options.length) {\n options.push({\n label: 'No actions available',\n value: 'no-actions',\n disabled: true,\n header: true,\n })\n }\n\n return options\n }, [groupedActions, unorderedCategories, categoryOrder])\n\n const featuredNumber = 2\n\n const featuredActions = useMemo(() => {\n // Filter and sort to get initial featured actions\n let tempFeaturedActions = actions\n .filter((action) => action.featured)\n .sort((a, b) => (a.order || 0) - (b.order || 0))\n .slice(0, featuredNumber)\n\n // Check if we need to add more actions to reach featuredNumber\n if (tempFeaturedActions.length < featuredNumber) {\n categories.forEach((category) => {\n if (tempFeaturedActions.length >= featuredNumber) return\n const actions = groupedActions[category]\n if (!actions || !actions.length) return\n\n for (let i = tempFeaturedActions.length; i < featuredNumber; i++) {\n const action = actions[i]\n if (!action) break\n if (!action.icon) continue\n tempFeaturedActions.push(action)\n }\n })\n }\n\n return tempFeaturedActions\n }, [actions, groupedActions, placeholder])\n\n const [executeAction, { isLoading: isLoadingExecution, originalArgs }] =\n useExecuteActionMutation()\n const executingAction = isLoadingExecution && originalArgs?.identifier\n\n const handleExecuteAction = async (\n identifier: string,\n e?: MouseEvent<HTMLElement> | null,\n formData?: InteractiveForm,\n ) => {\n e?.preventDefault()\n const action = actions.find((option) => option.identifier === identifier)\n\n if (!action) {\n toast.error('Action not found')\n console.warn('Action not found', identifier)\n return\n }\n\n const params = {\n addonName: action.addonName as string,\n addonVersion: action.addonVersion as string,\n variant: action.variant,\n identifier: action.identifier,\n }\n\n const actionContext = { ...context }\n if (formData) {\n actionContext.formData = formData\n }\n\n let response = null\n\n try {\n response = await executeAction({ actionContext, ...params }).unwrap()\n } catch (error: any) {\n console.error('Error executing action', error)\n toast.error(error?.data?.detail || 'Error executing action')\n return\n }\n\n try {\n // Toast the message if it is available\n if (response?.message) {\n if (response?.success) {\n toast.success(response.message, { autoClose: 2000 })\n } else {\n toast.error(response.message, { autoClose: 2000 })\n }\n }\n\n // Even if response?.success is false, we still want to handle the payload\n // as it may contain useful information - complex error messages in form,\n // redirect to another page etc. If the action just needs to abort,\n // it raises exception instead of returning a response with success: false\n\n // Use the new hook to handle payload\n if (response?.payload) {\n if (response.type === 'form') {\n // action requests additional information from the user.\n // we show a dialog with the form and when the user submits it we call the action again\n\n // It probably does not make sense to move to the useActionTriggers hook\n // as it need contexts and the dialog\n const intf = {\n identifier,\n // @ts-expect-error\n title: response.payload['title'],\n // @ts-expect-error\n fields: response.payload['fields'],\n // @ts-expect-error\n submitLabel: response.payload['submit_label'],\n // @ts-expect-error\n cancelLabel: response.payload['cancel_label'],\n // @ts-expect-error\n submitIcon: response.payload['submit_icon'],\n // @ts-expect-error\n cancelIcon: response.payload['cancel_icon'],\n }\n setInteractiveForm(intf)\n } else {\n handleActionPayload(response.type as string, response.payload)\n }\n }\n } catch (error) {\n // got response, but failed to process it\n console.warn('Error during action response processing', error)\n toast.error('Error occured during action processing')\n }\n }\n\n const handleConfigureAction = (identifier: string) => {\n const action = actions.find((data) => data.identifier === identifier)\n if (!action) return\n setActionBeingConfigured(action)\n }\n\n const handleSubmitInteractiveForm = async (identifier: string, formData: InteractiveForm) => {\n handleExecuteAction(identifier, null, formData)\n }\n\n const loadingActions = [placeholder, placeholder, placeholder]\n\n const isLoading = isFetchingActions || isLoadingEntity\n const featuredActionsToDisplay = isLoading ? loadingActions : featuredActions\n\n return (\n <Styled.Actions className=\"actions\">\n {featuredActionsToDisplay.map((action, i) => (\n <Styled.FeaturedAction\n key={action.identifier + '-' + i}\n className={clsx('action', {\n loading: isLoading,\n // @ts-expect-error\n isPlaceholder: action.isPlaceholder,\n })}\n data-tooltip={action.groupLabel ? action.groupLabel + ' ' + action.label : action.label}\n // @ts-expect-error\n disabled={action.isPlaceholder}\n onClick={(e) => handleExecuteAction(action.identifier, e)}\n >\n {/* @ts-ignore */}\n <ActionIcon icon={action.icon} isExecuting={executingAction === action.identifier} />\n </Styled.FeaturedAction>\n ))}\n <ActionsDropdown\n options={dropdownOptions}\n isLoading={isLoading}\n onAction={handleExecuteAction}\n onConfig={handleConfigureAction}\n />\n <ActionConfigDialog\n action={actionBeingConfigured}\n // @ts-expect-error\n context={context}\n onClose={() => setActionBeingConfigured(null)}\n />\n <InteractiveActionDialog\n interactiveForm={interactiveForm}\n onClose={() => setInteractiveForm(null)}\n // @ts-expect-error\n onSubmit={handleSubmitInteractiveForm}\n />\n </Styled.Actions>\n )\n}\n"],"names":["actions","data","jsxs","Styled.Actions","jsx","Styled.FeaturedAction"],"mappings":"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"}
@@ -83,10 +83,12 @@ const CommentInput = ({
83
83
  var _a2, _b, _c;
84
84
  if (isOpen) {
85
85
  (_b = (_a2 = editorRef.current) == null ? void 0 : _a2.getEditor()) == null ? void 0 : _b.enable();
86
- const blockAutoFocus = !!annotations.length && files.length === 0;
87
- !blockAutoFocus && ((_c = editorRef.current) == null ? void 0 : _c.focus());
86
+ if (annotations.length > 0 && files.length === 0) {
87
+ return;
88
+ }
89
+ (_c = editorRef.current) == null ? void 0 : _c.focus();
88
90
  }
89
- }, [isOpen, editorRef, annotations, files]);
91
+ }, [isOpen, editorRef]);
90
92
  mentionTypes.sort((a, b) => b.length - a.length);
91
93
  const mentionOptions = React.useMemo(
92
94
  () => getMentionOptions(