@drodil/backstage-plugin-qeta-react 3.59.6 → 3.59.9

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.
@@ -1,7 +1,7 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
2
  import { Autocomplete } from '@material-ui/lab';
3
3
  import { Box, TextField, CircularProgress, Tooltip, Typography, Chip } from '@material-ui/core';
4
- import { forwardRef, useState, useEffect, useMemo } from 'react';
4
+ import { forwardRef, useState, useRef, useEffect, useMemo } from 'react';
5
5
  import { qetaApiRef } from '../../api.esm.js';
6
6
  import { useApi, configApiRef } from '@backstage/core-plugin-api';
7
7
  import { qetaCreateTagPermission, filterTags } from '@drodil/backstage-plugin-qeta-common';
@@ -12,6 +12,87 @@ import { permissionApiRef } from '@backstage/plugin-permission-react';
12
12
  import { AuthorizeResult } from '@backstage/plugin-permission-common';
13
13
  import { useDebounce } from 'react-use';
14
14
 
15
+ const TAG_SEARCH_LIMIT = 25;
16
+ const isCreateTagOption = (option) => typeof option !== "string";
17
+ const getTagOptionValue = (option) => isCreateTagOption(option) ? option.inputValue : option;
18
+ const getTagOptionLabel = (option) => isCreateTagOption(option) ? option.label : option;
19
+ const normalizeTagInput = (input) => filterTags([input])[0];
20
+ const getTagSearchRequest = (term) => ({
21
+ limit: TAG_SEARCH_LIMIT,
22
+ orderBy: "postsCount",
23
+ order: "desc",
24
+ ...term ? { searchQuery: term } : {}
25
+ });
26
+ const getMatchingAllowedTags = (allowedTags, term) => {
27
+ const normalizedTerm = term.trim().toLocaleLowerCase();
28
+ if (!normalizedTerm) {
29
+ return allowedTags;
30
+ }
31
+ return allowedTags.filter(
32
+ (tag) => tag.toLocaleLowerCase().includes(normalizedTerm)
33
+ );
34
+ };
35
+ const mergeTags = (...groups) => {
36
+ const seen = /* @__PURE__ */ new Set();
37
+ const merged = [];
38
+ for (const tag of groups.flat()) {
39
+ if (!seen.has(tag)) {
40
+ seen.add(tag);
41
+ merged.push(tag);
42
+ }
43
+ }
44
+ return merged;
45
+ };
46
+ const getTagDescriptions = (tags) => tags.reduce(
47
+ (acc, tag) => {
48
+ if (!tag.description) {
49
+ return acc;
50
+ }
51
+ acc[tag.tag] = tag.description;
52
+ return acc;
53
+ },
54
+ {}
55
+ );
56
+ const getFilteredTagOptions = ({
57
+ allowCreation,
58
+ getCreateOptionLabel,
59
+ inputValue,
60
+ maximumTags,
61
+ options,
62
+ selectedTags
63
+ }) => {
64
+ const trimmedInput = inputValue.trim();
65
+ const normalizedInput = trimmedInput.toLocaleLowerCase();
66
+ const filteredOptions = options.filter((option) => {
67
+ if (!normalizedInput) {
68
+ return true;
69
+ }
70
+ return option.toLocaleLowerCase().includes(normalizedInput);
71
+ });
72
+ if (!allowCreation || !trimmedInput || selectedTags.length >= maximumTags) {
73
+ return filteredOptions;
74
+ }
75
+ const normalizedTag = normalizeTagInput(trimmedInput);
76
+ if (!normalizedTag) {
77
+ return filteredOptions;
78
+ }
79
+ const tagAlreadyExists = options.some(
80
+ (option) => option.toLocaleLowerCase() === normalizedTag
81
+ );
82
+ const tagAlreadySelected = selectedTags.some(
83
+ (tag) => tag.toLocaleLowerCase() === normalizedTag
84
+ );
85
+ if (tagAlreadyExists || tagAlreadySelected) {
86
+ return filteredOptions;
87
+ }
88
+ return [
89
+ ...filteredOptions,
90
+ {
91
+ inputValue: trimmedInput,
92
+ label: getCreateOptionLabel(trimmedInput)
93
+ }
94
+ ];
95
+ };
15
96
  const TagInput = forwardRef((props, _ref) => {
16
97
  const {
17
98
  value,
@@ -35,7 +116,10 @@ const TagInput = forwardRef((props, _ref) => {
35
116
  );
36
117
  const [loading, setLoading] = useState(true);
37
118
  const [suggestedTags, setSuggestedTags] = useState([]);
38
- const [, setLoadingSuggestions] = useState(false);
119
+ const [loadingSuggestions, setLoadingSuggestions] = useState(false);
120
+ const [inputValue, setInputValue] = useState("");
121
+ const searchCache = useRef(/* @__PURE__ */ new Map());
122
+ const activeRequest = useRef(0);
39
123
  useEffect(() => {
40
124
  if (allowCreate !== void 0) {
41
125
  return;
@@ -75,37 +159,73 @@ const TagInput = forwardRef((props, _ref) => {
75
159
  () => config.getOptionalStringArray("qeta.tags.allowedTags") ?? [],
76
160
  [config]
77
161
  );
162
+ const selectedTags = useMemo(() => value ?? [], [value]);
78
163
  const maximumTags = useMemo(
79
164
  () => config.getOptionalNumber("qeta.tags.max") ?? 5,
80
165
  [config]
81
166
  );
82
167
  const [availableTags, setAvailableTags] = useState([]);
83
168
  const [tagDescriptions, setTagDescriptions] = useState({});
84
- useEffect(() => {
85
- qetaApi.getTags().catch((_) => setAvailableTags([])).then((data) => {
86
- setLoading(false);
87
- if (!data) {
169
+ const loadTags = useMemo(
170
+ () => async (term) => {
171
+ const trimmed = term.trim();
172
+ const cacheKey = trimmed.toLocaleLowerCase();
173
+ const matchingAllowedTags = getMatchingAllowedTags(allowedTags, trimmed);
174
+ const cached = searchCache.current.get(cacheKey);
175
+ if (cached) {
176
+ setLoading(false);
177
+ setAvailableTags(
178
+ (prev) => mergeTags(prev, cached.tags, matchingAllowedTags)
179
+ );
180
+ setTagDescriptions((prev) => ({
181
+ ...prev,
182
+ ...cached.descriptions
183
+ }));
88
184
  return;
89
185
  }
90
- const uniqueTags = [
91
- .../* @__PURE__ */ new Set([...allowedTags, ...data.tags.map((tag) => tag.tag)])
92
- ].sort((a, b) => a.localeCompare(b));
93
- setAvailableTags(uniqueTags);
94
- setTagDescriptions(
95
- data.tags.reduce(
96
- (acc, tag) => {
97
- if (!tag.description) {
98
- return acc;
99
- }
100
- acc[tag.tag] = tag.description;
101
- return acc;
102
- },
103
- {}
104
- )
105
- );
106
- });
107
- }, [qetaApi, allowCreation, allowedTags]);
108
- if (!allowCreation && availableTags.length === 0) {
186
+ const requestId = activeRequest.current + 1;
187
+ activeRequest.current = requestId;
188
+ setLoading(true);
189
+ try {
190
+ const data = await qetaApi.getTags(getTagSearchRequest(trimmed));
191
+ const remoteTags = data.tags.map((tag) => tag.tag);
192
+ const descriptions = getTagDescriptions(data.tags);
193
+ const nextTags = mergeTags(remoteTags, matchingAllowedTags);
194
+ if (activeRequest.current !== requestId) {
195
+ return;
196
+ }
197
+ searchCache.current.set(cacheKey, {
198
+ tags: remoteTags,
199
+ descriptions
200
+ });
201
+ setAvailableTags((prev) => mergeTags(prev, nextTags));
202
+ setTagDescriptions((prev) => ({ ...prev, ...descriptions }));
203
+ } catch {
204
+ if (activeRequest.current === requestId) {
205
+ setAvailableTags((prev) => mergeTags(prev, matchingAllowedTags));
206
+ }
207
+ } finally {
208
+ if (activeRequest.current === requestId) {
209
+ setLoading(false);
210
+ }
211
+ }
212
+ },
213
+ [allowedTags, qetaApi]
214
+ );
215
+ useEffect(() => {
216
+ searchCache.current.clear();
217
+ activeRequest.current += 1;
218
+ setLoading(true);
219
+ loadTags("");
220
+ }, [loadTags]);
221
+ useDebounce(
222
+ () => {
223
+ loadTags(inputValue);
224
+ },
225
+ 300,
226
+ [inputValue, loadTags]
227
+ );
228
+ if (allowCreation === false && !loading && availableTags.length === 0) {
109
229
  return null;
110
230
  }
111
231
  const getHelperText = () => {
@@ -132,18 +252,41 @@ const TagInput = forwardRef((props, _ref) => {
132
252
  multiple: true,
133
253
  id: "tags-select",
134
254
  className: "qetaTagInput",
135
- value: value || [],
255
+ value: selectedTags,
136
256
  loading,
137
257
  autoHighlight: true,
138
258
  autoComplete: true,
139
259
  loadingText: t("common.loading"),
140
- options: availableTags ?? [],
260
+ options: availableTags,
141
261
  freeSolo: allowCreation,
142
262
  handleHomeEndKeys: true,
263
+ limitTags: maximumTags,
264
+ getOptionLabel: getTagOptionLabel,
265
+ filterOptions: (options, state) => getFilteredTagOptions({
266
+ allowCreation: allowCreation === true,
267
+ getCreateOptionLabel: (tag) => t("tagsInput.createOption", { tag }),
268
+ inputValue: state.inputValue,
269
+ maximumTags,
270
+ options: options.filter(
271
+ (option) => typeof option === "string"
272
+ ),
273
+ selectedTags
274
+ }),
275
+ inputValue,
276
+ onInputChange: (_event, nextValue, reason) => {
277
+ if (reason === "reset") {
278
+ setInputValue("");
279
+ return;
280
+ }
281
+ setInputValue(nextValue);
282
+ },
143
283
  ListboxComponent: AutocompleteListboxComponent,
144
284
  disableListWrap: true,
145
285
  style,
146
286
  renderOption: (option) => {
287
+ if (isCreateTagOption(option)) {
288
+ return option.label;
289
+ }
147
290
  if (tagDescriptions[option]) {
148
291
  return /* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsx(
149
292
  Tooltip,
@@ -158,8 +301,9 @@ const TagInput = forwardRef((props, _ref) => {
158
301
  return option;
159
302
  },
160
303
  onChange: (_e, newValue) => {
161
- const tags = filterTags(newValue);
162
- if (tags && tags.length <= maximumTags && tags.length === newValue.length) {
304
+ const nextValues = newValue.map(getTagOptionValue);
305
+ const tags = filterTags(nextValues);
306
+ if (tags && tags.length <= maximumTags && tags.length === nextValues.length) {
163
307
  onChange(tags);
164
308
  }
165
309
  },
@@ -171,7 +315,7 @@ const TagInput = forwardRef((props, _ref) => {
171
315
  margin: "normal",
172
316
  label: label ?? t("tagsInput.label"),
173
317
  placeholder: t("tagsInput.placeholder"),
174
- helperText: error !== void 0 ? error.message : getHelperText(),
318
+ helperText: error ? error.message : getHelperText(),
175
319
  FormHelperTextProps: {
176
320
  style: { marginLeft: "0.2em" }
177
321
  },
@@ -197,7 +341,7 @@ const TagInput = forwardRef((props, _ref) => {
197
341
  size: "small",
198
342
  onClick: () => handleSuggestedTagClick(tag),
199
343
  style: { margin: "0 4px 4px 0" },
200
- disabled: value?.includes(tag) || (value?.length ?? 0) >= maximumTags
344
+ disabled: value?.includes(tag) || (value?.length ?? 0) >= maximumTags || loadingSuggestions
201
345
  },
202
346
  tag
203
347
  )) })
@@ -1 +1 @@
1
- {"version":3,"file":"TagInput.esm.js","sources":["../../../src/components/PostForm/TagInput.tsx"],"sourcesContent":["import { Autocomplete } from '@material-ui/lab';\nimport {\n Box,\n Chip,\n CircularProgress,\n TextField,\n Tooltip,\n Typography,\n} from '@material-ui/core';\nimport {\n ComponentType,\n CSSProperties,\n forwardRef,\n HTMLAttributes,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport { qetaApiRef } from '../../api';\nimport { configApiRef, useApi } from '@backstage/core-plugin-api';\nimport {\n filterTags,\n qetaCreateTagPermission,\n} from '@drodil/backstage-plugin-qeta-common';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { qetaTranslationRef } from '../../translation.ts';\nimport { FieldError } from 'react-hook-form';\nimport { AutocompleteListboxComponent } from './AutocompleteListComponent';\nimport { permissionApiRef } from '@backstage/plugin-permission-react';\nimport { AuthorizeResult } from '@backstage/plugin-permission-common';\nimport { useDebounce } from 'react-use';\n\nexport const TagInput = forwardRef<\n any,\n {\n value?: string[];\n onChange: (value: string[]) => void;\n error?: FieldError;\n allowCreate?: boolean;\n hideHelpText?: boolean;\n style?: CSSProperties;\n title?: string;\n name?: string;\n content?: string;\n entities?: string[];\n label?: string;\n }\n>((props, _ref) => {\n const {\n value,\n onChange,\n error,\n allowCreate,\n hideHelpText = false,\n style,\n name = 'tags',\n title,\n content,\n entities,\n label,\n } = props;\n const qetaApi = useApi(qetaApiRef);\n const config = useApi(configApiRef);\n const permissions = useApi(permissionApiRef);\n const { t } = useTranslationRef(qetaTranslationRef);\n const [allowCreation, setAllowCreation] = useState<boolean | undefined>(\n allowCreate,\n );\n const [loading, setLoading] = useState(true);\n const [suggestedTags, setSuggestedTags] = useState<string[]>([]);\n const [, setLoadingSuggestions] = useState(false);\n\n useEffect(() => {\n if (allowCreate !== undefined) {\n return;\n }\n\n if (config.getOptionalBoolean('qeta.permissions') === true) {\n permissions\n .authorize({\n permission: qetaCreateTagPermission,\n })\n .catch(_ => setAllowCreation(false))\n .then(res => {\n if (res && res.result === AuthorizeResult.ALLOW) {\n setAllowCreation(true);\n } else {\n setAllowCreation(false);\n }\n });\n } else {\n setAllowCreation(\n config.getOptionalBoolean('qeta.tags.allowCreation') ?? true,\n );\n }\n }, [config, permissions, allowCreate]);\n\n useDebounce(\n () => {\n if (title && content) {\n setLoadingSuggestions(true);\n qetaApi\n .getTagSuggestions({ title, content, entities, limit: 5 })\n .then(response => {\n setSuggestedTags(response.tags);\n })\n .catch(() => {\n // Ignore errors\n })\n .finally(() => {\n setLoadingSuggestions(false);\n });\n }\n },\n 2000,\n [title, content, entities, qetaApi],\n );\n\n const allowedTags = useMemo(\n () => config.getOptionalStringArray('qeta.tags.allowedTags') ?? [],\n [config],\n );\n const maximumTags = useMemo(\n () => config.getOptionalNumber('qeta.tags.max') ?? 5,\n [config],\n );\n\n const [availableTags, setAvailableTags] = useState<string[]>([]);\n const [tagDescriptions, setTagDescriptions] = useState<\n Record<string, string>\n >({});\n useEffect(() => {\n qetaApi\n .getTags()\n .catch(_ => setAvailableTags([]))\n .then(data => {\n setLoading(false);\n if (!data) {\n return;\n }\n\n const uniqueTags = [\n ...new Set([...allowedTags, ...data.tags.map(tag => tag.tag)]),\n ].sort((a, b) => a.localeCompare(b));\n setAvailableTags(uniqueTags);\n setTagDescriptions(\n data.tags.reduce(\n (acc, tag) => {\n if (!tag.description) {\n return acc;\n }\n acc[tag.tag] = tag.description;\n return acc;\n },\n {} as Record<string, string>,\n ),\n );\n });\n }, [qetaApi, allowCreation, allowedTags]);\n\n if (!allowCreation && availableTags.length === 0) {\n return null;\n }\n\n const getHelperText = () => {\n if (hideHelpText) {\n return '';\n }\n\n const baseText = t('tagsInput.helperText', {\n max: maximumTags.toString(10),\n });\n\n if (!allowCreation) {\n return baseText;\n }\n return `${baseText}. ${t('tagsInput.allowAddHelperText')}`;\n };\n\n const handleSuggestedTagClick = (tag: string) => {\n if (value && value.length < maximumTags && !value.includes(tag)) {\n onChange([...value, tag]);\n }\n };\n\n return (\n <Box>\n <Autocomplete\n multiple\n id=\"tags-select\"\n className=\"qetaTagInput\"\n value={value || []}\n loading={loading}\n autoHighlight\n autoComplete\n loadingText={t('common.loading')}\n options={availableTags ?? []}\n freeSolo={allowCreation}\n handleHomeEndKeys\n ListboxComponent={\n AutocompleteListboxComponent as ComponentType<\n HTMLAttributes<HTMLElement>\n >\n }\n disableListWrap\n style={style}\n renderOption={option => {\n if (tagDescriptions[option]) {\n return (\n <span key={option}>\n <Tooltip\n arrow\n placement=\"right\"\n title={<Typography>{tagDescriptions[option]}</Typography>}\n >\n <span>{option}</span>\n </Tooltip>\n </span>\n );\n }\n return option;\n }}\n onChange={(_e, newValue) => {\n const tags = filterTags(newValue);\n if (\n tags &&\n tags.length <= maximumTags &&\n tags.length === newValue.length\n ) {\n onChange(tags);\n }\n }}\n renderInput={params => (\n <TextField\n {...params}\n variant=\"outlined\"\n margin=\"normal\"\n label={label ?? t('tagsInput.label')}\n placeholder={t('tagsInput.placeholder')}\n helperText={error !== undefined ? error.message : getHelperText()}\n FormHelperTextProps={{\n style: { marginLeft: '0.2em' },\n }}\n name={name}\n InputProps={{\n ...params.InputProps,\n endAdornment: (\n <>\n {loading ? (\n <CircularProgress color=\"inherit\" size={20} />\n ) : null}\n {params.InputProps.endAdornment}\n </>\n ),\n }}\n error={error !== undefined}\n />\n )}\n />\n {suggestedTags?.length > 0 && (\n <Box style={{ marginLeft: '4px' }}>\n <Typography variant=\"caption\" color=\"textSecondary\">\n {t('tagsInput.suggestedTags')}\n </Typography>\n <Box mt={0.5}>\n {suggestedTags.map(tag => (\n <Chip\n key={tag}\n label={tag}\n size=\"small\"\n onClick={() => handleSuggestedTagClick(tag)}\n style={{ margin: '0 4px 4px 0' }}\n disabled={\n value?.includes(tag) || (value?.length ?? 0) >= maximumTags\n }\n />\n ))}\n </Box>\n </Box>\n )}{' '}\n </Box>\n );\n});\n\nTagInput.displayName = 'TagInput';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TagInput.esm.js","sources":["../../../src/components/PostForm/TagInput.tsx"],"sourcesContent":["import { Autocomplete } from '@material-ui/lab';\nimport {\n Box,\n Chip,\n CircularProgress,\n TextField,\n Tooltip,\n Typography,\n} from '@material-ui/core';\nimport {\n ComponentType,\n CSSProperties,\n forwardRef,\n HTMLAttributes,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { qetaApiRef } from '../../api';\nimport { configApiRef, useApi } from '@backstage/core-plugin-api';\nimport {\n filterTags,\n qetaCreateTagPermission,\n type TagsQuery,\n} from '@drodil/backstage-plugin-qeta-common';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { qetaTranslationRef } from '../../translation.ts';\nimport { FieldError } from 'react-hook-form';\nimport { AutocompleteListboxComponent } from './AutocompleteListComponent';\nimport { permissionApiRef } from '@backstage/plugin-permission-react';\nimport { AuthorizeResult } from '@backstage/plugin-permission-common';\nimport { useDebounce } from 'react-use';\n\nconst TAG_SEARCH_LIMIT = 25;\n\ntype CreateTagOption = {\n inputValue: string;\n label: string;\n};\n\ntype TagAutocompleteOption = string | CreateTagOption;\n\nconst isCreateTagOption = (\n option: TagAutocompleteOption,\n): option is CreateTagOption => typeof option !== 'string';\n\nconst getTagOptionValue = (option: TagAutocompleteOption) =>\n isCreateTagOption(option) ? option.inputValue : option;\n\nconst getTagOptionLabel = (option: TagAutocompleteOption) =>\n isCreateTagOption(option) ? option.label : option;\n\nconst normalizeTagInput = (input: string) => filterTags([input])[0];\n\nconst getTagSearchRequest = (term: string): TagsQuery => ({\n limit: TAG_SEARCH_LIMIT,\n orderBy: 'postsCount',\n order: 'desc',\n ...(term ? { searchQuery: term } : {}),\n});\n\nconst getMatchingAllowedTags = (allowedTags: string[], term: string) => {\n const normalizedTerm = term.trim().toLocaleLowerCase();\n\n if (!normalizedTerm) {\n return allowedTags;\n }\n\n return allowedTags.filter(tag =>\n tag.toLocaleLowerCase().includes(normalizedTerm),\n );\n};\n\nconst mergeTags = (...groups: string[][]) => {\n const seen = new Set<string>();\n const merged: string[] = [];\n\n for (const tag of groups.flat()) {\n if (!seen.has(tag)) {\n seen.add(tag);\n merged.push(tag);\n }\n }\n\n return merged;\n};\n\nconst getTagDescriptions = (\n tags: Array<{ tag: string; description?: string }>,\n) =>\n tags.reduce(\n (acc, tag) => {\n if (!tag.description) {\n return acc;\n }\n acc[tag.tag] = tag.description;\n return acc;\n },\n {} as Record<string, string>,\n );\n\nconst getFilteredTagOptions = ({\n allowCreation,\n getCreateOptionLabel,\n inputValue,\n maximumTags,\n options,\n selectedTags,\n}: {\n allowCreation: boolean;\n getCreateOptionLabel: (tag: string) => string;\n inputValue: string;\n maximumTags: number;\n options: string[];\n selectedTags: string[];\n}): TagAutocompleteOption[] => {\n const trimmedInput = inputValue.trim();\n const normalizedInput = trimmedInput.toLocaleLowerCase();\n const filteredOptions = options.filter(option => {\n if (!normalizedInput) {\n return true;\n }\n\n return option.toLocaleLowerCase().includes(normalizedInput);\n });\n\n if (!allowCreation || !trimmedInput || selectedTags.length >= maximumTags) {\n return filteredOptions;\n }\n\n const normalizedTag = normalizeTagInput(trimmedInput);\n if (!normalizedTag) {\n return filteredOptions;\n }\n\n const tagAlreadyExists = options.some(\n option => option.toLocaleLowerCase() === normalizedTag,\n );\n const tagAlreadySelected = selectedTags.some(\n tag => tag.toLocaleLowerCase() === normalizedTag,\n );\n\n if (tagAlreadyExists || tagAlreadySelected) {\n return filteredOptions;\n }\n\n return [\n ...filteredOptions,\n {\n inputValue: trimmedInput,\n label: getCreateOptionLabel(trimmedInput),\n },\n ];\n};\n\nexport const TagInput = forwardRef<\n any,\n {\n value?: string[];\n onChange: (value: string[]) => void;\n error?: FieldError;\n allowCreate?: boolean;\n hideHelpText?: boolean;\n style?: CSSProperties;\n title?: string;\n name?: string;\n content?: string;\n entities?: string[];\n label?: string;\n }\n>((props, _ref) => {\n const {\n value,\n onChange,\n error,\n allowCreate,\n hideHelpText = false,\n style,\n name = 'tags',\n title,\n content,\n entities,\n label,\n } = props;\n const qetaApi = useApi(qetaApiRef);\n const config = useApi(configApiRef);\n const permissions = useApi(permissionApiRef);\n const { t } = useTranslationRef(qetaTranslationRef);\n const [allowCreation, setAllowCreation] = useState<boolean | undefined>(\n allowCreate,\n );\n const [loading, setLoading] = useState(true);\n const [suggestedTags, setSuggestedTags] = useState<string[]>([]);\n const [loadingSuggestions, setLoadingSuggestions] = useState(false);\n const [inputValue, setInputValue] = useState('');\n const searchCache = useRef<\n Map<string, { tags: string[]; descriptions: Record<string, string> }>\n >(new Map());\n const activeRequest = useRef(0);\n\n useEffect(() => {\n if (allowCreate !== undefined) {\n return;\n }\n\n if (config.getOptionalBoolean('qeta.permissions') === true) {\n permissions\n .authorize({\n permission: qetaCreateTagPermission,\n })\n .catch(_ => setAllowCreation(false))\n .then(res => {\n if (res && res.result === AuthorizeResult.ALLOW) {\n setAllowCreation(true);\n } else {\n setAllowCreation(false);\n }\n });\n } else {\n setAllowCreation(\n config.getOptionalBoolean('qeta.tags.allowCreation') ?? true,\n );\n }\n }, [config, permissions, allowCreate]);\n\n useDebounce(\n () => {\n if (title && content) {\n setLoadingSuggestions(true);\n qetaApi\n .getTagSuggestions({ title, content, entities, limit: 5 })\n .then(response => {\n setSuggestedTags(response.tags);\n })\n .catch(() => {\n // Ignore errors\n })\n .finally(() => {\n setLoadingSuggestions(false);\n });\n }\n },\n 2000,\n [title, content, entities, qetaApi],\n );\n\n const allowedTags = useMemo(\n () => config.getOptionalStringArray('qeta.tags.allowedTags') ?? [],\n [config],\n );\n const selectedTags = useMemo(() => value ?? [], [value]);\n const maximumTags = useMemo(\n () => config.getOptionalNumber('qeta.tags.max') ?? 5,\n [config],\n );\n\n const [availableTags, setAvailableTags] = useState<string[]>([]);\n const [tagDescriptions, setTagDescriptions] = useState<\n Record<string, string>\n >({});\n\n const loadTags = useMemo(\n () => async (term: string) => {\n const trimmed = term.trim();\n const cacheKey = trimmed.toLocaleLowerCase();\n const matchingAllowedTags = getMatchingAllowedTags(allowedTags, trimmed);\n const cached = searchCache.current.get(cacheKey);\n\n if (cached) {\n setLoading(false);\n setAvailableTags(prev =>\n mergeTags(prev, cached.tags, matchingAllowedTags),\n );\n setTagDescriptions(prev => ({\n ...prev,\n ...cached.descriptions,\n }));\n return;\n }\n\n const requestId = activeRequest.current + 1;\n activeRequest.current = requestId;\n setLoading(true);\n\n try {\n const data = await qetaApi.getTags(getTagSearchRequest(trimmed));\n const remoteTags = data.tags.map(tag => tag.tag);\n const descriptions = getTagDescriptions(data.tags);\n const nextTags = mergeTags(remoteTags, matchingAllowedTags);\n\n if (activeRequest.current !== requestId) {\n return;\n }\n\n searchCache.current.set(cacheKey, {\n tags: remoteTags,\n descriptions,\n });\n setAvailableTags(prev => mergeTags(prev, nextTags));\n setTagDescriptions(prev => ({ ...prev, ...descriptions }));\n } catch {\n if (activeRequest.current === requestId) {\n setAvailableTags(prev => mergeTags(prev, matchingAllowedTags));\n }\n } finally {\n if (activeRequest.current === requestId) {\n setLoading(false);\n }\n }\n },\n [allowedTags, qetaApi],\n );\n\n useEffect(() => {\n searchCache.current.clear();\n activeRequest.current += 1;\n setLoading(true);\n loadTags('');\n }, [loadTags]);\n\n useDebounce(\n () => {\n loadTags(inputValue);\n },\n 300,\n [inputValue, loadTags],\n );\n\n if (allowCreation === false && !loading && availableTags.length === 0) {\n return null;\n }\n\n const getHelperText = () => {\n if (hideHelpText) {\n return '';\n }\n\n const baseText = t('tagsInput.helperText', {\n max: maximumTags.toString(10),\n });\n\n if (!allowCreation) {\n return baseText;\n }\n return `${baseText}. ${t('tagsInput.allowAddHelperText')}`;\n };\n\n const handleSuggestedTagClick = (tag: string) => {\n if (value && value.length < maximumTags && !value.includes(tag)) {\n onChange([...value, tag]);\n }\n };\n\n return (\n <Box>\n <Autocomplete\n multiple\n id=\"tags-select\"\n className=\"qetaTagInput\"\n value={selectedTags as TagAutocompleteOption[]}\n loading={loading}\n autoHighlight\n autoComplete\n loadingText={t('common.loading')}\n options={availableTags as TagAutocompleteOption[]}\n freeSolo={allowCreation}\n handleHomeEndKeys\n limitTags={maximumTags}\n getOptionLabel={getTagOptionLabel}\n filterOptions={(options, state) =>\n getFilteredTagOptions({\n allowCreation: allowCreation === true,\n getCreateOptionLabel: tag =>\n t('tagsInput.createOption' as never, { tag } as never) as string,\n inputValue: state.inputValue,\n maximumTags,\n options: options.filter(\n (option): option is string => typeof option === 'string',\n ),\n selectedTags,\n })\n }\n inputValue={inputValue}\n onInputChange={(_event, nextValue, reason) => {\n if (reason === 'reset') {\n setInputValue('');\n return;\n }\n\n setInputValue(nextValue);\n }}\n ListboxComponent={\n AutocompleteListboxComponent as ComponentType<\n HTMLAttributes<HTMLElement>\n >\n }\n disableListWrap\n style={style}\n renderOption={option => {\n if (isCreateTagOption(option)) {\n return option.label;\n }\n\n if (tagDescriptions[option]) {\n return (\n <span key={option}>\n <Tooltip\n arrow\n placement=\"right\"\n title={<Typography>{tagDescriptions[option]}</Typography>}\n >\n <span>{option}</span>\n </Tooltip>\n </span>\n );\n }\n return option;\n }}\n onChange={(_e, newValue) => {\n const nextValues = newValue.map(getTagOptionValue);\n const tags = filterTags(nextValues);\n if (\n tags &&\n tags.length <= maximumTags &&\n tags.length === nextValues.length\n ) {\n onChange(tags);\n }\n }}\n renderInput={params => (\n <TextField\n {...params}\n variant=\"outlined\"\n margin=\"normal\"\n label={label ?? t('tagsInput.label')}\n placeholder={t('tagsInput.placeholder')}\n helperText={error ? error.message : getHelperText()}\n FormHelperTextProps={{\n style: { marginLeft: '0.2em' },\n }}\n name={name}\n InputProps={{\n ...params.InputProps,\n endAdornment: (\n <>\n {loading ? (\n <CircularProgress color=\"inherit\" size={20} />\n ) : null}\n {params.InputProps.endAdornment}\n </>\n ),\n }}\n error={error !== undefined}\n />\n )}\n />\n {suggestedTags?.length > 0 && (\n <Box style={{ marginLeft: '4px' }}>\n <Typography variant=\"caption\" color=\"textSecondary\">\n {t('tagsInput.suggestedTags')}\n </Typography>\n <Box mt={0.5}>\n {suggestedTags.map(tag => (\n <Chip\n key={tag}\n label={tag}\n size=\"small\"\n onClick={() => handleSuggestedTagClick(tag)}\n style={{ margin: '0 4px 4px 0' }}\n disabled={\n value?.includes(tag) ||\n (value?.length ?? 0) >= maximumTags ||\n loadingSuggestions\n }\n />\n ))}\n </Box>\n </Box>\n )}{' '}\n </Box>\n );\n});\n\nTagInput.displayName = 'TagInput';\n"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1040,6 +1040,7 @@ declare const qetaTranslationRef: _backstage_frontend_plugin_api.TranslationRef<
1040
1040
  readonly "tagsInput.helperText": "Add up to {{max}} tags";
1041
1041
  readonly "tagsInput.minimumError": "Please add at least {{min}} tags";
1042
1042
  readonly "tagsInput.allowAddHelperText": "You can create new tags by typing the tag and pressing enter";
1043
+ readonly "tagsInput.createOption": "Add {{tag}}";
1043
1044
  readonly "tagsInput.suggestedTags": "Suggested tags";
1044
1045
  readonly "askPage.title.newQuestion": "Ask a question";
1045
1046
  readonly "askPage.title.existingQuestion": "Edit question";
@@ -1121,7 +1122,6 @@ declare const qetaTranslationRef: _backstage_frontend_plugin_api.TranslationRef<
1121
1122
  readonly "favoritePage.title": "Favorited posts";
1122
1123
  readonly "leftMenu.tags": "Tags";
1123
1124
  readonly "leftMenu.entities": "Entities";
1124
- readonly "leftMenu.content": "Content";
1125
1125
  readonly "leftMenu.users": "Users";
1126
1126
  readonly "leftMenu.collections": "Collections";
1127
1127
  readonly "leftMenu.statistics": "Statistics";
@@ -1131,6 +1131,7 @@ declare const qetaTranslationRef: _backstage_frontend_plugin_api.TranslationRef<
1131
1131
  readonly "leftMenu.moderate": "Moderate";
1132
1132
  readonly "leftMenu.review": "Review";
1133
1133
  readonly "leftMenu.settings": "Settings";
1134
+ readonly "leftMenu.content": "Content";
1134
1135
  readonly "leftMenu.manage": "Manage";
1135
1136
  readonly "leftMenu.buttonLabel": "Menu";
1136
1137
  readonly "leftMenu.home": "Home";
@@ -1139,8 +1140,8 @@ declare const qetaTranslationRef: _backstage_frontend_plugin_api.TranslationRef<
1139
1140
  readonly "leftMenu.community": "Community";
1140
1141
  readonly "leftMenu.expand": "Expand menu";
1141
1142
  readonly "leftMenu.collapse": "Collapse menu";
1142
- readonly "moderatorPage.title": "Moderate";
1143
1143
  readonly "moderatorPage.templates": "Templates";
1144
+ readonly "moderatorPage.title": "Moderate";
1144
1145
  readonly "moderatorPage.tools": "Tools";
1145
1146
  readonly "moderatorPage.templatesInfo": "Templates can be used to prefill question content for the user";
1146
1147
  readonly "moderatorPage.deletedPosts": "Deleted posts";
@@ -1157,8 +1158,8 @@ declare const qetaTranslationRef: _backstage_frontend_plugin_api.TranslationRef<
1157
1158
  readonly "settingsPage.aiAnswerExpanded.label": "Expand AI Answers by Default";
1158
1159
  readonly "settingsPage.usePagination.description": "Use traditional pagination instead of infinite scrolling to load more items";
1159
1160
  readonly "settingsPage.usePagination.label": "Use Pagination";
1160
- readonly "settingsPage.viewTypePreferences.title": "View Type Preferences";
1161
1161
  readonly "settingsPage.viewTypePreferences.default": "Default";
1162
+ readonly "settingsPage.viewTypePreferences.title": "View Type Preferences";
1162
1163
  readonly "settingsPage.viewTypePreferences.description": "Choose how you want to view different types of content. Select \"Default\" to use the system default view.";
1163
1164
  readonly "settingsPage.viewTypePreferences.labels.tags": "Tags";
1164
1165
  readonly "settingsPage.viewTypePreferences.labels.entities": "Entities";
@@ -1230,15 +1231,15 @@ declare const qetaTranslationRef: _backstage_frontend_plugin_api.TranslationRef<
1230
1231
  readonly "communityActivity.period.1y": "Last year";
1231
1232
  readonly "homePage.tags": "Tags";
1232
1233
  readonly "homePage.entities": "Entities";
1233
- readonly "homePage.title": "Home";
1234
1234
  readonly "homePage.users": "Users";
1235
1235
  readonly "homePage.collections": "Collections";
1236
+ readonly "homePage.title": "Home";
1236
1237
  readonly "homePage.followedItems": "Following";
1237
1238
  readonly "homePage.noFollowedItems": "You are not following anything yet";
1238
1239
  readonly "impactCard.reputation": "Reputation";
1239
- readonly "impactCard.title": "Your impact";
1240
1240
  readonly "impactCard.error": "Failed to load impact data";
1241
1241
  readonly "impactCard.answers": "Answers";
1242
+ readonly "impactCard.title": "Your impact";
1242
1243
  readonly "impactCard.links": "Links";
1243
1244
  readonly "impactCard.questions": "Questions";
1244
1245
  readonly "impactCard.articles": "Articles";
@@ -1250,8 +1251,8 @@ declare const qetaTranslationRef: _backstage_frontend_plugin_api.TranslationRef<
1250
1251
  readonly "impactCard.answerScore": "Answer Score";
1251
1252
  readonly "impactCard.postScore": "Post Score";
1252
1253
  readonly "impactCard.correctAnswers": "Correct Answers";
1253
- readonly "userBadges.title": "Badges";
1254
1254
  readonly "userBadges.error": "Failed to load badges";
1255
+ readonly "userBadges.title": "Badges";
1255
1256
  readonly "userBadges.noBadges": "No badges earned yet";
1256
1257
  readonly "rightMenu.expand": "Expand sidebar";
1257
1258
  readonly "rightMenu.collapse": "Collapse sidebar";
@@ -1407,9 +1408,9 @@ declare const qetaTranslationRef: _backstage_frontend_plugin_api.TranslationRef<
1407
1408
  readonly "filterPanel.orderBy.updated": "Updated";
1408
1409
  readonly "filterPanel.orderBy.reputation": "Reputation";
1409
1410
  readonly "filterPanel.orderBy.entityRef": "Name";
1410
- readonly "filterPanel.orderBy.title": "Title";
1411
1411
  readonly "filterPanel.orderBy.posts": "Posts";
1412
1412
  readonly "filterPanel.orderBy.answers": "Answers";
1413
+ readonly "filterPanel.orderBy.title": "Title";
1413
1414
  readonly "filterPanel.orderBy.user": "Name";
1414
1415
  readonly "filterPanel.orderBy.links": "Links";
1415
1416
  readonly "filterPanel.orderBy.questions": "Questions";
@@ -1471,8 +1472,8 @@ declare const qetaTranslationRef: _backstage_frontend_plugin_api.TranslationRef<
1471
1472
  readonly "aiAnswerCard.regenerate": "Regenerate this answer";
1472
1473
  readonly "aiAnswerCard.show": "Show";
1473
1474
  readonly "aiAnswerCard.hide": "Hide";
1474
- readonly "usersPage.title": "Users";
1475
1475
  readonly "usersPage.users": "Users";
1476
+ readonly "usersPage.title": "Users";
1476
1477
  readonly "usersPage.search.label": "Search user";
1477
1478
  readonly "usersPage.search.placeholder": "Search...";
1478
1479
  readonly "usersPage.errorLoading": "Could not load users";
@@ -241,6 +241,7 @@ const qetaTranslationRef = createTranslationRef({
241
241
  placeholder: "Type or select tags",
242
242
  helperText: "Add up to {{max}} tags",
243
243
  allowAddHelperText: "You can create new tags by typing the tag and pressing enter",
244
+ createOption: "Add {{tag}}",
244
245
  minimumError: "Please add at least {{min}} tags",
245
246
  suggestedTags: "Suggested tags"
246
247
  },