@drodil/backstage-plugin-qeta-react 2.15.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/dist/api.esm.js +8 -0
  2. package/dist/api.esm.js.map +1 -0
  3. package/dist/components/AnswerCard/AnswerCard.esm.js +113 -0
  4. package/dist/components/AnswerCard/AnswerCard.esm.js.map +1 -0
  5. package/dist/components/AnswerForm/AnswerForm.esm.js +153 -0
  6. package/dist/components/AnswerForm/AnswerForm.esm.js.map +1 -0
  7. package/dist/components/AnswersContainer/AnswerList.esm.js +100 -0
  8. package/dist/components/AnswersContainer/AnswerList.esm.js.map +1 -0
  9. package/dist/components/AnswersContainer/AnswerListItem.esm.js +90 -0
  10. package/dist/components/AnswersContainer/AnswerListItem.esm.js.map +1 -0
  11. package/dist/components/AnswersContainer/AnswersContainer.esm.js +210 -0
  12. package/dist/components/AnswersContainer/AnswersContainer.esm.js.map +1 -0
  13. package/dist/components/ArticleContent/ArticleButtons.esm.js +90 -0
  14. package/dist/components/ArticleContent/ArticleButtons.esm.js.map +1 -0
  15. package/dist/components/ArticleContent/ArticleContent.esm.js +78 -0
  16. package/dist/components/ArticleContent/ArticleContent.esm.js.map +1 -0
  17. package/dist/components/AuthorBox/AuthorBox.esm.js +25 -0
  18. package/dist/components/AuthorBox/AuthorBox.esm.js.map +1 -0
  19. package/dist/components/Buttons/AddToCollectionButton.esm.js +68 -0
  20. package/dist/components/Buttons/AddToCollectionButton.esm.js.map +1 -0
  21. package/dist/components/Buttons/AskQuestionButton.esm.js +40 -0
  22. package/dist/components/Buttons/AskQuestionButton.esm.js.map +1 -0
  23. package/dist/components/Buttons/BackToArticlesButton.esm.js +40 -0
  24. package/dist/components/Buttons/BackToArticlesButton.esm.js.map +1 -0
  25. package/dist/components/Buttons/BackToCollectionsButton.esm.js +25 -0
  26. package/dist/components/Buttons/BackToCollectionsButton.esm.js.map +1 -0
  27. package/dist/components/Buttons/BackToQuestionsButton.esm.js +40 -0
  28. package/dist/components/Buttons/BackToQuestionsButton.esm.js.map +1 -0
  29. package/dist/components/Buttons/CreateCollectionButton.esm.js +29 -0
  30. package/dist/components/Buttons/CreateCollectionButton.esm.js.map +1 -0
  31. package/dist/components/Buttons/EntityFollowButton.esm.js +34 -0
  32. package/dist/components/Buttons/EntityFollowButton.esm.js.map +1 -0
  33. package/dist/components/Buttons/FavoriteButton.esm.js +45 -0
  34. package/dist/components/Buttons/FavoriteButton.esm.js.map +1 -0
  35. package/dist/components/Buttons/LinkButton.esm.js +28 -0
  36. package/dist/components/Buttons/LinkButton.esm.js.map +1 -0
  37. package/dist/components/Buttons/TagFollowButton.esm.js +34 -0
  38. package/dist/components/Buttons/TagFollowButton.esm.js.map +1 -0
  39. package/dist/components/Buttons/VoteButtons.esm.js +75 -0
  40. package/dist/components/Buttons/VoteButtons.esm.js.map +1 -0
  41. package/dist/components/Buttons/WriteArticleButton.esm.js +40 -0
  42. package/dist/components/Buttons/WriteArticleButton.esm.js.map +1 -0
  43. package/dist/components/CollectionCard/CollectionCard.esm.js +63 -0
  44. package/dist/components/CollectionCard/CollectionCard.esm.js.map +1 -0
  45. package/dist/components/CollectionForm/CollectionForm.esm.js +251 -0
  46. package/dist/components/CollectionForm/CollectionForm.esm.js.map +1 -0
  47. package/dist/components/CollectionsGrid/CollectionsGrid.esm.js +40 -0
  48. package/dist/components/CollectionsGrid/CollectionsGrid.esm.js.map +1 -0
  49. package/dist/components/CollectionsGrid/CollectionsGridContent.esm.js +67 -0
  50. package/dist/components/CollectionsGrid/CollectionsGridContent.esm.js.map +1 -0
  51. package/dist/components/CollectionsGrid/CollectionsGridItem.esm.js +48 -0
  52. package/dist/components/CollectionsGrid/CollectionsGridItem.esm.js.map +1 -0
  53. package/dist/components/CommentSection/CommentList.esm.js +47 -0
  54. package/dist/components/CommentSection/CommentList.esm.js.map +1 -0
  55. package/dist/components/CommentSection/CommentSection.esm.js +126 -0
  56. package/dist/components/CommentSection/CommentSection.esm.js.map +1 -0
  57. package/dist/components/DeleteModal/DeleteModal.esm.js +88 -0
  58. package/dist/components/DeleteModal/DeleteModal.esm.js.map +1 -0
  59. package/dist/components/EntitiesGrid/EntitiesGrid.esm.js +45 -0
  60. package/dist/components/EntitiesGrid/EntitiesGrid.esm.js.map +1 -0
  61. package/dist/components/EntitiesGrid/EntitiesGridItem.esm.js +61 -0
  62. package/dist/components/EntitiesGrid/EntitiesGridItem.esm.js.map +1 -0
  63. package/dist/components/FilterPanel/DateRangeFilter.esm.js +110 -0
  64. package/dist/components/FilterPanel/DateRangeFilter.esm.js.map +1 -0
  65. package/dist/components/FilterPanel/FilterPanel.esm.js +238 -0
  66. package/dist/components/FilterPanel/FilterPanel.esm.js.map +1 -0
  67. package/dist/components/FollowedLists/FollowedEntitiesList.esm.js +43 -0
  68. package/dist/components/FollowedLists/FollowedEntitiesList.esm.js.map +1 -0
  69. package/dist/components/FollowedLists/FollowedTagsList.esm.js +43 -0
  70. package/dist/components/FollowedLists/FollowedTagsList.esm.js.map +1 -0
  71. package/dist/components/HomePageCards/ImpactCard.esm.js +22 -0
  72. package/dist/components/HomePageCards/ImpactCard.esm.js.map +1 -0
  73. package/dist/components/HomePageCards/PostsCard.esm.js +42 -0
  74. package/dist/components/HomePageCards/PostsCard.esm.js.map +1 -0
  75. package/dist/components/Links/Links.esm.js +33 -0
  76. package/dist/components/Links/Links.esm.js.map +1 -0
  77. package/dist/components/MarkdownEditor/MarkdownEditor.esm.js +63 -0
  78. package/dist/components/MarkdownEditor/MarkdownEditor.esm.js.map +1 -0
  79. package/dist/components/MarkdownRenderer/MarkdownRenderer.esm.js +97 -0
  80. package/dist/components/MarkdownRenderer/MarkdownRenderer.esm.js.map +1 -0
  81. package/dist/components/PostAnonymouslyCheckbox/PostAnonymouslyCheckbox.esm.js +34 -0
  82. package/dist/components/PostAnonymouslyCheckbox/PostAnonymouslyCheckbox.esm.js.map +1 -0
  83. package/dist/components/PostForm/EntitiesInput.esm.js +100 -0
  84. package/dist/components/PostForm/EntitiesInput.esm.js.map +1 -0
  85. package/dist/components/PostForm/PostForm.esm.js +283 -0
  86. package/dist/components/PostForm/PostForm.esm.js.map +1 -0
  87. package/dist/components/PostForm/TagInput.esm.js +81 -0
  88. package/dist/components/PostForm/TagInput.esm.js.map +1 -0
  89. package/dist/components/PostHighlightList/PostHighlightList.esm.js +72 -0
  90. package/dist/components/PostHighlightList/PostHighlightList.esm.js.map +1 -0
  91. package/dist/components/PostsContainer/NoPostsCard.esm.js +50 -0
  92. package/dist/components/PostsContainer/NoPostsCard.esm.js.map +1 -0
  93. package/dist/components/PostsContainer/PostList.esm.js +113 -0
  94. package/dist/components/PostsContainer/PostList.esm.js.map +1 -0
  95. package/dist/components/PostsContainer/PostListItem.esm.js +138 -0
  96. package/dist/components/PostsContainer/PostListItem.esm.js.map +1 -0
  97. package/dist/components/PostsContainer/PostsContainer.esm.js +152 -0
  98. package/dist/components/PostsContainer/PostsContainer.esm.js.map +1 -0
  99. package/dist/components/PostsGrid/PostsGrid.esm.js +146 -0
  100. package/dist/components/PostsGrid/PostsGrid.esm.js.map +1 -0
  101. package/dist/components/PostsGrid/PostsGridContent.esm.js +90 -0
  102. package/dist/components/PostsGrid/PostsGridContent.esm.js.map +1 -0
  103. package/dist/components/PostsGrid/PostsGridItem.esm.js +57 -0
  104. package/dist/components/PostsGrid/PostsGridItem.esm.js.map +1 -0
  105. package/dist/components/QuestionCard/QuestionCard.esm.js +107 -0
  106. package/dist/components/QuestionCard/QuestionCard.esm.js.map +1 -0
  107. package/dist/components/QuestionsTable/QuestionTableRow.esm.js +21 -0
  108. package/dist/components/QuestionsTable/QuestionTableRow.esm.js.map +1 -0
  109. package/dist/components/QuestionsTable/QuestionsTable.esm.js +131 -0
  110. package/dist/components/QuestionsTable/QuestionsTable.esm.js.map +1 -0
  111. package/dist/components/RelativeTimeWithTooltip/RelativeTimeWithTooltip.esm.js +22 -0
  112. package/dist/components/RelativeTimeWithTooltip/RelativeTimeWithTooltip.esm.js.map +1 -0
  113. package/dist/components/StatsChart/StatsChart.esm.js +245 -0
  114. package/dist/components/StatsChart/StatsChart.esm.js.map +1 -0
  115. package/dist/components/SummaryStatsGrid/SummaryStatsGrid.esm.js +53 -0
  116. package/dist/components/SummaryStatsGrid/SummaryStatsGrid.esm.js.map +1 -0
  117. package/dist/components/TagsAndEntities/EntityChip.esm.js +80 -0
  118. package/dist/components/TagsAndEntities/EntityChip.esm.js.map +1 -0
  119. package/dist/components/TagsAndEntities/TagChip.esm.js +78 -0
  120. package/dist/components/TagsAndEntities/TagChip.esm.js.map +1 -0
  121. package/dist/components/TagsAndEntities/TagsAndEntities.esm.js +32 -0
  122. package/dist/components/TagsAndEntities/TagsAndEntities.esm.js.map +1 -0
  123. package/dist/components/TagsGrid/EditTagModal.esm.js +73 -0
  124. package/dist/components/TagsGrid/EditTagModal.esm.js.map +1 -0
  125. package/dist/components/TagsGrid/TagGridItem.esm.js +56 -0
  126. package/dist/components/TagsGrid/TagGridItem.esm.js.map +1 -0
  127. package/dist/components/TagsGrid/TagsGrid.esm.js +45 -0
  128. package/dist/components/TagsGrid/TagsGrid.esm.js.map +1 -0
  129. package/dist/components/TopRankingUsersCard/TopRankingUsersCard.esm.js +161 -0
  130. package/dist/components/TopRankingUsersCard/TopRankingUsersCard.esm.js.map +1 -0
  131. package/dist/components/TopRankingUsersCard/TrophyIcon.esm.js +19 -0
  132. package/dist/components/TopRankingUsersCard/TrophyIcon.esm.js.map +1 -0
  133. package/dist/components/TopRankingUsersCard/styles.esm.js +23 -0
  134. package/dist/components/TopRankingUsersCard/styles.esm.js.map +1 -0
  135. package/dist/components/UsersGrid/UsersGrid.esm.js +43 -0
  136. package/dist/components/UsersGrid/UsersGrid.esm.js.map +1 -0
  137. package/dist/components/UsersGrid/UsersGridItem.esm.js +66 -0
  138. package/dist/components/UsersGrid/UsersGridItem.esm.js.map +1 -0
  139. package/dist/index.d.ts +568 -1
  140. package/dist/index.esm.js +45 -1
  141. package/dist/index.esm.js.map +1 -1
  142. package/dist/routes.esm.js +56 -1
  143. package/dist/routes.esm.js.map +1 -1
  144. package/dist/translation.esm.js +470 -0
  145. package/dist/translation.esm.js.map +1 -0
  146. package/dist/utils/hooks.esm.js +734 -0
  147. package/dist/utils/hooks.esm.js.map +1 -0
  148. package/dist/utils/utils.esm.js +93 -0
  149. package/dist/utils/utils.esm.js.map +1 -0
  150. package/package.json +32 -5
@@ -0,0 +1,80 @@
1
+ import { stringifyEntityRef } from '@backstage/catalog-model';
2
+ import { Tooltip, Chip, Grid, Typography, Button } from '@material-ui/core';
3
+ import React, { useEffect } from 'react';
4
+ import { useRouteRef, useApi } from '@backstage/core-plugin-api';
5
+ import { useEntityPresentation } from '@backstage/plugin-catalog-react';
6
+ import { entityRouteRef } from '../../routes.esm.js';
7
+ import { qetaApiRef } from '../../api.esm.js';
8
+ import { useTranslation, useEntityFollow } from '../../utils/hooks.esm.js';
9
+
10
+ const cache = /* @__PURE__ */ new Map();
11
+ const EntityTooltip = (props) => {
12
+ const { entity } = props;
13
+ const entityRef = typeof entity === "string" ? entity : stringifyEntityRef(entity);
14
+ const qetaApi = useApi(qetaApiRef);
15
+ const { primaryTitle } = useEntityPresentation(entity);
16
+ const { t } = useTranslation();
17
+ const entitiesFollow = useEntityFollow();
18
+ const [resp, setResp] = React.useState();
19
+ useEffect(() => {
20
+ if (cache.has(entityRef)) {
21
+ setResp(cache.get(entityRef));
22
+ return;
23
+ }
24
+ qetaApi.getEntity(entityRef).then((res) => {
25
+ if (res) {
26
+ cache.set(entityRef, res);
27
+ setResp(res);
28
+ }
29
+ });
30
+ }, [qetaApi, entityRef]);
31
+ if (!resp) {
32
+ return null;
33
+ }
34
+ return /* @__PURE__ */ React.createElement(Grid, { container: true, style: { padding: "0.5rem" }, spacing: 1 }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Typography, { variant: "h6" }, primaryTitle)), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Typography, { variant: "subtitle2" }, t("common.posts", { count: resp.postsCount, itemType: "post" }), " \xB7 ", t("common.followers", { count: resp.followerCount }))), !entitiesFollow.loading && /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(
35
+ Button,
36
+ {
37
+ size: "small",
38
+ variant: "outlined",
39
+ color: entitiesFollow.isFollowingEntity(entityRef) ? "secondary" : "primary",
40
+ onClick: () => {
41
+ if (entitiesFollow.isFollowingEntity(entityRef)) {
42
+ entitiesFollow.followEntity(entityRef);
43
+ } else {
44
+ entitiesFollow.followEntity(entityRef);
45
+ }
46
+ }
47
+ },
48
+ entitiesFollow.isFollowingEntity(entityRef) ? t("entityButton.unfollow") : t("entityButton.follow")
49
+ )));
50
+ };
51
+ const EntityChip = (props) => {
52
+ const { entity } = props;
53
+ const entityRoute = useRouteRef(entityRouteRef);
54
+ const { primaryTitle } = useEntityPresentation(entity);
55
+ const entityRef = typeof entity === "string" ? entity : stringifyEntityRef(entity);
56
+ return /* @__PURE__ */ React.createElement(
57
+ Tooltip,
58
+ {
59
+ title: /* @__PURE__ */ React.createElement(EntityTooltip, { entity }),
60
+ arrow: true,
61
+ interactive: true,
62
+ enterDelay: 400
63
+ },
64
+ /* @__PURE__ */ React.createElement(
65
+ Chip,
66
+ {
67
+ label: primaryTitle,
68
+ size: "small",
69
+ variant: "outlined",
70
+ className: "qetaEntityChip",
71
+ component: "a",
72
+ href: entityRoute({ entityRef }),
73
+ clickable: true
74
+ }
75
+ )
76
+ );
77
+ };
78
+
79
+ export { EntityChip };
80
+ //# sourceMappingURL=EntityChip.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EntityChip.esm.js","sources":["../../../src/components/TagsAndEntities/EntityChip.tsx"],"sourcesContent":["import { Entity, stringifyEntityRef } from '@backstage/catalog-model';\nimport { Button, Chip, Grid, Tooltip, Typography } from '@material-ui/core';\nimport React, { useEffect } from 'react';\nimport { useApi, useRouteRef } from '@backstage/core-plugin-api';\nimport { useEntityPresentation } from '@backstage/plugin-catalog-react';\nimport { entityRouteRef } from '../../routes';\nimport { qetaApiRef } from '../../api';\nimport { useTranslation } from '../../utils';\nimport { useEntityFollow } from '../../utils/hooks';\nimport { EntityResponse } from '@drodil/backstage-plugin-qeta-common';\n\nconst cache: Map<string, EntityResponse> = new Map();\n\nconst EntityTooltip = (props: { entity: Entity | string }) => {\n const { entity } = props;\n const entityRef =\n typeof entity === 'string' ? entity : stringifyEntityRef(entity);\n const qetaApi = useApi(qetaApiRef);\n const { primaryTitle } = useEntityPresentation(entity);\n const { t } = useTranslation();\n const entitiesFollow = useEntityFollow();\n const [resp, setResp] = React.useState<undefined | EntityResponse>();\n\n useEffect(() => {\n if (cache.has(entityRef)) {\n setResp(cache.get(entityRef));\n return;\n }\n\n qetaApi.getEntity(entityRef).then(res => {\n if (res) {\n cache.set(entityRef, res);\n setResp(res);\n }\n });\n }, [qetaApi, entityRef]);\n\n if (!resp) {\n return null;\n }\n\n return (\n <Grid container style={{ padding: '0.5rem' }} spacing={1}>\n <Grid item xs={12}>\n <Typography variant=\"h6\">{primaryTitle}</Typography>\n </Grid>\n <Grid item xs={12}>\n <Typography variant=\"subtitle2\">\n {t('common.posts', { count: resp.postsCount, itemType: 'post' })}\n {' · '}\n {t('common.followers', { count: resp.followerCount })}\n </Typography>\n </Grid>\n {!entitiesFollow.loading && (\n <Grid item xs={12}>\n <Button\n size=\"small\"\n variant=\"outlined\"\n color={\n entitiesFollow.isFollowingEntity(entityRef)\n ? 'secondary'\n : 'primary'\n }\n onClick={() => {\n if (entitiesFollow.isFollowingEntity(entityRef)) {\n entitiesFollow.followEntity(entityRef);\n } else {\n entitiesFollow.followEntity(entityRef);\n }\n }}\n >\n {entitiesFollow.isFollowingEntity(entityRef)\n ? t('entityButton.unfollow')\n : t('entityButton.follow')}\n </Button>\n </Grid>\n )}\n </Grid>\n );\n};\n\nexport const EntityChip = (props: { entity: Entity | string }) => {\n const { entity } = props;\n const entityRoute = useRouteRef(entityRouteRef);\n const { primaryTitle } = useEntityPresentation(entity);\n const entityRef =\n typeof entity === 'string' ? entity : stringifyEntityRef(entity);\n return (\n <Tooltip\n title={<EntityTooltip entity={entity} />}\n arrow\n interactive\n enterDelay={400}\n >\n <Chip\n label={primaryTitle}\n size=\"small\"\n variant=\"outlined\"\n className=\"qetaEntityChip\"\n component=\"a\"\n href={entityRoute({ entityRef })}\n clickable\n />\n </Tooltip>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ import { Tooltip, Chip, Grid, Typography, Button } from '@material-ui/core';
2
+ import React, { useEffect } from 'react';
3
+ import { useRouteRef, useApi } from '@backstage/core-plugin-api';
4
+ import { tagRouteRef } from '../../routes.esm.js';
5
+ import { qetaApiRef } from '../../api.esm.js';
6
+ import { useNavigate } from 'react-router-dom';
7
+ import { useTranslation, useTagsFollow } from '../../utils/hooks.esm.js';
8
+ import { MarkdownRenderer } from '../MarkdownRenderer/MarkdownRenderer.esm.js';
9
+
10
+ const cache = /* @__PURE__ */ new Map();
11
+ const TagTooltip = (props) => {
12
+ const { tag } = props;
13
+ const qetaApi = useApi(qetaApiRef);
14
+ const { t } = useTranslation();
15
+ const tags = useTagsFollow();
16
+ const [resp, setResp] = React.useState();
17
+ useEffect(() => {
18
+ if (cache.has(tag)) {
19
+ setResp(cache.get(tag));
20
+ return;
21
+ }
22
+ qetaApi.getTag(tag).then((res) => {
23
+ if (res) {
24
+ cache.set(tag, res);
25
+ setResp(res);
26
+ }
27
+ });
28
+ }, [qetaApi, tag]);
29
+ if (!resp) {
30
+ return null;
31
+ }
32
+ return /* @__PURE__ */ React.createElement(Grid, { container: true, style: { padding: "0.5rem" }, spacing: 1 }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Typography, { variant: "h6" }, tag)), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Typography, { variant: "subtitle2" }, t("common.posts", { count: resp.postsCount, itemType: "post" }), " \xB7 ", t("common.followers", { count: resp.followerCount }))), resp.description && /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(MarkdownRenderer, { content: resp.description })), !tags.loading && /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(
33
+ Button,
34
+ {
35
+ size: "small",
36
+ variant: "outlined",
37
+ color: tags.isFollowingTag(tag) ? "secondary" : "primary",
38
+ onClick: () => {
39
+ if (tags.isFollowingTag(tag)) {
40
+ tags.unfollowTag(tag);
41
+ } else {
42
+ tags.followTag(tag);
43
+ }
44
+ }
45
+ },
46
+ tags.isFollowingTag(tag) ? t("tagButton.unfollow") : t("tagButton.follow")
47
+ )));
48
+ };
49
+ const TagChip = (props) => {
50
+ const tagRoute = useRouteRef(tagRouteRef);
51
+ const navigate = useNavigate();
52
+ const { tag } = props;
53
+ return /* @__PURE__ */ React.createElement(
54
+ Tooltip,
55
+ {
56
+ arrow: true,
57
+ title: /* @__PURE__ */ React.createElement(TagTooltip, { tag }),
58
+ interactive: true,
59
+ enterDelay: 400
60
+ },
61
+ /* @__PURE__ */ React.createElement(
62
+ Chip,
63
+ {
64
+ label: tag,
65
+ size: "small",
66
+ className: "qetaTagChip",
67
+ component: "a",
68
+ onClick: () => {
69
+ navigate(tagRoute({ tag }));
70
+ },
71
+ clickable: true
72
+ }
73
+ )
74
+ );
75
+ };
76
+
77
+ export { TagChip };
78
+ //# sourceMappingURL=TagChip.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TagChip.esm.js","sources":["../../../src/components/TagsAndEntities/TagChip.tsx"],"sourcesContent":["import { Button, Chip, Grid, Tooltip, Typography } from '@material-ui/core';\nimport React, { useEffect } from 'react';\nimport { useApi, useRouteRef } from '@backstage/core-plugin-api';\nimport { tagRouteRef } from '../../routes';\nimport { qetaApiRef } from '../../api';\nimport { TagResponse } from '@drodil/backstage-plugin-qeta-common';\nimport { useNavigate } from 'react-router-dom';\nimport { useTranslation } from '../../utils';\nimport { useTagsFollow } from '../../utils/hooks';\nimport { MarkdownRenderer } from '../MarkdownRenderer';\n\nconst cache: Map<string, TagResponse> = new Map();\n\nconst TagTooltip = (props: { tag: string }) => {\n const { tag } = props;\n const qetaApi = useApi(qetaApiRef);\n const { t } = useTranslation();\n const tags = useTagsFollow();\n const [resp, setResp] = React.useState<undefined | TagResponse>();\n\n useEffect(() => {\n if (cache.has(tag)) {\n setResp(cache.get(tag));\n return;\n }\n\n qetaApi.getTag(tag).then(res => {\n if (res) {\n cache.set(tag, res);\n setResp(res);\n }\n });\n }, [qetaApi, tag]);\n\n if (!resp) {\n return null;\n }\n\n return (\n <Grid container style={{ padding: '0.5rem' }} spacing={1}>\n <Grid item xs={12}>\n <Typography variant=\"h6\">{tag}</Typography>\n </Grid>\n <Grid item xs={12}>\n <Typography variant=\"subtitle2\">\n {t('common.posts', { count: resp.postsCount, itemType: 'post' })}\n {' · '}\n {t('common.followers', { count: resp.followerCount })}\n </Typography>\n </Grid>\n {resp.description && (\n <Grid item xs={12}>\n <MarkdownRenderer content={resp.description} />\n </Grid>\n )}\n {!tags.loading && (\n <Grid item xs={12}>\n <Button\n size=\"small\"\n variant=\"outlined\"\n color={tags.isFollowingTag(tag) ? 'secondary' : 'primary'}\n onClick={() => {\n if (tags.isFollowingTag(tag)) {\n tags.unfollowTag(tag);\n } else {\n tags.followTag(tag);\n }\n }}\n >\n {tags.isFollowingTag(tag)\n ? t('tagButton.unfollow')\n : t('tagButton.follow')}\n </Button>\n </Grid>\n )}\n </Grid>\n );\n};\n\nexport const TagChip = (props: { tag: string }) => {\n const tagRoute = useRouteRef(tagRouteRef);\n const navigate = useNavigate();\n const { tag } = props;\n return (\n <Tooltip\n arrow\n title={<TagTooltip tag={tag} />}\n interactive\n enterDelay={400}\n >\n <Chip\n label={tag}\n size=\"small\"\n className=\"qetaTagChip\"\n component=\"a\"\n onClick={() => {\n navigate(tagRoute({ tag }));\n }}\n clickable\n />\n </Tooltip>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import { useApi } from '@backstage/core-plugin-api';
2
+ import { catalogApiRef } from '@backstage/plugin-catalog-react';
3
+ import React, { useEffect } from 'react';
4
+ import { stringifyEntityRef } from '@backstage/catalog-model';
5
+ import { compact } from 'lodash';
6
+ import { EntityChip } from './EntityChip.esm.js';
7
+ import { TagChip } from './TagChip.esm.js';
8
+
9
+ const TagsAndEntities = (props) => {
10
+ const { entity } = props;
11
+ const catalogApi = useApi(catalogApiRef);
12
+ const [entities, setEntities] = React.useState([]);
13
+ useEffect(() => {
14
+ if (entity.entities && entity.entities.length > 0) {
15
+ catalogApi.getEntitiesByRefs({
16
+ entityRefs: entity.entities,
17
+ fields: [
18
+ "kind",
19
+ "metadata.name",
20
+ "metadata.namespace",
21
+ "metadata.title"
22
+ ]
23
+ }).catch((_) => setEntities([])).then(
24
+ (data) => data ? setEntities(compact(data.items)) : setEntities([])
25
+ );
26
+ }
27
+ }, [catalogApi, entity]);
28
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, entity.tags && entity.tags.map((tag) => /* @__PURE__ */ React.createElement(TagChip, { key: tag, tag })), entities && entities.map((component) => /* @__PURE__ */ React.createElement(EntityChip, { entity: component, key: stringifyEntityRef(component) })));
29
+ };
30
+
31
+ export { TagsAndEntities };
32
+ //# sourceMappingURL=TagsAndEntities.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TagsAndEntities.esm.js","sources":["../../../src/components/TagsAndEntities/TagsAndEntities.tsx"],"sourcesContent":["import {\n CollectionResponse,\n PostResponse,\n} from '@drodil/backstage-plugin-qeta-common';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { catalogApiRef } from '@backstage/plugin-catalog-react';\nimport React, { useEffect } from 'react';\nimport { Entity, stringifyEntityRef } from '@backstage/catalog-model';\nimport { compact } from 'lodash';\nimport { EntityChip } from './EntityChip';\nimport { TagChip } from './TagChip';\n\nexport const TagsAndEntities = (props: {\n entity: PostResponse | CollectionResponse;\n}) => {\n const { entity } = props;\n const catalogApi = useApi(catalogApiRef);\n const [entities, setEntities] = React.useState<Entity[]>([]);\n useEffect(() => {\n if (entity.entities && entity.entities.length > 0) {\n catalogApi\n .getEntitiesByRefs({\n entityRefs: entity.entities,\n fields: [\n 'kind',\n 'metadata.name',\n 'metadata.namespace',\n 'metadata.title',\n ],\n })\n .catch(_ => setEntities([]))\n .then(data =>\n data ? setEntities(compact(data.items)) : setEntities([]),\n );\n }\n }, [catalogApi, entity]);\n\n return (\n <>\n {entity.tags && entity.tags.map(tag => <TagChip key={tag} tag={tag} />)}\n {entities &&\n entities.map(component => (\n <EntityChip entity={component} key={stringifyEntityRef(component)} />\n ))}\n </>\n );\n};\n"],"names":[],"mappings":";;;;;;;;AAYa,MAAA,eAAA,GAAkB,CAAC,KAE1B,KAAA;AACJ,EAAM,MAAA,EAAE,QAAW,GAAA,KAAA,CAAA;AACnB,EAAM,MAAA,UAAA,GAAa,OAAO,aAAa,CAAA,CAAA;AACvC,EAAA,MAAM,CAAC,QAAU,EAAA,WAAW,IAAI,KAAM,CAAA,QAAA,CAAmB,EAAE,CAAA,CAAA;AAC3D,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,MAAO,CAAA,QAAA,IAAY,MAAO,CAAA,QAAA,CAAS,SAAS,CAAG,EAAA;AACjD,MAAA,UAAA,CACG,iBAAkB,CAAA;AAAA,QACjB,YAAY,MAAO,CAAA,QAAA;AAAA,QACnB,MAAQ,EAAA;AAAA,UACN,MAAA;AAAA,UACA,eAAA;AAAA,UACA,oBAAA;AAAA,UACA,gBAAA;AAAA,SACF;AAAA,OACD,EACA,KAAM,CAAA,CAAA,CAAA,KAAK,YAAY,EAAE,CAAC,CAC1B,CAAA,IAAA;AAAA,QAAK,CAAA,IAAA,KACJ,IAAO,GAAA,WAAA,CAAY,OAAQ,CAAA,IAAA,CAAK,KAAK,CAAC,CAAA,GAAI,WAAY,CAAA,EAAE,CAAA;AAAA,OAC1D,CAAA;AAAA,KACJ;AAAA,GACC,EAAA,CAAC,UAAY,EAAA,MAAM,CAAC,CAAA,CAAA;AAEvB,EACE,uBAAA,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,EACG,MAAO,CAAA,IAAA,IAAQ,MAAO,CAAA,IAAA,CAAK,GAAI,CAAA,CAAA,GAAA,qBAAQ,KAAA,CAAA,aAAA,CAAA,OAAA,EAAA,EAAQ,GAAK,EAAA,GAAA,EAAK,GAAU,EAAA,CAAE,CACrE,EAAA,QAAA,IACC,QAAS,CAAA,GAAA,CAAI,CACX,SAAA,qBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,MAAA,EAAQ,SAAW,EAAA,GAAA,EAAK,kBAAmB,CAAA,SAAS,CAAG,EAAA,CACpE,CACL,CAAA,CAAA;AAEJ;;;;"}
@@ -0,0 +1,73 @@
1
+ import { Modal, Backdrop, Box, Typography, Grid, TextField, Button } from '@material-ui/core';
2
+ import { Alert } from '@material-ui/lab';
3
+ import React from 'react';
4
+ import { useStyles, useTranslation } from '../../utils/hooks.esm.js';
5
+ import { useApi } from '@backstage/core-plugin-api';
6
+ import { qetaApiRef } from '../../api.esm.js';
7
+
8
+ const EditTagModal = (props) => {
9
+ const { tag, open, onClose } = props;
10
+ const [description, setDescription] = React.useState(tag.description);
11
+ const styles = useStyles();
12
+ const { t } = useTranslation();
13
+ const [error, setError] = React.useState(false);
14
+ const qetaApi = useApi(qetaApiRef);
15
+ const handleUpdate = () => {
16
+ qetaApi.updateTag(tag.tag, description).then((ret) => {
17
+ if (ret) {
18
+ onClose();
19
+ return;
20
+ }
21
+ setError(true);
22
+ }).catch(() => {
23
+ setError(true);
24
+ });
25
+ };
26
+ return /* @__PURE__ */ React.createElement(
27
+ Modal,
28
+ {
29
+ open,
30
+ onClose,
31
+ className: "qetaEditTagModal",
32
+ "aria-labelledby": "modal-modal-title",
33
+ "aria-describedby": "modal-modal-description",
34
+ closeAfterTransition: true,
35
+ BackdropComponent: Backdrop,
36
+ BackdropProps: {
37
+ timeout: 500
38
+ }
39
+ },
40
+ /* @__PURE__ */ React.createElement(Box, { className: `qetaEditTagContent ${styles.deleteModal}` }, error && /* @__PURE__ */ React.createElement(Alert, { severity: "error" }, t("editTagModal.errorPosting")), /* @__PURE__ */ React.createElement(
41
+ Typography,
42
+ {
43
+ id: "modal-modal-title",
44
+ className: "qetaEditTagModalTitle",
45
+ variant: "h6",
46
+ component: "h2"
47
+ },
48
+ t("editTagModal.title", { tag: tag.tag })
49
+ ), /* @__PURE__ */ React.createElement(Grid, { container: true }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(
50
+ TextField,
51
+ {
52
+ variant: "outlined",
53
+ label: t("editTagModal.description"),
54
+ multiline: true,
55
+ minRows: 10,
56
+ style: { width: "100%" },
57
+ value: description,
58
+ onChange: (e) => setDescription(e.target.value)
59
+ }
60
+ ))), /* @__PURE__ */ React.createElement(
61
+ Button,
62
+ {
63
+ onClick: handleUpdate,
64
+ className: "qetaEditTagModalSaveBtn",
65
+ color: "secondary"
66
+ },
67
+ t("editTagModal.saveButton")
68
+ ), /* @__PURE__ */ React.createElement(Button, { onClick: onClose, className: "qetaEditTagModalCancelBtn" }, t("editTagModal.cancelButton")))
69
+ );
70
+ };
71
+
72
+ export { EditTagModal };
73
+ //# sourceMappingURL=EditTagModal.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EditTagModal.esm.js","sources":["../../../src/components/TagsGrid/EditTagModal.tsx"],"sourcesContent":["import { TagResponse } from '@drodil/backstage-plugin-qeta-common';\nimport {\n Backdrop,\n Box,\n Button,\n Grid,\n Modal,\n TextField,\n Typography,\n} from '@material-ui/core';\nimport { Alert } from '@material-ui/lab';\nimport React from 'react';\nimport { useStyles, useTranslation } from '../../utils';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { qetaApiRef } from '../../api';\n\nexport const EditTagModal = (props: {\n tag: TagResponse;\n open: boolean;\n onClose: () => void;\n}) => {\n const { tag, open, onClose } = props;\n const [description, setDescription] = React.useState(tag.description);\n const styles = useStyles();\n const { t } = useTranslation();\n const [error, setError] = React.useState(false);\n const qetaApi = useApi(qetaApiRef);\n\n const handleUpdate = () => {\n qetaApi\n .updateTag(tag.tag, description)\n .then(ret => {\n if (ret) {\n onClose();\n return;\n }\n setError(true);\n })\n .catch(() => {\n setError(true);\n });\n };\n\n return (\n <Modal\n open={open}\n onClose={onClose}\n className=\"qetaEditTagModal\"\n aria-labelledby=\"modal-modal-title\"\n aria-describedby=\"modal-modal-description\"\n closeAfterTransition\n BackdropComponent={Backdrop}\n BackdropProps={{\n timeout: 500,\n }}\n >\n <Box className={`qetaEditTagContent ${styles.deleteModal}`}>\n {error && (\n <Alert severity=\"error\">{t('editTagModal.errorPosting')}</Alert>\n )}\n <Typography\n id=\"modal-modal-title\"\n className=\"qetaEditTagModalTitle\"\n variant=\"h6\"\n component=\"h2\"\n >\n {t('editTagModal.title', { tag: tag.tag })}\n </Typography>\n <Grid container>\n <Grid item xs={12}>\n <TextField\n variant=\"outlined\"\n label={t('editTagModal.description')}\n multiline\n minRows={10}\n style={{ width: '100%' }}\n value={description}\n onChange={e => setDescription(e.target.value)}\n />\n </Grid>\n </Grid>\n <Button\n onClick={handleUpdate}\n className=\"qetaEditTagModalSaveBtn\"\n color=\"secondary\"\n >\n {t('editTagModal.saveButton')}\n </Button>\n <Button onClick={onClose} className=\"qetaEditTagModalCancelBtn\">\n {t('editTagModal.cancelButton')}\n </Button>\n </Box>\n </Modal>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ import { truncate, removeMarkdownFormatting } from '@drodil/backstage-plugin-qeta-common';
2
+ import { Grid, Card, CardActionArea, CardHeader, CardContent, Typography, CardActions, Button } from '@material-ui/core';
3
+ import React from 'react';
4
+ import { useRouteRef } from '@backstage/core-plugin-api';
5
+ import { tagRouteRef } from '../../routes.esm.js';
6
+ import { useNavigate } from 'react-router-dom';
7
+ import { useTranslation, useTagsFollow } from '../../utils/hooks.esm.js';
8
+ import { EditTagModal } from './EditTagModal.esm.js';
9
+ import DOMPurify from 'dompurify';
10
+
11
+ const TagGridItem = (props) => {
12
+ const { tag } = props;
13
+ const tagRoute = useRouteRef(tagRouteRef);
14
+ const navigate = useNavigate();
15
+ const { t } = useTranslation();
16
+ const tags = useTagsFollow();
17
+ const [editModalOpen, setEditModalOpen] = React.useState(false);
18
+ const handleEditModalOpen = () => setEditModalOpen(true);
19
+ const handleEditModalClose = () => setEditModalOpen(false);
20
+ return /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 3 }, /* @__PURE__ */ React.createElement(
21
+ Card,
22
+ {
23
+ variant: "outlined",
24
+ style: { height: "100%", display: "flex", flexDirection: "column" }
25
+ },
26
+ /* @__PURE__ */ React.createElement(CardActionArea, { onClick: () => navigate(tagRoute({ tag: tag.tag })) }, /* @__PURE__ */ React.createElement(CardHeader, { title: tag.tag }), /* @__PURE__ */ React.createElement(CardContent, null, /* @__PURE__ */ React.createElement(Typography, { variant: "caption" }, t("common.posts", { count: tag.postsCount, itemType: "post" }), " \xB7 ", t("common.followers", { count: tag.followerCount })), /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, " ", DOMPurify.sanitize(
27
+ truncate(removeMarkdownFormatting(tag.description ?? ""), 150)
28
+ )))),
29
+ /* @__PURE__ */ React.createElement(CardActions, { style: { marginTop: "auto" } }, /* @__PURE__ */ React.createElement(
30
+ Button,
31
+ {
32
+ size: "small",
33
+ variant: "outlined",
34
+ color: tags.isFollowingTag(tag.tag) ? "secondary" : "primary",
35
+ onClick: () => {
36
+ if (tags.isFollowingTag(tag.tag)) {
37
+ tags.unfollowTag(tag.tag);
38
+ } else {
39
+ tags.followTag(tag.tag);
40
+ }
41
+ }
42
+ },
43
+ tags.isFollowingTag(tag.tag) ? t("tagButton.unfollow") : t("tagButton.follow")
44
+ ), /* @__PURE__ */ React.createElement(Button, { size: "small", onClick: handleEditModalOpen, variant: "outlined" }, t("tagButton.edit")))
45
+ ), /* @__PURE__ */ React.createElement(
46
+ EditTagModal,
47
+ {
48
+ tag,
49
+ open: editModalOpen,
50
+ onClose: handleEditModalClose
51
+ }
52
+ ));
53
+ };
54
+
55
+ export { TagGridItem };
56
+ //# sourceMappingURL=TagGridItem.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TagGridItem.esm.js","sources":["../../../src/components/TagsGrid/TagGridItem.tsx"],"sourcesContent":["import {\n removeMarkdownFormatting,\n TagResponse,\n truncate,\n} from '@drodil/backstage-plugin-qeta-common';\nimport {\n Button,\n Card,\n CardActionArea,\n CardActions,\n CardContent,\n CardHeader,\n Grid,\n Typography,\n} from '@material-ui/core';\nimport React from 'react';\nimport { useRouteRef } from '@backstage/core-plugin-api';\nimport { tagRouteRef } from '../../routes';\nimport { useNavigate } from 'react-router-dom';\nimport { useTranslation } from '../../utils';\nimport { useTagsFollow } from '../../utils/hooks';\nimport { EditTagModal } from './EditTagModal';\nimport DOMPurify from 'dompurify';\n\nexport const TagGridItem = (props: { tag: TagResponse }) => {\n const { tag } = props;\n const tagRoute = useRouteRef(tagRouteRef);\n const navigate = useNavigate();\n const { t } = useTranslation();\n const tags = useTagsFollow();\n\n const [editModalOpen, setEditModalOpen] = React.useState(false);\n const handleEditModalOpen = () => setEditModalOpen(true);\n const handleEditModalClose = () => setEditModalOpen(false);\n\n return (\n <Grid item xs={3}>\n <Card\n variant=\"outlined\"\n style={{ height: '100%', display: 'flex', flexDirection: 'column' }}\n >\n <CardActionArea onClick={() => navigate(tagRoute({ tag: tag.tag }))}>\n <CardHeader title={tag.tag} />\n <CardContent>\n <Typography variant=\"caption\">\n {t('common.posts', { count: tag.postsCount, itemType: 'post' })}\n {' · '}\n {t('common.followers', { count: tag.followerCount })}\n </Typography>\n <Typography variant=\"body2\">\n {' '}\n {DOMPurify.sanitize(\n truncate(removeMarkdownFormatting(tag.description ?? ''), 150),\n )}\n </Typography>\n </CardContent>\n </CardActionArea>\n <CardActions style={{ marginTop: 'auto' }}>\n <Button\n size=\"small\"\n variant=\"outlined\"\n color={tags.isFollowingTag(tag.tag) ? 'secondary' : 'primary'}\n onClick={() => {\n if (tags.isFollowingTag(tag.tag)) {\n tags.unfollowTag(tag.tag);\n } else {\n tags.followTag(tag.tag);\n }\n }}\n >\n {tags.isFollowingTag(tag.tag)\n ? t('tagButton.unfollow')\n : t('tagButton.follow')}\n </Button>\n <Button size=\"small\" onClick={handleEditModalOpen} variant=\"outlined\">\n {t('tagButton.edit')}\n </Button>\n </CardActions>\n </Card>\n <EditTagModal\n tag={tag}\n open={editModalOpen}\n onClose={handleEditModalClose}\n />\n </Grid>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import { Grid, TextField, IconButton, Typography } from '@material-ui/core';
2
+ import React from 'react';
3
+ import { useTranslation, useQetaApi } from '../../utils/hooks.esm.js';
4
+ import { Progress, WarningPanel } from '@backstage/core-components';
5
+ import { TagGridItem } from './TagGridItem.esm.js';
6
+
7
+ const TagsGrid = () => {
8
+ const [searchQuery, setSearchQuery] = React.useState("");
9
+ const { t } = useTranslation();
10
+ const {
11
+ value: response,
12
+ loading,
13
+ error
14
+ } = useQetaApi((api) => api.getTags(), []);
15
+ if (loading) {
16
+ return /* @__PURE__ */ React.createElement(Progress, null);
17
+ }
18
+ if (error || response === void 0) {
19
+ return /* @__PURE__ */ React.createElement(WarningPanel, { severity: "error", title: t("tagPage.errorLoading") }, error?.message);
20
+ }
21
+ const filterData = (query, data) => {
22
+ if (!query) {
23
+ return data;
24
+ }
25
+ return data.filter(
26
+ (tag) => tag.tag.toLowerCase().includes(query) || tag.description?.toLowerCase().includes(query)
27
+ );
28
+ };
29
+ const tags = filterData(searchQuery, response);
30
+ return /* @__PURE__ */ React.createElement(Grid, { container: true, className: "qetaTagsContainer" }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(
31
+ TextField,
32
+ {
33
+ id: "search-bar",
34
+ className: "text qetaTagsContainerSearchInput",
35
+ onChange: (event) => setSearchQuery(event.target.value),
36
+ label: t("tagPage.search.label"),
37
+ variant: "outlined",
38
+ placeholder: t("tagPage.search.placeholder"),
39
+ size: "small"
40
+ }
41
+ ), /* @__PURE__ */ React.createElement(IconButton, { type: "submit", "aria-label": "search" })), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Typography, { variant: "h6", className: "qetaTagsContainerTitle" }, t("tagPage.tags", { count: tags.length }))), /* @__PURE__ */ React.createElement(Grid, { container: true, item: true, xs: 12, alignItems: "stretch" }, tags.map((tag) => /* @__PURE__ */ React.createElement(TagGridItem, { tag, key: tag.tag }))));
42
+ };
43
+
44
+ export { TagsGrid };
45
+ //# sourceMappingURL=TagsGrid.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TagsGrid.esm.js","sources":["../../../src/components/TagsGrid/TagsGrid.tsx"],"sourcesContent":["import { Grid, IconButton, TextField, Typography } from '@material-ui/core';\nimport React from 'react';\nimport { useQetaApi, useTranslation } from '../../utils/hooks';\nimport { Progress, WarningPanel } from '@backstage/core-components';\nimport { TagResponse } from '@drodil/backstage-plugin-qeta-common';\nimport { TagGridItem } from './TagGridItem';\n\nexport const TagsGrid = () => {\n const [searchQuery, setSearchQuery] = React.useState('');\n const { t } = useTranslation();\n\n const {\n value: response,\n loading,\n error,\n } = useQetaApi(api => api.getTags(), []);\n\n if (loading) {\n return <Progress />;\n }\n\n if (error || response === undefined) {\n return (\n <WarningPanel severity=\"error\" title={t('tagPage.errorLoading')}>\n {error?.message}\n </WarningPanel>\n );\n }\n\n const filterData = (query: string, data: TagResponse[]) => {\n if (!query) {\n return data;\n }\n return data.filter(\n tag =>\n tag.tag.toLowerCase().includes(query) ||\n tag.description?.toLowerCase().includes(query),\n );\n };\n\n const tags = filterData(searchQuery, response);\n\n return (\n <Grid container className=\"qetaTagsContainer\">\n <Grid item xs={12}>\n <TextField\n id=\"search-bar\"\n className=\"text qetaTagsContainerSearchInput\"\n onChange={(\n event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>,\n ) => setSearchQuery(event.target.value)}\n label={t('tagPage.search.label')}\n variant=\"outlined\"\n placeholder={t('tagPage.search.placeholder')}\n size=\"small\"\n />\n <IconButton type=\"submit\" aria-label=\"search\" />\n </Grid>\n <Grid item xs={12}>\n <Typography variant=\"h6\" className=\"qetaTagsContainerTitle\">\n {t('tagPage.tags', { count: tags.length })}\n </Typography>\n </Grid>\n <Grid container item xs={12} alignItems=\"stretch\">\n {tags.map(tag => (\n <TagGridItem tag={tag} key={tag.tag} />\n ))}\n </Grid>\n </Grid>\n );\n};\n"],"names":[],"mappings":";;;;;;AAOO,MAAM,WAAW,MAAM;AAC5B,EAAA,MAAM,CAAC,WAAa,EAAA,cAAc,CAAI,GAAA,KAAA,CAAM,SAAS,EAAE,CAAA,CAAA;AACvD,EAAM,MAAA,EAAE,CAAE,EAAA,GAAI,cAAe,EAAA,CAAA;AAE7B,EAAM,MAAA;AAAA,IACJ,KAAO,EAAA,QAAA;AAAA,IACP,OAAA;AAAA,IACA,KAAA;AAAA,MACE,UAAW,CAAA,CAAA,GAAA,KAAO,IAAI,OAAQ,EAAA,EAAG,EAAE,CAAA,CAAA;AAEvC,EAAA,IAAI,OAAS,EAAA;AACX,IAAA,2CAAQ,QAAS,EAAA,IAAA,CAAA,CAAA;AAAA,GACnB;AAEA,EAAI,IAAA,KAAA,IAAS,aAAa,KAAW,CAAA,EAAA;AACnC,IACE,uBAAA,KAAA,CAAA,aAAA,CAAC,gBAAa,QAAS,EAAA,OAAA,EAAQ,OAAO,CAAE,CAAA,sBAAsB,CAC3D,EAAA,EAAA,KAAA,EAAO,OACV,CAAA,CAAA;AAAA,GAEJ;AAEA,EAAM,MAAA,UAAA,GAAa,CAAC,KAAA,EAAe,IAAwB,KAAA;AACzD,IAAA,IAAI,CAAC,KAAO,EAAA;AACV,MAAO,OAAA,IAAA,CAAA;AAAA,KACT;AACA,IAAA,OAAO,IAAK,CAAA,MAAA;AAAA,MACV,CACE,GAAA,KAAA,GAAA,CAAI,GAAI,CAAA,WAAA,EAAc,CAAA,QAAA,CAAS,KAAK,CAAA,IACpC,GAAI,CAAA,WAAA,EAAa,WAAY,EAAA,CAAE,SAAS,KAAK,CAAA;AAAA,KACjD,CAAA;AAAA,GACF,CAAA;AAEA,EAAM,MAAA,IAAA,GAAO,UAAW,CAAA,WAAA,EAAa,QAAQ,CAAA,CAAA;AAE7C,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,IAAK,EAAA,EAAA,SAAA,EAAS,IAAC,EAAA,SAAA,EAAU,mBACxB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,IAAK,EAAA,EAAA,IAAA,EAAI,IAAC,EAAA,EAAA,EAAI,EACb,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,EAAG,EAAA,YAAA;AAAA,MACH,SAAU,EAAA,mCAAA;AAAA,MACV,UAAU,CACR,KAAA,KACG,cAAe,CAAA,KAAA,CAAM,OAAO,KAAK,CAAA;AAAA,MACtC,KAAA,EAAO,EAAE,sBAAsB,CAAA;AAAA,MAC/B,OAAQ,EAAA,UAAA;AAAA,MACR,WAAA,EAAa,EAAE,4BAA4B,CAAA;AAAA,MAC3C,IAAK,EAAA,OAAA;AAAA,KAAA;AAAA,GACP,kBACC,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,IAAK,EAAA,QAAA,EAAS,cAAW,QAAS,EAAA,CAChD,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,IAAK,EAAA,EAAA,IAAA,EAAI,MAAC,EAAI,EAAA,EAAA,EAAA,kBACZ,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,IAAA,EAAK,WAAU,wBAChC,EAAA,EAAA,CAAA,CAAE,cAAgB,EAAA,EAAE,KAAO,EAAA,IAAA,CAAK,QAAQ,CAC3C,CACF,CAAA,kBACC,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,WAAS,IAAC,EAAA,IAAA,EAAI,IAAC,EAAA,EAAA,EAAI,EAAI,EAAA,UAAA,EAAW,aACrC,IAAK,CAAA,GAAA,CAAI,CACR,GAAA,qBAAA,KAAA,CAAA,aAAA,CAAC,WAAY,EAAA,EAAA,GAAA,EAAU,KAAK,GAAI,CAAA,GAAA,EAAK,CACtC,CACH,CACF,CAAA,CAAA;AAEJ;;;;"}
@@ -0,0 +1,161 @@
1
+ import React from 'react';
2
+ import { WarningPanel, CardTab, TabbedCard, Progress } from '@backstage/core-components';
3
+ import { List, ListItem, ListItemAvatar, Avatar, ListItemText, Typography } from '@material-ui/core';
4
+ import { useTranslation, useQetaApi } from '../../utils/hooks.esm.js';
5
+ import { TrophyIcon } from './TrophyIcon.esm.js';
6
+ import { useStyles } from './styles.esm.js';
7
+ import { UserLink } from '../Links/Links.esm.js';
8
+
9
+ const DefaultRankingIcons = /* @__PURE__ */ new Map([
10
+ [
11
+ 1,
12
+ /* @__PURE__ */ React.createElement(
13
+ TrophyIcon,
14
+ {
15
+ style: { color: "#DAA520", height: "2.2rem", width: "2.2rem" }
16
+ }
17
+ )
18
+ ],
19
+ [
20
+ 2,
21
+ /* @__PURE__ */ React.createElement(
22
+ TrophyIcon,
23
+ {
24
+ style: { color: "#C0C0C0", height: "2.1rem", width: "2.1rem" }
25
+ }
26
+ )
27
+ ],
28
+ [
29
+ 3,
30
+ /* @__PURE__ */ React.createElement(TrophyIcon, { style: { color: "#B87333", height: "2rem", width: "2rem" } })
31
+ ]
32
+ ]);
33
+ const DefaultUserIcon = /* @__PURE__ */ React.createElement(TrophyIcon, { style: { height: "2rem", width: "2rem" } });
34
+ const getOrdinal = (n) => {
35
+ if (n % 10 === 1 && n % 100 !== 11) {
36
+ return `${n}st`;
37
+ } else if (n % 10 === 2 && n % 100 !== 12) {
38
+ return `${n}nd`;
39
+ } else if (n % 10 === 3 && n % 100 !== 13) {
40
+ return `${n}rd`;
41
+ }
42
+ return `${n}th`;
43
+ };
44
+ const RankingRow = (props) => {
45
+ const classes = useStyles();
46
+ const userRef = props.userRef;
47
+ const ordinalPosition = props?.position ? getOrdinal(props?.position) : "";
48
+ const userIcon = props.rankingIcon?.userRankingIcon ? props.rankingIcon?.userRankingIcon : DefaultUserIcon;
49
+ const topRankingIcon = props.rankingIcon ? props.rankingIcon.iconsByRanking.get(Number(props?.position)) : DefaultRankingIcons.get(Number(props?.position)) || DefaultUserIcon;
50
+ const rankingIcon = props?.position > 3 ? userIcon : topRankingIcon;
51
+ return /* @__PURE__ */ React.createElement(ListItem, { className: "qetaRankingCardRow" }, /* @__PURE__ */ React.createElement(ListItemAvatar, null, /* @__PURE__ */ React.createElement(Avatar, { className: classes.trophyIcon }, rankingIcon)), /* @__PURE__ */ React.createElement(
52
+ ListItemText,
53
+ {
54
+ disableTypography: true,
55
+ style: {
56
+ display: "flex",
57
+ justifyContent: "center"
58
+ },
59
+ primary: /* @__PURE__ */ React.createElement("div", { style: { display: "flex" } }, /* @__PURE__ */ React.createElement(
60
+ Typography,
61
+ {
62
+ style: { marginRight: "10px", fontWeight: 400 },
63
+ variant: "subtitle1"
64
+ },
65
+ `${ordinalPosition}`,
66
+ " ",
67
+ /* @__PURE__ */ React.createElement(UserLink, { entityRef: userRef ?? "" })
68
+ ))
69
+ }
70
+ ), /* @__PURE__ */ React.createElement("div", { className: classes.votesText }, /* @__PURE__ */ React.createElement(Typography, { variant: "subtitle1" }, props?.total, " ", props.unit)));
71
+ };
72
+ const RankingCard = (props) => {
73
+ const rankingStats = props.limit ? props.statistic?.ranking.slice(0, props.limit) : props.statistic?.ranking;
74
+ return /* @__PURE__ */ React.createElement("div", { style: { display: "block" }, className: "qetaRankingCard" }, /* @__PURE__ */ React.createElement("span", { className: "qetaRankingCardDescription" }, props.description), /* @__PURE__ */ React.createElement(List, { className: "qetaRankingCardList" }, rankingStats?.map((authorStats) => {
75
+ return /* @__PURE__ */ React.createElement(
76
+ RankingRow,
77
+ {
78
+ total: authorStats.total || 0,
79
+ position: authorStats.position || 0,
80
+ userRef: authorStats.author,
81
+ unit: props.unit
82
+ }
83
+ );
84
+ }), !rankingStats?.some(
85
+ (authorStats) => authorStats.author === props.statistic?.loggedUser?.author
86
+ ) && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("hr", null), /* @__PURE__ */ React.createElement(
87
+ RankingRow,
88
+ {
89
+ total: props.statistic?.loggedUser?.total || 0,
90
+ position: props.statistic?.loggedUser?.position || 0,
91
+ userRef: props.statistic?.loggedUser?.author,
92
+ unit: props.unit
93
+ }
94
+ ))));
95
+ };
96
+ const TopRankingUsers = (props) => {
97
+ const { t } = useTranslation();
98
+ const {
99
+ value: topStatistics,
100
+ loading,
101
+ error
102
+ } = useQetaApi(
103
+ (api) => api.getTopStatisticsHomepage({
104
+ options: { limit: 50 }
105
+ })
106
+ );
107
+ const tabData = [
108
+ {
109
+ title: t("statistics.mostQuestions.title"),
110
+ description: t("statistics.mostQuestions.description"),
111
+ unit: "questions"
112
+ },
113
+ {
114
+ title: t("statistics.mostAnswers.title"),
115
+ description: t("statistics.mostAnswers.description"),
116
+ unit: "answers"
117
+ },
118
+ {
119
+ title: t("statistics.topVotedQuestions.title"),
120
+ description: t("statistics.topVotedQuestions.description"),
121
+ unit: "votes"
122
+ },
123
+ {
124
+ title: t("statistics.topVotedAnswers.title"),
125
+ description: t("statistics.topVotedAnswers.description"),
126
+ unit: "votes"
127
+ },
128
+ {
129
+ title: t("statistics.topVotedCorrectAnswers.title"),
130
+ description: t("statistics.topVotedCorrectAnswers.description"),
131
+ unit: "votes"
132
+ }
133
+ ];
134
+ if ((error || topStatistics === void 0) && !loading) {
135
+ return /* @__PURE__ */ React.createElement(WarningPanel, { severity: "error", title: t("statistics.errorLoading") }, error?.message);
136
+ }
137
+ let content;
138
+ if (loading) {
139
+ content = [
140
+ /* @__PURE__ */ React.createElement(CardTab, null, /* @__PURE__ */ React.createElement(Progress, null))
141
+ ];
142
+ } else if (topStatistics && topStatistics.length > 0) {
143
+ content = topStatistics?.map((stats, index) => {
144
+ return /* @__PURE__ */ React.createElement(CardTab, { label: tabData[index].title }, /* @__PURE__ */ React.createElement(
145
+ RankingCard,
146
+ {
147
+ description: tabData[index].description,
148
+ limit: props.limit,
149
+ statistic: stats,
150
+ unit: tabData[index].unit
151
+ }
152
+ ));
153
+ });
154
+ } else {
155
+ content = [/* @__PURE__ */ React.createElement(CardTab, null, t("statistics.notAvailable"))];
156
+ }
157
+ return /* @__PURE__ */ React.createElement(TabbedCard, { title: props.title || t("statistics.ranking") }, content);
158
+ };
159
+
160
+ export { RankingCard, RankingRow, TopRankingUsers };
161
+ //# sourceMappingURL=TopRankingUsersCard.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TopRankingUsersCard.esm.js","sources":["../../../src/components/TopRankingUsersCard/TopRankingUsersCard.tsx"],"sourcesContent":["import React, { ReactElement, ReactNode } from 'react';\nimport {\n CardTab,\n Progress,\n TabbedCard,\n WarningPanel,\n} from '@backstage/core-components';\nimport {\n Avatar,\n List,\n ListItem,\n ListItemAvatar,\n ListItemText,\n Typography,\n} from '@material-ui/core';\nimport { StatisticResponse } from '@drodil/backstage-plugin-qeta-common';\nimport { useQetaApi, useTranslation } from '../../utils/hooks';\nimport { TrophyIcon } from './TrophyIcon';\nimport { useStyles } from './styles';\nimport { UserLink } from '../Links';\n\ntype RankingIcon = {\n iconsByRanking: Map<number, ReactNode>;\n userRankingIcon: ReactNode;\n};\n\nconst DefaultRankingIcons = new Map<number, ReactNode>([\n [\n 1,\n <TrophyIcon\n style={{ color: '#DAA520', height: '2.2rem', width: '2.2rem' }}\n />,\n ],\n [\n 2,\n <TrophyIcon\n style={{ color: '#C0C0C0', height: '2.1rem', width: '2.1rem' }}\n />,\n ],\n [\n 3,\n <TrophyIcon style={{ color: '#B87333', height: '2rem', width: '2rem' }} />,\n ],\n]);\n\nconst DefaultUserIcon = (\n <TrophyIcon style={{ height: '2rem', width: '2rem' }} />\n);\n\nconst getOrdinal = (n: number) => {\n if (n % 10 === 1 && n % 100 !== 11) {\n return `${n}st`;\n } else if (n % 10 === 2 && n % 100 !== 12) {\n return `${n}nd`;\n } else if (n % 10 === 3 && n % 100 !== 13) {\n return `${n}rd`;\n }\n\n return `${n}th`;\n};\n\nexport const RankingRow = (props: {\n userRef?: string;\n total: number;\n position: number;\n rankingIcon?: RankingIcon;\n unit: string;\n}) => {\n const classes = useStyles();\n const userRef = props.userRef;\n\n const ordinalPosition = props?.position ? getOrdinal(props?.position) : '';\n\n const userIcon = props.rankingIcon?.userRankingIcon\n ? props.rankingIcon?.userRankingIcon\n : DefaultUserIcon;\n\n const topRankingIcon = props.rankingIcon\n ? props.rankingIcon.iconsByRanking.get(Number(props?.position))\n : DefaultRankingIcons.get(Number(props?.position)) || DefaultUserIcon;\n\n const rankingIcon = props?.position > 3 ? userIcon : topRankingIcon;\n\n return (\n <ListItem className=\"qetaRankingCardRow\">\n <ListItemAvatar>\n <Avatar className={classes.trophyIcon}>{rankingIcon}</Avatar>\n </ListItemAvatar>\n\n <ListItemText\n disableTypography\n style={{\n display: 'flex',\n justifyContent: 'center',\n }}\n primary={\n <div style={{ display: 'flex' }}>\n <Typography\n style={{ marginRight: '10px', fontWeight: 400 }}\n variant=\"subtitle1\"\n >\n {`${ordinalPosition}`} <UserLink entityRef={userRef ?? ''} />\n </Typography>\n </div>\n }\n />\n\n <div className={classes.votesText}>\n <Typography variant=\"subtitle1\">\n {props?.total} {props.unit}\n </Typography>\n </div>\n </ListItem>\n );\n};\n\nexport const RankingCard = (props: {\n limit?: number;\n description: string;\n statistic?: StatisticResponse;\n unit: string;\n}) => {\n const rankingStats = props.limit\n ? props.statistic?.ranking.slice(0, props.limit)\n : props.statistic?.ranking;\n\n return (\n <div style={{ display: 'block' }} className=\"qetaRankingCard\">\n <span className=\"qetaRankingCardDescription\">{props.description}</span>\n <List className=\"qetaRankingCardList\">\n {rankingStats?.map(authorStats => {\n return (\n <RankingRow\n total={authorStats.total || 0}\n position={authorStats.position || 0}\n userRef={authorStats.author}\n unit={props.unit}\n />\n );\n })}\n {!rankingStats?.some(\n authorStats =>\n authorStats.author === props.statistic?.loggedUser?.author,\n ) && (\n <>\n <hr />\n <RankingRow\n total={props.statistic?.loggedUser?.total || 0}\n position={props.statistic?.loggedUser?.position || 0}\n userRef={props.statistic?.loggedUser?.author}\n unit={props.unit}\n />\n </>\n )}\n </List>\n </div>\n );\n};\n\nexport const TopRankingUsers = (props: {\n title?: string;\n hideTitle?: boolean;\n limit?: number;\n}) => {\n const { t } = useTranslation();\n const {\n value: topStatistics,\n loading,\n error,\n } = useQetaApi(api =>\n api.getTopStatisticsHomepage({\n options: { limit: 50 },\n }),\n );\n\n const tabData = [\n {\n title: t('statistics.mostQuestions.title'),\n description: t('statistics.mostQuestions.description'),\n unit: 'questions',\n },\n {\n title: t('statistics.mostAnswers.title'),\n description: t('statistics.mostAnswers.description'),\n unit: 'answers',\n },\n {\n title: t('statistics.topVotedQuestions.title'),\n description: t('statistics.topVotedQuestions.description'),\n unit: 'votes',\n },\n {\n title: t('statistics.topVotedAnswers.title'),\n description: t('statistics.topVotedAnswers.description'),\n unit: 'votes',\n },\n {\n title: t('statistics.topVotedCorrectAnswers.title'),\n description: t('statistics.topVotedCorrectAnswers.description'),\n unit: 'votes',\n },\n ];\n\n if ((error || topStatistics === undefined) && !loading) {\n return (\n <WarningPanel severity=\"error\" title={t('statistics.errorLoading')}>\n {error?.message}\n </WarningPanel>\n );\n }\n\n let content: ReactElement[];\n\n if (loading) {\n content = [\n <CardTab>\n <Progress />\n </CardTab>,\n ];\n } else if (topStatistics && topStatistics.length > 0) {\n content = topStatistics?.map((stats, index) => {\n return (\n <CardTab label={tabData[index].title}>\n <RankingCard\n description={tabData[index].description}\n limit={props.limit}\n statistic={stats}\n unit={tabData[index].unit}\n />\n </CardTab>\n );\n });\n } else {\n content = [<CardTab>{t('statistics.notAvailable')}</CardTab>];\n }\n\n return (\n <TabbedCard title={props.title || t('statistics.ranking')}>\n {content}\n </TabbedCard>\n );\n};\n"],"names":[],"mappings":"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"}