synapse-react-client 4.0.13 → 4.0.15

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 (98) hide show
  1. package/dist/SWC.index.js +1 -1
  2. package/dist/components/ChallengeRegisterButton/ChallengeRegisterButton.d.ts.map +1 -1
  3. package/dist/components/ChallengeRegisterButton/ChallengeRegisterButton.js +76 -45
  4. package/dist/components/ChallengeRegisterButton/ChallengeRegisterButton.js.map +1 -1
  5. package/dist/components/ChallengeRequirementsModal/ChallengeRequirementsModal.d.ts.map +1 -1
  6. package/dist/components/ChallengeRequirementsModal/ChallengeRequirementsModal.js +2 -2
  7. package/dist/components/ChallengeRequirementsModal/ChallengeRequirementsModal.js.map +1 -1
  8. package/dist/components/ChallengeTeamWizard/ChallengeTeamWizard.d.ts.map +1 -1
  9. package/dist/components/ChallengeTeamWizard/ChallengeTeamWizard.js +2 -2
  10. package/dist/components/ChallengeTeamWizard/ChallengeTeamWizard.js.map +1 -1
  11. package/dist/components/DataGrid/utils/DataGridUtils.js +1 -1
  12. package/dist/components/DataGrid/utils/DataGridUtils.js.map +1 -1
  13. package/dist/components/EntityDownloadButton/EntityDownloadButton.d.ts +6 -0
  14. package/dist/components/EntityDownloadButton/EntityDownloadButton.d.ts.map +1 -1
  15. package/dist/components/EntityDownloadButton/EntityDownloadButton.js +6 -1
  16. package/dist/components/EntityDownloadButton/EntityDownloadButton.js.map +1 -1
  17. package/dist/components/FullTextSearch/FullTextSearch.d.ts.map +1 -1
  18. package/dist/components/FullTextSearch/FullTextSearch.js +28 -20
  19. package/dist/components/FullTextSearch/FullTextSearch.js.map +1 -1
  20. package/dist/components/FullTextSearch/FullTextSearchUtils.d.ts.map +1 -1
  21. package/dist/components/FullTextSearch/FullTextSearchUtils.js +7 -2
  22. package/dist/components/FullTextSearch/FullTextSearchUtils.js.map +1 -1
  23. package/dist/components/GenericCard/BioregistryRules.d.ts.map +1 -1
  24. package/dist/components/GenericCard/BioregistryRules.js +9 -1
  25. package/dist/components/GenericCard/BioregistryRules.js.map +1 -1
  26. package/dist/components/Goals/Goals.Desktop.d.ts +3 -1
  27. package/dist/components/Goals/Goals.Desktop.d.ts.map +1 -1
  28. package/dist/components/Goals/Goals.Desktop.js +2 -3
  29. package/dist/components/Goals/Goals.Desktop.js.map +1 -1
  30. package/dist/components/Goals/Goals.d.ts +1 -0
  31. package/dist/components/Goals/Goals.d.ts.map +1 -1
  32. package/dist/components/Goals/Goals.js +33 -27
  33. package/dist/components/Goals/Goals.js.map +1 -1
  34. package/dist/components/Markdown/widget/MarkdownTableOfContents.d.ts.map +1 -1
  35. package/dist/components/Markdown/widget/MarkdownTableOfContents.js +15 -11
  36. package/dist/components/Markdown/widget/MarkdownTableOfContents.js.map +1 -1
  37. package/dist/components/QueryWrapper/useOnQueryDataChange.d.ts.map +1 -1
  38. package/dist/components/QueryWrapper/useOnQueryDataChange.js +19 -17
  39. package/dist/components/QueryWrapper/useOnQueryDataChange.js.map +1 -1
  40. package/dist/components/SearchQueryWrapper/SearchQueryUseQueryOptions.d.ts.map +1 -1
  41. package/dist/components/SearchQueryWrapper/SearchQueryUseQueryOptions.js +2 -2
  42. package/dist/components/SearchQueryWrapper/SearchQueryUseQueryOptions.js.map +1 -1
  43. package/dist/components/SearchQueryWrapper/SearchQueryWrapper.d.ts.map +1 -1
  44. package/dist/components/SearchQueryWrapper/SearchQueryWrapper.js +30 -30
  45. package/dist/components/SearchQueryWrapper/SearchQueryWrapper.js.map +1 -1
  46. package/dist/components/SearchQueryWrapperPlotNav/SearchQueryWrapperPlotNav.d.ts +1 -1
  47. package/dist/components/SearchQueryWrapperPlotNav/SearchQueryWrapperPlotNav.d.ts.map +1 -1
  48. package/dist/components/SearchQueryWrapperPlotNav/SearchQueryWrapperPlotNav.js +4 -2
  49. package/dist/components/SearchQueryWrapperPlotNav/SearchQueryWrapperPlotNav.js.map +1 -1
  50. package/dist/components/SynapseHomepageV2/WordPressNews.d.ts.map +1 -1
  51. package/dist/components/SynapseHomepageV2/WordPressNews.js +13 -36
  52. package/dist/components/SynapseHomepageV2/WordPressNews.js.map +1 -1
  53. package/dist/components/SynapseSearchPageResults/SearchPagePortalBanners.d.ts.map +1 -1
  54. package/dist/components/SynapseSearchPageResults/SearchPagePortalBanners.js +1 -1
  55. package/dist/components/SynapseSearchPageResults/SearchPagePortalBanners.js.map +1 -1
  56. package/dist/components/SynapseSearchPageResults/SynapseSearchPageRouter.d.ts.map +1 -1
  57. package/dist/components/SynapseSearchPageResults/SynapseSearchPageRouter.js +14 -12
  58. package/dist/components/SynapseSearchPageResults/SynapseSearchPageRouter.js.map +1 -1
  59. package/dist/components/SynapseTable/SearchV2.d.ts +11 -0
  60. package/dist/components/SynapseTable/SearchV2.d.ts.map +1 -1
  61. package/dist/components/SynapseTable/SearchV2.js.map +1 -1
  62. package/dist/components/WordPress/WordPressLatestPostChip.css +1 -0
  63. package/dist/components/WordPress/WordPressLatestPostChip.d.ts +5 -0
  64. package/dist/components/WordPress/WordPressLatestPostChip.d.ts.map +1 -0
  65. package/dist/components/WordPress/WordPressLatestPostChip.js +29 -0
  66. package/dist/components/WordPress/WordPressLatestPostChip.js.map +1 -0
  67. package/dist/components/WordPress/WordPressLatestPostChip.module.js +9 -0
  68. package/dist/components/WordPress/WordPressLatestPostChip.module.js.map +1 -0
  69. package/dist/components/WordPress/WordPressLatestPostChip.module.scss +33 -0
  70. package/dist/components/WordPress/useWordPressCategories.d.ts +3 -0
  71. package/dist/components/WordPress/useWordPressCategories.d.ts.map +1 -0
  72. package/dist/components/WordPress/useWordPressCategories.js +19 -0
  73. package/dist/components/WordPress/useWordPressCategories.js.map +1 -0
  74. package/dist/components/WordPress/useWordPressPosts.d.ts +3 -0
  75. package/dist/components/WordPress/useWordPressPosts.d.ts.map +1 -0
  76. package/dist/components/WordPress/useWordPressPosts.js +23 -0
  77. package/dist/components/WordPress/useWordPressPosts.js.map +1 -0
  78. package/dist/features/curator/dashboard/components/CurationTaskCard.js +1 -1
  79. package/dist/features/curator/dashboard/components/CurationTaskCard.js.map +1 -1
  80. package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.d.ts.map +1 -1
  81. package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.js +6 -6
  82. package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.js.map +1 -1
  83. package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask.d.ts.map +1 -1
  84. package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask.js +24 -20
  85. package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask.js.map +1 -1
  86. package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.d.ts +2 -2
  87. package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.d.ts.map +1 -1
  88. package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.js +30 -21
  89. package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.js.map +1 -1
  90. package/dist/features/entity/metadata-task/utils/constants.d.ts +1 -0
  91. package/dist/features/entity/metadata-task/utils/constants.d.ts.map +1 -1
  92. package/dist/features/entity/metadata-task/utils/constants.js +2 -2
  93. package/dist/features/entity/metadata-task/utils/constants.js.map +1 -1
  94. package/dist/tsconfig.build.tsbuildinfo +1 -1
  95. package/dist/utils/hooks/useShowDesktop.d.ts.map +1 -1
  96. package/dist/utils/hooks/useShowDesktop.js +4 -9
  97. package/dist/utils/hooks/useShowDesktop.js.map +1 -1
  98. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"SearchPagePortalBanners.js","names":[],"sources":["../../../src/components/SynapseSearchPageResults/SearchPagePortalBanners.tsx"],"sourcesContent":["import { useGetQueryResultBundleWithAsyncStatus } from '@/synapse-queries'\nimport { useSourceAppConfigs } from '@/utils/hooks'\nimport { BUNDLE_MASK_QUERY_RESULTS } from '@/utils/SynapseConstants'\nimport { Box, Link, Typography } from '@mui/material'\nimport {\n ColumnSingleValueQueryFilter,\n ColumnSingleValueFilterOperator,\n} from '@sage-bionetworks/synapse-types'\n\nexport type SearchPagePortalBannersProps = {\n entityIds: string[]\n dataCatalogEntityId?: string\n sourceAppConfigTableID?: string\n}\n\n/**\n * Portal banner based on entities found in the first page of search results.\n */\nexport default function SearchPagePortalBanners({\n entityIds,\n dataCatalogEntityId = 'syn61609402',\n sourceAppConfigTableID = 'syn45291362',\n}: SearchPagePortalBannersProps) {\n // Query data catalog to find portal mappings for the entity IDs\n const dataCatalogAdditionalFilters: ColumnSingleValueQueryFilter[] =\n entityIds.length > 0\n ? [\n {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n columnName: 'id',\n operator: ColumnSingleValueFilterOperator.IN,\n values: entityIds,\n },\n ]\n : []\n\n const { data: dataCatalogData } = useGetQueryResultBundleWithAsyncStatus(\n {\n entityId: dataCatalogEntityId,\n query: {\n sql: `SELECT appId, link FROM ${dataCatalogEntityId}`,\n additionalFilters: dataCatalogAdditionalFilters,\n },\n partMask: BUNDLE_MASK_QUERY_RESULTS,\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n },\n {\n enabled: entityIds.length > 0,\n },\n )\n\n const rowSet = dataCatalogData?.responseBody?.queryResult?.queryResults\n const hasPortalBanners = !!rowSet && rowSet?.rows.length > 0\n const appIds = rowSet?.rows.map(row => row.values[0]) as string[]\n\n // Get source app configurations for the found portal app IDs\n const sourceAppConfigFilters: ColumnSingleValueQueryFilter[] =\n appIds && appIds.length > 0\n ? [\n {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n columnName: 'appId',\n operator: ColumnSingleValueFilterOperator.IN,\n values: appIds,\n },\n ]\n : []\n\n const sourceAppConfigs = useSourceAppConfigs(\n sourceAppConfigTableID,\n sourceAppConfigFilters,\n )\n const hasSourceAppConfigs = !!sourceAppConfigs && sourceAppConfigs.length > 0\n const hasAppIds = appIds && appIds.length > 0\n if (!hasAppIds || !hasPortalBanners || !hasSourceAppConfigs) {\n return null\n }\n\n return (\n <>\n {sourceAppConfigs.map((appConfig, index) => {\n return (\n <Box\n key={index}\n sx={{\n display: 'flex',\n padding: '32px',\n backgroundColor: 'secondary.100',\n borderRadius: '8px',\n width: '100%',\n transition: 'background-color 0.3s',\n justifyContent: 'space-between',\n alignItems: 'center',\n gap: '50px',\n boxShadow:\n '0 4px 10px 0 rgba(0, 0, 0, 0.10), 0 1px 1px 0 rgba(0, 0, 0, 0.05)',\n }}\n >\n <Box>\n <Typography\n variant=\"smallText1\"\n sx={{ color: 'grey.900', mt: '4px', lineHeight: '20px' }}\n >\n Looks like you’re searching for information about{' '}\n {appConfig.area}\n {'. '}\n <Link\n component={'a'}\n href={appConfig.appURL}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n sx={{\n color: theme => `${theme.palette.grey[900]} !important`,\n textDecorationColor: theme =>\n `${theme.palette.grey[900]} !important`,\n }}\n >\n Visit the {appConfig.friendlyName}\n </Link>\n .\n </Typography>\n </Box>\n <Box\n sx={{\n '> *': {\n height: '48px',\n width: 'auto',\n },\n }}\n >\n {appConfig?.logo}\n </Box>\n </Box>\n )\n })}\n </>\n )\n}\n"],"mappings":";;;;;;;;;AAkBA,SAAwB,EAAwB,EAC9C,cACA,yBAAsB,eACtB,4BAAyB,iBACM;CAE/B,IAAM,IACJ,EAAU,SAAS,IACf,CACE;EACE,cACE;EACF,YAAY;EACZ,UAAU,EAAgC;EAC1C,QAAQ;EACT,CACF,GACD,EAAE,EAEF,EAAE,MAAM,MAAoB,EAChC;EACE,UAAU;EACV,OAAO;GACL,KAAK,2BAA2B;GAChC,mBAAmB;GACpB;EACD,UAAA;EACA,cAAc;EACf,EACD,EACE,SAAS,EAAU,SAAS,GAC7B,CACF,EAEK,IAAS,GAAiB,cAAc,aAAa,cACrD,IAAmB,CAAC,CAAC,KAAU,GAAQ,KAAK,SAAS,GACrD,IAAS,GAAQ,KAAK,KAAI,MAAO,EAAI,OAAO,GAAG,EAgB/C,IAAmB,EACvB,GAbA,KAAU,EAAO,SAAS,IACtB,CACE;EACE,cACE;EACF,YAAY;EACZ,UAAU,EAAgC;EAC1C,QAAQ;EACT,CACF,GACD,EAAE,CAKP,EACK,IAAsB,CAAC,CAAC,KAAoB,EAAiB,SAAS;AAM5E,QAJI,EADc,KAAU,EAAO,SAAS,MAC1B,CAAC,KAAoB,CAAC,IAC/B,OAIP,kBAAA,GAAA,EAAA,UACG,EAAiB,KAAK,GAAW,MAE9B,kBAAC,GAAD;EAEE,IAAI;GACF,SAAS;GACT,SAAS;GACT,iBAAiB;GACjB,cAAc;GACd,OAAO;GACP,YAAY;GACZ,gBAAgB;GAChB,YAAY;GACZ,KAAK;GACL,WACE;GACH;YAdH,CAgBE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;GACE,SAAQ;GACR,IAAI;IAAE,OAAO;IAAY,IAAI;IAAO,YAAY;IAAQ;aAF1D;IAGC;IACmD;IACjD,EAAU;IACV;IACD,kBAAC,GAAD;KACE,WAAW;KACX,MAAM,EAAU;KAChB,QAAO;KACP,KAAI;KACJ,IAAI;MACF,QAAO,MAAS,GAAG,EAAM,QAAQ,KAAK,KAAK;MAC3C,sBAAqB,MACnB,GAAG,EAAM,QAAQ,KAAK,KAAK;MAC9B;eATH,CAUC,cACY,EAAU,aAChB;;;IAEI;MACT,CAAA,EACN,kBAAC,GAAD;GACE,IAAI,EACF,OAAO;IACL,QAAQ;IACR,OAAO;IACR,EACF;aAEA,GAAW;GACR,CAAA,CACF;IAjDC,EAiDD,CAER,EACD,CAAA"}
1
+ {"version":3,"file":"SearchPagePortalBanners.js","names":[],"sources":["../../../src/components/SynapseSearchPageResults/SearchPagePortalBanners.tsx"],"sourcesContent":["import { useGetQueryResultBundleWithAsyncStatus } from '@/synapse-queries'\nimport { useSourceAppConfigs } from '@/utils/hooks'\nimport { BUNDLE_MASK_QUERY_RESULTS } from '@/utils/SynapseConstants'\nimport { Box, Link, Typography } from '@mui/material'\nimport {\n ColumnSingleValueQueryFilter,\n ColumnSingleValueFilterOperator,\n} from '@sage-bionetworks/synapse-types'\n\nexport type SearchPagePortalBannersProps = {\n entityIds: string[]\n dataCatalogEntityId?: string\n sourceAppConfigTableID?: string\n}\n\n/**\n * Portal banner based on entities found in the first page of search results.\n */\nexport default function SearchPagePortalBanners({\n entityIds,\n dataCatalogEntityId = 'syn61609402',\n sourceAppConfigTableID = 'syn45291362',\n}: SearchPagePortalBannersProps) {\n // Query data catalog to find portal mappings for the entity IDs\n const dataCatalogAdditionalFilters: ColumnSingleValueQueryFilter[] =\n entityIds.length > 0\n ? [\n {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n columnName: 'id',\n operator: ColumnSingleValueFilterOperator.IN,\n values: entityIds,\n },\n ]\n : []\n\n const { data: dataCatalogData } = useGetQueryResultBundleWithAsyncStatus(\n {\n entityId: dataCatalogEntityId,\n query: {\n sql: `SELECT appId, link FROM ${dataCatalogEntityId}`,\n additionalFilters: dataCatalogAdditionalFilters,\n },\n partMask: BUNDLE_MASK_QUERY_RESULTS,\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n },\n {\n enabled: entityIds.length > 0,\n },\n )\n\n const rowSet = dataCatalogData?.responseBody?.queryResult?.queryResults\n const hasPortalBanners = !!rowSet && rowSet?.rows.length > 0\n const appIds = rowSet?.rows\n .map(row => row.values[0])\n .filter((v): v is string => !!v) as string[]\n\n // Get source app configurations for the found portal app IDs\n const sourceAppConfigFilters: ColumnSingleValueQueryFilter[] =\n appIds && appIds.length > 0\n ? [\n {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n columnName: 'appId',\n operator: ColumnSingleValueFilterOperator.IN,\n values: appIds,\n },\n ]\n : []\n\n const sourceAppConfigs = useSourceAppConfigs(\n sourceAppConfigTableID,\n sourceAppConfigFilters,\n )\n const hasSourceAppConfigs = !!sourceAppConfigs && sourceAppConfigs.length > 0\n const hasAppIds = appIds && appIds.length > 0\n if (!hasAppIds || !hasPortalBanners || !hasSourceAppConfigs) {\n return null\n }\n\n return (\n <>\n {sourceAppConfigs.map((appConfig, index) => {\n return (\n <Box\n key={index}\n sx={{\n display: 'flex',\n padding: '32px',\n backgroundColor: 'secondary.100',\n borderRadius: '8px',\n width: '100%',\n transition: 'background-color 0.3s',\n justifyContent: 'space-between',\n alignItems: 'center',\n gap: '50px',\n boxShadow:\n '0 4px 10px 0 rgba(0, 0, 0, 0.10), 0 1px 1px 0 rgba(0, 0, 0, 0.05)',\n }}\n >\n <Box>\n <Typography\n variant=\"smallText1\"\n sx={{ color: 'grey.900', mt: '4px', lineHeight: '20px' }}\n >\n Looks like you’re searching for information about{' '}\n {appConfig.area}\n {'. '}\n <Link\n component={'a'}\n href={appConfig.appURL}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n sx={{\n color: theme => `${theme.palette.grey[900]} !important`,\n textDecorationColor: theme =>\n `${theme.palette.grey[900]} !important`,\n }}\n >\n Visit the {appConfig.friendlyName}\n </Link>\n .\n </Typography>\n </Box>\n <Box\n sx={{\n '> *': {\n height: '48px',\n width: 'auto',\n },\n }}\n >\n {appConfig?.logo}\n </Box>\n </Box>\n )\n })}\n </>\n )\n}\n"],"mappings":";;;;;;;;;AAkBA,SAAwB,EAAwB,EAC9C,cACA,yBAAsB,eACtB,4BAAyB,iBACM;CAE/B,IAAM,IACJ,EAAU,SAAS,IACf,CACE;EACE,cACE;EACF,YAAY;EACZ,UAAU,EAAgC;EAC1C,QAAQ;EACT,CACF,GACD,EAAE,EAEF,EAAE,MAAM,MAAoB,EAChC;EACE,UAAU;EACV,OAAO;GACL,KAAK,2BAA2B;GAChC,mBAAmB;GACpB;EACD,UAAA;EACA,cAAc;EACf,EACD,EACE,SAAS,EAAU,SAAS,GAC7B,CACF,EAEK,IAAS,GAAiB,cAAc,aAAa,cACrD,IAAmB,CAAC,CAAC,KAAU,GAAQ,KAAK,SAAS,GACrD,IAAS,GAAQ,KACpB,KAAI,MAAO,EAAI,OAAO,GAAG,CACzB,QAAQ,MAAmB,CAAC,CAAC,EAAE,EAgB5B,IAAmB,EACvB,GAbA,KAAU,EAAO,SAAS,IACtB,CACE;EACE,cACE;EACF,YAAY;EACZ,UAAU,EAAgC;EAC1C,QAAQ;EACT,CACF,GACD,EAAE,CAKP,EACK,IAAsB,CAAC,CAAC,KAAoB,EAAiB,SAAS;AAM5E,QAJI,EADc,KAAU,EAAO,SAAS,MAC1B,CAAC,KAAoB,CAAC,IAC/B,OAIP,kBAAA,GAAA,EAAA,UACG,EAAiB,KAAK,GAAW,MAE9B,kBAAC,GAAD;EAEE,IAAI;GACF,SAAS;GACT,SAAS;GACT,iBAAiB;GACjB,cAAc;GACd,OAAO;GACP,YAAY;GACZ,gBAAgB;GAChB,YAAY;GACZ,KAAK;GACL,WACE;GACH;YAdH,CAgBE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;GACE,SAAQ;GACR,IAAI;IAAE,OAAO;IAAY,IAAI;IAAO,YAAY;IAAQ;aAF1D;IAGC;IACmD;IACjD,EAAU;IACV;IACD,kBAAC,GAAD;KACE,WAAW;KACX,MAAM,EAAU;KAChB,QAAO;KACP,KAAI;KACJ,IAAI;MACF,QAAO,MAAS,GAAG,EAAM,QAAQ,KAAK,KAAK;MAC3C,sBAAqB,MACnB,GAAG,EAAM,QAAQ,KAAK,KAAK;MAC9B;eATH,CAUC,cACY,EAAU,aAChB;;;IAEI;MACT,CAAA,EACN,kBAAC,GAAD;GACE,IAAI,EACF,OAAO;IACL,QAAQ;IACR,OAAO;IACR,EACF;aAEA,GAAW;GACR,CAAA,CACF;IAjDC,EAiDD,CAER,EACD,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"SynapseSearchPageRouter.d.ts","sourceRoot":"","sources":["../../../src/components/SynapseSearchPageResults/SynapseSearchPageRouter.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAW,MAAM,OAAO,CAAA;AASlD,MAAM,MAAM,4BAA4B,GAAG,iBAAiB,CAAC;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B,CAAC,CAAA;AAEF,MAAM,CAAC,OAAO,UAAU,uBAAuB,CAC7C,KAAK,EAAE,4BAA4B,2CAkCpC"}
1
+ {"version":3,"file":"SynapseSearchPageRouter.d.ts","sourceRoot":"","sources":["../../../src/components/SynapseSearchPageResults/SynapseSearchPageRouter.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAW,MAAM,OAAO,CAAA;AASlD,MAAM,MAAM,4BAA4B,GAAG,iBAAiB,CAAC;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B,CAAC,CAAA;AAEF,MAAM,CAAC,OAAO,UAAU,uBAAuB,CAC7C,KAAK,EAAE,4BAA4B,2CAmCpC"}
@@ -1,20 +1,22 @@
1
- import { useMemo as e } from "react";
2
- import { Fragment as t, jsx as n } from "react/jsx-runtime";
3
- import { RouterProvider as r, createBrowserRouter as i, createMemoryRouter as a } from "react-router";
4
- import { RouterProvider as o } from "react-router/dom";
1
+ import { RouteErrorBoundary as e } from "../error/RouteErrorBoundary.js";
2
+ import { useMemo as t } from "react";
3
+ import { Fragment as n, jsx as r } from "react/jsx-runtime";
4
+ import { RouterProvider as i, createBrowserRouter as a, createMemoryRouter as o } from "react-router";
5
+ import { RouterProvider as s } from "react-router/dom";
5
6
  //#region src/components/SynapseSearchPageResults/SynapseSearchPageRouter.tsx
6
- function s(s) {
7
- let { children: c, routerBaseName: l = "/SearchV2:default", useMemoryRouter: u = !1 } = s, d = e(() => [{
7
+ function c(c) {
8
+ let { children: l, routerBaseName: u = "/SearchV2:default", useMemoryRouter: d = !1 } = c, f = t(() => [{
8
9
  path: "/",
9
- element: /* @__PURE__ */ n(t, { children: c })
10
- }], [c, u]), f = e(() => u ? a(d, { basename: l }) : i(d, { basename: l }), [
11
- u,
10
+ element: /* @__PURE__ */ r(n, { children: l }),
11
+ errorElement: /* @__PURE__ */ r(e, {})
12
+ }], [l, d]), p = t(() => d ? o(f, { basename: u }) : a(f, { basename: u }), [
12
13
  d,
13
- l
14
+ f,
15
+ u
14
16
  ]);
15
- return n(u ? r : o, { router: f });
17
+ return r(d ? i : s, { router: p });
16
18
  }
17
19
  //#endregion
18
- export { s as default };
20
+ export { c as default };
19
21
 
20
22
  //# sourceMappingURL=SynapseSearchPageRouter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SynapseSearchPageRouter.js","names":[],"sources":["../../../src/components/SynapseSearchPageResults/SynapseSearchPageRouter.tsx"],"sourcesContent":["import { PropsWithChildren, useMemo } from 'react'\nimport {\n createBrowserRouter,\n createMemoryRouter,\n RouteObject,\n RouterProvider,\n} from 'react-router'\nimport { RouterProvider as DOMRouterProvider } from 'react-router/dom'\n\nexport type SynapseSearchPageRouterProps = PropsWithChildren<{\n routerBaseName?: string\n useMemoryRouter?: boolean\n}>\n\nexport default function SynapseSearchPageRouter(\n props: SynapseSearchPageRouterProps,\n) {\n const {\n children,\n routerBaseName = '/SearchV2:default',\n useMemoryRouter = false,\n } = props\n const routes: RouteObject[] = useMemo(\n () => [\n {\n path: '/',\n element: <>{children}</>,\n },\n ],\n [children, useMemoryRouter],\n )\n\n const router = useMemo(() => {\n if (useMemoryRouter) {\n return createMemoryRouter(routes, {\n basename: routerBaseName,\n })\n } else {\n return createBrowserRouter(routes, {\n basename: routerBaseName,\n })\n }\n }, [useMemoryRouter, routes, routerBaseName])\n\n if (useMemoryRouter) {\n return <RouterProvider router={router} />\n }\n\n return <DOMRouterProvider router={router} />\n}\n"],"mappings":";;;;;AAcA,SAAwB,EACtB,GACA;CACA,IAAM,EACJ,aACA,oBAAiB,qBACjB,qBAAkB,OAChB,GACE,IAAwB,QACtB,CACJ;EACE,MAAM;EACN,SAAS,kBAAA,GAAA,EAAG,aAAY,CAAA;EACzB,CACF,EACD,CAAC,GAAU,EAAgB,CAC5B,EAEK,IAAS,QACT,IACK,EAAmB,GAAQ,EAChC,UAAU,GACX,CAAC,GAEK,EAAoB,GAAQ,EACjC,UAAU,GACX,CAAC,EAEH;EAAC;EAAiB;EAAQ;EAAe,CAAC;AAM7C,QAHS,EADL,IACM,IAGF,GAHC,EAAwB,WAAU,CAAA"}
1
+ {"version":3,"file":"SynapseSearchPageRouter.js","names":[],"sources":["../../../src/components/SynapseSearchPageResults/SynapseSearchPageRouter.tsx"],"sourcesContent":["import { RouteErrorBoundary } from '@/components/error/RouteErrorBoundary'\nimport { PropsWithChildren, useMemo } from 'react'\nimport {\n createBrowserRouter,\n createMemoryRouter,\n RouteObject,\n RouterProvider,\n} from 'react-router'\nimport { RouterProvider as DOMRouterProvider } from 'react-router/dom'\n\nexport type SynapseSearchPageRouterProps = PropsWithChildren<{\n routerBaseName?: string\n useMemoryRouter?: boolean\n}>\n\nexport default function SynapseSearchPageRouter(\n props: SynapseSearchPageRouterProps,\n) {\n const {\n children,\n routerBaseName = '/SearchV2:default',\n useMemoryRouter = false,\n } = props\n const routes: RouteObject[] = useMemo(\n () => [\n {\n path: '/',\n element: <>{children}</>,\n errorElement: <RouteErrorBoundary />,\n },\n ],\n [children, useMemoryRouter],\n )\n\n const router = useMemo(() => {\n if (useMemoryRouter) {\n return createMemoryRouter(routes, {\n basename: routerBaseName,\n })\n } else {\n return createBrowserRouter(routes, {\n basename: routerBaseName,\n })\n }\n }, [useMemoryRouter, routes, routerBaseName])\n\n if (useMemoryRouter) {\n return <RouterProvider router={router} />\n }\n\n return <DOMRouterProvider router={router} />\n}\n"],"mappings":";;;;;;AAeA,SAAwB,EACtB,GACA;CACA,IAAM,EACJ,aACA,oBAAiB,qBACjB,qBAAkB,OAChB,GACE,IAAwB,QACtB,CACJ;EACE,MAAM;EACN,SAAS,kBAAA,GAAA,EAAG,aAAY,CAAA;EACxB,cAAc,kBAAC,GAAD,EAAsB,CAAA;EACrC,CACF,EACD,CAAC,GAAU,EAAgB,CAC5B,EAEK,IAAS,QACT,IACK,EAAmB,GAAQ,EAChC,UAAU,GACX,CAAC,GAEK,EAAoB,GAAQ,EACjC,UAAU,GACX,CAAC,EAEH;EAAC;EAAiB;EAAQ;EAAe,CAAC;AAM7C,QAHS,EADL,IACM,IAGF,GAHC,EAAwB,WAAU,CAAA"}
@@ -29,6 +29,17 @@ export type FTSConfig = {
29
29
  * @returns A promise resolving to an array of suggestion strings
30
30
  */
31
31
  getSuggestions?: (searchText: string) => Promise<string[]>;
32
+ /**
33
+ * Override the minimum number of characters required before a search is executed.
34
+ * Defaults to 3 (see PLFM-7011).
35
+ */
36
+ minSearchQueryLength?: number;
37
+ /**
38
+ * When true, submitting a new search term replaces any existing TextMatchesQueryFilter
39
+ * in additionalFilters rather than appending a new one.
40
+ * Defaults to false (existing behaviour: filters accumulate).
41
+ */
42
+ replaceExistingFilter?: boolean;
32
43
  };
33
44
  export default function Search(props: SearchV2Props): import("react/jsx-runtime").JSX.Element;
34
45
  //# sourceMappingURL=SearchV2.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SearchV2.d.ts","sourceRoot":"","sources":["../../../src/components/SynapseTable/SearchV2.tsx"],"names":[],"mappings":"AAAA,OAAO,EAGL,YAAY,EACb,MAAM,SAAS,CAAA;AAoBhB,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,EAAE,6BAA6B,EAAE,MAAM,8BAA8B,CAAA;AAE5E,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAexC,MAAM,MAAM,mBAAmB,GAAG,MAAM,EAAE,CAAA;AAE1C,MAAM,MAAM,aAAa,GAAG;IAC1B,YAAY,EAAE,gBAAgB,CAAA;IAC9B,yBAAyB,EAAE,6BAA6B,CAAA;IACxD,uBAAuB,CAAC,EAAE,OAAO,CAAA;IACjC,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,UAAU,CAAC,EAAE,mBAAmB,CAAA;IAChC,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B;;;;OAIG;IACH,SAAS,CAAC,EAAE,YAAY,CAAC,SAAS,CAAC,CAAA;CACpC,CAAA;AAED,MAAM,MAAM,eAAe,GAAG,kBAAkB,GAAG,SAAS,CAAA;AAC5D,MAAM,MAAM,SAAS,GAAG;IACtB,eAAe,EAAE,eAAe,CAAA;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;CAC3D,CAAA;AA0SD,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,KAAK,EAAE,aAAa,2CAGlD"}
1
+ {"version":3,"file":"SearchV2.d.ts","sourceRoot":"","sources":["../../../src/components/SynapseTable/SearchV2.tsx"],"names":[],"mappings":"AAAA,OAAO,EAGL,YAAY,EACb,MAAM,SAAS,CAAA;AAoBhB,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,EAAE,6BAA6B,EAAE,MAAM,8BAA8B,CAAA;AAE5E,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAexC,MAAM,MAAM,mBAAmB,GAAG,MAAM,EAAE,CAAA;AAE1C,MAAM,MAAM,aAAa,GAAG;IAC1B,YAAY,EAAE,gBAAgB,CAAA;IAC9B,yBAAyB,EAAE,6BAA6B,CAAA;IACxD,uBAAuB,CAAC,EAAE,OAAO,CAAA;IACjC,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,UAAU,CAAC,EAAE,mBAAmB,CAAA;IAChC,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B;;;;OAIG;IACH,SAAS,CAAC,EAAE,YAAY,CAAC,SAAS,CAAC,CAAA;CACpC,CAAA;AAED,MAAM,MAAM,eAAe,GAAG,kBAAkB,GAAG,SAAS,CAAA;AAC5D,MAAM,MAAM,SAAS,GAAG;IACtB,eAAe,EAAE,eAAe,CAAA;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IAC1D;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAA;CAChC,CAAA;AA0SD,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,KAAK,EAAE,aAAa,2CAGlD"}
@@ -1 +1 @@
1
- {"version":3,"file":"SearchV2.js","names":[],"sources":["../../../src/components/SynapseTable/SearchV2.tsx"],"sourcesContent":["import {\n isColumnMultiValueFunctionQueryFilter,\n isColumnSingleValueQueryFilter,\n LockedColumn,\n} from '@/utils'\nimport { Collapse } from '@mui/material'\nimport {\n ColumnModel,\n ColumnMultiValueFunction,\n ColumnMultiValueFunctionQueryFilter,\n ColumnSingleValueFilterOperator,\n ColumnSingleValueQueryFilter,\n ColumnTypeEnum,\n QueryFilter,\n} from '@sage-bionetworks/synapse-types'\nimport {\n Component,\n createRef,\n FormEvent,\n RefObject,\n SyntheticEvent,\n} from 'react'\nimport { CSSTransition } from 'react-transition-group'\nimport IconSvg from '../IconSvg/IconSvg'\nimport { QueryContextType } from '../QueryContext'\nimport { QueryVisualizationContextType } from '../QueryVisualizationWrapper'\nimport { useGetQueryMetadata } from '../QueryWrapper/useGetQueryMetadata'\nimport { ReadonlyDeep } from 'type-fest'\n\ntype SearchState = {\n show: boolean\n /* \n When the component is revealed in queryplotnav we want to focus on the input field and reveal the dropdown\n there is an issue where the method handleClickOutsideForm will override the state from componentDidUpdate\n so we track when componentDidUpdate just fired so that `show` is not overriden on the click event which\n triggers componentDidUpdate \n */\n didUpdateRanLast: boolean\n searchText: string\n columnName: string\n}\n\nexport type SearchableColumnsV2 = string[]\n\nexport type SearchV2Props = {\n queryContext: QueryContextType\n queryVisualizationContext: QueryVisualizationContextType\n isQueryWrapperMenuChild?: boolean\n defaultColumn?: string\n searchable?: SearchableColumnsV2\n lockedColumn?: LockedColumn\n /**\n * PLFM-8897, PORTALS-3534: Full-Text Search configuration.\n * For Tables that have FTS enabled...\n * If specified, use the specified mode and distance (if BOOLEAN mode). Otherwise default to NATURAL_LANGUAGE mode.\n */\n ftsConfig?: ReadonlyDeep<FTSConfig>\n}\n\nexport type TextMatchesMode = 'NATURAL_LANGUAGE' | 'BOOLEAN'\nexport type FTSConfig = {\n textMatchesMode: TextMatchesMode\n distance?: number // In BOOLEAN mode, this operator tests whether two or more words all start within a specified distance from each other, measured in words.\n searchHelpURL?: string\n /**\n * Optional function to provide autocomplete suggestions for the search bar.\n * When provided, the search input will show a dropdown of suggestions as the user types.\n * @param searchText - The current text in the search input\n * @returns A promise resolving to an array of suggestion strings\n */\n getSuggestions?: (searchText: string) => Promise<string[]>\n}\n\ntype InternalSearchProps = SearchV2Props & {\n columnModels: ColumnModel[] | undefined\n}\n\nclass _Search extends Component<InternalSearchProps, SearchState> {\n public searchFormRef: RefObject<HTMLFormElement | null>\n public radioFormRef: RefObject<HTMLFormElement | null>\n\n constructor(props: InternalSearchProps) {\n super(props)\n this.state = {\n show: false,\n didUpdateRanLast: false,\n searchText: '',\n columnName: this.props.defaultColumn ?? '',\n }\n this.searchFormRef = createRef()\n this.radioFormRef = createRef()\n }\n\n componentDidMount() {\n // @ts-expect-error\n document.addEventListener('click', this.handleClickOutsideForm)\n }\n\n componentDidUpdate(prevProps: InternalSearchProps) {\n if (\n !prevProps.queryVisualizationContext?.showSearchBar &&\n this.props.queryVisualizationContext?.showSearchBar\n ) {\n this.setState({\n show: true,\n didUpdateRanLast: true,\n })\n this.searchFormRef?.current?.querySelector('input')?.focus()\n }\n }\n\n componentWillUnmount() {\n // @ts-expect-error\n document.removeEventListener('click', this.handleClickOutsideForm)\n }\n\n handleClickOutsideForm = (event: SyntheticEvent) => {\n if (\n // @ts-expect-error\n !this.searchFormRef.current?.contains(event?.target) &&\n // @ts-expect-error\n !this.radioFormRef.current?.contains(event?.target)\n ) {\n if (this.state.didUpdateRanLast) {\n this.setState({\n didUpdateRanLast: false,\n })\n } else {\n this.setState({\n show: false,\n })\n }\n }\n }\n\n public search = (event: SyntheticEvent<HTMLFormElement>) => {\n // form completion by default causes the page to reload, so we prevent that\n event.preventDefault()\n const { searchText } = this.state\n let { columnName } = this.state\n const { searchable, lockedColumn } = this.props\n if (columnName === '') {\n if (searchable) {\n // If searchable column names are defined in the config, grab the first one (that is not locked)\n columnName = searchable.filter(\n colName => colName !== lockedColumn?.columnName,\n )[0]\n } else {\n // Otherwise, get the first column model that can be searched.\n // And for study details page: if lockedColumn is defined, remove it from the search\n const searchableColumnModels = this.props.columnModels\n ?.filter(el => el.name !== lockedColumn?.columnName)\n .filter(el => this.isSupportedColumn(el))\n columnName = searchableColumnModels?.[0].name ?? ''\n }\n }\n this.setState({\n show: false,\n })\n const { executeQueryRequest, getCurrentQueryRequest } =\n this.props.queryContext\n\n const lastQueryRequestDeepClone = getCurrentQueryRequest()\n\n const { additionalFilters = [] } = lastQueryRequestDeepClone.query\n\n const indexOfColumn = additionalFilters.findIndex((el: QueryFilter) => {\n if (\n isColumnSingleValueQueryFilter(el) ||\n (isColumnMultiValueFunctionQueryFilter(el) &&\n el.columnName === columnName)\n ) {\n return true\n }\n return false\n })\n if (indexOfColumn === -1) {\n // get the column model to figure out what kind of filter we should apply.\n const columnModel: ColumnModel | undefined =\n this.props.columnModels?.filter(el => el.name === columnName)[0]\n if (columnModel?.columnType.endsWith('_LIST')) {\n const columnMultiValueQueryFilter: ColumnMultiValueFunctionQueryFilter =\n {\n columnName,\n function: ColumnMultiValueFunction.HAS_LIKE,\n _function: ColumnMultiValueFunction.HAS_LIKE,\n values: [`%${searchText}%`],\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnMultiValueFunctionQueryFilter',\n }\n additionalFilters.push(columnMultiValueQueryFilter)\n } else {\n if (columnModel?.columnType == ColumnTypeEnum.ENTITYID) {\n const columnSingleValueQueryFilter: ColumnSingleValueQueryFilter = {\n columnName,\n operator: ColumnSingleValueFilterOperator.EQUAL,\n values: [`${searchText.toLowerCase().replace('syn', '')}`],\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n }\n additionalFilters.push(columnSingleValueQueryFilter)\n } else {\n const columnSingleValueQueryFilter: ColumnSingleValueQueryFilter = {\n columnName,\n operator: ColumnSingleValueFilterOperator.LIKE,\n values: [`%${searchText}%`],\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n }\n additionalFilters.push(columnSingleValueQueryFilter)\n }\n }\n } else {\n ;(\n additionalFilters[indexOfColumn] as\n | ColumnSingleValueQueryFilter\n | ColumnMultiValueFunctionQueryFilter\n ).values.push(`%${searchText}%`)\n }\n lastQueryRequestDeepClone.query.additionalFilters = additionalFilters\n executeQueryRequest(lastQueryRequestDeepClone)\n }\n\n public handleChange = (event: FormEvent<HTMLInputElement>) => {\n this.setState({\n searchText: event.currentTarget.value,\n })\n }\n\n public isSupportedColumn = (columnModel?: ColumnModel) => {\n switch (columnModel?.columnType) {\n case ColumnTypeEnum.FILEHANDLEID:\n case ColumnTypeEnum.DATE:\n case ColumnTypeEnum.DATE_LIST:\n case ColumnTypeEnum.USERID:\n // case ColumnTypeEnum.ENTITYID: //PORTALS-2995: users may want to search on Synapse ID\n return false\n default:\n return true\n }\n }\n\n public isSupportedColumnAndInProps = (columnModel?: ColumnModel) => {\n if (this.isSupportedColumn(columnModel)) {\n // return true if the searchable array contains this column name\n const { searchable } = this.props\n return searchable?.some(e => e === columnModel?.name)\n }\n return false\n }\n\n render() {\n const {\n searchable,\n lockedColumn,\n columnModels,\n queryVisualizationContext: { showSearchBar, getColumnDisplayName },\n } = this.props\n const { searchText, show, columnName } = this.state\n let searchColumns: string[] = []\n\n // searchable specifies the order of the columns to search\n if (searchable) {\n searchColumns = searchable\n .map(el => columnModels?.find(model => model.name === el))\n .filter(this.isSupportedColumnAndInProps)\n .map(el => el!.name)\n } else if (columnModels) {\n searchColumns = columnModels\n ?.filter(this.isSupportedColumn)\n .map(el => el.name)\n }\n\n // For study details page: if lockedColumn is defined, remove it from the radio dropdown\n if (searchColumns.length && lockedColumn?.columnName) {\n searchColumns = searchColumns.filter(\n el => el !== lockedColumn?.columnName,\n )\n }\n return (\n <div className={`QueryWrapperSearchInput`}>\n <Collapse in={showSearchBar}>\n <form\n className=\"QueryWrapperSearchInput__searchbar\"\n onSubmit={this.search}\n onClick={() => {\n this.setState({ show: true })\n }}\n ref={this.searchFormRef}\n >\n <span className=\"QueryWrapperSearchInput__searchbar__searchicon\">\n <IconSvg icon=\"search\" />\n </span>\n <input\n onChange={this.handleChange}\n onClick={() => {\n this.setState({\n show: true,\n })\n }}\n placeholder=\"Enter Search Terms\"\n value={searchText}\n type=\"text\"\n />\n {this.state.searchText.length > 0 && (\n <button\n className=\"QueryWrapperSearchInput__searchbar__clearbutton\"\n type=\"button\"\n onClick={() => {\n this.setState({\n searchText: '',\n })\n }}\n >\n <IconSvg icon=\"close\" />\n </button>\n )}\n </form>\n </Collapse>\n <div className=\"QueryWrapperSearchInput__dropdown_pos\">\n <CSSTransition\n nodeRef={this.radioFormRef}\n in={show}\n classNames=\"QueryWrapperSearchInput__animate_dropdown\"\n timeout={{ enter: 0, exit: 300 }}\n >\n <form\n ref={this.radioFormRef}\n className=\"QueryWrapperSearchInput__column-select QueryWrapperSearchInput__animate_height\"\n >\n <p className=\"deemphasized\">\n <i> Search In Field: </i>\n </p>\n {searchColumns.map((name, index) => {\n const displayName = getColumnDisplayName(name)\n const isSelected =\n (columnName === '' && index === 0) || columnName === name\n return (\n <div className=\"radio\" key={`search-field-${name}-${index}`}>\n <label>\n <span>\n <input\n id={name}\n type=\"radio\"\n value={name}\n checked={isSelected}\n onClick={() => {\n this.searchFormRef?.current\n ?.querySelector('input')\n ?.focus()\n this.setState({\n columnName: name,\n })\n }}\n />\n <span>{displayName}</span>\n </span>\n </label>\n </div>\n )\n })}\n </form>\n </CSSTransition>\n </div>\n </div>\n )\n }\n}\n\nexport default function Search(props: SearchV2Props) {\n const { data: queryMetadata } = useGetQueryMetadata()\n return <_Search {...props} columnModels={queryMetadata?.columnModels} />\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"SearchV2.js","names":[],"sources":["../../../src/components/SynapseTable/SearchV2.tsx"],"sourcesContent":["import {\n isColumnMultiValueFunctionQueryFilter,\n isColumnSingleValueQueryFilter,\n LockedColumn,\n} from '@/utils'\nimport { Collapse } from '@mui/material'\nimport {\n ColumnModel,\n ColumnMultiValueFunction,\n ColumnMultiValueFunctionQueryFilter,\n ColumnSingleValueFilterOperator,\n ColumnSingleValueQueryFilter,\n ColumnTypeEnum,\n QueryFilter,\n} from '@sage-bionetworks/synapse-types'\nimport {\n Component,\n createRef,\n FormEvent,\n RefObject,\n SyntheticEvent,\n} from 'react'\nimport { CSSTransition } from 'react-transition-group'\nimport IconSvg from '../IconSvg/IconSvg'\nimport { QueryContextType } from '../QueryContext'\nimport { QueryVisualizationContextType } from '../QueryVisualizationWrapper'\nimport { useGetQueryMetadata } from '../QueryWrapper/useGetQueryMetadata'\nimport { ReadonlyDeep } from 'type-fest'\n\ntype SearchState = {\n show: boolean\n /* \n When the component is revealed in queryplotnav we want to focus on the input field and reveal the dropdown\n there is an issue where the method handleClickOutsideForm will override the state from componentDidUpdate\n so we track when componentDidUpdate just fired so that `show` is not overriden on the click event which\n triggers componentDidUpdate \n */\n didUpdateRanLast: boolean\n searchText: string\n columnName: string\n}\n\nexport type SearchableColumnsV2 = string[]\n\nexport type SearchV2Props = {\n queryContext: QueryContextType\n queryVisualizationContext: QueryVisualizationContextType\n isQueryWrapperMenuChild?: boolean\n defaultColumn?: string\n searchable?: SearchableColumnsV2\n lockedColumn?: LockedColumn\n /**\n * PLFM-8897, PORTALS-3534: Full-Text Search configuration.\n * For Tables that have FTS enabled...\n * If specified, use the specified mode and distance (if BOOLEAN mode). Otherwise default to NATURAL_LANGUAGE mode.\n */\n ftsConfig?: ReadonlyDeep<FTSConfig>\n}\n\nexport type TextMatchesMode = 'NATURAL_LANGUAGE' | 'BOOLEAN'\nexport type FTSConfig = {\n textMatchesMode: TextMatchesMode\n distance?: number // In BOOLEAN mode, this operator tests whether two or more words all start within a specified distance from each other, measured in words.\n searchHelpURL?: string\n /**\n * Optional function to provide autocomplete suggestions for the search bar.\n * When provided, the search input will show a dropdown of suggestions as the user types.\n * @param searchText - The current text in the search input\n * @returns A promise resolving to an array of suggestion strings\n */\n getSuggestions?: (searchText: string) => Promise<string[]>\n /**\n * Override the minimum number of characters required before a search is executed.\n * Defaults to 3 (see PLFM-7011).\n */\n minSearchQueryLength?: number\n /**\n * When true, submitting a new search term replaces any existing TextMatchesQueryFilter\n * in additionalFilters rather than appending a new one.\n * Defaults to false (existing behaviour: filters accumulate).\n */\n replaceExistingFilter?: boolean\n}\n\ntype InternalSearchProps = SearchV2Props & {\n columnModels: ColumnModel[] | undefined\n}\n\nclass _Search extends Component<InternalSearchProps, SearchState> {\n public searchFormRef: RefObject<HTMLFormElement | null>\n public radioFormRef: RefObject<HTMLFormElement | null>\n\n constructor(props: InternalSearchProps) {\n super(props)\n this.state = {\n show: false,\n didUpdateRanLast: false,\n searchText: '',\n columnName: this.props.defaultColumn ?? '',\n }\n this.searchFormRef = createRef()\n this.radioFormRef = createRef()\n }\n\n componentDidMount() {\n // @ts-expect-error\n document.addEventListener('click', this.handleClickOutsideForm)\n }\n\n componentDidUpdate(prevProps: InternalSearchProps) {\n if (\n !prevProps.queryVisualizationContext?.showSearchBar &&\n this.props.queryVisualizationContext?.showSearchBar\n ) {\n this.setState({\n show: true,\n didUpdateRanLast: true,\n })\n this.searchFormRef?.current?.querySelector('input')?.focus()\n }\n }\n\n componentWillUnmount() {\n // @ts-expect-error\n document.removeEventListener('click', this.handleClickOutsideForm)\n }\n\n handleClickOutsideForm = (event: SyntheticEvent) => {\n if (\n // @ts-expect-error\n !this.searchFormRef.current?.contains(event?.target) &&\n // @ts-expect-error\n !this.radioFormRef.current?.contains(event?.target)\n ) {\n if (this.state.didUpdateRanLast) {\n this.setState({\n didUpdateRanLast: false,\n })\n } else {\n this.setState({\n show: false,\n })\n }\n }\n }\n\n public search = (event: SyntheticEvent<HTMLFormElement>) => {\n // form completion by default causes the page to reload, so we prevent that\n event.preventDefault()\n const { searchText } = this.state\n let { columnName } = this.state\n const { searchable, lockedColumn } = this.props\n if (columnName === '') {\n if (searchable) {\n // If searchable column names are defined in the config, grab the first one (that is not locked)\n columnName = searchable.filter(\n colName => colName !== lockedColumn?.columnName,\n )[0]\n } else {\n // Otherwise, get the first column model that can be searched.\n // And for study details page: if lockedColumn is defined, remove it from the search\n const searchableColumnModels = this.props.columnModels\n ?.filter(el => el.name !== lockedColumn?.columnName)\n .filter(el => this.isSupportedColumn(el))\n columnName = searchableColumnModels?.[0].name ?? ''\n }\n }\n this.setState({\n show: false,\n })\n const { executeQueryRequest, getCurrentQueryRequest } =\n this.props.queryContext\n\n const lastQueryRequestDeepClone = getCurrentQueryRequest()\n\n const { additionalFilters = [] } = lastQueryRequestDeepClone.query\n\n const indexOfColumn = additionalFilters.findIndex((el: QueryFilter) => {\n if (\n isColumnSingleValueQueryFilter(el) ||\n (isColumnMultiValueFunctionQueryFilter(el) &&\n el.columnName === columnName)\n ) {\n return true\n }\n return false\n })\n if (indexOfColumn === -1) {\n // get the column model to figure out what kind of filter we should apply.\n const columnModel: ColumnModel | undefined =\n this.props.columnModels?.filter(el => el.name === columnName)[0]\n if (columnModel?.columnType.endsWith('_LIST')) {\n const columnMultiValueQueryFilter: ColumnMultiValueFunctionQueryFilter =\n {\n columnName,\n function: ColumnMultiValueFunction.HAS_LIKE,\n _function: ColumnMultiValueFunction.HAS_LIKE,\n values: [`%${searchText}%`],\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnMultiValueFunctionQueryFilter',\n }\n additionalFilters.push(columnMultiValueQueryFilter)\n } else {\n if (columnModel?.columnType == ColumnTypeEnum.ENTITYID) {\n const columnSingleValueQueryFilter: ColumnSingleValueQueryFilter = {\n columnName,\n operator: ColumnSingleValueFilterOperator.EQUAL,\n values: [`${searchText.toLowerCase().replace('syn', '')}`],\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n }\n additionalFilters.push(columnSingleValueQueryFilter)\n } else {\n const columnSingleValueQueryFilter: ColumnSingleValueQueryFilter = {\n columnName,\n operator: ColumnSingleValueFilterOperator.LIKE,\n values: [`%${searchText}%`],\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n }\n additionalFilters.push(columnSingleValueQueryFilter)\n }\n }\n } else {\n ;(\n additionalFilters[indexOfColumn] as\n | ColumnSingleValueQueryFilter\n | ColumnMultiValueFunctionQueryFilter\n ).values.push(`%${searchText}%`)\n }\n lastQueryRequestDeepClone.query.additionalFilters = additionalFilters\n executeQueryRequest(lastQueryRequestDeepClone)\n }\n\n public handleChange = (event: FormEvent<HTMLInputElement>) => {\n this.setState({\n searchText: event.currentTarget.value,\n })\n }\n\n public isSupportedColumn = (columnModel?: ColumnModel) => {\n switch (columnModel?.columnType) {\n case ColumnTypeEnum.FILEHANDLEID:\n case ColumnTypeEnum.DATE:\n case ColumnTypeEnum.DATE_LIST:\n case ColumnTypeEnum.USERID:\n // case ColumnTypeEnum.ENTITYID: //PORTALS-2995: users may want to search on Synapse ID\n return false\n default:\n return true\n }\n }\n\n public isSupportedColumnAndInProps = (columnModel?: ColumnModel) => {\n if (this.isSupportedColumn(columnModel)) {\n // return true if the searchable array contains this column name\n const { searchable } = this.props\n return searchable?.some(e => e === columnModel?.name)\n }\n return false\n }\n\n render() {\n const {\n searchable,\n lockedColumn,\n columnModels,\n queryVisualizationContext: { showSearchBar, getColumnDisplayName },\n } = this.props\n const { searchText, show, columnName } = this.state\n let searchColumns: string[] = []\n\n // searchable specifies the order of the columns to search\n if (searchable) {\n searchColumns = searchable\n .map(el => columnModels?.find(model => model.name === el))\n .filter(this.isSupportedColumnAndInProps)\n .map(el => el!.name)\n } else if (columnModels) {\n searchColumns = columnModels\n ?.filter(this.isSupportedColumn)\n .map(el => el.name)\n }\n\n // For study details page: if lockedColumn is defined, remove it from the radio dropdown\n if (searchColumns.length && lockedColumn?.columnName) {\n searchColumns = searchColumns.filter(\n el => el !== lockedColumn?.columnName,\n )\n }\n return (\n <div className={`QueryWrapperSearchInput`}>\n <Collapse in={showSearchBar}>\n <form\n className=\"QueryWrapperSearchInput__searchbar\"\n onSubmit={this.search}\n onClick={() => {\n this.setState({ show: true })\n }}\n ref={this.searchFormRef}\n >\n <span className=\"QueryWrapperSearchInput__searchbar__searchicon\">\n <IconSvg icon=\"search\" />\n </span>\n <input\n onChange={this.handleChange}\n onClick={() => {\n this.setState({\n show: true,\n })\n }}\n placeholder=\"Enter Search Terms\"\n value={searchText}\n type=\"text\"\n />\n {this.state.searchText.length > 0 && (\n <button\n className=\"QueryWrapperSearchInput__searchbar__clearbutton\"\n type=\"button\"\n onClick={() => {\n this.setState({\n searchText: '',\n })\n }}\n >\n <IconSvg icon=\"close\" />\n </button>\n )}\n </form>\n </Collapse>\n <div className=\"QueryWrapperSearchInput__dropdown_pos\">\n <CSSTransition\n nodeRef={this.radioFormRef}\n in={show}\n classNames=\"QueryWrapperSearchInput__animate_dropdown\"\n timeout={{ enter: 0, exit: 300 }}\n >\n <form\n ref={this.radioFormRef}\n className=\"QueryWrapperSearchInput__column-select QueryWrapperSearchInput__animate_height\"\n >\n <p className=\"deemphasized\">\n <i> Search In Field: </i>\n </p>\n {searchColumns.map((name, index) => {\n const displayName = getColumnDisplayName(name)\n const isSelected =\n (columnName === '' && index === 0) || columnName === name\n return (\n <div className=\"radio\" key={`search-field-${name}-${index}`}>\n <label>\n <span>\n <input\n id={name}\n type=\"radio\"\n value={name}\n checked={isSelected}\n onClick={() => {\n this.searchFormRef?.current\n ?.querySelector('input')\n ?.focus()\n this.setState({\n columnName: name,\n })\n }}\n />\n <span>{displayName}</span>\n </span>\n </label>\n </div>\n )\n })}\n </form>\n </CSSTransition>\n </div>\n </div>\n )\n }\n}\n\nexport default function Search(props: SearchV2Props) {\n const { data: queryMetadata } = useGetQueryMetadata()\n return <_Search {...props} columnModels={queryMetadata?.columnModels} />\n}\n"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ ._chip_1j1zq_1.MuiButton-root{border:1px solid var(--UI-Gray-500,#d0d4d9);color:#16181e;background:linear-gradient(127deg,#dcdcdc33 .7%,#ffffff14 100%);border-radius:500px;justify-content:center;align-items:center;gap:12px;padding:4px 12px 4px 5px;font-weight:500;text-decoration:none;display:flex}._chip_1j1zq_1.MuiButton-root .MuiButton-endIcon{color:#5a488f;margin:0}._categoryChip_1j1zq_19.MuiChip-root{color:#fff;background-color:#ee986d;border-radius:500px;padding:5px 8px 6px}._categorySkeleton_1j1zq_26{border-radius:5px}
@@ -0,0 +1,5 @@
1
+ export type WordPressLatestPostChipProps = {
2
+ wordpressSiteUrl: string;
3
+ };
4
+ export declare function WordPressLatestPostChip({ wordpressSiteUrl, }: WordPressLatestPostChipProps): import("react/jsx-runtime").JSX.Element | null;
5
+ //# sourceMappingURL=WordPressLatestPostChip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WordPressLatestPostChip.d.ts","sourceRoot":"","sources":["../../../src/components/WordPress/WordPressLatestPostChip.tsx"],"names":[],"mappings":"AAMA,MAAM,MAAM,4BAA4B,GAAG;IACzC,gBAAgB,EAAE,MAAM,CAAA;CACzB,CAAA;AAED,wBAAgB,uBAAuB,CAAC,EACtC,gBAAgB,GACjB,EAAE,4BAA4B,kDAsB9B"}
@@ -0,0 +1,29 @@
1
+ import { useWordPressCategories as e } from "./useWordPressCategories.js";
2
+ import { useWordPressPosts as t } from "./useWordPressPosts.js";
3
+ import n from "./WordPressLatestPostChip.module.js";
4
+ import { Button as r, Chip as i } from "@mui/material";
5
+ import { jsx as a, jsxs as o } from "react/jsx-runtime";
6
+ import s from "@mui/icons-material/ArrowForward";
7
+ //#region src/components/WordPress/WordPressLatestPostChip.tsx
8
+ function c({ wordpressSiteUrl: c }) {
9
+ let { data: l } = t(c, 1), { data: u } = e(c), d = l?.[0];
10
+ if (!d) return null;
11
+ let f = u?.find((e) => e.id === d.categories[0])?.name;
12
+ return /* @__PURE__ */ o(r, {
13
+ component: "a",
14
+ href: d.link,
15
+ target: "_blank",
16
+ rel: "noopener noreferrer",
17
+ className: n.chip,
18
+ endIcon: /* @__PURE__ */ a(s, {}),
19
+ children: [/* @__PURE__ */ a(i, {
20
+ label: f,
21
+ size: "small",
22
+ className: n.categoryChip
23
+ }), /* @__PURE__ */ a("span", { dangerouslySetInnerHTML: { __html: d.title.rendered } })]
24
+ });
25
+ }
26
+ //#endregion
27
+ export { c as WordPressLatestPostChip };
28
+
29
+ //# sourceMappingURL=WordPressLatestPostChip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WordPressLatestPostChip.js","names":[],"sources":["../../../src/components/WordPress/WordPressLatestPostChip.tsx"],"sourcesContent":["import { Button, Chip } from '@mui/material'\nimport ArrowForwardIcon from '@mui/icons-material/ArrowForward'\nimport { useWordPressCategories } from './useWordPressCategories'\nimport { useWordPressPosts } from './useWordPressPosts'\nimport styles from './WordPressLatestPostChip.module.scss'\n\nexport type WordPressLatestPostChipProps = {\n wordpressSiteUrl: string\n}\n\nexport function WordPressLatestPostChip({\n wordpressSiteUrl,\n}: WordPressLatestPostChipProps) {\n const { data: posts } = useWordPressPosts(wordpressSiteUrl, 1)\n const { data: categories } = useWordPressCategories(wordpressSiteUrl)\n\n const post = posts?.[0]\n if (!post) return null\n\n const categoryName = categories?.find(c => c.id === post.categories[0])?.name\n\n return (\n <Button\n component=\"a\"\n href={post.link}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={styles.chip}\n endIcon={<ArrowForwardIcon />}\n >\n <Chip label={categoryName} size=\"small\" className={styles.categoryChip} />\n <span dangerouslySetInnerHTML={{ __html: post.title.rendered }} />\n </Button>\n )\n}\n"],"mappings":";;;;;;;AAUA,SAAgB,EAAwB,EACtC,uBAC+B;CAC/B,IAAM,EAAE,MAAM,MAAU,EAAkB,GAAkB,EAAE,EACxD,EAAE,MAAM,MAAe,EAAuB,EAAiB,EAE/D,IAAO,IAAQ;AACrB,KAAI,CAAC,EAAM,QAAO;CAElB,IAAM,IAAe,GAAY,MAAK,MAAK,EAAE,OAAO,EAAK,WAAW,GAAG,EAAE;AAEzE,QACE,kBAAC,GAAD;EACE,WAAU;EACV,MAAM,EAAK;EACX,QAAO;EACP,KAAI;EACJ,WAAW,EAAO;EAClB,SAAS,kBAAC,GAAD,EAAoB,CAAA;YAN/B,CAQE,kBAAC,GAAD;GAAM,OAAO;GAAc,MAAK;GAAQ,WAAW,EAAO;GAAgB,CAAA,EAC1E,kBAAC,QAAD,EAAM,yBAAyB,EAAE,QAAQ,EAAK,MAAM,UAAU,EAAI,CAAA,CAC3D"}
@@ -0,0 +1,9 @@
1
+ import './WordPressLatestPostChip.css';var e = {
2
+ chip: "_chip_1j1zq_1",
3
+ categoryChip: "_categoryChip_1j1zq_19",
4
+ categorySkeleton: "_categorySkeleton_1j1zq_26"
5
+ };
6
+ //#endregion
7
+ export { e as default };
8
+
9
+ //# sourceMappingURL=WordPressLatestPostChip.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WordPressLatestPostChip.module.js","names":[],"sources":["../../../src/components/WordPress/WordPressLatestPostChip.module.scss"],"sourcesContent":[".chip:global(.MuiButton-root) {\n display: flex;\n padding: 4px 12px 4px 5px;\n justify-content: center;\n align-items: center;\n gap: 12px;\n border-radius: 500px;\n border: 1px solid var(--UI-Gray-500, #d0d4d9);\n background: linear-gradient(\n 127deg,\n rgba(220, 220, 220, 0.2) 0.7%,\n rgba(255, 255, 255, 0.08) 100%\n );\n color: #16181e;\n font-weight: 500;\n text-decoration: none;\n\n :global(.MuiButton-endIcon) {\n margin: 0;\n color: #5a488f;\n }\n}\n\n.categoryChip:global(.MuiChip-root) {\n background-color: #ee986d;\n color: #fff;\n border-radius: 500px;\n padding: 5px 8px 6px 8px;\n}\n\n.categorySkeleton {\n border-radius: 5px;\n}\n"],"mappings":""}
@@ -0,0 +1,33 @@
1
+ .chip:global(.MuiButton-root) {
2
+ display: flex;
3
+ padding: 4px 12px 4px 5px;
4
+ justify-content: center;
5
+ align-items: center;
6
+ gap: 12px;
7
+ border-radius: 500px;
8
+ border: 1px solid var(--UI-Gray-500, #d0d4d9);
9
+ background: linear-gradient(
10
+ 127deg,
11
+ rgba(220, 220, 220, 0.2) 0.7%,
12
+ rgba(255, 255, 255, 0.08) 100%
13
+ );
14
+ color: #16181e;
15
+ font-weight: 500;
16
+ text-decoration: none;
17
+
18
+ :global(.MuiButton-endIcon) {
19
+ margin: 0;
20
+ color: #5a488f;
21
+ }
22
+ }
23
+
24
+ .categoryChip:global(.MuiChip-root) {
25
+ background-color: #ee986d;
26
+ color: #fff;
27
+ border-radius: 500px;
28
+ padding: 5px 8px 6px 8px;
29
+ }
30
+
31
+ .categorySkeleton {
32
+ border-radius: 5px;
33
+ }
@@ -0,0 +1,3 @@
1
+ import { WordPressCategory } from '../SynapseHomepageV2/WordPressNewsItem';
2
+ export declare function useWordPressCategories(wordpressSiteUrl: string): import("@tanstack/react-query").UseQueryResult<WordPressCategory[], Error>;
3
+ //# sourceMappingURL=useWordPressCategories.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useWordPressCategories.d.ts","sourceRoot":"","sources":["../../../src/components/WordPress/useWordPressCategories.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAA;AAgB1E,wBAAgB,sBAAsB,CAAC,gBAAgB,EAAE,MAAM,8EAK9D"}
@@ -0,0 +1,19 @@
1
+ import { useQuery as e } from "@tanstack/react-query";
2
+ //#region src/components/WordPress/useWordPressCategories.ts
3
+ async function t(e) {
4
+ let t = new URL(`${e}/wp-json/wp/v2/categories`);
5
+ t.searchParams.set("_fields", "id,name,slug");
6
+ let n = await fetch(t.toString());
7
+ if (!n.ok) throw Error(`Failed to fetch WordPress categories: ${n.statusText}`);
8
+ return n.json();
9
+ }
10
+ function n(n) {
11
+ return e({
12
+ queryKey: ["wordpressCategories", n],
13
+ queryFn: () => t(n)
14
+ });
15
+ }
16
+ //#endregion
17
+ export { n as useWordPressCategories };
18
+
19
+ //# sourceMappingURL=useWordPressCategories.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useWordPressCategories.js","names":[],"sources":["../../../src/components/WordPress/useWordPressCategories.ts"],"sourcesContent":["import { useQuery } from '@tanstack/react-query'\nimport { WordPressCategory } from '../SynapseHomepageV2/WordPressNewsItem'\n\nasync function fetchWordPressCategories(\n wordpressSiteUrl: string,\n): Promise<WordPressCategory[]> {\n const url = new URL(`${wordpressSiteUrl}/wp-json/wp/v2/categories`)\n url.searchParams.set('_fields', 'id,name,slug')\n const response = await fetch(url.toString())\n if (!response.ok) {\n throw new Error(\n `Failed to fetch WordPress categories: ${response.statusText}`,\n )\n }\n return response.json() as Promise<WordPressCategory[]>\n}\n\nexport function useWordPressCategories(wordpressSiteUrl: string) {\n return useQuery({\n queryKey: ['wordpressCategories', wordpressSiteUrl],\n queryFn: () => fetchWordPressCategories(wordpressSiteUrl),\n })\n}\n"],"mappings":";;AAGA,eAAe,EACb,GAC8B;CAC9B,IAAM,IAAM,IAAI,IAAI,GAAG,EAAiB,2BAA2B;AACnE,GAAI,aAAa,IAAI,WAAW,eAAe;CAC/C,IAAM,IAAW,MAAM,MAAM,EAAI,UAAU,CAAC;AAC5C,KAAI,CAAC,EAAS,GACZ,OAAU,MACR,yCAAyC,EAAS,aACnD;AAEH,QAAO,EAAS,MAAM;;AAGxB,SAAgB,EAAuB,GAA0B;AAC/D,QAAO,EAAS;EACd,UAAU,CAAC,uBAAuB,EAAiB;EACnD,eAAe,EAAyB,EAAiB;EAC1D,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { WordPressPost } from '../SynapseHomepageV2/WordPressNewsItem';
2
+ export declare function useWordPressPosts(wordpressSiteUrl: string, postCount: number): import("@tanstack/react-query").UseQueryResult<WordPressPost[], Error>;
3
+ //# sourceMappingURL=useWordPressPosts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useWordPressPosts.d.ts","sourceRoot":"","sources":["../../../src/components/WordPress/useWordPressPosts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAkBtE,wBAAgB,iBAAiB,CAAC,gBAAgB,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,0EAK5E"}
@@ -0,0 +1,23 @@
1
+ import { useQuery as e } from "@tanstack/react-query";
2
+ //#region src/components/WordPress/useWordPressPosts.ts
3
+ async function t(e, t) {
4
+ let n = new URL(`${e}/wp-json/wp/v2/posts`);
5
+ n.searchParams.set("per_page", String(t)), n.searchParams.set("orderby", "date"), n.searchParams.set("order", "desc"), n.searchParams.set("_fields", "id,date,link,title,categories");
6
+ let r = await fetch(n.toString());
7
+ if (!r.ok) throw Error(`Failed to fetch WordPress posts: ${r.statusText}`);
8
+ return r.json();
9
+ }
10
+ function n(n, r) {
11
+ return e({
12
+ queryKey: [
13
+ "wordpressPosts",
14
+ n,
15
+ r
16
+ ],
17
+ queryFn: () => t(n, r)
18
+ });
19
+ }
20
+ //#endregion
21
+ export { n as useWordPressPosts };
22
+
23
+ //# sourceMappingURL=useWordPressPosts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useWordPressPosts.js","names":[],"sources":["../../../src/components/WordPress/useWordPressPosts.ts"],"sourcesContent":["import { useQuery } from '@tanstack/react-query'\nimport { WordPressPost } from '../SynapseHomepageV2/WordPressNewsItem'\n\nasync function fetchWordPressPosts(\n wordpressSiteUrl: string,\n postCount: number,\n): Promise<WordPressPost[]> {\n const url = new URL(`${wordpressSiteUrl}/wp-json/wp/v2/posts`)\n url.searchParams.set('per_page', String(postCount))\n url.searchParams.set('orderby', 'date')\n url.searchParams.set('order', 'desc')\n url.searchParams.set('_fields', 'id,date,link,title,categories')\n const response = await fetch(url.toString())\n if (!response.ok) {\n throw new Error(`Failed to fetch WordPress posts: ${response.statusText}`)\n }\n return response.json() as Promise<WordPressPost[]>\n}\n\nexport function useWordPressPosts(wordpressSiteUrl: string, postCount: number) {\n return useQuery({\n queryKey: ['wordpressPosts', wordpressSiteUrl, postCount],\n queryFn: () => fetchWordPressPosts(wordpressSiteUrl, postCount),\n })\n}\n"],"mappings":";;AAGA,eAAe,EACb,GACA,GAC0B;CAC1B,IAAM,IAAM,IAAI,IAAI,GAAG,EAAiB,sBAAsB;AAI9D,CAHA,EAAI,aAAa,IAAI,YAAY,OAAO,EAAU,CAAC,EACnD,EAAI,aAAa,IAAI,WAAW,OAAO,EACvC,EAAI,aAAa,IAAI,SAAS,OAAO,EACrC,EAAI,aAAa,IAAI,WAAW,gCAAgC;CAChE,IAAM,IAAW,MAAM,MAAM,EAAI,UAAU,CAAC;AAC5C,KAAI,CAAC,EAAS,GACZ,OAAU,MAAM,oCAAoC,EAAS,aAAa;AAE5E,QAAO,EAAS,MAAM;;AAGxB,SAAgB,EAAkB,GAA0B,GAAmB;AAC7E,QAAO,EAAS;EACd,UAAU;GAAC;GAAkB;GAAkB;GAAU;EACzD,eAAe,EAAoB,GAAkB,EAAU;EAChE,CAAC"}
@@ -11,7 +11,7 @@ import { jsx as d, jsxs as f } from "react/jsx-runtime";
11
11
  import p from "classnames";
12
12
  //#region src/features/curator/dashboard/components/CurationTaskCard.tsx
13
13
  function m(t) {
14
- let { onClick: r, isLoading: i, isPending: a, hasPermission: o } = n(t.task);
14
+ let { onClick: r, isLoading: i, isPending: a, hasPermission: o } = n(t);
15
15
  if (!t.task || !t.status) throw Error("Task bundle is missing required properties");
16
16
  switch (t.task?.taskProperties?.concreteType) {
17
17
  case "org.sagebionetworks.repo.model.curation.metadata.FileBasedMetadataTaskProperties":
@@ -1 +1 @@
1
- {"version":3,"file":"CurationTaskCard.js","names":[],"sources":["../../../../../src/features/curator/dashboard/components/CurationTaskCard.tsx"],"sourcesContent":["import { displayToast } from '@/components'\nimport useOpenCuratorFromTaskButton from '@/features/entity/metadata-task/hooks/useOpenCuratorButton'\nimport { OPEN_CURATOR_NO_PERMISSION_ON_SOURCE_ERROR_MESSAGE } from '@/features/entity/metadata-task/utils/constants'\nimport { Card, Chip, Divider, Typography } from '@mui/material'\nimport { TaskBundle } from '@sage-bionetworks/synapse-client'\nimport classNames from 'classnames'\nimport styles from './CurationTaskCard.module.scss'\nimport NextStepButton from './NextStepButton'\nimport sharedStyles from './shared.module.scss'\nimport UserOrTeamChip from './UserOrTeamChip'\n\nexport type CurationTaskCardProps = {\n taskBundle: TaskBundle\n}\n\nfunction useUiForTask(taskBundle: TaskBundle) {\n const { onClick, isLoading, isPending, hasPermission } =\n useOpenCuratorFromTaskButton(taskBundle.task!)\n\n if (!taskBundle.task || !taskBundle.status) {\n throw new Error('Task bundle is missing required properties')\n }\n\n switch (taskBundle.task?.taskProperties?.concreteType) {\n case 'org.sagebionetworks.repo.model.curation.metadata.FileBasedMetadataTaskProperties':\n case 'org.sagebionetworks.repo.model.curation.metadata.RecordBasedMetadataTaskProperties':\n return {\n title: taskBundle.task.dataType,\n description: taskBundle.task.instructions ?? '',\n principalIds: taskBundle.task.assigneePrincipalId\n ? [taskBundle.task.assigneePrincipalId]\n : [],\n buttonText: 'Open Curator',\n taskType: 'Curate Data',\n onClickNextStep: onClick,\n isLoading,\n isPending,\n hasPermission,\n }\n default: {\n console.error(\n 'No UI implemented for task type: ' +\n // @ts-expect-error - the switch should be exhaustive for known types\n taskBundle.task?.taskProperties?.concreteType,\n )\n }\n }\n\n return {\n title: taskBundle.task.dataType,\n description: taskBundle.task.instructions ?? '',\n principalIds: taskBundle.task.assigneePrincipalId\n ? [taskBundle.task.assigneePrincipalId]\n : [],\n buttonText: 'Continue',\n taskType: '',\n onClickNextStep: () => {\n displayToast('No action defined for this task type', 'danger', {\n title: 'Unexpected Error',\n })\n },\n isLoading: false,\n isPending: false,\n hasPermission: undefined,\n }\n}\n\nfunction TaskTypeChip(props: { label: string }) {\n const { label } = props\n return (\n <Chip sx={{ fontWeight: 600, backgroundColor: '#BFD3ED' }} label={label} />\n )\n}\n\n/**\n * Card component for displaying a curation task on the curator dashboard. Shows relevant information about the task and includes a button to proceed to the next step in the workflow.\n */\nexport default function CurationTaskCard(props: CurationTaskCardProps) {\n const { taskBundle } = props\n const {\n title,\n description,\n taskType,\n principalIds,\n buttonText,\n onClickNextStep,\n hasPermission,\n isLoading,\n isPending,\n } = useUiForTask(taskBundle)\n\n return (\n <Card className={classNames(sharedStyles.card, styles.card)}>\n <div className={styles.cardContent}>\n <div className={styles.mainContent}>\n <div className={styles.titleChipContainer}>\n <Typography variant=\"headline3\">{title}</Typography>\n {taskType && <TaskTypeChip label={taskType} />}\n </div>\n <Typography variant=\"body1\">{description}</Typography>\n <div className={styles.userChipContainer}>\n {principalIds.map(principalId => (\n <UserOrTeamChip key={principalId} principalId={principalId} />\n ))}\n </div>\n </div>\n <Divider\n orientation=\"vertical\"\n flexItem\n sx={{ display: { xs: 'none', md: 'block' } }}\n />\n <NextStepButton\n className={styles.cardButton}\n buttonText={buttonText}\n onClick={\n hasPermission\n ? onClickNextStep\n : () => {\n displayToast(\n OPEN_CURATOR_NO_PERMISSION_ON_SOURCE_ERROR_MESSAGE,\n 'danger',\n )\n }\n }\n disabled={isLoading}\n loading={isPending}\n />\n </div>\n </Card>\n )\n}\n"],"mappings":";;;;;;;;;;;;AAeA,SAAS,EAAa,GAAwB;CAC5C,IAAM,EAAE,YAAS,cAAW,cAAW,qBACrC,EAA6B,EAAW,KAAM;AAEhD,KAAI,CAAC,EAAW,QAAQ,CAAC,EAAW,OAClC,OAAU,MAAM,6CAA6C;AAG/D,SAAQ,EAAW,MAAM,gBAAgB,cAAzC;EACE,KAAK;EACL,KAAK,qFACH,QAAO;GACL,OAAO,EAAW,KAAK;GACvB,aAAa,EAAW,KAAK,gBAAgB;GAC7C,cAAc,EAAW,KAAK,sBAC1B,CAAC,EAAW,KAAK,oBAAoB,GACrC,EAAE;GACN,YAAY;GACZ,UAAU;GACV,iBAAiB;GACjB;GACA;GACA;GACD;EACH,QACE,SAAQ,MACN,sCAEE,EAAW,MAAM,gBAAgB,aACpC;;AAIL,QAAO;EACL,OAAO,EAAW,KAAK;EACvB,aAAa,EAAW,KAAK,gBAAgB;EAC7C,cAAc,EAAW,KAAK,sBAC1B,CAAC,EAAW,KAAK,oBAAoB,GACrC,EAAE;EACN,YAAY;EACZ,UAAU;EACV,uBAAuB;AACrB,KAAa,wCAAwC,UAAU,EAC7D,OAAO,oBACR,CAAC;;EAEJ,WAAW;EACX,WAAW;EACX,eAAe,KAAA;EAChB;;AAGH,SAAS,EAAa,GAA0B;CAC9C,IAAM,EAAE,aAAU;AAClB,QACE,kBAAC,GAAD;EAAM,IAAI;GAAE,YAAY;GAAK,iBAAiB;GAAW;EAAS;EAAS,CAAA;;AAO/E,SAAwB,EAAiB,GAA8B;CACrE,IAAM,EAAE,kBAAe,GACjB,EACJ,UACA,gBACA,aACA,iBACA,eACA,oBACA,kBACA,cACA,iBACE,EAAa,EAAW;AAE5B,QACE,kBAAC,GAAD;EAAM,WAAW,EAAW,EAAa,MAAM,EAAO,KAAK;YACzD,kBAAC,OAAD;GAAK,WAAW,EAAO;aAAvB;IACE,kBAAC,OAAD;KAAK,WAAW,EAAO;eAAvB;MACE,kBAAC,OAAD;OAAK,WAAW,EAAO;iBAAvB,CACE,kBAAC,GAAD;QAAY,SAAQ;kBAAa;QAAmB,CAAA,EACnD,KAAY,kBAAC,GAAD,EAAc,OAAO,GAAY,CAAA,CAC1C;;MACN,kBAAC,GAAD;OAAY,SAAQ;iBAAS;OAAyB,CAAA;MACtD,kBAAC,OAAD;OAAK,WAAW,EAAO;iBACpB,EAAa,KAAI,MAChB,kBAAC,GAAD,EAA+C,gBAAe,EAAzC,EAAyC,CAC9D;OACE,CAAA;MACF;;IACN,kBAAC,GAAD;KACE,aAAY;KACZ,UAAA;KACA,IAAI,EAAE,SAAS;MAAE,IAAI;MAAQ,IAAI;MAAS,EAAE;KAC5C,CAAA;IACF,kBAAC,GAAD;KACE,WAAW,EAAO;KACN;KACZ,SACE,IACI,UACM;AACJ,QACE,GACA,SACD;;KAGT,UAAU;KACV,SAAS;KACT,CAAA;IACE;;EACD,CAAA"}
1
+ {"version":3,"file":"CurationTaskCard.js","names":[],"sources":["../../../../../src/features/curator/dashboard/components/CurationTaskCard.tsx"],"sourcesContent":["import { displayToast } from '@/components'\nimport useOpenCuratorFromTaskButton from '@/features/entity/metadata-task/hooks/useOpenCuratorButton'\nimport { OPEN_CURATOR_NO_PERMISSION_ON_SOURCE_ERROR_MESSAGE } from '@/features/entity/metadata-task/utils/constants'\nimport { Card, Chip, Divider, Typography } from '@mui/material'\nimport { TaskBundle } from '@sage-bionetworks/synapse-client'\nimport classNames from 'classnames'\nimport styles from './CurationTaskCard.module.scss'\nimport NextStepButton from './NextStepButton'\nimport sharedStyles from './shared.module.scss'\nimport UserOrTeamChip from './UserOrTeamChip'\n\nexport type CurationTaskCardProps = {\n taskBundle: TaskBundle\n}\n\nfunction useUiForTask(taskBundle: TaskBundle) {\n const { onClick, isLoading, isPending, hasPermission } =\n useOpenCuratorFromTaskButton(taskBundle)\n\n if (!taskBundle.task || !taskBundle.status) {\n throw new Error('Task bundle is missing required properties')\n }\n\n switch (taskBundle.task?.taskProperties?.concreteType) {\n case 'org.sagebionetworks.repo.model.curation.metadata.FileBasedMetadataTaskProperties':\n case 'org.sagebionetworks.repo.model.curation.metadata.RecordBasedMetadataTaskProperties':\n return {\n title: taskBundle.task.dataType,\n description: taskBundle.task.instructions ?? '',\n principalIds: taskBundle.task.assigneePrincipalId\n ? [taskBundle.task.assigneePrincipalId]\n : [],\n buttonText: 'Open Curator',\n taskType: 'Curate Data',\n onClickNextStep: onClick,\n isLoading,\n isPending,\n hasPermission,\n }\n default: {\n console.error(\n 'No UI implemented for task type: ' +\n // @ts-expect-error - the switch should be exhaustive for known types\n taskBundle.task?.taskProperties?.concreteType,\n )\n }\n }\n\n return {\n title: taskBundle.task.dataType,\n description: taskBundle.task.instructions ?? '',\n principalIds: taskBundle.task.assigneePrincipalId\n ? [taskBundle.task.assigneePrincipalId]\n : [],\n buttonText: 'Continue',\n taskType: '',\n onClickNextStep: () => {\n displayToast('No action defined for this task type', 'danger', {\n title: 'Unexpected Error',\n })\n },\n isLoading: false,\n isPending: false,\n hasPermission: undefined,\n }\n}\n\nfunction TaskTypeChip(props: { label: string }) {\n const { label } = props\n return (\n <Chip sx={{ fontWeight: 600, backgroundColor: '#BFD3ED' }} label={label} />\n )\n}\n\n/**\n * Card component for displaying a curation task on the curator dashboard. Shows relevant information about the task and includes a button to proceed to the next step in the workflow.\n */\nexport default function CurationTaskCard(props: CurationTaskCardProps) {\n const { taskBundle } = props\n const {\n title,\n description,\n taskType,\n principalIds,\n buttonText,\n onClickNextStep,\n hasPermission,\n isLoading,\n isPending,\n } = useUiForTask(taskBundle)\n\n return (\n <Card className={classNames(sharedStyles.card, styles.card)}>\n <div className={styles.cardContent}>\n <div className={styles.mainContent}>\n <div className={styles.titleChipContainer}>\n <Typography variant=\"headline3\">{title}</Typography>\n {taskType && <TaskTypeChip label={taskType} />}\n </div>\n <Typography variant=\"body1\">{description}</Typography>\n <div className={styles.userChipContainer}>\n {principalIds.map(principalId => (\n <UserOrTeamChip key={principalId} principalId={principalId} />\n ))}\n </div>\n </div>\n <Divider\n orientation=\"vertical\"\n flexItem\n sx={{ display: { xs: 'none', md: 'block' } }}\n />\n <NextStepButton\n className={styles.cardButton}\n buttonText={buttonText}\n onClick={\n hasPermission\n ? onClickNextStep\n : () => {\n displayToast(\n OPEN_CURATOR_NO_PERMISSION_ON_SOURCE_ERROR_MESSAGE,\n 'danger',\n )\n }\n }\n disabled={isLoading}\n loading={isPending}\n />\n </div>\n </Card>\n )\n}\n"],"mappings":";;;;;;;;;;;;AAeA,SAAS,EAAa,GAAwB;CAC5C,IAAM,EAAE,YAAS,cAAW,cAAW,qBACrC,EAA6B,EAAW;AAE1C,KAAI,CAAC,EAAW,QAAQ,CAAC,EAAW,OAClC,OAAU,MAAM,6CAA6C;AAG/D,SAAQ,EAAW,MAAM,gBAAgB,cAAzC;EACE,KAAK;EACL,KAAK,qFACH,QAAO;GACL,OAAO,EAAW,KAAK;GACvB,aAAa,EAAW,KAAK,gBAAgB;GAC7C,cAAc,EAAW,KAAK,sBAC1B,CAAC,EAAW,KAAK,oBAAoB,GACrC,EAAE;GACN,YAAY;GACZ,UAAU;GACV,iBAAiB;GACjB;GACA;GACA;GACD;EACH,QACE,SAAQ,MACN,sCAEE,EAAW,MAAM,gBAAgB,aACpC;;AAIL,QAAO;EACL,OAAO,EAAW,KAAK;EACvB,aAAa,EAAW,KAAK,gBAAgB;EAC7C,cAAc,EAAW,KAAK,sBAC1B,CAAC,EAAW,KAAK,oBAAoB,GACrC,EAAE;EACN,YAAY;EACZ,UAAU;EACV,uBAAuB;AACrB,KAAa,wCAAwC,UAAU,EAC7D,OAAO,oBACR,CAAC;;EAEJ,WAAW;EACX,WAAW;EACX,eAAe,KAAA;EAChB;;AAGH,SAAS,EAAa,GAA0B;CAC9C,IAAM,EAAE,aAAU;AAClB,QACE,kBAAC,GAAD;EAAM,IAAI;GAAE,YAAY;GAAK,iBAAiB;GAAW;EAAS;EAAS,CAAA;;AAO/E,SAAwB,EAAiB,GAA8B;CACrE,IAAM,EAAE,kBAAe,GACjB,EACJ,UACA,gBACA,aACA,iBACA,eACA,oBACA,kBACA,cACA,iBACE,EAAa,EAAW;AAE5B,QACE,kBAAC,GAAD;EAAM,WAAW,EAAW,EAAa,MAAM,EAAO,KAAK;YACzD,kBAAC,OAAD;GAAK,WAAW,EAAO;aAAvB;IACE,kBAAC,OAAD;KAAK,WAAW,EAAO;eAAvB;MACE,kBAAC,OAAD;OAAK,WAAW,EAAO;iBAAvB,CACE,kBAAC,GAAD;QAAY,SAAQ;kBAAa;QAAmB,CAAA,EACnD,KAAY,kBAAC,GAAD,EAAc,OAAO,GAAY,CAAA,CAC1C;;MACN,kBAAC,GAAD;OAAY,SAAQ;iBAAS;OAAyB,CAAA;MACtD,kBAAC,OAAD;OAAK,WAAW,EAAO;iBACpB,EAAa,KAAI,MAChB,kBAAC,GAAD,EAA+C,gBAAe,EAAzC,EAAyC,CAC9D;OACE,CAAA;MACF;;IACN,kBAAC,GAAD;KACE,aAAY;KACZ,UAAA;KACA,IAAI,EAAE,SAAS;MAAE,IAAI;MAAQ,IAAI;MAAS,EAAE;KAC5C,CAAA;IACF,kBAAC,GAAD;KACE,WAAW,EAAO;KACN;KACZ,SACE,IACI,UACM;AACJ,QACE,GACA,SACD;;KAGT,UAAU;KACV,SAAS;KACT,CAAA;IACE;;EACD,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"MetadataTaskTableActionCell.d.ts","sourceRoot":"","sources":["../../../../../src/features/entity/metadata-task/components/MetadataTaskTableActionCell.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAA;AAO7D,eAAO,MAAM,qCAAqC,uBAAuB,CAAA;AAEzE;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,2BAA2B,CAAC,KAAK,EAAE;IACzD,UAAU,EAAE,UAAU,CAAA;IACtB,OAAO,EAAE,OAAO,CAAA;CACjB,2CAgCA"}
1
+ {"version":3,"file":"MetadataTaskTableActionCell.d.ts","sourceRoot":"","sources":["../../../../../src/features/entity/metadata-task/components/MetadataTaskTableActionCell.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAA;AAO7D,eAAO,MAAM,qCAAqC,uBAAuB,CAAA;AAEzE;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,2BAA2B,CAAC,KAAK,EAAE;IACzD,UAAU,EAAE,UAAU,CAAA;IACtB,OAAO,EAAE,OAAO,CAAA;CACjB,2CA+BA"}
@@ -6,15 +6,15 @@ import { StickyNote2Outlined as s } from "@mui/icons-material";
6
6
  //#region src/features/entity/metadata-task/components/MetadataTaskTableActionCell.tsx
7
7
  var c = "Task is Unassigned";
8
8
  function l(c) {
9
- let { taskBundle: l } = c, u = l.task, { hasPermission: d, isLoading: f, isPending: p, onClick: m } = n(u), h = p || f || !d, g;
10
- return d === !0 ? g = t : d === !1 && (g = e), /* @__PURE__ */ o(a, { children: /* @__PURE__ */ o(i, {
11
- title: g,
9
+ let { taskBundle: l } = c, { hasPermission: u, isLoading: d, isPending: f, onClick: p } = n(l), m = f || d || !u, h;
10
+ return u === !0 ? h = t : u === !1 && (h = e), /* @__PURE__ */ o(a, { children: /* @__PURE__ */ o(i, {
11
+ title: h,
12
12
  children: /* @__PURE__ */ o("span", { children: /* @__PURE__ */ o(r, {
13
13
  size: "small",
14
14
  startIcon: /* @__PURE__ */ o(s, {}),
15
- loading: p,
16
- disabled: h,
17
- onClick: m,
15
+ loading: f,
16
+ disabled: m,
17
+ onClick: p,
18
18
  children: "Open Curator"
19
19
  }) })
20
20
  }) });
@@ -1 +1 @@
1
- {"version":3,"file":"MetadataTaskTableActionCell.js","names":[],"sources":["../../../../../src/features/entity/metadata-task/components/MetadataTaskTableActionCell.tsx"],"sourcesContent":["import { StickyNote2Outlined } from '@mui/icons-material'\nimport { Button, Tooltip } from '@mui/material'\nimport { TaskBundle } from '@sage-bionetworks/synapse-client'\nimport useOpenCuratorFromTaskButton from '../hooks/useOpenCuratorButton'\nimport {\n OPEN_CURATOR_TOOLTIP_TITLE,\n OPEN_CURATOR_NO_PERMISSION_ON_SOURCE_ERROR_MESSAGE,\n} from '../utils/constants'\n\nexport const NO_TASK_ASSIGNEE_WARNING_DIALOG_TITLE = 'Task is Unassigned'\n\n/**\n * Handles rendering the 'Actions' cell in the Metadata Task table, which provides buttons for the user\n * to accomplish the actions they can take on a Metadata Task, such as opening a data grid for the entity referenced\n * by the task.\n */\nexport default function MetadataTaskTableActionCell(props: {\n taskBundle: TaskBundle\n canEdit: boolean\n}) {\n const { taskBundle } = props\n const curationTask = taskBundle.task!\n\n const { hasPermission, isLoading, isPending, onClick } =\n useOpenCuratorFromTaskButton(curationTask)\n\n const disableButton = isPending || isLoading || !hasPermission\n let tooltipTitle: string | undefined = undefined\n if (hasPermission === true) {\n tooltipTitle = OPEN_CURATOR_TOOLTIP_TITLE\n } else if (hasPermission === false) {\n tooltipTitle = OPEN_CURATOR_NO_PERMISSION_ON_SOURCE_ERROR_MESSAGE\n }\n\n return (\n <>\n <Tooltip title={tooltipTitle}>\n <span>\n <Button\n size={'small'}\n startIcon={<StickyNote2Outlined />}\n loading={isPending}\n disabled={disableButton}\n onClick={onClick}\n >\n Open Curator\n </Button>\n </span>\n </Tooltip>\n </>\n )\n}\n"],"mappings":";;;;;;AASA,IAAa,IAAwC;AAOrD,SAAwB,EAA4B,GAGjD;CACD,IAAM,EAAE,kBAAe,GACjB,IAAe,EAAW,MAE1B,EAAE,kBAAe,cAAW,cAAW,eAC3C,EAA6B,EAAa,EAEtC,IAAgB,KAAa,KAAa,CAAC,GAC7C;AAOJ,QANI,MAAkB,KACpB,IAAe,IACN,MAAkB,OAC3B,IAAe,IAIf,kBAAA,GAAA,EAAA,UACE,kBAAC,GAAD;EAAS,OAAO;YACd,kBAAC,QAAD,EAAA,UACE,kBAAC,GAAD;GACE,MAAM;GACN,WAAW,kBAAC,GAAD,EAAuB,CAAA;GAClC,SAAS;GACT,UAAU;GACD;aACV;GAEQ,CAAA,EACJ,CAAA;EACC,CAAA,EACT,CAAA"}
1
+ {"version":3,"file":"MetadataTaskTableActionCell.js","names":[],"sources":["../../../../../src/features/entity/metadata-task/components/MetadataTaskTableActionCell.tsx"],"sourcesContent":["import { StickyNote2Outlined } from '@mui/icons-material'\nimport { Button, Tooltip } from '@mui/material'\nimport { TaskBundle } from '@sage-bionetworks/synapse-client'\nimport useOpenCuratorFromTaskButton from '../hooks/useOpenCuratorButton'\nimport {\n OPEN_CURATOR_TOOLTIP_TITLE,\n OPEN_CURATOR_NO_PERMISSION_ON_SOURCE_ERROR_MESSAGE,\n} from '../utils/constants'\n\nexport const NO_TASK_ASSIGNEE_WARNING_DIALOG_TITLE = 'Task is Unassigned'\n\n/**\n * Handles rendering the 'Actions' cell in the Metadata Task table, which provides buttons for the user\n * to accomplish the actions they can take on a Metadata Task, such as opening a data grid for the entity referenced\n * by the task.\n */\nexport default function MetadataTaskTableActionCell(props: {\n taskBundle: TaskBundle\n canEdit: boolean\n}) {\n const { taskBundle } = props\n\n const { hasPermission, isLoading, isPending, onClick } =\n useOpenCuratorFromTaskButton(taskBundle)\n\n const disableButton = isPending || isLoading || !hasPermission\n let tooltipTitle: string | undefined = undefined\n if (hasPermission === true) {\n tooltipTitle = OPEN_CURATOR_TOOLTIP_TITLE\n } else if (hasPermission === false) {\n tooltipTitle = OPEN_CURATOR_NO_PERMISSION_ON_SOURCE_ERROR_MESSAGE\n }\n\n return (\n <>\n <Tooltip title={tooltipTitle}>\n <span>\n <Button\n size={'small'}\n startIcon={<StickyNote2Outlined />}\n loading={isPending}\n disabled={disableButton}\n onClick={onClick}\n >\n Open Curator\n </Button>\n </span>\n </Tooltip>\n </>\n )\n}\n"],"mappings":";;;;;;AASA,IAAa,IAAwC;AAOrD,SAAwB,EAA4B,GAGjD;CACD,IAAM,EAAE,kBAAe,GAEjB,EAAE,kBAAe,cAAW,cAAW,eAC3C,EAA6B,EAAW,EAEpC,IAAgB,KAAa,KAAa,CAAC,GAC7C;AAOJ,QANI,MAAkB,KACpB,IAAe,IACN,MAAkB,OAC3B,IAAe,IAIf,kBAAA,GAAA,EAAA,UACE,kBAAC,GAAD;EAAS,OAAO;YACd,kBAAC,QAAD,EAAA,UACE,kBAAC,GAAD;GACE,MAAM;GACN,WAAW,kBAAC,GAAD,EAAuB,CAAA;GAClC,SAAS;GACT,UAAU;GACD;aACV;GAEQ,CAAA,EACJ,CAAA;EACC,CAAA,EACT,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"useGridSessionForCurationTask.d.ts","sourceRoot":"","sources":["../../../../../src/features/entity/metadata-task/hooks/useGridSessionForCurationTask.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,UAAU,EACX,MAAM,kCAAkC,CAAA;AAKzC,MAAM,MAAM,mCAAmC,GAAG;IAChD,WAAW,EAAE,WAAW,CAAA;IACxB,mCAAmC,EAAE,OAAO,CAAA;CAC7C,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,UAAU,6BAA6B,oIA6FpD"}
1
+ {"version":3,"file":"useGridSessionForCurationTask.d.ts","sourceRoot":"","sources":["../../../../../src/features/entity/metadata-task/hooks/useGridSessionForCurationTask.ts"],"names":[],"mappings":"AAOA,OAAO,EAEL,WAAW,EACX,kBAAkB,EAClB,UAAU,EACX,MAAM,kCAAkC,CAAA;AAMzC,MAAM,MAAM,mCAAmC,GAAG;IAChD,WAAW,EAAE,WAAW,CAAA;IACxB,mCAAmC,EAAE,OAAO,CAAA;CAC7C,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,UAAU,6BAA6B,oIA8FpD"}
@@ -2,22 +2,23 @@ import { useSynapseContext as e } from "../../../../utils/context/SynapseContext
2
2
  import "../../../../utils/index.js";
3
3
  import { getGridSessionQuery as t, useCreateGridSession as n, useDeleteGridSession as r } from "../../../../synapse-queries/grid/useGridSession.js";
4
4
  import { useUpdateCurationTaskStatus as i } from "../../../../synapse-queries/curation/task/useCurationTask.js";
5
- import a from "../utils/taskHasAssignee.js";
6
- import { getCreateGridRequestForMetadataTask as o } from "../utils/getCreateGridRequestForMetadataTask.js";
7
- import { SynapseClientError as s } from "@sage-bionetworks/synapse-client";
8
- import { useMutation as c, useQueryClient as l } from "@tanstack/react-query";
5
+ import { OPEN_CURATOR_LINK_TASK_CONFLICT_ERROR_MESSAGE as a } from "../utils/constants.js";
6
+ import o from "../utils/taskHasAssignee.js";
7
+ import { getCreateGridRequestForMetadataTask as s } from "../utils/getCreateGridRequestForMetadataTask.js";
8
+ import { SynapseClientError as c } from "@sage-bionetworks/synapse-client";
9
+ import { useMutation as l, useQueryClient as u } from "@tanstack/react-query";
9
10
  //#region src/features/entity/metadata-task/hooks/useGridSessionForCurationTask.ts
10
- function u() {
11
- let { mutateAsync: u } = n(), { mutateAsync: d } = i(), { mutateAsync: f } = r(), p = e(), m = l();
12
- return c({ mutationFn: async (e) => {
11
+ function d() {
12
+ let { mutateAsync: d } = n(), { mutateAsync: f } = i(), { mutateAsync: p } = r(), m = e(), h = u();
13
+ return l({ mutationFn: async (e) => {
13
14
  let { task: n, status: r } = e;
14
15
  if (!n || !r) throw Error("CurationTaskBundle is missing task or status");
15
- let i = a(n), c = r?.executionDetails?.activeSessionId;
16
- if (c) try {
17
- let e = await m.fetchQuery({
18
- ...t(c, {
19
- ...p,
20
- queryClient: m
16
+ let i = o(n), l = r?.executionDetails?.activeSessionId;
17
+ if (l) try {
18
+ let e = await h.fetchQuery({
19
+ ...t(l, {
20
+ ...m,
21
+ queryClient: h
21
22
  }),
22
23
  staleTime: 0
23
24
  });
@@ -26,29 +27,32 @@ function u() {
26
27
  gridSessionOwnerMatchesTaskAssignee: i && e.ownerPrincipalId == n.assigneePrincipalId
27
28
  };
28
29
  } catch (e) {
29
- if (!(e instanceof s && e.status === 404)) throw e;
30
+ if (!(e instanceof c && e.status === 404)) throw e;
30
31
  }
31
32
  if (n.taskProperties == null) throw Error("CurationTask is missing taskProperties");
32
- let l = (await u(o(n))).gridSession;
33
+ let u = (await d({
34
+ ...s(n),
35
+ authorizationMode: "SOURCE_BENEFACTOR"
36
+ })).gridSession;
33
37
  try {
34
- await d({
38
+ await f({
35
39
  ...r,
36
40
  executionDetails: {
37
41
  ...r.executionDetails,
38
- activeSessionId: l.sessionId,
42
+ activeSessionId: u.sessionId,
39
43
  concreteType: "org.sagebionetworks.repo.model.curation.execution.GridExecutionDetails"
40
44
  }
41
45
  });
42
46
  } catch (e) {
43
- throw e instanceof s && e.status === 412 ? (await f(l.sessionId), Error("Failed to link Grid session to Curation Task. The task was updated since it was last retrieved. Please refresh and try again.")) : e;
47
+ throw e instanceof c && e.status === 412 ? (await p(u.sessionId), Error(a)) : e;
44
48
  }
45
49
  return {
46
- gridSession: l,
50
+ gridSession: u,
47
51
  gridSessionOwnerMatchesTaskAssignee: i
48
52
  };
49
53
  } });
50
54
  }
51
55
  //#endregion
52
- export { u as default };
56
+ export { d as default };
53
57
 
54
58
  //# sourceMappingURL=useGridSessionForCurationTask.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useGridSessionForCurationTask.js","names":[],"sources":["../../../../../src/features/entity/metadata-task/hooks/useGridSessionForCurationTask.ts"],"sourcesContent":["import { useUpdateCurationTaskStatus } from '@/synapse-queries/curation/task/useCurationTask'\nimport {\n getGridSessionQuery,\n useCreateGridSession,\n useDeleteGridSession,\n} from '@/synapse-queries/grid/useGridSession'\nimport { useSynapseContext } from '@/utils'\nimport {\n GridSession,\n SynapseClientError,\n TaskBundle,\n} from '@sage-bionetworks/synapse-client'\nimport { useMutation, useQueryClient } from '@tanstack/react-query'\nimport { getCreateGridRequestForMetadataTask } from '../utils/getCreateGridRequestForMetadataTask'\nimport taskHasAssignee from '../utils/taskHasAssignee'\n\nexport type UseGridSessionForCurationTaskResult = {\n gridSession: GridSession\n gridSessionOwnerMatchesTaskAssignee: boolean\n}\n\n/**\n * A hook to get or create a GridSession for a given CurationTask. If an appropriate GridSession exists, it will be returned.\n * If not, a new GridSession will be created based on the CurationTask's properties.\n *\n * @returns A mutation object with a function to get or create a GridSession for a CurationTask. The response will also indicate\n * if the GridSession owner matches the task assignee (if there is one).\n * @throws SynapseClientError with status 403 if the user does not have permission to access an existing GridSession\n */\nexport default function useGridSessionForCurationTask() {\n const { mutateAsync: createGridSession } = useCreateGridSession()\n const { mutateAsync: updateCurationTaskStatus } =\n useUpdateCurationTaskStatus()\n const { mutateAsync: deleteGridSession } = useDeleteGridSession()\n\n const synapseContext = useSynapseContext()\n const queryClient = useQueryClient()\n\n return useMutation<\n UseGridSessionForCurationTaskResult,\n SynapseClientError,\n TaskBundle\n >({\n mutationFn: async curationTaskBundle => {\n const { task, status } = curationTaskBundle\n if (!task || !status) {\n throw new Error('CurationTaskBundle is missing task or status')\n }\n\n const hasAssignee = taskHasAssignee(task)\n\n const gridSessionId = status?.executionDetails?.activeSessionId\n if (gridSessionId) {\n try {\n // Verify the session is still active before returning it\n const gridSession = await queryClient.fetchQuery({\n ...getGridSessionQuery(gridSessionId, {\n ...synapseContext,\n queryClient,\n }),\n staleTime: 0,\n })\n\n const assigneeMatchesGridSessionOwner =\n hasAssignee &&\n gridSession.ownerPrincipalId == task.assigneePrincipalId\n\n return {\n gridSession,\n gridSessionOwnerMatchesTaskAssignee:\n assigneeMatchesGridSessionOwner,\n }\n } catch (e) {\n if (e instanceof SynapseClientError && e.status === 404) {\n // Session not found, will create a new one\n } else {\n throw e\n }\n }\n }\n // Create a session and link it to the task\n const taskProperties = task.taskProperties\n if (taskProperties == null) {\n throw new Error('CurationTask is missing taskProperties')\n }\n\n const createGridRequest = getCreateGridRequestForMetadataTask(task)\n const createGridResponse = await createGridSession(createGridRequest)\n const gridSession = createGridResponse.gridSession!\n\n // Associate the new session with the task\n try {\n await updateCurationTaskStatus({\n ...status,\n executionDetails: {\n ...status.executionDetails,\n activeSessionId: gridSession.sessionId!,\n concreteType:\n 'org.sagebionetworks.repo.model.curation.execution.GridExecutionDetails',\n },\n })\n } catch (e) {\n if (e instanceof SynapseClientError && e.status === 412) {\n // etag mismatch -- possible race condition.\n // Delete the session we just created to avoid orphaned sessions, and throw an error to notify the user that they may need to refresh and try again.\n await deleteGridSession(gridSession.sessionId!)\n throw new Error(\n 'Failed to link Grid session to Curation Task. The task was updated since it was last retrieved. Please refresh and try again.',\n )\n } else {\n // Rethrow any other error\n throw e\n }\n }\n\n // Since we just created the session, the user must have access, and the owner must match the assignee (if there is one).\n return {\n gridSession,\n gridSessionOwnerMatchesTaskAssignee: hasAssignee,\n }\n },\n })\n}\n"],"mappings":";;;;;;;;;AA6BA,SAAwB,IAAgC;CACtD,IAAM,EAAE,aAAa,MAAsB,GAAsB,EAC3D,EAAE,aAAa,MACnB,GAA6B,EACzB,EAAE,aAAa,MAAsB,GAAsB,EAE3D,IAAiB,GAAmB,EACpC,IAAc,GAAgB;AAEpC,QAAO,EAIL,EACA,YAAY,OAAM,MAAsB;EACtC,IAAM,EAAE,SAAM,cAAW;AACzB,MAAI,CAAC,KAAQ,CAAC,EACZ,OAAU,MAAM,+CAA+C;EAGjE,IAAM,IAAc,EAAgB,EAAK,EAEnC,IAAgB,GAAQ,kBAAkB;AAChD,MAAI,EACF,KAAI;GAEF,IAAM,IAAc,MAAM,EAAY,WAAW;IAC/C,GAAG,EAAoB,GAAe;KACpC,GAAG;KACH;KACD,CAAC;IACF,WAAW;IACZ,CAAC;AAMF,UAAO;IACL;IACA,qCALA,KACA,EAAY,oBAAoB,EAAK;IAMtC;WACM,GAAG;AACV,OAAI,eAAa,KAAsB,EAAE,WAAW,KAGlD,OAAM;;AAMZ,MADuB,EAAK,kBACN,KACpB,OAAU,MAAM,yCAAyC;EAK3D,IAAM,KAAc,MADa,EADP,EAAoC,EACX,CAAkB,EAC9B;AAGvC,MAAI;AACF,SAAM,EAAyB;IAC7B,GAAG;IACH,kBAAkB;KAChB,GAAG,EAAO;KACV,iBAAiB,EAAY;KAC7B,cACE;KACH;IACF,CAAC;WACK,GAAG;AAUR,SATE,aAAa,KAAsB,EAAE,WAAW,OAGlD,MAAM,EAAkB,EAAY,UAAW,EACrC,MACR,gIACD,IAGK;;AAKV,SAAO;GACL;GACA,qCAAqC;GACtC;IAEJ,CAAC"}
1
+ {"version":3,"file":"useGridSessionForCurationTask.js","names":[],"sources":["../../../../../src/features/entity/metadata-task/hooks/useGridSessionForCurationTask.ts"],"sourcesContent":["import { useUpdateCurationTaskStatus } from '@/synapse-queries/curation/task/useCurationTask'\nimport {\n getGridSessionQuery,\n useCreateGridSession,\n useDeleteGridSession,\n} from '@/synapse-queries/grid/useGridSession'\nimport { useSynapseContext } from '@/utils'\nimport {\n CreateGridRequest,\n GridSession,\n SynapseClientError,\n TaskBundle,\n} from '@sage-bionetworks/synapse-client'\nimport { useMutation, useQueryClient } from '@tanstack/react-query'\nimport { OPEN_CURATOR_LINK_TASK_CONFLICT_ERROR_MESSAGE } from '../utils/constants'\nimport { getCreateGridRequestForMetadataTask } from '../utils/getCreateGridRequestForMetadataTask'\nimport taskHasAssignee from '../utils/taskHasAssignee'\n\nexport type UseGridSessionForCurationTaskResult = {\n gridSession: GridSession\n gridSessionOwnerMatchesTaskAssignee: boolean\n}\n\n/**\n * A hook to get or create a GridSession for a given CurationTask. If an appropriate GridSession exists, it will be returned.\n * If not, a new GridSession will be created based on the CurationTask's properties.\n *\n * @returns A mutation object with a function to get or create a GridSession for a CurationTask. The response will also indicate\n * if the GridSession owner matches the task assignee (if there is one).\n * @throws SynapseClientError with status 403 if the user does not have permission to access an existing GridSession\n */\nexport default function useGridSessionForCurationTask() {\n const { mutateAsync: createGridSession } = useCreateGridSession()\n const { mutateAsync: updateCurationTaskStatus } =\n useUpdateCurationTaskStatus()\n const { mutateAsync: deleteGridSession } = useDeleteGridSession()\n\n const synapseContext = useSynapseContext()\n const queryClient = useQueryClient()\n\n return useMutation<\n UseGridSessionForCurationTaskResult,\n SynapseClientError,\n TaskBundle\n >({\n mutationFn: async curationTaskBundle => {\n const { task, status } = curationTaskBundle\n if (!task || !status) {\n throw new Error('CurationTaskBundle is missing task or status')\n }\n\n const hasAssignee = taskHasAssignee(task)\n\n const gridSessionId = status?.executionDetails?.activeSessionId\n if (gridSessionId) {\n try {\n // Verify the session is still active before returning it\n const gridSession = await queryClient.fetchQuery({\n ...getGridSessionQuery(gridSessionId, {\n ...synapseContext,\n queryClient,\n }),\n staleTime: 0,\n })\n\n const assigneeMatchesGridSessionOwner =\n hasAssignee &&\n gridSession.ownerPrincipalId == task.assigneePrincipalId\n\n return {\n gridSession,\n gridSessionOwnerMatchesTaskAssignee:\n assigneeMatchesGridSessionOwner,\n }\n } catch (e) {\n if (e instanceof SynapseClientError && e.status === 404) {\n // Session not found, will create a new one\n } else {\n throw e\n }\n }\n }\n // Create a session and link it to the task\n const taskProperties = task.taskProperties\n if (taskProperties == null) {\n throw new Error('CurationTask is missing taskProperties')\n }\n\n const createGridRequest: CreateGridRequest = {\n ...getCreateGridRequestForMetadataTask(task),\n authorizationMode: 'SOURCE_BENEFACTOR',\n }\n const createGridResponse = await createGridSession(createGridRequest)\n const gridSession = createGridResponse.gridSession!\n\n // Associate the new session with the task\n try {\n await updateCurationTaskStatus({\n ...status,\n executionDetails: {\n ...status.executionDetails,\n activeSessionId: gridSession.sessionId!,\n concreteType:\n 'org.sagebionetworks.repo.model.curation.execution.GridExecutionDetails',\n },\n })\n } catch (e) {\n if (e instanceof SynapseClientError && e.status === 412) {\n // etag mismatch -- possible race condition.\n // Delete the session we just created to avoid orphaned sessions, and throw an error to notify the user that they may need to refresh and try again.\n await deleteGridSession(gridSession.sessionId!)\n throw new Error(OPEN_CURATOR_LINK_TASK_CONFLICT_ERROR_MESSAGE)\n } else {\n // Rethrow any other error\n throw e\n }\n }\n\n // Since we just created the session, the user must have access, and the owner must match the assignee (if there is one).\n return {\n gridSession,\n gridSessionOwnerMatchesTaskAssignee: hasAssignee,\n }\n },\n })\n}\n"],"mappings":";;;;;;;;;;AA+BA,SAAwB,IAAgC;CACtD,IAAM,EAAE,aAAa,MAAsB,GAAsB,EAC3D,EAAE,aAAa,MACnB,GAA6B,EACzB,EAAE,aAAa,MAAsB,GAAsB,EAE3D,IAAiB,GAAmB,EACpC,IAAc,GAAgB;AAEpC,QAAO,EAIL,EACA,YAAY,OAAM,MAAsB;EACtC,IAAM,EAAE,SAAM,cAAW;AACzB,MAAI,CAAC,KAAQ,CAAC,EACZ,OAAU,MAAM,+CAA+C;EAGjE,IAAM,IAAc,EAAgB,EAAK,EAEnC,IAAgB,GAAQ,kBAAkB;AAChD,MAAI,EACF,KAAI;GAEF,IAAM,IAAc,MAAM,EAAY,WAAW;IAC/C,GAAG,EAAoB,GAAe;KACpC,GAAG;KACH;KACD,CAAC;IACF,WAAW;IACZ,CAAC;AAMF,UAAO;IACL;IACA,qCALA,KACA,EAAY,oBAAoB,EAAK;IAMtC;WACM,GAAG;AACV,OAAI,eAAa,KAAsB,EAAE,WAAW,KAGlD,OAAM;;AAMZ,MADuB,EAAK,kBACN,KACpB,OAAU,MAAM,yCAAyC;EAQ3D,IAAM,KAAc,MADa,EAAkB;GAHjD,GAAG,EAAoC,EAAK;GAC5C,mBAAmB;GAE8B,CAAkB,EAC9B;AAGvC,MAAI;AACF,SAAM,EAAyB;IAC7B,GAAG;IACH,kBAAkB;KAChB,GAAG,EAAO;KACV,iBAAiB,EAAY;KAC7B,cACE;KACH;IACF,CAAC;WACK,GAAG;AAQR,SAPE,aAAa,KAAsB,EAAE,WAAW,OAGlD,MAAM,EAAkB,EAAY,UAAW,EACrC,MAAM,EAA8C,IAGxD;;AAKV,SAAO;GACL;GACA,qCAAqC;GACtC;IAEJ,CAAC"}
@@ -1,10 +1,10 @@
1
- import { CurationTask } from '@sage-bionetworks/synapse-client';
1
+ import { TaskBundle } from '@sage-bionetworks/synapse-client';
2
2
  type UseOpenCuratorFromTaskButtonReturn = {
3
3
  isLoading: boolean;
4
4
  isPending: boolean;
5
5
  hasPermission?: boolean;
6
6
  onClick: () => void;
7
7
  };
8
- export default function useOpenCuratorFromTaskButton(curationTask: CurationTask): UseOpenCuratorFromTaskButtonReturn;
8
+ export default function useOpenCuratorFromTaskButton(taskBundle: TaskBundle): UseOpenCuratorFromTaskButtonReturn;
9
9
  export {};
10
10
  //# sourceMappingURL=useOpenCuratorButton.d.ts.map