@drodil/backstage-plugin-qeta-react 3.51.0 → 3.52.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 (65) hide show
  1. package/dist/components/AIAnswerCard/AIAnswerCard.esm.js +1 -1
  2. package/dist/components/AnswersContainer/AnswerList.esm.js +13 -34
  3. package/dist/components/AnswersContainer/AnswerList.esm.js.map +1 -1
  4. package/dist/components/AnswersContainer/AnswersContainer.esm.js +24 -29
  5. package/dist/components/AnswersContainer/AnswersContainer.esm.js.map +1 -1
  6. package/dist/components/Badges/UserBadges.esm.js +1 -1
  7. package/dist/components/CollectionsGrid/CollectionsGrid.esm.js +21 -19
  8. package/dist/components/CollectionsGrid/CollectionsGrid.esm.js.map +1 -1
  9. package/dist/components/CollectionsGrid/CollectionsGridContent.esm.js +26 -6
  10. package/dist/components/CollectionsGrid/CollectionsGridContent.esm.js.map +1 -1
  11. package/dist/components/EntitiesGrid/EntitiesGrid.esm.js +20 -17
  12. package/dist/components/EntitiesGrid/EntitiesGrid.esm.js.map +1 -1
  13. package/dist/components/EntitiesGrid/EntitiesGridContent.esm.js +24 -4
  14. package/dist/components/EntitiesGrid/EntitiesGridContent.esm.js.map +1 -1
  15. package/dist/components/FollowedLists/FollowedEntitiesList.esm.js +1 -1
  16. package/dist/components/FollowedLists/FollowedTagsList.esm.js +1 -1
  17. package/dist/components/FollowedLists/FollowedUsersList.esm.js +1 -1
  18. package/dist/components/HomePageCards/ImpactCard.esm.js +40 -4
  19. package/dist/components/HomePageCards/ImpactCard.esm.js.map +1 -1
  20. package/dist/components/HomePageCards/PostsCard.esm.js +1 -1
  21. package/dist/components/LeftMenu/LeftMenu.esm.js +37 -42
  22. package/dist/components/LeftMenu/LeftMenu.esm.js.map +1 -1
  23. package/dist/components/Links/Links.esm.js +1 -1
  24. package/dist/components/PostHighlightList/PostHighlightList.esm.js +1 -1
  25. package/dist/components/PostsContainer/PostList.esm.js +15 -30
  26. package/dist/components/PostsContainer/PostList.esm.js.map +1 -1
  27. package/dist/components/PostsContainer/PostsContainer.esm.js +8 -12
  28. package/dist/components/PostsContainer/PostsContainer.esm.js.map +1 -1
  29. package/dist/components/PostsGrid/PostsGrid.esm.js +8 -12
  30. package/dist/components/PostsGrid/PostsGrid.esm.js.map +1 -1
  31. package/dist/components/PostsGrid/PostsGridContent.esm.js +14 -30
  32. package/dist/components/PostsGrid/PostsGridContent.esm.js.map +1 -1
  33. package/dist/components/SuggestionsCard/SuggestionsCard.esm.js +35 -5
  34. package/dist/components/SuggestionsCard/SuggestionsCard.esm.js.map +1 -1
  35. package/dist/components/TagsAndEntities/EntityChip.esm.js +1 -1
  36. package/dist/components/TagsAndEntities/TagChip.esm.js +1 -1
  37. package/dist/components/TagsAndEntities/UserChip.esm.js +1 -1
  38. package/dist/components/TagsGrid/TagsGrid.esm.js +20 -17
  39. package/dist/components/TagsGrid/TagsGrid.esm.js.map +1 -1
  40. package/dist/components/TagsGrid/TagsGridContent.esm.js +40 -12
  41. package/dist/components/TagsGrid/TagsGridContent.esm.js.map +1 -1
  42. package/dist/components/TemplateList/TemplateForm.esm.js +1 -1
  43. package/dist/components/TemplateList/TemplateList.esm.js +1 -1
  44. package/dist/components/Timeline/Timeline.esm.js +83 -0
  45. package/dist/components/Timeline/Timeline.esm.js.map +1 -0
  46. package/dist/components/Timeline/TimelineItem.esm.js +162 -0
  47. package/dist/components/Timeline/TimelineItem.esm.js.map +1 -0
  48. package/dist/components/UsersGrid/UsersGrid.esm.js +24 -13
  49. package/dist/components/UsersGrid/UsersGrid.esm.js.map +1 -1
  50. package/dist/components/UsersGrid/UsersGridContent.esm.js +24 -4
  51. package/dist/components/UsersGrid/UsersGridContent.esm.js.map +1 -1
  52. package/dist/hooks/useCanReview.esm.js +11 -5
  53. package/dist/hooks/useCanReview.esm.js.map +1 -1
  54. package/dist/hooks/useGridPageSize.esm.js +55 -0
  55. package/dist/hooks/useGridPageSize.esm.js.map +1 -0
  56. package/dist/hooks/usePaginatedPosts.esm.js +22 -5
  57. package/dist/hooks/usePaginatedPosts.esm.js.map +1 -1
  58. package/dist/index.d.ts +64 -31
  59. package/dist/index.esm.js +3 -0
  60. package/dist/index.esm.js.map +1 -1
  61. package/dist/translation.esm.js +32 -5
  62. package/dist/translation.esm.js.map +1 -1
  63. package/package.json +3 -2
  64. package/dist/components/QetaPagination/QetaPagination.esm.js +0 -69
  65. package/dist/components/QetaPagination/QetaPagination.esm.js.map +0 -1
@@ -0,0 +1,162 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { makeStyles, ListItem, ListItemAvatar, Avatar, ListItemText } from '@material-ui/core';
3
+ import { Link } from 'react-router-dom';
4
+ import { useRouteRef } from '@backstage/core-plugin-api';
5
+ import { questionRouteRef, articleRouteRef, linkRouteRef, collectionRouteRef } from '../../routes.esm.js';
6
+ import { RelativeTimeWithTooltip } from '../RelativeTimeWithTooltip/RelativeTimeWithTooltip.esm.js';
7
+ import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
8
+ import { qetaTranslationRef } from '../../translation.esm.js';
9
+ import { UserLink } from '../Links/Links.esm.js';
10
+ import '../../api.esm.js';
11
+ import 'react-use';
12
+ import 'react';
13
+ import { useUserInfo } from '../../hooks/useEntityAuthor.esm.js';
14
+ import 'react-use/lib/useAsync';
15
+ import '@backstage/plugin-permission-react';
16
+ import '@drodil/backstage-plugin-qeta-common';
17
+ import '@backstage/plugin-permission-common';
18
+
19
+ const useStyles = makeStyles((theme) => ({
20
+ root: {
21
+ width: "100%",
22
+ padding: theme.spacing(1, 1.5),
23
+ marginBottom: 0,
24
+ borderBottom: `1px solid ${theme.palette.divider}`,
25
+ borderRadius: theme.shape.borderRadius,
26
+ transition: "background-color 0.15s ease-in-out",
27
+ position: "relative",
28
+ cursor: "pointer",
29
+ "&:hover": {
30
+ backgroundColor: theme.palette.action.hover
31
+ },
32
+ "&:last-child": {
33
+ borderBottom: "none"
34
+ }
35
+ },
36
+ overlayLink: {
37
+ position: "absolute",
38
+ top: 0,
39
+ left: 0,
40
+ right: 0,
41
+ bottom: 0,
42
+ zIndex: 0
43
+ },
44
+ contentWrapper: {
45
+ pointerEvents: "none"
46
+ },
47
+ contentClickable: {
48
+ position: "relative",
49
+ zIndex: 1,
50
+ pointerEvents: "auto"
51
+ },
52
+ inline: {
53
+ display: "inline"
54
+ },
55
+ avatar: {
56
+ minWidth: "36px"
57
+ },
58
+ text: {
59
+ whiteSpace: "nowrap",
60
+ overflow: "hidden",
61
+ textOverflow: "ellipsis",
62
+ display: "flex",
63
+ alignItems: "center",
64
+ gap: "6px"
65
+ },
66
+ link: {
67
+ fontWeight: "bold",
68
+ overflow: "hidden",
69
+ textOverflow: "ellipsis",
70
+ whiteSpace: "nowrap",
71
+ maxWidth: "450px",
72
+ display: "inline-block",
73
+ verticalAlign: "bottom"
74
+ },
75
+ action: {
76
+ opacity: 0.8
77
+ },
78
+ time: {
79
+ opacity: 0.6,
80
+ fontSize: "0.8em",
81
+ marginLeft: "auto"
82
+ }
83
+ }));
84
+ const TimelineItemCard = ({ item }) => {
85
+ const classes = useStyles();
86
+ const { t } = useTranslationRef(qetaTranslationRef);
87
+ const questionRoute = useRouteRef(questionRouteRef);
88
+ const articleRoute = useRouteRef(articleRouteRef);
89
+ const linkRoute = useRouteRef(linkRouteRef);
90
+ const collectionRoute = useRouteRef(collectionRouteRef);
91
+ const { user } = useUserInfo(item.author);
92
+ let title = item.title;
93
+ let link = "";
94
+ let action = "";
95
+ if (item.type === "post") {
96
+ const postType = item.postType || "question";
97
+ const isUpdated = item.action === "updated";
98
+ if (postType === "article") {
99
+ link = articleRoute({ id: item.id.toString() });
100
+ action = isUpdated ? t("timeline.updatedArticle") : t("timeline.postedArticle");
101
+ } else if (postType === "link") {
102
+ link = linkRoute({ id: item.id.toString() });
103
+ action = isUpdated ? t("timeline.updatedLink") : t("timeline.postedLink");
104
+ } else {
105
+ link = questionRoute({ id: item.id.toString() });
106
+ action = isUpdated ? t("timeline.updatedQuestion") : t("timeline.postedQuestion");
107
+ }
108
+ } else if (item.type === "answer") {
109
+ link = `${questionRoute({ id: item.postId.toString() })}#answer_${item.id}`;
110
+ title = item.postTitle;
111
+ action = t("timeline.answered");
112
+ } else if (item.type === "comment") {
113
+ title = item.postTitle;
114
+ const postType = item.postType || "question";
115
+ if (postType === "article") {
116
+ link = articleRoute({ id: item.postId.toString() });
117
+ action = t("timeline.commentedOnArticle");
118
+ } else if (postType === "link") {
119
+ link = linkRoute({ id: item.postId.toString() });
120
+ action = t("timeline.commentedOnLink");
121
+ } else {
122
+ link = questionRoute({ id: item.postId.toString() });
123
+ action = t("timeline.commentedOnQuestion");
124
+ }
125
+ } else if (item.type === "collection") {
126
+ link = collectionRoute({ id: item.id.toString() });
127
+ action = t("timeline.createdCollection");
128
+ }
129
+ return /* @__PURE__ */ jsxs(ListItem, { alignItems: "center", className: classes.root, dense: true, children: [
130
+ /* @__PURE__ */ jsx(
131
+ Link,
132
+ {
133
+ to: link,
134
+ className: classes.overlayLink,
135
+ "aria-label": title
136
+ }
137
+ ),
138
+ /* @__PURE__ */ jsx(ListItemAvatar, { className: `${classes.avatar} ${classes.contentWrapper}`, children: /* @__PURE__ */ jsx(
139
+ Avatar,
140
+ {
141
+ alt: item.author,
142
+ src: item.headerImage || user?.spec?.profile?.picture,
143
+ style: { width: "26px", height: "26px", fontSize: "14px" }
144
+ }
145
+ ) }),
146
+ /* @__PURE__ */ jsx(
147
+ ListItemText,
148
+ {
149
+ className: classes.contentWrapper,
150
+ primary: /* @__PURE__ */ jsxs("div", { className: classes.text, children: [
151
+ /* @__PURE__ */ jsx("span", { className: classes.contentClickable, children: /* @__PURE__ */ jsx(UserLink, { entityRef: item.author }) }),
152
+ /* @__PURE__ */ jsx("span", { className: classes.action, children: action }),
153
+ /* @__PURE__ */ jsx("span", { className: classes.link, children: title }),
154
+ /* @__PURE__ */ jsx("span", { className: classes.time, children: /* @__PURE__ */ jsx(RelativeTimeWithTooltip, { value: item.date }) })
155
+ ] })
156
+ }
157
+ )
158
+ ] });
159
+ };
160
+
161
+ export { TimelineItemCard };
162
+ //# sourceMappingURL=TimelineItem.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TimelineItem.esm.js","sources":["../../../src/components/Timeline/TimelineItem.tsx"],"sourcesContent":["import { TimelineItem } from '@drodil/backstage-plugin-qeta-common';\nimport {\n ListItem,\n ListItemAvatar,\n ListItemText,\n Avatar,\n makeStyles,\n} from '@material-ui/core';\nimport { Link as RouterLink } from 'react-router-dom';\n\nimport { useRouteRef } from '@backstage/core-plugin-api';\nimport {\n questionRouteRef,\n articleRouteRef,\n linkRouteRef,\n collectionRouteRef,\n} from '../../routes';\nimport { RelativeTimeWithTooltip } from '../RelativeTimeWithTooltip';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { qetaTranslationRef } from '../../translation';\nimport { UserLink } from '../Links';\n\nimport { useUserInfo } from '../../hooks';\n\nconst useStyles = makeStyles(theme => ({\n root: {\n width: '100%',\n padding: theme.spacing(1, 1.5),\n marginBottom: 0,\n borderBottom: `1px solid ${theme.palette.divider}`,\n borderRadius: theme.shape.borderRadius,\n transition: 'background-color 0.15s ease-in-out',\n position: 'relative',\n cursor: 'pointer',\n '&:hover': {\n backgroundColor: theme.palette.action.hover,\n },\n '&:last-child': {\n borderBottom: 'none',\n },\n },\n overlayLink: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 0,\n },\n contentWrapper: {\n pointerEvents: 'none',\n },\n contentClickable: {\n position: 'relative',\n zIndex: 1,\n pointerEvents: 'auto',\n },\n inline: {\n display: 'inline',\n },\n avatar: {\n minWidth: '36px',\n },\n text: {\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n display: 'flex',\n alignItems: 'center',\n gap: '6px',\n },\n link: {\n fontWeight: 'bold',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n maxWidth: '450px',\n display: 'inline-block',\n verticalAlign: 'bottom',\n },\n action: {\n opacity: 0.8,\n },\n time: {\n opacity: 0.6,\n fontSize: '0.8em',\n marginLeft: 'auto',\n },\n}));\n\nexport const TimelineItemCard = ({ item }: { item: TimelineItem }) => {\n const classes = useStyles();\n const { t } = useTranslationRef(qetaTranslationRef);\n const questionRoute = useRouteRef(questionRouteRef);\n const articleRoute = useRouteRef(articleRouteRef);\n const linkRoute = useRouteRef(linkRouteRef);\n const collectionRoute = useRouteRef(collectionRouteRef);\n const { user } = useUserInfo(item.author);\n\n let title = item.title;\n let link: string = '';\n let action: string = '';\n\n if (item.type === 'post') {\n const postType = item.postType || 'question';\n const isUpdated = item.action === 'updated';\n if (postType === 'article') {\n link = articleRoute({ id: item.id.toString() });\n action = isUpdated\n ? t('timeline.updatedArticle')\n : t('timeline.postedArticle');\n } else if (postType === 'link') {\n link = linkRoute({ id: item.id.toString() });\n action = isUpdated ? t('timeline.updatedLink') : t('timeline.postedLink');\n } else {\n link = questionRoute({ id: item.id.toString() });\n action = isUpdated\n ? t('timeline.updatedQuestion')\n : t('timeline.postedQuestion');\n }\n } else if (item.type === 'answer') {\n link = `${questionRoute({ id: item.postId.toString() })}#answer_${item.id}`;\n title = item.postTitle;\n action = t('timeline.answered');\n } else if (item.type === 'comment') {\n title = item.postTitle;\n const postType = item.postType || 'question';\n if (postType === 'article') {\n link = articleRoute({ id: item.postId.toString() });\n action = t('timeline.commentedOnArticle');\n } else if (postType === 'link') {\n link = linkRoute({ id: item.postId.toString() });\n action = t('timeline.commentedOnLink');\n } else {\n link = questionRoute({ id: item.postId.toString() });\n action = t('timeline.commentedOnQuestion');\n }\n } else if (item.type === 'collection') {\n link = collectionRoute({ id: item.id.toString() });\n action = t('timeline.createdCollection');\n }\n\n return (\n <ListItem alignItems=\"center\" className={classes.root} dense>\n <RouterLink\n to={link}\n className={classes.overlayLink}\n aria-label={title}\n />\n <ListItemAvatar className={`${classes.avatar} ${classes.contentWrapper}`}>\n <Avatar\n alt={item.author}\n src={item.headerImage || user?.spec?.profile?.picture}\n style={{ width: '26px', height: '26px', fontSize: '14px' }}\n />\n </ListItemAvatar>\n <ListItemText\n className={classes.contentWrapper}\n primary={\n <div className={classes.text}>\n <span className={classes.contentClickable}>\n <UserLink entityRef={item.author} />\n </span>\n <span className={classes.action}>{action}</span>\n <span className={classes.link}>{title}</span>\n <span className={classes.time}>\n <RelativeTimeWithTooltip value={item.date} />\n </span>\n </div>\n }\n />\n </ListItem>\n );\n};\n"],"names":["RouterLink"],"mappings":"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"}
@@ -12,7 +12,7 @@ import 'react-use/lib/useAsync';
12
12
  import '@backstage/plugin-permission-react';
13
13
  import '@drodil/backstage-plugin-qeta-common';
14
14
  import '@backstage/plugin-permission-common';
15
- import { QetaPagination } from '../QetaPagination/QetaPagination.esm.js';
15
+ import { useGridPageSize } from '../../hooks/useGridPageSize.esm.js';
16
16
  import { UsersGridContent } from './UsersGridContent.esm.js';
17
17
  import useDebounce from 'react-use/lib/useDebounce';
18
18
  import { QetaGridHeader } from '../Utility/QetaGridHeader.esm.js';
@@ -23,8 +23,7 @@ import FilterList from '@material-ui/icons/FilterList';
23
23
  const EXPANDED_LOCAL_STORAGE_KEY = "qeta-users-filters-expanded";
24
24
  const UsersGrid = () => {
25
25
  const [page, setPage] = useState(1);
26
- const [pageCount, setPageCount] = useState(1);
27
- const [entitiesPerPage, setEntitiesPerPage] = useState(25);
26
+ const entitiesPerPage = useGridPageSize("users", 24);
28
27
  const [searchQuery, setSearchQuery] = useState("");
29
28
  const [showFilterPanel, setShowFilterPanel] = useState(
30
29
  localStorage.getItem(EXPANDED_LOCAL_STORAGE_KEY) === "true"
@@ -34,6 +33,9 @@ const UsersGrid = () => {
34
33
  orderBy: "totalPosts",
35
34
  searchQuery: ""
36
35
  });
36
+ const [users, setUsers] = useState([]);
37
+ const [hasMore, setHasMore] = useState(true);
38
+ const [total, setTotal] = useState(0);
37
39
  useEffect(() => {
38
40
  localStorage.setItem(
39
41
  EXPANDED_LOCAL_STORAGE_KEY,
@@ -43,6 +45,7 @@ const UsersGrid = () => {
43
45
  const onFilterChange = (changes) => {
44
46
  const changesArray = Array.isArray(changes) ? changes : [changes];
45
47
  setPage(1);
48
+ setUsers([]);
46
49
  setFilters((prev) => {
47
50
  const newValue = { ...prev };
48
51
  for (const { key, value } of changesArray) {
@@ -67,6 +70,8 @@ const UsersGrid = () => {
67
70
  useDebounce(
68
71
  () => {
69
72
  if (filters.searchQuery !== searchQuery) {
73
+ setPage(1);
74
+ setUsers([]);
70
75
  setFilters({ ...filters, searchQuery });
71
76
  }
72
77
  },
@@ -75,9 +80,16 @@ const UsersGrid = () => {
75
80
  );
76
81
  useEffect(() => {
77
82
  if (response) {
78
- setPageCount(Math.ceil(response.total / entitiesPerPage));
83
+ if (page === 1) {
84
+ setUsers(response.users);
85
+ } else {
86
+ setUsers((prev) => [...prev, ...response.users]);
87
+ }
88
+ setHasMore(response.users.length >= entitiesPerPage);
89
+ setTotal(response.total);
79
90
  }
80
- }, [response, entitiesPerPage]);
91
+ }, [response, entitiesPerPage, page]);
92
+ const combinedResponse = response ? { ...response, users, total } : void 0;
81
93
  return /* @__PURE__ */ jsxs(Fragment, { children: [
82
94
  /* @__PURE__ */ jsx(
83
95
  QetaGridHeader,
@@ -104,15 +116,14 @@ const UsersGrid = () => {
104
116
  mode: "users"
105
117
  }
106
118
  ) }),
107
- /* @__PURE__ */ jsx(UsersGridContent, { response, loading, error }),
108
- response && response?.total > 0 && /* @__PURE__ */ jsx(
109
- QetaPagination,
119
+ /* @__PURE__ */ jsx(
120
+ UsersGridContent,
110
121
  {
111
- pageSize: entitiesPerPage,
112
- handlePageChange: (_e, p) => setPage(p),
113
- handlePageSizeChange: (e) => setEntitiesPerPage(Number(e.target.value)),
114
- page,
115
- pageCount
122
+ response: combinedResponse,
123
+ loading,
124
+ error,
125
+ hasMore,
126
+ loadNextPage: () => setPage((prev) => prev + 1)
116
127
  }
117
128
  )
118
129
  ] });
@@ -1 +1 @@
1
- {"version":3,"file":"UsersGrid.esm.js","sources":["../../../src/components/UsersGrid/UsersGrid.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { useQetaApi } from '../../hooks';\nimport { QetaPagination } from '../QetaPagination/QetaPagination';\nimport { UsersGridContent } from './UsersGridContent';\nimport useDebounce from 'react-use/lib/useDebounce';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { qetaTranslationRef } from '../../translation.ts';\nimport { QetaGridHeader } from '../Utility/QetaGridHeader';\n\nimport { Change, FilterPanel, UserFilters } from '../FilterPanel/FilterPanel';\nimport { Button, Collapse } from '@material-ui/core';\nimport FilterList from '@material-ui/icons/FilterList';\n\nconst EXPANDED_LOCAL_STORAGE_KEY = 'qeta-users-filters-expanded';\n\nexport const UsersGrid = () => {\n const [page, setPage] = useState(1);\n const [pageCount, setPageCount] = useState(1);\n const [entitiesPerPage, setEntitiesPerPage] = useState(25);\n const [searchQuery, setSearchQuery] = useState('');\n const [showFilterPanel, setShowFilterPanel] = useState(\n localStorage.getItem(EXPANDED_LOCAL_STORAGE_KEY) === 'true',\n );\n const [filters, setFilters] = useState<UserFilters>({\n order: 'desc',\n orderBy: 'totalPosts',\n searchQuery: '',\n });\n\n useEffect(() => {\n localStorage.setItem(\n EXPANDED_LOCAL_STORAGE_KEY,\n showFilterPanel ? 'true' : 'false',\n );\n }, [showFilterPanel]);\n\n const onFilterChange = (\n changes: Change<UserFilters> | Change<UserFilters>[],\n ) => {\n const changesArray = Array.isArray(changes) ? changes : [changes];\n setPage(1);\n setFilters(prev => {\n const newValue = { ...prev };\n for (const { key, value } of changesArray) {\n (newValue as any)[key] = value;\n }\n return newValue;\n });\n };\n const { t } = useTranslationRef(qetaTranslationRef);\n\n const {\n value: response,\n loading,\n error,\n } = useQetaApi(\n api =>\n api.getUsers({\n limit: entitiesPerPage,\n offset: (page - 1) * entitiesPerPage,\n ...filters,\n }),\n [entitiesPerPage, page, filters],\n );\n\n useDebounce(\n () => {\n if (filters.searchQuery !== searchQuery) {\n setFilters({ ...filters, searchQuery: searchQuery });\n }\n },\n 400,\n [searchQuery],\n );\n\n useEffect(() => {\n if (response) {\n setPageCount(Math.ceil(response.total / entitiesPerPage));\n }\n }, [response, entitiesPerPage]);\n\n return (\n <>\n <QetaGridHeader\n title={response ? t('usersPage.users', { count: response.total }) : ''}\n searchBarLabel={t('usersPage.search.label')}\n loading={loading}\n onSearch={setSearchQuery}\n buttons={\n <Button\n onClick={() => setShowFilterPanel(!showFilterPanel)}\n startIcon={<FilterList />}\n >\n {t('filterPanel.filterButton')}\n </Button>\n }\n />\n <Collapse in={showFilterPanel}>\n <FilterPanel<UserFilters>\n onChange={onFilterChange}\n filters={filters}\n mode=\"users\"\n />\n </Collapse>\n <UsersGridContent response={response} loading={loading} error={error} />\n {response && response?.total > 0 && (\n <QetaPagination\n pageSize={entitiesPerPage}\n handlePageChange={(_e, p) => setPage(p)}\n handlePageSizeChange={e => setEntitiesPerPage(Number(e.target.value))}\n page={page}\n pageCount={pageCount}\n />\n )}\n </>\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"UsersGrid.esm.js","sources":["../../../src/components/UsersGrid/UsersGrid.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { useGridPageSize, useQetaApi } from '../../hooks';\n\nimport { UsersGridContent } from './UsersGridContent';\nimport useDebounce from 'react-use/lib/useDebounce';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { qetaTranslationRef } from '../../translation.ts';\nimport { QetaGridHeader } from '../Utility/QetaGridHeader';\n\nimport { Change, FilterPanel, UserFilters } from '../FilterPanel/FilterPanel';\nimport { Button, Collapse } from '@material-ui/core';\nimport FilterList from '@material-ui/icons/FilterList';\n\nconst EXPANDED_LOCAL_STORAGE_KEY = 'qeta-users-filters-expanded';\n\nexport const UsersGrid = () => {\n const [page, setPage] = useState(1);\n const entitiesPerPage = useGridPageSize('users', 24);\n const [searchQuery, setSearchQuery] = useState('');\n const [showFilterPanel, setShowFilterPanel] = useState(\n localStorage.getItem(EXPANDED_LOCAL_STORAGE_KEY) === 'true',\n );\n const [filters, setFilters] = useState<UserFilters>({\n order: 'desc',\n orderBy: 'totalPosts',\n searchQuery: '',\n });\n const [users, setUsers] = useState<any[]>([]);\n const [hasMore, setHasMore] = useState(true);\n const [total, setTotal] = useState(0);\n\n useEffect(() => {\n localStorage.setItem(\n EXPANDED_LOCAL_STORAGE_KEY,\n showFilterPanel ? 'true' : 'false',\n );\n }, [showFilterPanel]);\n\n const onFilterChange = (\n changes: Change<UserFilters> | Change<UserFilters>[],\n ) => {\n const changesArray = Array.isArray(changes) ? changes : [changes];\n setPage(1);\n setUsers([]);\n setFilters(prev => {\n const newValue = { ...prev };\n for (const { key, value } of changesArray) {\n (newValue as any)[key] = value;\n }\n return newValue;\n });\n };\n const { t } = useTranslationRef(qetaTranslationRef);\n\n const {\n value: response,\n loading,\n error,\n } = useQetaApi(\n api =>\n api.getUsers({\n limit: entitiesPerPage,\n offset: (page - 1) * entitiesPerPage,\n ...filters,\n }),\n [entitiesPerPage, page, filters],\n );\n\n useDebounce(\n () => {\n if (filters.searchQuery !== searchQuery) {\n setPage(1);\n setUsers([]);\n setFilters({ ...filters, searchQuery: searchQuery });\n }\n },\n 400,\n [searchQuery],\n );\n\n useEffect(() => {\n if (response) {\n if (page === 1) {\n setUsers(response.users);\n } else {\n setUsers(prev => [...prev, ...response.users]);\n }\n setHasMore(response.users.length >= entitiesPerPage);\n setTotal(response.total);\n }\n }, [response, entitiesPerPage, page]);\n\n const combinedResponse = response ? { ...response, users, total } : undefined;\n\n return (\n <>\n <QetaGridHeader\n title={response ? t('usersPage.users', { count: response.total }) : ''}\n searchBarLabel={t('usersPage.search.label')}\n loading={loading}\n onSearch={setSearchQuery}\n buttons={\n <Button\n onClick={() => setShowFilterPanel(!showFilterPanel)}\n startIcon={<FilterList />}\n >\n {t('filterPanel.filterButton')}\n </Button>\n }\n />\n <Collapse in={showFilterPanel}>\n <FilterPanel<UserFilters>\n onChange={onFilterChange}\n filters={filters}\n mode=\"users\"\n />\n </Collapse>\n <UsersGridContent\n response={combinedResponse}\n loading={loading}\n error={error}\n hasMore={hasMore}\n loadNextPage={() => setPage(prev => prev + 1)}\n />\n </>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { jsx } from 'react/jsx-runtime';
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
2
  import { WarningPanel } from '@backstage/core-components';
3
3
  import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
4
4
  import { qetaTranslationRef } from '../../translation.esm.js';
@@ -6,11 +6,21 @@ import { UsersGridItem } from './UsersGridItem.esm.js';
6
6
  import { NoUsersCard } from './NoUsersCard.esm.js';
7
7
  import { LoadingGrid } from '../LoadingGrid/LoadingGrid.esm.js';
8
8
  import { Grid } from '@material-ui/core';
9
+ import { useInfiniteScroll } from 'infinite-scroll-hook';
9
10
 
10
11
  const UsersGridContent = (props) => {
11
- const { response, error, loading } = props;
12
+ const { response, error, loading, hasMore, loadNextPage } = props;
12
13
  const { t } = useTranslationRef(qetaTranslationRef);
13
- if (loading) {
14
+ const { containerRef: sentryRef } = useInfiniteScroll({
15
+ shouldStop: !hasMore || !!error || loading,
16
+ onLoadMore: async () => {
17
+ if (loadNextPage) {
18
+ await loadNextPage();
19
+ }
20
+ },
21
+ offset: "800px"
22
+ });
23
+ if (loading && (!response || response.users.length === 0)) {
14
24
  return /* @__PURE__ */ jsx(LoadingGrid, {});
15
25
  }
16
26
  if (error || response === void 0) {
@@ -19,7 +29,17 @@ const UsersGridContent = (props) => {
19
29
  if (!response?.users || response.users.length === 0) {
20
30
  return /* @__PURE__ */ jsx(Grid, { xs: 12, children: /* @__PURE__ */ jsx(NoUsersCard, {}) });
21
31
  }
22
- return /* @__PURE__ */ jsx(Grid, { container: true, spacing: 3, alignItems: "stretch", children: response.users.map((entity) => /* @__PURE__ */ jsx(UsersGridItem, { user: entity }, entity.userRef)) });
32
+ return /* @__PURE__ */ jsxs(Grid, { container: true, spacing: 3, alignItems: "stretch", children: [
33
+ response.users.map((entity) => /* @__PURE__ */ jsx(UsersGridItem, { user: entity }, entity.userRef)),
34
+ /* @__PURE__ */ jsx(
35
+ "div",
36
+ {
37
+ ref: sentryRef,
38
+ style: { width: "100%", marginTop: "10px", textAlign: "center" },
39
+ children: loading && /* @__PURE__ */ jsx(LoadingGrid, {})
40
+ }
41
+ )
42
+ ] });
23
43
  };
24
44
 
25
45
  export { UsersGridContent };
@@ -1 +1 @@
1
- {"version":3,"file":"UsersGridContent.esm.js","sources":["../../../src/components/UsersGrid/UsersGridContent.tsx"],"sourcesContent":["import { UsersResponse } from '@drodil/backstage-plugin-qeta-common';\nimport { WarningPanel } from '@backstage/core-components';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { qetaTranslationRef } from '../../translation.ts';\nimport { UsersGridItem } from './UsersGridItem';\nimport { NoUsersCard } from './NoUsersCard';\nimport { LoadingGrid } from '../LoadingGrid/LoadingGrid';\nimport { Grid } from '@material-ui/core';\n\nexport const UsersGridContent = (props: {\n loading: boolean;\n error: any;\n response?: UsersResponse;\n}) => {\n const { response, error, loading } = props;\n const { t } = useTranslationRef(qetaTranslationRef);\n\n if (loading) {\n return <LoadingGrid />;\n }\n\n if (error || response === undefined) {\n return (\n <WarningPanel severity=\"error\" title={t('usersPage.errorLoading')}>\n {error?.message}\n </WarningPanel>\n );\n }\n\n if (!response?.users || response.users.length === 0) {\n return (\n <Grid xs={12}>\n <NoUsersCard />\n </Grid>\n );\n }\n\n return (\n <Grid container spacing={3} alignItems=\"stretch\">\n {response.users.map(entity => (\n <UsersGridItem user={entity} key={entity.userRef} />\n ))}\n </Grid>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;AASa,MAAA,gBAAA,GAAmB,CAAC,KAI3B,KAAA;AACJ,EAAA,MAAM,EAAE,QAAA,EAAU,KAAO,EAAA,OAAA,EAAY,GAAA,KAAA;AACrC,EAAA,MAAM,EAAE,CAAA,EAAM,GAAA,iBAAA,CAAkB,kBAAkB,CAAA;AAElD,EAAA,IAAI,OAAS,EAAA;AACX,IAAA,2BAAQ,WAAY,EAAA,EAAA,CAAA;AAAA;AAGtB,EAAI,IAAA,KAAA,IAAS,aAAa,KAAW,CAAA,EAAA;AACnC,IACE,uBAAA,GAAA,CAAC,gBAAa,QAAS,EAAA,OAAA,EAAQ,OAAO,CAAE,CAAA,wBAAwB,CAC7D,EAAA,QAAA,EAAA,KAAA,EAAO,OACV,EAAA,CAAA;AAAA;AAIJ,EAAA,IAAI,CAAC,QAAU,EAAA,KAAA,IAAS,QAAS,CAAA,KAAA,CAAM,WAAW,CAAG,EAAA;AACnD,IAAA,2BACG,IAAK,EAAA,EAAA,EAAA,EAAI,EACR,EAAA,QAAA,kBAAA,GAAA,CAAC,eAAY,CACf,EAAA,CAAA;AAAA;AAIJ,EAAA,2BACG,IAAK,EAAA,EAAA,SAAA,EAAS,MAAC,OAAS,EAAA,CAAA,EAAG,YAAW,SACpC,EAAA,QAAA,EAAA,QAAA,CAAS,MAAM,GAAI,CAAA,CAAA,MAAA,yBACjB,aAAc,EAAA,EAAA,IAAA,EAAM,UAAa,MAAO,CAAA,OAAS,CACnD,CACH,EAAA,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"UsersGridContent.esm.js","sources":["../../../src/components/UsersGrid/UsersGridContent.tsx"],"sourcesContent":["import { UsersResponse } from '@drodil/backstage-plugin-qeta-common';\nimport { WarningPanel } from '@backstage/core-components';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { qetaTranslationRef } from '../../translation.ts';\nimport { UsersGridItem } from './UsersGridItem';\nimport { NoUsersCard } from './NoUsersCard';\nimport { LoadingGrid } from '../LoadingGrid/LoadingGrid';\nimport { Grid } from '@material-ui/core';\nimport { useInfiniteScroll } from 'infinite-scroll-hook';\n\nexport const UsersGridContent = (props: {\n loading: boolean;\n error: any;\n response?: UsersResponse;\n hasMore?: boolean;\n loadNextPage?: () => void;\n}) => {\n const { response, error, loading, hasMore, loadNextPage } = props;\n const { t } = useTranslationRef(qetaTranslationRef);\n\n const { containerRef: sentryRef } = useInfiniteScroll({\n shouldStop: !hasMore || !!error || loading,\n onLoadMore: async () => {\n if (loadNextPage) {\n await loadNextPage();\n }\n },\n offset: '800px',\n }) as any;\n\n if (loading && (!response || response.users.length === 0)) {\n return <LoadingGrid />;\n }\n\n if (error || response === undefined) {\n return (\n <WarningPanel severity=\"error\" title={t('usersPage.errorLoading')}>\n {error?.message}\n </WarningPanel>\n );\n }\n\n if (!response?.users || response.users.length === 0) {\n return (\n <Grid xs={12}>\n <NoUsersCard />\n </Grid>\n );\n }\n\n return (\n <Grid container spacing={3} alignItems=\"stretch\">\n {response.users.map(entity => (\n <UsersGridItem user={entity} key={entity.userRef} />\n ))}\n <div\n ref={sentryRef}\n style={{ width: '100%', marginTop: '10px', textAlign: 'center' }}\n >\n {loading && <LoadingGrid />}\n </div>\n </Grid>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;AAUa,MAAA,gBAAA,GAAmB,CAAC,KAM3B,KAAA;AACJ,EAAA,MAAM,EAAE,QAAU,EAAA,KAAA,EAAO,OAAS,EAAA,OAAA,EAAS,cAAiB,GAAA,KAAA;AAC5D,EAAA,MAAM,EAAE,CAAA,EAAM,GAAA,iBAAA,CAAkB,kBAAkB,CAAA;AAElD,EAAA,MAAM,EAAE,YAAA,EAAc,SAAU,EAAA,GAAI,iBAAkB,CAAA;AAAA,IACpD,UAAY,EAAA,CAAC,OAAW,IAAA,CAAC,CAAC,KAAS,IAAA,OAAA;AAAA,IACnC,YAAY,YAAY;AACtB,MAAA,IAAI,YAAc,EAAA;AAChB,QAAA,MAAM,YAAa,EAAA;AAAA;AACrB,KACF;AAAA,IACA,MAAQ,EAAA;AAAA,GACT,CAAA;AAED,EAAA,IAAI,YAAY,CAAC,QAAA,IAAY,QAAS,CAAA,KAAA,CAAM,WAAW,CAAI,CAAA,EAAA;AACzD,IAAA,2BAAQ,WAAY,EAAA,EAAA,CAAA;AAAA;AAGtB,EAAI,IAAA,KAAA,IAAS,aAAa,KAAW,CAAA,EAAA;AACnC,IACE,uBAAA,GAAA,CAAC,gBAAa,QAAS,EAAA,OAAA,EAAQ,OAAO,CAAE,CAAA,wBAAwB,CAC7D,EAAA,QAAA,EAAA,KAAA,EAAO,OACV,EAAA,CAAA;AAAA;AAIJ,EAAA,IAAI,CAAC,QAAU,EAAA,KAAA,IAAS,QAAS,CAAA,KAAA,CAAM,WAAW,CAAG,EAAA;AACnD,IAAA,2BACG,IAAK,EAAA,EAAA,EAAA,EAAI,EACR,EAAA,QAAA,kBAAA,GAAA,CAAC,eAAY,CACf,EAAA,CAAA;AAAA;AAIJ,EAAA,4BACG,IAAK,EAAA,EAAA,SAAA,EAAS,MAAC,OAAS,EAAA,CAAA,EAAG,YAAW,SACpC,EAAA,QAAA,EAAA;AAAA,IAAS,QAAA,CAAA,KAAA,CAAM,IAAI,CAClB,MAAA,qBAAA,GAAA,CAAC,iBAAc,IAAM,EAAA,MAAA,EAAA,EAAa,MAAO,CAAA,OAAS,CACnD,CAAA;AAAA,oBACD,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAK,EAAA,SAAA;AAAA,QACL,OAAO,EAAE,KAAA,EAAO,QAAQ,SAAW,EAAA,MAAA,EAAQ,WAAW,QAAS,EAAA;AAAA,QAE9D,QAAA,EAAA,OAAA,wBAAY,WAAY,EAAA,EAAA;AAAA;AAAA;AAC3B,GACF,EAAA,CAAA;AAEJ;;;;"}
@@ -1,7 +1,7 @@
1
1
  import { useApi, configApiRef } from '@backstage/core-plugin-api';
2
2
  import { useState, useMemo, useEffect } from 'react';
3
3
  import { permissionApiRef } from '@backstage/plugin-permission-react';
4
- import { qetaReadPostReviewPermission } from '@drodil/backstage-plugin-qeta-common';
4
+ import { qetaCreatePostReviewPermission, qetaReadPostReviewPermission } from '@drodil/backstage-plugin-qeta-common';
5
5
  import { AuthorizeResult } from '@backstage/plugin-permission-common';
6
6
  import { useIsModerator } from './useIsModerator.esm.js';
7
7
 
@@ -10,6 +10,7 @@ const useCanReview = () => {
10
10
  const permissionApi = useApi(permissionApiRef);
11
11
  const { isModerator } = useIsModerator();
12
12
  const [canReview, setCanReview] = useState(false);
13
+ const [canRead, setCanRead] = useState(false);
13
14
  const [loading, setLoading] = useState(true);
14
15
  const usePermissions = useMemo(
15
16
  () => configApi.getOptionalBoolean("qeta.permissions") ?? false,
@@ -17,19 +18,24 @@ const useCanReview = () => {
17
18
  );
18
19
  useEffect(() => {
19
20
  if (usePermissions) {
20
- permissionApi.authorize({ permission: qetaReadPostReviewPermission }).then((resp) => {
21
+ permissionApi.authorize({ permission: qetaCreatePostReviewPermission }).then((resp) => {
21
22
  setCanReview(resp.result === AuthorizeResult.ALLOW);
22
- setLoading(false);
23
23
  }).catch(() => {
24
24
  setCanReview(false);
25
- setLoading(false);
26
25
  });
26
+ permissionApi.authorize({ permission: qetaReadPostReviewPermission }).then((resp) => {
27
+ setCanRead(resp.result === AuthorizeResult.ALLOW);
28
+ }).catch(() => {
29
+ setCanRead(false);
30
+ });
31
+ setLoading(false);
27
32
  return;
28
33
  }
29
34
  setCanReview(isModerator);
35
+ setCanRead(isModerator);
30
36
  setLoading(false);
31
37
  }, [isModerator, permissionApi, usePermissions]);
32
- return { canReview, loading };
38
+ return { canReview, canRead, loading };
33
39
  };
34
40
 
35
41
  export { useCanReview };
@@ -1 +1 @@
1
- {"version":3,"file":"useCanReview.esm.js","sources":["../../src/hooks/useCanReview.ts"],"sourcesContent":["import { configApiRef, useApi } from '@backstage/core-plugin-api';\nimport { useEffect, useMemo, useState } from 'react';\nimport { permissionApiRef } from '@backstage/plugin-permission-react';\nimport { qetaReadPostReviewPermission } from '@drodil/backstage-plugin-qeta-common';\nimport { AuthorizeResult } from '@backstage/plugin-permission-common';\nimport { useIsModerator } from './useIsModerator';\n\nexport const useCanReview = () => {\n const configApi = useApi(configApiRef);\n const permissionApi = useApi(permissionApiRef);\n const { isModerator } = useIsModerator();\n const [canReview, setCanReview] = useState(false);\n const [loading, setLoading] = useState(true);\n\n const usePermissions = useMemo(\n () => configApi.getOptionalBoolean('qeta.permissions') ?? false,\n [configApi],\n );\n\n useEffect(() => {\n if (usePermissions) {\n permissionApi\n .authorize({ permission: qetaReadPostReviewPermission })\n .then(resp => {\n setCanReview(resp.result === AuthorizeResult.ALLOW);\n setLoading(false);\n })\n .catch(() => {\n setCanReview(false);\n setLoading(false);\n });\n return;\n }\n\n setCanReview(isModerator);\n setLoading(false);\n }, [isModerator, permissionApi, usePermissions]);\n\n return { canReview, loading };\n};\n"],"names":[],"mappings":";;;;;;;AAOO,MAAM,eAAe,MAAM;AAChC,EAAM,MAAA,SAAA,GAAY,OAAO,YAAY,CAAA;AACrC,EAAM,MAAA,aAAA,GAAgB,OAAO,gBAAgB,CAAA;AAC7C,EAAM,MAAA,EAAE,WAAY,EAAA,GAAI,cAAe,EAAA;AACvC,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAI,SAAS,KAAK,CAAA;AAChD,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,IAAI,CAAA;AAE3C,EAAA,MAAM,cAAiB,GAAA,OAAA;AAAA,IACrB,MAAM,SAAA,CAAU,kBAAmB,CAAA,kBAAkB,CAAK,IAAA,KAAA;AAAA,IAC1D,CAAC,SAAS;AAAA,GACZ;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,cAAgB,EAAA;AAClB,MAAA,aAAA,CACG,UAAU,EAAE,UAAA,EAAY,8BAA8B,CAAA,CACtD,KAAK,CAAQ,IAAA,KAAA;AACZ,QAAa,YAAA,CAAA,IAAA,CAAK,MAAW,KAAA,eAAA,CAAgB,KAAK,CAAA;AAClD,QAAA,UAAA,CAAW,KAAK,CAAA;AAAA,OACjB,CACA,CAAA,KAAA,CAAM,MAAM;AACX,QAAA,YAAA,CAAa,KAAK,CAAA;AAClB,QAAA,UAAA,CAAW,KAAK,CAAA;AAAA,OACjB,CAAA;AACH,MAAA;AAAA;AAGF,IAAA,YAAA,CAAa,WAAW,CAAA;AACxB,IAAA,UAAA,CAAW,KAAK,CAAA;AAAA,GACf,EAAA,CAAC,WAAa,EAAA,aAAA,EAAe,cAAc,CAAC,CAAA;AAE/C,EAAO,OAAA,EAAE,WAAW,OAAQ,EAAA;AAC9B;;;;"}
1
+ {"version":3,"file":"useCanReview.esm.js","sources":["../../src/hooks/useCanReview.ts"],"sourcesContent":["import { configApiRef, useApi } from '@backstage/core-plugin-api';\nimport { useEffect, useMemo, useState } from 'react';\nimport { permissionApiRef } from '@backstage/plugin-permission-react';\nimport {\n qetaCreatePostReviewPermission,\n qetaReadPostReviewPermission,\n} from '@drodil/backstage-plugin-qeta-common';\nimport { AuthorizeResult } from '@backstage/plugin-permission-common';\nimport { useIsModerator } from './useIsModerator';\n\nexport const useCanReview = () => {\n const configApi = useApi(configApiRef);\n const permissionApi = useApi(permissionApiRef);\n const { isModerator } = useIsModerator();\n const [canReview, setCanReview] = useState(false);\n const [canRead, setCanRead] = useState(false);\n const [loading, setLoading] = useState(true);\n\n const usePermissions = useMemo(\n () => configApi.getOptionalBoolean('qeta.permissions') ?? false,\n [configApi],\n );\n\n useEffect(() => {\n if (usePermissions) {\n permissionApi\n .authorize({ permission: qetaCreatePostReviewPermission })\n .then(resp => {\n setCanReview(resp.result === AuthorizeResult.ALLOW);\n })\n .catch(() => {\n setCanReview(false);\n });\n permissionApi\n .authorize({ permission: qetaReadPostReviewPermission })\n .then(resp => {\n setCanRead(resp.result === AuthorizeResult.ALLOW);\n })\n .catch(() => {\n setCanRead(false);\n });\n setLoading(false);\n return;\n }\n\n setCanReview(isModerator);\n setCanRead(isModerator);\n setLoading(false);\n }, [isModerator, permissionApi, usePermissions]);\n\n return { canReview, canRead, loading };\n};\n"],"names":[],"mappings":";;;;;;;AAUO,MAAM,eAAe,MAAM;AAChC,EAAM,MAAA,SAAA,GAAY,OAAO,YAAY,CAAA;AACrC,EAAM,MAAA,aAAA,GAAgB,OAAO,gBAAgB,CAAA;AAC7C,EAAM,MAAA,EAAE,WAAY,EAAA,GAAI,cAAe,EAAA;AACvC,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAI,SAAS,KAAK,CAAA;AAChD,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,KAAK,CAAA;AAC5C,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,IAAI,CAAA;AAE3C,EAAA,MAAM,cAAiB,GAAA,OAAA;AAAA,IACrB,MAAM,SAAA,CAAU,kBAAmB,CAAA,kBAAkB,CAAK,IAAA,KAAA;AAAA,IAC1D,CAAC,SAAS;AAAA,GACZ;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,cAAgB,EAAA;AAClB,MAAA,aAAA,CACG,UAAU,EAAE,UAAA,EAAY,gCAAgC,CAAA,CACxD,KAAK,CAAQ,IAAA,KAAA;AACZ,QAAa,YAAA,CAAA,IAAA,CAAK,MAAW,KAAA,eAAA,CAAgB,KAAK,CAAA;AAAA,OACnD,CACA,CAAA,KAAA,CAAM,MAAM;AACX,QAAA,YAAA,CAAa,KAAK,CAAA;AAAA,OACnB,CAAA;AACH,MAAA,aAAA,CACG,UAAU,EAAE,UAAA,EAAY,8BAA8B,CAAA,CACtD,KAAK,CAAQ,IAAA,KAAA;AACZ,QAAW,UAAA,CAAA,IAAA,CAAK,MAAW,KAAA,eAAA,CAAgB,KAAK,CAAA;AAAA,OACjD,CACA,CAAA,KAAA,CAAM,MAAM;AACX,QAAA,UAAA,CAAW,KAAK,CAAA;AAAA,OACjB,CAAA;AACH,MAAA,UAAA,CAAW,KAAK,CAAA;AAChB,MAAA;AAAA;AAGF,IAAA,YAAA,CAAa,WAAW,CAAA;AACxB,IAAA,UAAA,CAAW,WAAW,CAAA;AACtB,IAAA,UAAA,CAAW,KAAK,CAAA;AAAA,GACf,EAAA,CAAC,WAAa,EAAA,aAAA,EAAe,cAAc,CAAC,CAAA;AAE/C,EAAO,OAAA,EAAE,SAAW,EAAA,OAAA,EAAS,OAAQ,EAAA;AACvC;;;;"}
@@ -0,0 +1,55 @@
1
+ import { useTheme, useMediaQuery } from '@material-ui/core';
2
+
3
+ function useGridPageSize(gridType, basePageSize = 24) {
4
+ const theme = useTheme();
5
+ const isXl = useMediaQuery(theme.breakpoints.up("xl"));
6
+ const isLg = useMediaQuery(theme.breakpoints.up("lg"));
7
+ const isMd = useMediaQuery(theme.breakpoints.up("md"));
8
+ const isSm = useMediaQuery(theme.breakpoints.up("sm"));
9
+ let itemsPerRow;
10
+ switch (gridType) {
11
+ case "tags":
12
+ case "entities":
13
+ if (isXl) {
14
+ itemsPerRow = 3;
15
+ } else if (isSm) {
16
+ itemsPerRow = 2;
17
+ } else {
18
+ itemsPerRow = 1;
19
+ }
20
+ break;
21
+ case "users":
22
+ if (isXl) {
23
+ itemsPerRow = 3;
24
+ } else if (isMd) {
25
+ itemsPerRow = 2;
26
+ } else {
27
+ itemsPerRow = 1;
28
+ }
29
+ break;
30
+ case "posts":
31
+ if (isXl) {
32
+ itemsPerRow = 2;
33
+ } else {
34
+ itemsPerRow = 1;
35
+ }
36
+ break;
37
+ case "collections":
38
+ if (isLg) {
39
+ itemsPerRow = 2;
40
+ } else {
41
+ itemsPerRow = 1;
42
+ }
43
+ break;
44
+ default:
45
+ itemsPerRow = 1;
46
+ }
47
+ const remainder = basePageSize % itemsPerRow;
48
+ if (remainder === 0) {
49
+ return basePageSize;
50
+ }
51
+ return basePageSize + (itemsPerRow - remainder);
52
+ }
53
+
54
+ export { useGridPageSize };
55
+ //# sourceMappingURL=useGridPageSize.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useGridPageSize.esm.js","sources":["../../src/hooks/useGridPageSize.ts"],"sourcesContent":["import { useTheme, useMediaQuery } from '@material-ui/core';\n\nexport type GridType = 'posts' | 'tags' | 'entities' | 'users' | 'collections';\n\nexport function useGridPageSize(\n gridType: GridType,\n basePageSize: number = 24,\n): number {\n const theme = useTheme();\n\n const isXl = useMediaQuery(theme.breakpoints.up('xl'));\n const isLg = useMediaQuery(theme.breakpoints.up('lg'));\n const isMd = useMediaQuery(theme.breakpoints.up('md'));\n const isSm = useMediaQuery(theme.breakpoints.up('sm'));\n\n let itemsPerRow: number;\n\n switch (gridType) {\n case 'tags':\n case 'entities':\n if (isXl) {\n itemsPerRow = 3;\n } else if (isSm) {\n itemsPerRow = 2;\n } else {\n itemsPerRow = 1;\n }\n break;\n\n case 'users':\n if (isXl) {\n itemsPerRow = 3;\n } else if (isMd) {\n itemsPerRow = 2;\n } else {\n itemsPerRow = 1;\n }\n break;\n\n case 'posts':\n if (isXl) {\n itemsPerRow = 2;\n } else {\n itemsPerRow = 1;\n }\n break;\n\n case 'collections':\n if (isLg) {\n itemsPerRow = 2;\n } else {\n itemsPerRow = 1;\n }\n break;\n\n default:\n itemsPerRow = 1;\n }\n\n const remainder = basePageSize % itemsPerRow;\n if (remainder === 0) {\n return basePageSize;\n }\n return basePageSize + (itemsPerRow - remainder);\n}\n"],"names":[],"mappings":";;AAIgB,SAAA,eAAA,CACd,QACA,EAAA,YAAA,GAAuB,EACf,EAAA;AACR,EAAA,MAAM,QAAQ,QAAS,EAAA;AAEvB,EAAA,MAAM,OAAO,aAAc,CAAA,KAAA,CAAM,WAAY,CAAA,EAAA,CAAG,IAAI,CAAC,CAAA;AACrD,EAAA,MAAM,OAAO,aAAc,CAAA,KAAA,CAAM,WAAY,CAAA,EAAA,CAAG,IAAI,CAAC,CAAA;AACrD,EAAA,MAAM,OAAO,aAAc,CAAA,KAAA,CAAM,WAAY,CAAA,EAAA,CAAG,IAAI,CAAC,CAAA;AACrD,EAAA,MAAM,OAAO,aAAc,CAAA,KAAA,CAAM,WAAY,CAAA,EAAA,CAAG,IAAI,CAAC,CAAA;AAErD,EAAI,IAAA,WAAA;AAEJ,EAAA,QAAQ,QAAU;AAAA,IAChB,KAAK,MAAA;AAAA,IACL,KAAK,UAAA;AACH,MAAA,IAAI,IAAM,EAAA;AACR,QAAc,WAAA,GAAA,CAAA;AAAA,iBACL,IAAM,EAAA;AACf,QAAc,WAAA,GAAA,CAAA;AAAA,OACT,MAAA;AACL,QAAc,WAAA,GAAA,CAAA;AAAA;AAEhB,MAAA;AAAA,IAEF,KAAK,OAAA;AACH,MAAA,IAAI,IAAM,EAAA;AACR,QAAc,WAAA,GAAA,CAAA;AAAA,iBACL,IAAM,EAAA;AACf,QAAc,WAAA,GAAA,CAAA;AAAA,OACT,MAAA;AACL,QAAc,WAAA,GAAA,CAAA;AAAA;AAEhB,MAAA;AAAA,IAEF,KAAK,OAAA;AACH,MAAA,IAAI,IAAM,EAAA;AACR,QAAc,WAAA,GAAA,CAAA;AAAA,OACT,MAAA;AACL,QAAc,WAAA,GAAA,CAAA;AAAA;AAEhB,MAAA;AAAA,IAEF,KAAK,aAAA;AACH,MAAA,IAAI,IAAM,EAAA;AACR,QAAc,WAAA,GAAA,CAAA;AAAA,OACT,MAAA;AACL,QAAc,WAAA,GAAA,CAAA;AAAA;AAEhB,MAAA;AAAA,IAEF;AACE,MAAc,WAAA,GAAA,CAAA;AAAA;AAGlB,EAAA,MAAM,YAAY,YAAe,GAAA,WAAA;AACjC,EAAA,IAAI,cAAc,CAAG,EAAA;AACnB,IAAO,OAAA,YAAA;AAAA;AAET,EAAA,OAAO,gBAAgB,WAAc,GAAA,SAAA,CAAA;AACvC;;;;"}
@@ -21,8 +21,8 @@ function usePaginatedPosts(props) {
21
21
  } = props;
22
22
  const analytics = useAnalytics();
23
23
  const [page, setPage] = useState(1);
24
- const [pageCount, setPageCount] = useState(1);
25
- const [postsPerPage, setPostsPerPage] = useState(initialPageSize ?? 10);
24
+ const pageCount = 1;
25
+ const [postsPerPage, setPostsPerPage] = useState(initialPageSize ?? 25);
26
26
  const [showFilterPanel, setShowFilterPanel] = useState(
27
27
  localStorage.getItem(EXPANDED_LOCAL_STORAGE_KEY) === "true"
28
28
  );
@@ -42,6 +42,9 @@ function usePaginatedPosts(props) {
42
42
  status,
43
43
  type
44
44
  });
45
+ const [posts, setPosts] = useState([]);
46
+ const [hasMore, setHasMore] = useState(true);
47
+ const [total, setTotal] = useState(0);
45
48
  useEffect(() => {
46
49
  localStorage.setItem(
47
50
  EXPANDED_LOCAL_STORAGE_KEY,
@@ -58,6 +61,7 @@ function usePaginatedPosts(props) {
58
61
  collectionId: props.collectionId
59
62
  }));
60
63
  setPage(1);
64
+ setPosts([]);
61
65
  }, [tags, entities, entity, type, status, props.collectionId]);
62
66
  const onPageChange = (value) => {
63
67
  setPage(value);
@@ -73,6 +77,7 @@ function usePaginatedPosts(props) {
73
77
  const onFilterChange = (changes) => {
74
78
  const changesArray = Array.isArray(changes) ? changes : [changes];
75
79
  setPage(1);
80
+ setPosts([]);
76
81
  setFilters((prev) => {
77
82
  const newValue = { ...prev };
78
83
  for (const { key, value } of changesArray) {
@@ -107,6 +112,7 @@ function usePaginatedPosts(props) {
107
112
  };
108
113
  const onSearchQueryChange = (query) => {
109
114
  onPageChange(1);
115
+ setPosts([]);
110
116
  if (query) {
111
117
  analytics.captureEvent("qeta_search", query);
112
118
  }
@@ -131,6 +137,7 @@ function usePaginatedPosts(props) {
131
137
  setPage(pv);
132
138
  } else {
133
139
  setPage(1);
140
+ setPosts([]);
134
141
  }
135
142
  } else if (key === "postsPerPage") {
136
143
  const qpp = Number.parseInt(value, 10);
@@ -179,9 +186,15 @@ function usePaginatedPosts(props) {
179
186
  );
180
187
  useEffect(() => {
181
188
  if (response) {
182
- setPageCount(Math.ceil(response.total / postsPerPage));
189
+ if (page === 1) {
190
+ setPosts(response.posts);
191
+ } else {
192
+ setPosts((prev) => [...prev, ...response.posts]);
193
+ }
194
+ setHasMore(response.posts.length >= postsPerPage);
195
+ setTotal(response.total);
183
196
  }
184
- }, [response, postsPerPage]);
197
+ }, [response, page, postsPerPage]);
185
198
  const onPageSizeChange = (value) => {
186
199
  if (response) {
187
200
  let newPage = page;
@@ -215,11 +228,15 @@ function usePaginatedPosts(props) {
215
228
  onFilterChange,
216
229
  onSearchQueryChange,
217
230
  response,
231
+ posts,
232
+ hasMore,
233
+ total,
218
234
  loading,
219
235
  error,
220
236
  loadNextPage,
221
237
  pageCount,
222
- retry
238
+ retry,
239
+ fetchNextPage: loadNextPage
223
240
  };
224
241
  }
225
242