@drodil/backstage-plugin-qeta 1.10.2 → 1.11.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.
- package/dist/esm/{index-7d99dfe6.esm.js → index-4867abd8.esm.js} +5 -2
- package/dist/esm/index-4867abd8.esm.js.map +1 -0
- package/dist/esm/{index-ceb65cf4.esm.js → index-6bfa5b72.esm.js} +300 -39
- package/dist/esm/index-6bfa5b72.esm.js.map +1 -0
- package/dist/esm/{index-6535e416.esm.js → index-8cc27392.esm.js} +17 -32
- package/dist/esm/index-8cc27392.esm.js.map +1 -0
- package/dist/index.d.ts +47 -11
- package/dist/index.esm.js +4 -1
- package/dist/index.esm.js.map +1 -1
- package/package.json +7 -7
- package/dist/esm/index-6535e416.esm.js.map +0 -1
- package/dist/esm/index-7d99dfe6.esm.js.map +0 -1
- package/dist/esm/index-ceb65cf4.esm.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { C as Content,
|
|
1
|
+
export { C as Content, g as QuestionsTable } from './index-6bfa5b72.esm.js';
|
|
2
2
|
import '@backstage/core-plugin-api';
|
|
3
3
|
import '@backstage/plugin-home';
|
|
4
4
|
import '@backstage/errors';
|
|
@@ -25,4 +25,7 @@ import 'react-mde/lib/styles/css/react-mde-editor.css';
|
|
|
25
25
|
import 'react-mde/lib/styles/css/react-mde-toolbar.css';
|
|
26
26
|
import 'file-type';
|
|
27
27
|
import '@material-ui/icons/Refresh';
|
|
28
|
-
|
|
28
|
+
import '@material-ui/icons/HomeOutlined';
|
|
29
|
+
import '@backstage/plugin-permission-react';
|
|
30
|
+
import '@drodil/backstage-plugin-qeta-common';
|
|
31
|
+
//# sourceMappingURL=index-4867abd8.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-4867abd8.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { createRouteRef, createApiRef, createPlugin, createApiFactory,
|
|
1
|
+
import { createRouteRef, createApiRef, createPlugin, createApiFactory, fetchApiRef, discoveryApiRef, createRoutableExtension, useApi, identityApiRef, configApiRef, errorApiRef, useAnalytics } from '@backstage/core-plugin-api';
|
|
2
2
|
import { createCardExtension } from '@backstage/plugin-home';
|
|
3
3
|
import { CustomErrorBase } from '@backstage/errors';
|
|
4
4
|
import omitBy from 'lodash/omitBy';
|
|
5
5
|
import isEmpty from 'lodash/isEmpty';
|
|
6
6
|
import { useAsync } from 'react-use';
|
|
7
|
-
import { makeStyles, Box, Grid, FormGroup, FormLabel, FormControlLabel, Checkbox, FormControl, RadioGroup, Radio, Chip, Tooltip, useTheme, Card, CardContent, Typography, Divider, Select, MenuItem, TextField, Button, Collapse, ButtonGroup, TableContainer, Table, TableHead, TableRow, TableCell, TableBody, TablePagination } from '@material-ui/core';
|
|
7
|
+
import { makeStyles, Box, Grid, FormGroup, FormLabel, FormControlLabel, Checkbox, FormControl, RadioGroup, Radio, Chip, Tooltip, useTheme, Card, CardContent, Typography, Divider, Select, MenuItem, TextField, Button, Collapse, ButtonGroup, TableContainer, Table, TableHead, TableRow, TableCell, TableBody, TablePagination, SvgIcon, ListItem, ListItemAvatar, Avatar, ListItemText, List, Container } from '@material-ui/core';
|
|
8
8
|
import { catalogApiRef } from '@backstage/plugin-catalog-react';
|
|
9
9
|
import { trimEnd, compact } from 'lodash';
|
|
10
10
|
import React, { useEffect, useMemo } from 'react';
|
|
11
11
|
import useDebounce from 'react-use/lib/useDebounce';
|
|
12
|
-
import { Link, Progress, WarningPanel, LinkButton, MarkdownContent } from '@backstage/core-components';
|
|
12
|
+
import { Link, Progress, WarningPanel, LinkButton, MarkdownContent, CardTab, TabbedCard, Content as Content$1, ContentHeader } from '@backstage/core-components';
|
|
13
13
|
import RelativeTime from 'react-relative-time';
|
|
14
14
|
import DOMPurify from 'dompurify';
|
|
15
15
|
import { stringifyEntityRef } from '@backstage/catalog-model';
|
|
@@ -24,6 +24,9 @@ import 'react-mde/lib/styles/css/react-mde-editor.css';
|
|
|
24
24
|
import 'react-mde/lib/styles/css/react-mde-toolbar.css';
|
|
25
25
|
import FileType from 'file-type';
|
|
26
26
|
import RefreshIcon from '@material-ui/icons/Refresh';
|
|
27
|
+
import HomeOutlined from '@material-ui/icons/HomeOutlined';
|
|
28
|
+
import { RequirePermission } from '@backstage/plugin-permission-react';
|
|
29
|
+
import { qetaCreateQuestionPermission } from '@drodil/backstage-plugin-qeta-common';
|
|
27
30
|
|
|
28
31
|
const rootRouteRef = createRouteRef({
|
|
29
32
|
id: "qeta"
|
|
@@ -41,11 +44,14 @@ class QetaError extends CustomErrorBase {
|
|
|
41
44
|
class QetaClient {
|
|
42
45
|
constructor(options) {
|
|
43
46
|
this.fetchApi = options.fetchApi;
|
|
44
|
-
this.
|
|
47
|
+
this.discoveryApi = options.discoveryApi;
|
|
48
|
+
}
|
|
49
|
+
async getBaseUrl() {
|
|
50
|
+
return this.discoveryApi.getBaseUrl("qeta");
|
|
45
51
|
}
|
|
46
52
|
async getQuestions(options) {
|
|
47
53
|
const query = this.getQueryParameters(options).toString();
|
|
48
|
-
let url = `${this.
|
|
54
|
+
let url = `${await this.getBaseUrl()}/questions`;
|
|
49
55
|
if (query) {
|
|
50
56
|
url += `?${query}`;
|
|
51
57
|
}
|
|
@@ -61,7 +67,7 @@ class QetaClient {
|
|
|
61
67
|
}
|
|
62
68
|
async getQuestionsList(type) {
|
|
63
69
|
const query = new URLSearchParams({ limit: "7" }).toString();
|
|
64
|
-
let url = `${this.
|
|
70
|
+
let url = `${await this.getBaseUrl()}/questions/list/${type}`;
|
|
65
71
|
if (query) {
|
|
66
72
|
url += `?${query}`;
|
|
67
73
|
}
|
|
@@ -77,7 +83,7 @@ class QetaClient {
|
|
|
77
83
|
}
|
|
78
84
|
async postQuestion(question) {
|
|
79
85
|
const response = await this.fetchApi.fetch(
|
|
80
|
-
`${this.
|
|
86
|
+
`${await this.getBaseUrl()}/questions`,
|
|
81
87
|
{
|
|
82
88
|
method: "POST",
|
|
83
89
|
body: JSON.stringify(question),
|
|
@@ -92,7 +98,7 @@ class QetaClient {
|
|
|
92
98
|
}
|
|
93
99
|
async commentQuestion(id, content) {
|
|
94
100
|
const response = await this.fetchApi.fetch(
|
|
95
|
-
`${this.
|
|
101
|
+
`${await this.getBaseUrl()}/questions/${id}/comments`,
|
|
96
102
|
{
|
|
97
103
|
method: "POST",
|
|
98
104
|
body: JSON.stringify({ content }),
|
|
@@ -107,7 +113,7 @@ class QetaClient {
|
|
|
107
113
|
}
|
|
108
114
|
async deleteQuestionComment(questionId, id) {
|
|
109
115
|
const response = await this.fetchApi.fetch(
|
|
110
|
-
`${this.
|
|
116
|
+
`${await this.getBaseUrl()}/questions/${questionId}/comments/${id}`,
|
|
111
117
|
{
|
|
112
118
|
method: "DELETE"
|
|
113
119
|
}
|
|
@@ -123,7 +129,7 @@ class QetaClient {
|
|
|
123
129
|
throw new QetaError("Invalid id provided", void 0);
|
|
124
130
|
}
|
|
125
131
|
const response = await this.fetchApi.fetch(
|
|
126
|
-
`${this.
|
|
132
|
+
`${await this.getBaseUrl()}/questions/${id}`
|
|
127
133
|
);
|
|
128
134
|
const data = await response.json();
|
|
129
135
|
if ("errors" in data) {
|
|
@@ -132,7 +138,9 @@ class QetaClient {
|
|
|
132
138
|
return data;
|
|
133
139
|
}
|
|
134
140
|
async getTags() {
|
|
135
|
-
const response = await this.fetchApi.fetch(
|
|
141
|
+
const response = await this.fetchApi.fetch(
|
|
142
|
+
`${await this.getBaseUrl()}/tags`
|
|
143
|
+
);
|
|
136
144
|
return await response.json();
|
|
137
145
|
}
|
|
138
146
|
async voteQuestionUp(id) {
|
|
@@ -140,7 +148,7 @@ class QetaClient {
|
|
|
140
148
|
throw new QetaError("Invalid id provided", void 0);
|
|
141
149
|
}
|
|
142
150
|
const response = await this.fetchApi.fetch(
|
|
143
|
-
`${this.
|
|
151
|
+
`${await this.getBaseUrl()}/questions/${id}/upvote`
|
|
144
152
|
);
|
|
145
153
|
const data = await response.json();
|
|
146
154
|
if ("errors" in data) {
|
|
@@ -153,7 +161,7 @@ class QetaClient {
|
|
|
153
161
|
throw new QetaError("Invalid id provided", void 0);
|
|
154
162
|
}
|
|
155
163
|
const response = await this.fetchApi.fetch(
|
|
156
|
-
`${this.
|
|
164
|
+
`${await this.getBaseUrl()}/questions/${id}/downvote`
|
|
157
165
|
);
|
|
158
166
|
const data = await response.json();
|
|
159
167
|
if ("errors" in data) {
|
|
@@ -166,7 +174,7 @@ class QetaClient {
|
|
|
166
174
|
throw new QetaError("Invalid id provided", void 0);
|
|
167
175
|
}
|
|
168
176
|
const response = await this.fetchApi.fetch(
|
|
169
|
-
`${this.
|
|
177
|
+
`${await this.getBaseUrl()}/questions/${id}/favorite`
|
|
170
178
|
);
|
|
171
179
|
const data = await response.json();
|
|
172
180
|
if ("errors" in data) {
|
|
@@ -179,7 +187,7 @@ class QetaClient {
|
|
|
179
187
|
throw new QetaError("Invalid id provided", void 0);
|
|
180
188
|
}
|
|
181
189
|
const response = await this.fetchApi.fetch(
|
|
182
|
-
`${this.
|
|
190
|
+
`${await this.getBaseUrl()}/questions/${id}/unfavorite`
|
|
183
191
|
);
|
|
184
192
|
const data = await response.json();
|
|
185
193
|
if ("errors" in data) {
|
|
@@ -189,7 +197,7 @@ class QetaClient {
|
|
|
189
197
|
}
|
|
190
198
|
async postAnswer(answer) {
|
|
191
199
|
const response = await this.fetchApi.fetch(
|
|
192
|
-
`${this.
|
|
200
|
+
`${await this.getBaseUrl()}/questions/${answer.questionId}/answers`,
|
|
193
201
|
{
|
|
194
202
|
method: "POST",
|
|
195
203
|
body: JSON.stringify({ answer: answer.answer, images: answer.images }),
|
|
@@ -204,7 +212,7 @@ class QetaClient {
|
|
|
204
212
|
}
|
|
205
213
|
async commentAnswer(questionId, id, content) {
|
|
206
214
|
const response = await this.fetchApi.fetch(
|
|
207
|
-
`${this.
|
|
215
|
+
`${await this.getBaseUrl()}/questions/${questionId}/answers/${id}/comments`,
|
|
208
216
|
{
|
|
209
217
|
method: "POST",
|
|
210
218
|
body: JSON.stringify({ content }),
|
|
@@ -219,7 +227,7 @@ class QetaClient {
|
|
|
219
227
|
}
|
|
220
228
|
async deleteAnswerComment(questionId, answerId, id) {
|
|
221
229
|
const response = await this.fetchApi.fetch(
|
|
222
|
-
`${this.
|
|
230
|
+
`${await this.getBaseUrl()}/questions/${questionId}/answers/${answerId}/comments/${id}`,
|
|
223
231
|
{
|
|
224
232
|
method: "DELETE"
|
|
225
233
|
}
|
|
@@ -235,7 +243,7 @@ class QetaClient {
|
|
|
235
243
|
throw new QetaError("Invalid id provided", void 0);
|
|
236
244
|
}
|
|
237
245
|
const response = await this.fetchApi.fetch(
|
|
238
|
-
`${this.
|
|
246
|
+
`${await this.getBaseUrl()}/questions/${questionId}/answers/${id}/upvote`
|
|
239
247
|
);
|
|
240
248
|
const data = await response.json();
|
|
241
249
|
if ("errors" in data) {
|
|
@@ -248,7 +256,7 @@ class QetaClient {
|
|
|
248
256
|
throw new QetaError("Invalid id provided", void 0);
|
|
249
257
|
}
|
|
250
258
|
const response = await this.fetchApi.fetch(
|
|
251
|
-
`${this.
|
|
259
|
+
`${await this.getBaseUrl()}/questions/${questionId}/answers/${id}/downvote`
|
|
252
260
|
);
|
|
253
261
|
const data = await response.json();
|
|
254
262
|
if ("errors" in data) {
|
|
@@ -261,7 +269,7 @@ class QetaClient {
|
|
|
261
269
|
throw new QetaError("Invalid id provided", void 0);
|
|
262
270
|
}
|
|
263
271
|
const response = await this.fetchApi.fetch(
|
|
264
|
-
`${this.
|
|
272
|
+
`${await this.getBaseUrl()}/questions/${questionId}/answers/${id}/correct`
|
|
265
273
|
);
|
|
266
274
|
const data = await response;
|
|
267
275
|
return data.ok;
|
|
@@ -271,7 +279,7 @@ class QetaClient {
|
|
|
271
279
|
throw new QetaError("Invalid id provided", void 0);
|
|
272
280
|
}
|
|
273
281
|
const response = await this.fetchApi.fetch(
|
|
274
|
-
`${this.
|
|
282
|
+
`${await this.getBaseUrl()}/questions/${questionId}/answers/${id}/incorrect`
|
|
275
283
|
);
|
|
276
284
|
const data = await response;
|
|
277
285
|
return data.ok;
|
|
@@ -281,7 +289,7 @@ class QetaClient {
|
|
|
281
289
|
throw new QetaError("Invalid id provided", void 0);
|
|
282
290
|
}
|
|
283
291
|
const response = await this.fetchApi.fetch(
|
|
284
|
-
`${this.
|
|
292
|
+
`${await this.getBaseUrl()}/questions/${questionId}`,
|
|
285
293
|
{
|
|
286
294
|
method: "DELETE"
|
|
287
295
|
}
|
|
@@ -294,7 +302,7 @@ class QetaClient {
|
|
|
294
302
|
throw new QetaError("Invalid id provided", void 0);
|
|
295
303
|
}
|
|
296
304
|
const response = await this.fetchApi.fetch(
|
|
297
|
-
`${this.
|
|
305
|
+
`${await this.getBaseUrl()}/questions/${questionId}/answers/${id}`,
|
|
298
306
|
{
|
|
299
307
|
method: "DELETE"
|
|
300
308
|
}
|
|
@@ -304,7 +312,7 @@ class QetaClient {
|
|
|
304
312
|
}
|
|
305
313
|
async updateQuestion(id, question) {
|
|
306
314
|
const response = await this.fetchApi.fetch(
|
|
307
|
-
`${this.
|
|
315
|
+
`${await this.getBaseUrl()}/questions/${id}`,
|
|
308
316
|
{
|
|
309
317
|
method: "POST",
|
|
310
318
|
body: JSON.stringify(question),
|
|
@@ -319,7 +327,7 @@ class QetaClient {
|
|
|
319
327
|
}
|
|
320
328
|
async updateAnswer(id, answer) {
|
|
321
329
|
const response = await this.fetchApi.fetch(
|
|
322
|
-
`${this.
|
|
330
|
+
`${await this.getBaseUrl()}/questions/${answer.questionId}/answers/${id}`,
|
|
323
331
|
{
|
|
324
332
|
method: "POST",
|
|
325
333
|
body: JSON.stringify({ answer: answer.answer, images: answer.images }),
|
|
@@ -337,7 +345,7 @@ class QetaClient {
|
|
|
337
345
|
throw new QetaError("Invalid id provided", void 0);
|
|
338
346
|
}
|
|
339
347
|
const response = await this.fetchApi.fetch(
|
|
340
|
-
`${this.
|
|
348
|
+
`${await this.getBaseUrl()}/questions/${questionId}/answers/${id}`
|
|
341
349
|
);
|
|
342
350
|
const data = await response.json();
|
|
343
351
|
if ("errors" in data) {
|
|
@@ -346,7 +354,7 @@ class QetaClient {
|
|
|
346
354
|
return data;
|
|
347
355
|
}
|
|
348
356
|
async postAttachment(file) {
|
|
349
|
-
const qetaUrl = `${this.
|
|
357
|
+
const qetaUrl = `${await this.getBaseUrl()}/attachments`;
|
|
350
358
|
const formData = new FormData();
|
|
351
359
|
formData.append("image", file);
|
|
352
360
|
const requestOptions = {
|
|
@@ -356,6 +364,44 @@ class QetaClient {
|
|
|
356
364
|
const response = await fetch(qetaUrl, requestOptions);
|
|
357
365
|
return await response.json();
|
|
358
366
|
}
|
|
367
|
+
async getMostUpvotedAnswers(options) {
|
|
368
|
+
const query = this.getQueryParameters(options.options).toString();
|
|
369
|
+
let url = `${await this.getBaseUrl()}/statistics/answers/top-upvoted-users`;
|
|
370
|
+
if (query) {
|
|
371
|
+
url += `?${query}`;
|
|
372
|
+
}
|
|
373
|
+
const response = await this.fetchApi.fetch(url);
|
|
374
|
+
const data = await response.json();
|
|
375
|
+
return data;
|
|
376
|
+
}
|
|
377
|
+
async getMostUpvotedCorrectAnswers(options) {
|
|
378
|
+
const query = this.getQueryParameters(options.options).toString();
|
|
379
|
+
let url = `${await this.getBaseUrl()}/statistics/answers/top-correct-upvoted-users`;
|
|
380
|
+
if (query) {
|
|
381
|
+
url += `?${query}`;
|
|
382
|
+
}
|
|
383
|
+
const response = await this.fetchApi.fetch(url);
|
|
384
|
+
const data = await response.json();
|
|
385
|
+
return data;
|
|
386
|
+
}
|
|
387
|
+
async getMostUpvotedQuestions(options) {
|
|
388
|
+
const query = this.getQueryParameters(options.options).toString();
|
|
389
|
+
let url = `${await this.getBaseUrl()}/statistics/answers/top-correct-upvoted-users`;
|
|
390
|
+
if (query) {
|
|
391
|
+
url += `?${query}`;
|
|
392
|
+
}
|
|
393
|
+
const response = await this.fetchApi.fetch(url);
|
|
394
|
+
const data = await response.json();
|
|
395
|
+
return data;
|
|
396
|
+
}
|
|
397
|
+
async getTopStatisticsHomepage(options) {
|
|
398
|
+
const response = await Promise.all([
|
|
399
|
+
this.getMostUpvotedQuestions(options),
|
|
400
|
+
this.getMostUpvotedAnswers(options),
|
|
401
|
+
this.getMostUpvotedCorrectAnswers(options)
|
|
402
|
+
]);
|
|
403
|
+
return response;
|
|
404
|
+
}
|
|
359
405
|
getQueryParameters(params) {
|
|
360
406
|
const asStrings = Object.fromEntries(
|
|
361
407
|
Object.entries(params).map(([k, v]) => {
|
|
@@ -377,15 +423,15 @@ const qetaPlugin = createPlugin({
|
|
|
377
423
|
apis: [
|
|
378
424
|
createApiFactory({
|
|
379
425
|
api: qetaApiRef,
|
|
380
|
-
deps: {
|
|
381
|
-
factory: ({
|
|
426
|
+
deps: { fetchApi: fetchApiRef, discoveryApi: discoveryApiRef },
|
|
427
|
+
factory: ({ fetchApi, discoveryApi }) => new QetaClient({ fetchApi, discoveryApi })
|
|
382
428
|
})
|
|
383
429
|
]
|
|
384
430
|
});
|
|
385
431
|
const QetaPage = qetaPlugin.provide(
|
|
386
432
|
createRoutableExtension({
|
|
387
433
|
name: "QetaPage",
|
|
388
|
-
component: () => import('./index-
|
|
434
|
+
component: () => import('./index-8cc27392.esm.js').then((m) => m.HomePage),
|
|
389
435
|
mountPoint: rootRouteRef
|
|
390
436
|
})
|
|
391
437
|
);
|
|
@@ -394,7 +440,7 @@ const QuestionTableCard = qetaPlugin.provide(
|
|
|
394
440
|
name: "QuestionsTableCard",
|
|
395
441
|
title: "Q&A",
|
|
396
442
|
description: "Shows Q&A questions",
|
|
397
|
-
components: () => import('./index-
|
|
443
|
+
components: () => import('./index-4867abd8.esm.js'),
|
|
398
444
|
layout: {
|
|
399
445
|
height: { minRows: 6 },
|
|
400
446
|
width: { minColumns: 6 }
|
|
@@ -434,7 +480,7 @@ function useIdentityApi(f, deps = []) {
|
|
|
434
480
|
return await f(identityApi);
|
|
435
481
|
}, deps);
|
|
436
482
|
}
|
|
437
|
-
const useStyles = makeStyles((theme) => {
|
|
483
|
+
const useStyles$1 = makeStyles((theme) => {
|
|
438
484
|
return {
|
|
439
485
|
markdownEditor: {
|
|
440
486
|
backgroundColor: "initial",
|
|
@@ -575,6 +621,11 @@ const useStyles = makeStyles((theme) => {
|
|
|
575
621
|
marginTop: theme.spacing(2),
|
|
576
622
|
float: "right"
|
|
577
623
|
}
|
|
624
|
+
},
|
|
625
|
+
authorLink: {
|
|
626
|
+
textOverflow: "ellipsis",
|
|
627
|
+
overflow: "hidden",
|
|
628
|
+
whiteSpace: "nowrap"
|
|
578
629
|
}
|
|
579
630
|
};
|
|
580
631
|
});
|
|
@@ -613,7 +664,7 @@ const filterKeys = [
|
|
|
613
664
|
];
|
|
614
665
|
const FilterPanel = (props) => {
|
|
615
666
|
const { onChange, filters } = props;
|
|
616
|
-
const styles = useStyles();
|
|
667
|
+
const styles = useStyles$1();
|
|
617
668
|
const handleChange = (event) => {
|
|
618
669
|
let value = event.target.value;
|
|
619
670
|
if (event.target.type === "checkbox") {
|
|
@@ -805,7 +856,7 @@ const QuestionList = (props) => {
|
|
|
805
856
|
page,
|
|
806
857
|
onPageSizeChange
|
|
807
858
|
} = props;
|
|
808
|
-
const styles = useStyles();
|
|
859
|
+
const styles = useStyles$1();
|
|
809
860
|
const handlePageChange = (_event, value) => {
|
|
810
861
|
onPageChange(value);
|
|
811
862
|
};
|
|
@@ -1034,7 +1085,7 @@ const MarkdownEditor = (props) => {
|
|
|
1034
1085
|
const [selectedTab, setSelectedTab] = React.useState(
|
|
1035
1086
|
"write"
|
|
1036
1087
|
);
|
|
1037
|
-
const styles = useStyles();
|
|
1088
|
+
const styles = useStyles$1();
|
|
1038
1089
|
const errorApi = useApi(errorApiRef);
|
|
1039
1090
|
const qetaApi = useApi(qetaApiRef);
|
|
1040
1091
|
const imageUpload = () => {
|
|
@@ -1147,7 +1198,7 @@ const AskForm = (props) => {
|
|
|
1147
1198
|
const qetaApi = useApi(qetaApiRef);
|
|
1148
1199
|
const catalogApi = useApi(catalogApiRef);
|
|
1149
1200
|
const configApi = useApi(configApiRef);
|
|
1150
|
-
const styles = useStyles();
|
|
1201
|
+
const styles = useStyles$1();
|
|
1151
1202
|
const {
|
|
1152
1203
|
register,
|
|
1153
1204
|
handleSubmit,
|
|
@@ -1496,5 +1547,215 @@ const Content = (props) => {
|
|
|
1496
1547
|
return /* @__PURE__ */ React.createElement(QuestionsTable, { hideTitle: true, ...props });
|
|
1497
1548
|
};
|
|
1498
1549
|
|
|
1499
|
-
|
|
1500
|
-
|
|
1550
|
+
const TrophyIcon = (props) => /* @__PURE__ */ React.createElement(SvgIcon, { ...props, viewBox: "0 0 24 24" }, /* @__PURE__ */ React.createElement(
|
|
1551
|
+
"path",
|
|
1552
|
+
{
|
|
1553
|
+
id: "secondary",
|
|
1554
|
+
d: "M17,12a1,1,0,0,1,0-2,3,3,0,0,0,3-3V6H17.17a1,1,0,0,1,0-2H20a2,2,0,0,1,2,2V7A5,5,0,0,1,17,12ZM8,11a1,1,0,0,0-1-1A3,3,0,0,1,4,7V6H6.74a1,1,0,0,0,0-2H4A2,2,0,0,0,2,6V7a5,5,0,0,0,5,5A1,1,0,0,0,8,11Zm5,10V16.18a1,1,0,0,0-2,0V21a1,1,0,0,0,2,0Z"
|
|
1555
|
+
}
|
|
1556
|
+
), /* @__PURE__ */ React.createElement(
|
|
1557
|
+
"path",
|
|
1558
|
+
{
|
|
1559
|
+
id: "primary",
|
|
1560
|
+
d: "M16,22H8a1,1,0,0,1,0-2h8a1,1,0,0,1,0,2ZM17,2H7A1,1,0,0,0,6,3V9.57a7.75,7.75,0,0,0,4.89,7.22A3,3,0,0,0,12,17a3.13,3.13,0,0,0,1.12-.21A7.76,7.76,0,0,0,18,9.57V3A1,1,0,0,0,17,2Z"
|
|
1561
|
+
}
|
|
1562
|
+
));
|
|
1563
|
+
|
|
1564
|
+
const useStyles = makeStyles((theme) => {
|
|
1565
|
+
return {
|
|
1566
|
+
trophyIcon: {
|
|
1567
|
+
backgroundColor: "initial",
|
|
1568
|
+
color: theme.palette.text.primary,
|
|
1569
|
+
borderRadius: "50%",
|
|
1570
|
+
boxSizing: "border-box",
|
|
1571
|
+
padding: "1rem",
|
|
1572
|
+
height: 100,
|
|
1573
|
+
width: 100
|
|
1574
|
+
},
|
|
1575
|
+
votesText: {
|
|
1576
|
+
display: "grid",
|
|
1577
|
+
placeItems: "center",
|
|
1578
|
+
marginLeft: "16px"
|
|
1579
|
+
}
|
|
1580
|
+
};
|
|
1581
|
+
});
|
|
1582
|
+
|
|
1583
|
+
const DefaultRankingIcons = /* @__PURE__ */ new Map([
|
|
1584
|
+
[
|
|
1585
|
+
1,
|
|
1586
|
+
/* @__PURE__ */ React.createElement(
|
|
1587
|
+
TrophyIcon,
|
|
1588
|
+
{
|
|
1589
|
+
style: { color: "#DAA520", height: "2.2rem", width: "2.2rem" }
|
|
1590
|
+
}
|
|
1591
|
+
)
|
|
1592
|
+
],
|
|
1593
|
+
[
|
|
1594
|
+
2,
|
|
1595
|
+
/* @__PURE__ */ React.createElement(
|
|
1596
|
+
TrophyIcon,
|
|
1597
|
+
{
|
|
1598
|
+
style: { color: "#C0C0C0", height: "2.1rem", width: "2.1rem" }
|
|
1599
|
+
}
|
|
1600
|
+
)
|
|
1601
|
+
],
|
|
1602
|
+
[
|
|
1603
|
+
3,
|
|
1604
|
+
/* @__PURE__ */ React.createElement(TrophyIcon, { style: { color: "#B87333", height: "2rem", width: "2rem" } })
|
|
1605
|
+
]
|
|
1606
|
+
]);
|
|
1607
|
+
const DefaultUserIcon = /* @__PURE__ */ React.createElement(TrophyIcon, { style: { height: "2rem", width: "2rem" } });
|
|
1608
|
+
const getOrdinal = (n) => {
|
|
1609
|
+
if (n % 10 === 1 && n % 100 !== 11) {
|
|
1610
|
+
return `${n}st`;
|
|
1611
|
+
} else if (n % 10 === 2 && n % 100 !== 12) {
|
|
1612
|
+
return `${n}nd`;
|
|
1613
|
+
} else if (n % 10 === 3 && n % 100 !== 13) {
|
|
1614
|
+
return `${n}rd`;
|
|
1615
|
+
}
|
|
1616
|
+
return `${n}th`;
|
|
1617
|
+
};
|
|
1618
|
+
const RankingRow = (props) => {
|
|
1619
|
+
var _a, _b, _c;
|
|
1620
|
+
const classes = useStyles();
|
|
1621
|
+
const ordinalPosition = (props == null ? void 0 : props.position) ? getOrdinal(props == null ? void 0 : props.position) : "";
|
|
1622
|
+
const name = (_a = props == null ? void 0 : props.userRef) == null ? void 0 : _a.split("/")[1];
|
|
1623
|
+
const userIcon = ((_b = props.rankingIcon) == null ? void 0 : _b.userRankingIcon) ? (_c = props.rankingIcon) == null ? void 0 : _c.userRankingIcon : DefaultUserIcon;
|
|
1624
|
+
const topRankingIcon = props.rankingIcon ? props.rankingIcon.iconsByRanking.get(Number(props == null ? void 0 : props.position)) : DefaultRankingIcons.get(Number(props == null ? void 0 : props.position)) || DefaultUserIcon;
|
|
1625
|
+
const rankingIcon = (props == null ? void 0 : props.position) > 3 ? userIcon : topRankingIcon;
|
|
1626
|
+
return /* @__PURE__ */ React.createElement(ListItem, null, /* @__PURE__ */ React.createElement(ListItemAvatar, null, /* @__PURE__ */ React.createElement(Avatar, { className: classes.trophyIcon }, rankingIcon)), /* @__PURE__ */ React.createElement(
|
|
1627
|
+
ListItemText,
|
|
1628
|
+
{
|
|
1629
|
+
disableTypography: true,
|
|
1630
|
+
style: {
|
|
1631
|
+
display: "flex",
|
|
1632
|
+
justifyContent: "center"
|
|
1633
|
+
},
|
|
1634
|
+
primary: /* @__PURE__ */ React.createElement("div", { style: { display: "flex" } }, /* @__PURE__ */ React.createElement(
|
|
1635
|
+
Typography,
|
|
1636
|
+
{
|
|
1637
|
+
style: { marginRight: "10px", fontWeight: 400 },
|
|
1638
|
+
variant: "subtitle1"
|
|
1639
|
+
},
|
|
1640
|
+
`${ordinalPosition}`
|
|
1641
|
+
), /* @__PURE__ */ React.createElement(
|
|
1642
|
+
Link,
|
|
1643
|
+
{
|
|
1644
|
+
to: `/qeta/users/${name}`,
|
|
1645
|
+
variant: "subtitle1"
|
|
1646
|
+
},
|
|
1647
|
+
`${name}`
|
|
1648
|
+
))
|
|
1649
|
+
}
|
|
1650
|
+
), /* @__PURE__ */ React.createElement("div", { className: classes.votesText }, /* @__PURE__ */ React.createElement(Typography, { variant: "subtitle1" }, props == null ? void 0 : props.votes, " votes")));
|
|
1651
|
+
};
|
|
1652
|
+
const RankingCard = (props) => {
|
|
1653
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1654
|
+
const rankingStats = props.limit ? (_a = props.statistic) == null ? void 0 : _a.ranking.slice(0, props.limit) : (_b = props.statistic) == null ? void 0 : _b.ranking;
|
|
1655
|
+
return /* @__PURE__ */ React.createElement("div", { style: { display: "block" } }, /* @__PURE__ */ React.createElement("span", null, props.description), /* @__PURE__ */ React.createElement(List, null, rankingStats == null ? void 0 : rankingStats.map((authorStats) => {
|
|
1656
|
+
return /* @__PURE__ */ React.createElement(
|
|
1657
|
+
RankingRow,
|
|
1658
|
+
{
|
|
1659
|
+
votes: authorStats.total || 0,
|
|
1660
|
+
position: authorStats.position || 0,
|
|
1661
|
+
userRef: authorStats.author
|
|
1662
|
+
}
|
|
1663
|
+
);
|
|
1664
|
+
}), !(rankingStats == null ? void 0 : rankingStats.some(
|
|
1665
|
+
(authorStats) => {
|
|
1666
|
+
var _a2, _b2;
|
|
1667
|
+
return authorStats.author === ((_b2 = (_a2 = props.statistic) == null ? void 0 : _a2.loggedUser) == null ? void 0 : _b2.author);
|
|
1668
|
+
}
|
|
1669
|
+
)) && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("hr", null), /* @__PURE__ */ React.createElement(
|
|
1670
|
+
RankingRow,
|
|
1671
|
+
{
|
|
1672
|
+
votes: ((_d = (_c = props.statistic) == null ? void 0 : _c.loggedUser) == null ? void 0 : _d.total) || 0,
|
|
1673
|
+
position: ((_f = (_e = props.statistic) == null ? void 0 : _e.loggedUser) == null ? void 0 : _f.position) || 0,
|
|
1674
|
+
userRef: (_h = (_g = props.statistic) == null ? void 0 : _g.loggedUser) == null ? void 0 : _h.author
|
|
1675
|
+
}
|
|
1676
|
+
))));
|
|
1677
|
+
};
|
|
1678
|
+
const TopRankingUsers = (props) => {
|
|
1679
|
+
const {
|
|
1680
|
+
value: topStatistics,
|
|
1681
|
+
loading,
|
|
1682
|
+
error
|
|
1683
|
+
} = useQetaApi(
|
|
1684
|
+
(api) => api.getTopStatisticsHomepage({
|
|
1685
|
+
options: { limit: 50 }
|
|
1686
|
+
})
|
|
1687
|
+
);
|
|
1688
|
+
const tabData = [
|
|
1689
|
+
{
|
|
1690
|
+
title: "Top Upvoted Questions",
|
|
1691
|
+
description: "People who have the highest rated questions"
|
|
1692
|
+
},
|
|
1693
|
+
{
|
|
1694
|
+
title: "Top Upvoted Answers",
|
|
1695
|
+
description: "People who have the highest rated answers"
|
|
1696
|
+
},
|
|
1697
|
+
{
|
|
1698
|
+
title: "Top Upvoted Correct Answers",
|
|
1699
|
+
description: "People who have the highest rated correct answers"
|
|
1700
|
+
}
|
|
1701
|
+
];
|
|
1702
|
+
if ((error || topStatistics === void 0) && !loading) {
|
|
1703
|
+
return /* @__PURE__ */ React.createElement(WarningPanel, { severity: "error", title: "Could not load statistics." }, error == null ? void 0 : error.message);
|
|
1704
|
+
}
|
|
1705
|
+
let content;
|
|
1706
|
+
if (loading) {
|
|
1707
|
+
content = [
|
|
1708
|
+
/* @__PURE__ */ React.createElement(CardTab, null, /* @__PURE__ */ React.createElement(Progress, null))
|
|
1709
|
+
];
|
|
1710
|
+
} else if (topStatistics && topStatistics.length > 0) {
|
|
1711
|
+
content = topStatistics == null ? void 0 : topStatistics.map((stats, index) => {
|
|
1712
|
+
return /* @__PURE__ */ React.createElement(CardTab, { label: tabData[index].title }, /* @__PURE__ */ React.createElement(
|
|
1713
|
+
RankingCard,
|
|
1714
|
+
{
|
|
1715
|
+
description: tabData[index].description,
|
|
1716
|
+
limit: 3,
|
|
1717
|
+
statistic: stats
|
|
1718
|
+
}
|
|
1719
|
+
));
|
|
1720
|
+
});
|
|
1721
|
+
} else {
|
|
1722
|
+
content = [/* @__PURE__ */ React.createElement(CardTab, null, "No statistics available")];
|
|
1723
|
+
}
|
|
1724
|
+
return /* @__PURE__ */ React.createElement(TabbedCard, { title: props.title || "Ranking Q&A \u{1F3C6}" }, content);
|
|
1725
|
+
};
|
|
1726
|
+
|
|
1727
|
+
const AskQuestionButton = () => {
|
|
1728
|
+
return /* @__PURE__ */ React.createElement(
|
|
1729
|
+
RequirePermission,
|
|
1730
|
+
{
|
|
1731
|
+
permission: qetaCreateQuestionPermission,
|
|
1732
|
+
errorPage: /* @__PURE__ */ React.createElement(React.Fragment, null)
|
|
1733
|
+
},
|
|
1734
|
+
/* @__PURE__ */ React.createElement(
|
|
1735
|
+
LinkButton,
|
|
1736
|
+
{
|
|
1737
|
+
variant: "contained",
|
|
1738
|
+
to: "/qeta/ask",
|
|
1739
|
+
color: "primary",
|
|
1740
|
+
startIcon: /* @__PURE__ */ React.createElement(HelpOutline, null)
|
|
1741
|
+
},
|
|
1742
|
+
"Ask question"
|
|
1743
|
+
)
|
|
1744
|
+
);
|
|
1745
|
+
};
|
|
1746
|
+
|
|
1747
|
+
const StatisticsPage = () => {
|
|
1748
|
+
const styles = useStyles$1();
|
|
1749
|
+
return /* @__PURE__ */ React.createElement(Content$1, null, /* @__PURE__ */ React.createElement(Container, { maxWidth: "lg" }, /* @__PURE__ */ React.createElement(ContentHeader, { title: "Statistics" }, /* @__PURE__ */ React.createElement(
|
|
1750
|
+
LinkButton,
|
|
1751
|
+
{
|
|
1752
|
+
to: "/qeta",
|
|
1753
|
+
className: styles.marginRight,
|
|
1754
|
+
startIcon: /* @__PURE__ */ React.createElement(HomeOutlined, null)
|
|
1755
|
+
},
|
|
1756
|
+
"Back to questions"
|
|
1757
|
+
), /* @__PURE__ */ React.createElement(AskQuestionButton, null)), /* @__PURE__ */ React.createElement(TopRankingUsers, null)));
|
|
1758
|
+
};
|
|
1759
|
+
|
|
1760
|
+
export { AskForm as A, Content as C, MarkdownEditor as M, QuestionsContainer as Q, RankingRow as R, StatisticsPage as S, TagsAndEntities as T, useStyles$1 as a, useQetaApi as b, AskQuestionButton as c, useIdentityApi as d, TrophyIcon as e, formatEntityName as f, QuestionsTable as g, qetaPlugin as h, QetaPage as i, QuestionTableCard as j, RankingCard as k, TopRankingUsers as l, QetaClient as m, qetaApiRef as q, useBasePath as u };
|
|
1761
|
+
//# sourceMappingURL=index-6bfa5b72.esm.js.map
|