@stackoverflow/backstage-plugin-stack-overflow-teams 1.6.2 → 1.6.3
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/api/StackOverflowAPI.esm.js +125 -0
- package/dist/api/StackOverflowAPI.esm.js.map +1 -0
- package/dist/components/StackOverflow/StackOverflowMe.esm.js +125 -0
- package/dist/components/StackOverflow/StackOverflowMe.esm.js.map +1 -0
- package/dist/components/StackOverflow/StackOverflowPostQuestionModal.esm.js +803 -0
- package/dist/components/StackOverflow/StackOverflowPostQuestionModal.esm.js.map +1 -0
- package/dist/components/StackOverflow/StackOverflowPosts.esm.js +444 -0
- package/dist/components/StackOverflow/StackOverflowPosts.esm.js.map +1 -0
- package/dist/components/StackOverflow/StackOverflowSearchResultListItem.esm.js +175 -0
- package/dist/components/StackOverflow/StackOverflowSearchResultListItem.esm.js.map +1 -0
- package/dist/components/StackOverflow/StackOverflowTags.esm.js +127 -0
- package/dist/components/StackOverflow/StackOverflowTags.esm.js.map +1 -0
- package/dist/components/StackOverflow/StackOverflowUsers.esm.js +226 -0
- package/dist/components/StackOverflow/StackOverflowUsers.esm.js.map +1 -0
- package/dist/components/StackOverflow/TiptapEditor.esm.js +312 -0
- package/dist/components/StackOverflow/TiptapEditor.esm.js.map +1 -0
- package/dist/components/StackOverflow/hooks/useStackOverflowData.esm.js +128 -0
- package/dist/components/StackOverflow/hooks/useStackOverflowData.esm.js.map +1 -0
- package/dist/components/StackOverflow/hooks/useStackOverflowSearch.esm.js +53 -0
- package/dist/components/StackOverflow/hooks/useStackOverflowSearch.esm.js.map +1 -0
- package/dist/components/StackOverflow/hooks/useStackOverflowStyles.esm.js +39 -0
- package/dist/components/StackOverflow/hooks/useStackOverflowStyles.esm.js.map +1 -0
- package/dist/components/StackOverflowAuth/StackAuthCallback.esm.js +48 -0
- package/dist/components/StackOverflowAuth/StackAuthCallback.esm.js.map +1 -0
- package/dist/components/StackOverflowAuth/StackAuthFailed.esm.js +38 -0
- package/dist/components/StackOverflowAuth/StackAuthFailed.esm.js.map +1 -0
- package/dist/components/StackOverflowAuth/StackAuthLoading.esm.js +22 -0
- package/dist/components/StackOverflowAuth/StackAuthLoading.esm.js.map +1 -0
- package/dist/components/StackOverflowAuth/StackAuthStart.esm.js +238 -0
- package/dist/components/StackOverflowAuth/StackAuthStart.esm.js.map +1 -0
- package/dist/components/StackOverflowAuth/StackAuthSuccess.esm.js +40 -0
- package/dist/components/StackOverflowAuth/StackAuthSuccess.esm.js.map +1 -0
- package/dist/icons/LogoutIcon.esm.js +24 -0
- package/dist/icons/LogoutIcon.esm.js.map +1 -0
- package/dist/icons/StackOverflowIcon.esm.js +27 -0
- package/dist/icons/StackOverflowIcon.esm.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.esm.js +19 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/package.json.esm.js +6 -0
- package/dist/package.json.esm.js.map +1 -0
- package/dist/pages/StackOverflowHub.esm.js +138 -0
- package/dist/pages/StackOverflowHub.esm.js.map +1 -0
- package/dist/pages/StackOverflowTeamsPage.esm.js +43 -0
- package/dist/pages/StackOverflowTeamsPage.esm.js.map +1 -0
- package/dist/pages/index.esm.js +3 -0
- package/dist/pages/index.esm.js.map +1 -0
- package/dist/plugin.esm.js +27 -0
- package/dist/plugin.esm.js.map +1 -0
- package/dist/routes.esm.js +8 -0
- package/dist/routes.esm.js.map +1 -0
- package/dist/utils/decodeHtml.esm.js +8 -0
- package/dist/utils/decodeHtml.esm.js.map +1 -0
- package/dist/utils/getTimeAgo.esm.js +30 -0
- package/dist/utils/getTimeAgo.esm.js.map +1 -0
- package/package.json +12 -4
- package/src/index.ts +0 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StackOverflowPosts.esm.js","sources":["../../../src/components/StackOverflow/StackOverflowPosts.tsx"],"sourcesContent":["import { useEffect, useState, useCallback, useMemo, useRef } from 'react';\nimport {\n makeStyles,\n Theme,\n Grid,\n Paper,\n Typography,\n Button,\n ButtonGroup,\n TextField,\n InputAdornment,\n Box,\n} from '@material-ui/core';\nimport Skeleton from '@mui/material/Skeleton';\nimport { ResponseErrorPanel } from '@backstage/core-components';\nimport { useStackOverflowSearch } from './hooks';\nimport { useStackOverflowData } from './hooks';\nimport { StackOverflowSearchResultListItem } from './StackOverflowSearchResultListItem';\nimport SearchIcon from '@material-ui/icons/Search';\nimport { StackOverflowIcon } from '../../icons';\n\nconst useStyles = makeStyles((theme: Theme) => ({\n filters: {\n padding: theme.spacing(2),\n marginTop: theme.spacing(2),\n },\n buttonGroup: {\n flexWrap: 'wrap',\n },\n resultCount: {\n marginTop: theme.spacing(1),\n fontSize: '0.875rem',\n color: theme.palette.text.secondary,\n },\n searchField: {\n borderRadius: 40,\n paddingLeft: 16,\n paddingRight: 16,\n },\n pagination: {\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n marginTop: theme.spacing(2),\n marginBottom: theme.spacing(2),\n },\n loadingContainer: {\n minHeight: '600px', // Fixed height for consistency\n },\n loadingSkeletonItem: {\n padding: theme.spacing(2),\n marginBottom: theme.spacing(2),\n borderRadius: theme.shape.borderRadius,\n },\n skeletonContent: {\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(1),\n },\n skeletonHeader: {\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(1),\n marginBottom: theme.spacing(1),\n },\n skeletonTags: {\n display: 'flex',\n gap: theme.spacing(1),\n marginTop: theme.spacing(1),\n },\n}));\n\ntype FilterType = {\n id: string;\n label: string;\n};\n\nconst FILTERS: FilterType[] = [\n { id: 'unanswered', label: 'Unanswered' },\n { id: 'newest', label: 'Newest' },\n { id: 'active', label: 'Active' },\n { id: 'score', label: 'Score' },\n];\n\nconst CLIENT_ITEMS_PER_PAGE = 5;\nconst SERVER_ITEMS_PER_PAGE = 30;\nconst SEARCH_ITEMS_PER_PAGE = 30;\n\n// Custom debounce hook\nconst useDebounce = (value: string, delay: number) => {\n const [debouncedValue, setDebouncedValue] = useState(value);\n\n useEffect(() => {\n const handler = setTimeout(() => {\n setDebouncedValue(value);\n }, delay);\n\n return () => {\n clearTimeout(handler);\n };\n }, [value, delay]);\n\n return debouncedValue;\n};\n\n// Loading skeleton component for consistent UI height\n \nconst LoadingSkeleton = () => {\n const classes = useStyles();\n \n // Generate stable, unique keys for skeleton items\n const skeletonKeys = useMemo(() => \n Array.from({ length: CLIENT_ITEMS_PER_PAGE }, (_, index) => \n `skeleton-${index}-${Math.random().toString(36).substr(2, 9)}`\n ), []\n );\n \n return (\n <div className={classes.loadingContainer}>\n {skeletonKeys.map(key => (\n <Paper key={key} className={classes.loadingSkeletonItem} elevation={1}>\n <div className={classes.skeletonContent}>\n <div className={classes.skeletonHeader}>\n <Skeleton variant=\"circular\" width={32} height={32} />\n <div style={{ flex: 1 }}>\n <Skeleton variant=\"text\" width=\"60%\" height={20} />\n <Skeleton variant=\"text\" width=\"40%\" height={16} />\n </div>\n <Skeleton variant=\"rectangular\" width={60} height={24} />\n </div>\n \n <Skeleton variant=\"text\" width=\"90%\" height={24} />\n <Skeleton variant=\"text\" width=\"75%\" height={20} />\n <Skeleton variant=\"text\" width=\"60%\" height={20} />\n \n <div className={classes.skeletonTags}>\n <Skeleton variant=\"rectangular\" width={60} height={20} />\n <Skeleton variant=\"rectangular\" width={80} height={20} />\n <Skeleton variant=\"rectangular\" width={45} height={20} />\n </div>\n \n <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginTop: 8 }}>\n <Skeleton variant=\"text\" width={120} height={16} />\n <Skeleton variant=\"text\" width={80} height={16} />\n </div>\n </div>\n </Paper>\n ))}\n </div>\n );\n};\n\n// Universal pagination utility functions\nconst calculateServerPage = (clientPage: number, serverPageSize: number = SERVER_ITEMS_PER_PAGE): number => {\n return Math.ceil((clientPage * CLIENT_ITEMS_PER_PAGE) / serverPageSize);\n};\n\nconst calculateItemsRange = (clientPage: number, serverPage: number, serverPageSize: number = SERVER_ITEMS_PER_PAGE) => {\n const globalStartIndex = (clientPage - 1) * CLIENT_ITEMS_PER_PAGE;\n const serverStartIndex = (serverPage - 1) * serverPageSize;\n const localStartIndex = globalStartIndex - serverStartIndex;\n const localEndIndex = localStartIndex + CLIENT_ITEMS_PER_PAGE;\n \n return { localStartIndex, localEndIndex };\n};\n\n// Enhanced search data management\nconst useEnhancedSearch = () => {\n const searchHook = useStackOverflowSearch();\n const [searchCache, setSearchCache] = useState<{[key: string]: any}>({});\n const lastSearchRef = useRef<{term: string, page: number} | null>(null);\n\n // Get the actual page size from the search response, fallback to our constant\n const getActualSearchPageSize = useCallback(() => {\n return searchHook.searchData?.pageSize || SEARCH_ITEMS_PER_PAGE;\n }, [searchHook.searchData?.pageSize]);\n\n const enhancedSearch = useCallback((term: string, clientPage: number) => {\n const actualPageSize = getActualSearchPageSize();\n const serverPage = calculateServerPage(clientPage, actualPageSize);\n const cacheKey = `${term}-${serverPage}`;\n \n // Prevent duplicate requests\n const currentSearch = { term, page: serverPage };\n if (lastSearchRef.current && \n lastSearchRef.current.term === currentSearch.term && \n lastSearchRef.current.page === currentSearch.page) {\n return;\n }\n \n if (searchCache[cacheKey]) {\n return;\n }\n \n // Store the search reference to prevent duplicates\n lastSearchRef.current = currentSearch;\n \n // Perform the search for the required server page\n searchHook.search(term, serverPage);\n }, [getActualSearchPageSize, searchCache, searchHook]);\n\n // Cache search results when they arrive\n useEffect(() => {\n if (searchHook.searchData && lastSearchRef.current) {\n const serverPage = searchHook.searchData.page;\n const searchTerm = lastSearchRef.current.term;\n const cacheKey = `${searchTerm}-${serverPage}`;\n \n setSearchCache(prev => ({\n ...prev,\n [cacheKey]: {\n items: searchHook?.searchData?.items,\n totalCount: searchHook?.searchData?.totalCount,\n pageSize: searchHook?.searchData?.pageSize,\n timestamp: Date.now()\n }\n }));\n }\n }, [searchHook.searchData]);\n\n const getSearchDisplayData = useCallback((term: string, clientPage: number) => {\n const actualPageSize = getActualSearchPageSize();\n const serverPage = calculateServerPage(clientPage, actualPageSize);\n const cacheKey = `${term}-${serverPage}`;\n const cachedData = searchCache[cacheKey];\n \n if (!cachedData) {\n return {\n currentPageData: [],\n totalCount: 0,\n loading: searchHook.loading,\n error: searchHook.error\n };\n }\n \n const { localStartIndex, localEndIndex } = calculateItemsRange(\n clientPage, \n serverPage, \n cachedData.pageSize\n );\n \n const currentPageData = cachedData.items.slice(localStartIndex, localEndIndex);\n \n return {\n currentPageData,\n totalCount: cachedData.totalCount,\n loading: false,\n error: null\n };\n }, [searchCache, searchHook.loading, searchHook.error, getActualSearchPageSize]);\n\n const clearSearchCache = useCallback(() => {\n setSearchCache({});\n lastSearchRef.current = null;\n }, []);\n\n return {\n enhancedSearch,\n getSearchDisplayData,\n clearSearch: searchHook.clearSearch,\n clearSearchCache,\n loading: searchHook.loading,\n error: searchHook.error\n };\n};\n\nexport const StackOverflowQuestions = () => {\n const classes = useStyles();\n \n const { \n data: questionsData, \n loading: questionsLoading, \n error: questionsError,\n fetchActiveQuestions,\n fetchNewestQuestions,\n fetchTopScoredQuestions,\n fetchUnansweredQuestions\n } = useStackOverflowData('questions');\n \n const { \n enhancedSearch,\n getSearchDisplayData,\n clearSearch,\n clearSearchCache,\n } = useEnhancedSearch();\n \n const [searchTerm, setSearchTerm] = useState('');\n const [activeFilter, setActiveFilter] = useState<string>('active');\n const [currentPage, setCurrentPage] = useState(1);\n const [questionsPage, setQuestionsPage] = useState(1);\n const prevSearchModeRef = useRef(false);\n\n // Store stable references to search functions\n const enhancedSearchRef = useRef(enhancedSearch);\n const clearSearchRef = useRef(clearSearch);\n const clearSearchCacheRef = useRef(clearSearchCache);\n\n // Update refs when functions change\n useEffect(() => {\n enhancedSearchRef.current = enhancedSearch;\n clearSearchRef.current = clearSearch;\n clearSearchCacheRef.current = clearSearchCache;\n });\n\n const debouncedSearchTerm = useDebounce(searchTerm, 500);\n\n const isSearchMode = !!searchTerm.trim();\n\n // Calculate required server page for current client page (only for questions)\n const requiredServerPage = useMemo(() => {\n return calculateServerPage(questionsPage, SERVER_ITEMS_PER_PAGE);\n }, [questionsPage]);\n\n // Load questions when filter or required server page changes (only in non-search mode)\n useEffect(() => {\n if (!isSearchMode) {\n switch (activeFilter) {\n case 'active':\n fetchActiveQuestions(requiredServerPage);\n break;\n case 'newest':\n fetchNewestQuestions(requiredServerPage);\n break;\n case 'score':\n fetchTopScoredQuestions(requiredServerPage);\n break;\n case 'unanswered':\n fetchUnansweredQuestions(requiredServerPage);\n break;\n default:\n fetchActiveQuestions(requiredServerPage);\n break;\n }\n }\n }, [activeFilter, requiredServerPage, isSearchMode, fetchActiveQuestions, fetchNewestQuestions, fetchTopScoredQuestions, fetchUnansweredQuestions]);\n\n // Handle search mode transitions\n useEffect(() => {\n const wasInSearchMode = prevSearchModeRef.current;\n \n if (isSearchMode && !wasInSearchMode) {\n // Entering search mode - reset search page to 1\n setCurrentPage(1);\n } else if (!isSearchMode && wasInSearchMode) {\n // Exiting search mode - reset questions page to 1 and current page to 1\n setQuestionsPage(1);\n setCurrentPage(1);\n }\n \n prevSearchModeRef.current = isSearchMode;\n }, [isSearchMode]);\n\n // Reset pagination when filter changes (only in non-search mode)\n useEffect(() => {\n if (!isSearchMode) {\n setQuestionsPage(1);\n setCurrentPage(1);\n }\n }, [activeFilter, isSearchMode]);\n\n // Handle search when debounced term changes\n useEffect(() => {\n if (debouncedSearchTerm.trim()) {\n // Only search if we're in search mode and current page is set\n if (isSearchMode) {\n enhancedSearchRef.current(debouncedSearchTerm, currentPage);\n }\n } else {\n clearSearchRef.current();\n clearSearchCacheRef.current();\n }\n }, [debouncedSearchTerm, currentPage, isSearchMode]);\n\n // Handle Enter key press for immediate search\n const handleKeyPress = (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' && searchTerm.trim()) {\n enhancedSearchRef.current(searchTerm, currentPage);\n }\n };\n\n // Calculate display data and pagination info\n const displayInfo = useMemo(() => {\n if (isSearchMode) {\n const searchDisplayData = getSearchDisplayData(searchTerm, currentPage);\n const totalPages = Math.ceil(searchDisplayData.totalCount / CLIENT_ITEMS_PER_PAGE);\n \n return {\n currentPageData: searchDisplayData.currentPageData,\n totalPages,\n totalCount: searchDisplayData.totalCount,\n loading: searchDisplayData.loading,\n error: searchDisplayData.error\n };\n }\n\n // For regular questions, slice the server data\n if (!questionsData?.questions) {\n return {\n currentPageData: [],\n totalPages: 1,\n totalCount: 0,\n loading: questionsLoading,\n error: questionsError\n };\n }\n\n const { localStartIndex, localEndIndex } = calculateItemsRange(\n questionsPage, \n requiredServerPage, \n SERVER_ITEMS_PER_PAGE\n );\n const currentPageData = questionsData.questions.slice(localStartIndex, localEndIndex);\n \n // Calculate total pages based on total items from server\n const totalServerItems = questionsData.totalCount || 0;\n const totalPages = Math.ceil(totalServerItems / CLIENT_ITEMS_PER_PAGE);\n\n return {\n currentPageData,\n totalPages,\n totalCount: totalServerItems,\n loading: questionsLoading,\n error: questionsError\n };\n }, [\n isSearchMode, \n getSearchDisplayData,\n searchTerm,\n currentPage,\n questionsPage,\n questionsData?.questions,\n questionsData?.totalCount,\n requiredServerPage,\n questionsLoading,\n questionsError\n ]);\n\n // Unified pagination handler\n const handlePageChange = (newPage: number) => {\n if (isSearchMode) {\n setCurrentPage(newPage);\n if (searchTerm.trim()) {\n enhancedSearchRef.current(searchTerm, newPage);\n }\n } else {\n setQuestionsPage(newPage);\n setCurrentPage(newPage);\n }\n };\n\n const toggleFilter = (filterId: string) => {\n setActiveFilter(filterId);\n };\n\n // Get the correct page number to display\n const displayPageNumber = isSearchMode ? currentPage : questionsPage;\n\n // Pagination component to reuse\n const PaginationControls = () => {\n // Only show pagination if we have data or are in a valid state\n if (displayInfo.totalPages <= 1 && displayInfo.totalCount === 0 && !displayInfo.loading) {\n return null;\n }\n\n return (\n <div className={classes.pagination}>\n <Button\n disabled={displayPageNumber <= 1}\n onClick={() => handlePageChange(displayPageNumber - 1)}\n variant=\"outlined\"\n >\n Previous\n </Button>\n <Typography variant=\"body1\" style={{ margin: '0 16px' }}>\n Page {displayPageNumber} of {displayInfo.totalPages || 1}\n </Typography>\n <Button\n disabled={displayPageNumber >= (displayInfo.totalPages || 1)}\n onClick={() => handlePageChange(displayPageNumber + 1)}\n variant=\"outlined\"\n >\n Next\n </Button>\n </div>\n );\n };\n\n // Show error state\n if (displayInfo.error) return <ResponseErrorPanel error={displayInfo.error} />;\n\n return (\n <div>\n <Box mb={3}>\n <TextField\n fullWidth\n variant=\"outlined\"\n placeholder=\"Search questions...\"\n value={searchTerm}\n onChange={e => setSearchTerm(e.target.value)}\n onKeyDown={handleKeyPress}\n InputProps={{\n startAdornment: (\n <InputAdornment position=\"start\">\n <SearchIcon />\n </InputAdornment>\n ),\n className: classes.searchField,\n }}\n />\n </Box>\n\n <PaginationControls />\n\n {/* Only show filters when not in search mode */}\n {!isSearchMode && (\n <Paper className={classes.filters}>\n <ButtonGroup className={classes.buttonGroup}>\n {FILTERS.map(({ id, label }) => (\n <Button\n key={id}\n variant={activeFilter === id ? 'contained' : 'outlined'}\n color=\"primary\"\n onClick={() => toggleFilter(id)}\n >\n {label}\n </Button>\n ))}\n </ButtonGroup>\n </Paper>\n )}\n\n <Typography className={classes.resultCount}>\n {isSearchMode \n ? `Search results: ${displayInfo.totalCount} total found` \n : `Showing ${displayInfo.currentPageData.length} of ${displayInfo.totalCount} results`}\n </Typography>\n\n {displayInfo.loading && <LoadingSkeleton />}\n\n {!displayInfo.loading && (\n <>\n {/* No results */}\n {displayInfo.currentPageData && displayInfo.totalCount === 0 && (\n <Box textAlign=\"center\" py={4}>\n <Typography variant=\"body1\" gutterBottom>\n {searchTerm.trim()\n ? `No questions found matching \"${searchTerm}\"`\n : \"No questions found\"\n }\n </Typography>\n </Box>\n )}\n\n {/* Results */}\n {displayInfo.currentPageData.length > 0 && (\n <>\n <Grid container spacing={2}>\n {displayInfo.currentPageData.map((question: any) => (\n <Grid item xs={12} key={question.id}>\n <StackOverflowSearchResultListItem\n result={{\n location: question.webUrl,\n title: question.title,\n text: question.owner?.name,\n answers: question.answerCount,\n tags: question.tags,\n created: question.creationDate,\n author: question.owner?.name,\n score: question.score,\n isAnswered: question.isAnswered,\n creationDate: question.creationDate,\n userRole: question.owner?.role,\n userProfile: question.owner?.webUrl,\n avatar: question.owner?.avatarUrl,\n userReputation: question.owner?.reputation,\n }}\n icon={<StackOverflowIcon />}\n />\n </Grid>\n ))}\n </Grid>\n </>\n )}\n </>\n )}\n\n <PaginationControls />\n </div>\n );\n};"],"names":["totalPages"],"mappings":"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"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { Link } from '@backstage/core-components';
|
|
3
|
+
import Divider from '@material-ui/core/Divider';
|
|
4
|
+
import ListItem from '@material-ui/core/ListItem';
|
|
5
|
+
import ListItemText from '@material-ui/core/ListItemText';
|
|
6
|
+
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
|
7
|
+
import Box from '@material-ui/core/Box';
|
|
8
|
+
import Chip from '@material-ui/core/Chip';
|
|
9
|
+
import { useAnalytics } from '@backstage/core-plugin-api';
|
|
10
|
+
import { HighlightedSearchResultText } from '@backstage/plugin-search-react';
|
|
11
|
+
import { decodeHtml } from '../../utils/decodeHtml.esm.js';
|
|
12
|
+
import { getTimeAgo } from '../../utils/getTimeAgo.esm.js';
|
|
13
|
+
import { Typography, Avatar } from '@material-ui/core';
|
|
14
|
+
|
|
15
|
+
const StackOverflowSearchResultListItem = (props) => {
|
|
16
|
+
const { result, highlight } = props;
|
|
17
|
+
const analytics = useAnalytics();
|
|
18
|
+
const handleClick = () => {
|
|
19
|
+
analytics.captureEvent("discover", result.title, {
|
|
20
|
+
attributes: { to: result.location },
|
|
21
|
+
value: props.rank
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
if (!result) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
const timeAgo = getTimeAgo(result.creationDate);
|
|
28
|
+
const userRole = result.userRole;
|
|
29
|
+
const isModerator = userRole === "Moderator";
|
|
30
|
+
const isAdmin = userRole === "Admin";
|
|
31
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
32
|
+
/* @__PURE__ */ jsxs(ListItem, { alignItems: "center", children: [
|
|
33
|
+
props.icon && /* @__PURE__ */ jsx(ListItemIcon, { children: props.icon }),
|
|
34
|
+
/* @__PURE__ */ jsxs(
|
|
35
|
+
Box,
|
|
36
|
+
{
|
|
37
|
+
display: "flex",
|
|
38
|
+
flexDirection: "column",
|
|
39
|
+
alignItems: "center",
|
|
40
|
+
mr: 2,
|
|
41
|
+
minWidth: "80px",
|
|
42
|
+
children: [
|
|
43
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "subtitle2", color: "textSecondary", children: [
|
|
44
|
+
result.score,
|
|
45
|
+
" votes"
|
|
46
|
+
] }),
|
|
47
|
+
/* @__PURE__ */ jsxs(
|
|
48
|
+
Typography,
|
|
49
|
+
{
|
|
50
|
+
variant: "subtitle2",
|
|
51
|
+
color: result.answers > 0 ? "primary" : "textSecondary",
|
|
52
|
+
style: {
|
|
53
|
+
fontWeight: result.isAnswered ? "bold" : "normal"
|
|
54
|
+
},
|
|
55
|
+
children: [
|
|
56
|
+
result.answers,
|
|
57
|
+
" answers"
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
),
|
|
61
|
+
result.isAnswered && /* @__PURE__ */ jsx(
|
|
62
|
+
Typography,
|
|
63
|
+
{
|
|
64
|
+
variant: "subtitle2",
|
|
65
|
+
color: "primary",
|
|
66
|
+
style: { fontWeight: "bold" },
|
|
67
|
+
children: "\u2714 Accepted"
|
|
68
|
+
}
|
|
69
|
+
)
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
),
|
|
73
|
+
/* @__PURE__ */ jsxs(Box, { flexWrap: "wrap", flexGrow: 1, children: [
|
|
74
|
+
/* @__PURE__ */ jsx(
|
|
75
|
+
ListItemText,
|
|
76
|
+
{
|
|
77
|
+
primaryTypographyProps: { variant: "h6" },
|
|
78
|
+
primary: (
|
|
79
|
+
// Currently, the backend send the referrer to fill out the questions index, however, this component is shared for both the questions that come from the index and also the question that are actively with a live API request, my solution for now is to add the referrer when it doesn't exist already until this is changed in the future.
|
|
80
|
+
/* @__PURE__ */ jsx(
|
|
81
|
+
Link,
|
|
82
|
+
{
|
|
83
|
+
to: result.location.includes("?r=") ? result.location : `${result.location}?r=Backstage_Plugin`,
|
|
84
|
+
noTrack: true,
|
|
85
|
+
onClick: handleClick,
|
|
86
|
+
children: highlight?.fields?.title ? /* @__PURE__ */ jsx(
|
|
87
|
+
HighlightedSearchResultText,
|
|
88
|
+
{
|
|
89
|
+
text: decodeHtml(highlight.fields.title),
|
|
90
|
+
preTag: highlight.preTag,
|
|
91
|
+
postTag: highlight.postTag
|
|
92
|
+
}
|
|
93
|
+
) : decodeHtml(result.title)
|
|
94
|
+
}
|
|
95
|
+
)
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
),
|
|
99
|
+
/* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "center", mt: 1, children: [
|
|
100
|
+
result.avatar && /* @__PURE__ */ jsx(Link, { to: result.userProfile, noTrack: true, children: /* @__PURE__ */ jsx(
|
|
101
|
+
Avatar,
|
|
102
|
+
{
|
|
103
|
+
src: result.avatar,
|
|
104
|
+
alt: result.text,
|
|
105
|
+
style: { width: 20, height: 20, marginRight: 8 }
|
|
106
|
+
}
|
|
107
|
+
) }),
|
|
108
|
+
/* @__PURE__ */ jsx(Link, { to: result.userProfile, noTrack: true, children: /* @__PURE__ */ jsx(
|
|
109
|
+
Typography,
|
|
110
|
+
{
|
|
111
|
+
variant: "body2",
|
|
112
|
+
color: "textPrimary",
|
|
113
|
+
component: "span",
|
|
114
|
+
children: decodeHtml(result.text)
|
|
115
|
+
}
|
|
116
|
+
) }, result.text),
|
|
117
|
+
result.userReputation && /* @__PURE__ */ jsxs(
|
|
118
|
+
Typography,
|
|
119
|
+
{
|
|
120
|
+
variant: "body2",
|
|
121
|
+
color: "textSecondary",
|
|
122
|
+
component: "span",
|
|
123
|
+
style: { marginLeft: 4 },
|
|
124
|
+
children: [
|
|
125
|
+
"(",
|
|
126
|
+
result.userReputation,
|
|
127
|
+
")"
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
),
|
|
131
|
+
(isModerator || isAdmin) && /* @__PURE__ */ jsx(
|
|
132
|
+
Chip,
|
|
133
|
+
{
|
|
134
|
+
label: isModerator ? "Moderator" : "Admin",
|
|
135
|
+
size: "small",
|
|
136
|
+
style: {
|
|
137
|
+
marginTop: 6,
|
|
138
|
+
marginLeft: 8,
|
|
139
|
+
backgroundColor: isModerator ? "lightblue" : "lightcoral",
|
|
140
|
+
color: isModerator ? "black" : "#fff",
|
|
141
|
+
fontWeight: "bold"
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
),
|
|
145
|
+
/* @__PURE__ */ jsxs(
|
|
146
|
+
Typography,
|
|
147
|
+
{
|
|
148
|
+
variant: "body2",
|
|
149
|
+
color: "textSecondary",
|
|
150
|
+
component: "span",
|
|
151
|
+
style: { marginLeft: 4 },
|
|
152
|
+
children: [
|
|
153
|
+
"asked ",
|
|
154
|
+
timeAgo
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
)
|
|
158
|
+
] }),
|
|
159
|
+
result.tags && /* @__PURE__ */ jsx(Box, { display: "flex", flexWrap: "wrap", mt: 1, children: result.tags.map((tag) => /* @__PURE__ */ jsx(Link, { to: tag.location, noTrack: true, children: /* @__PURE__ */ jsx(
|
|
160
|
+
Chip,
|
|
161
|
+
{
|
|
162
|
+
label: tag.name,
|
|
163
|
+
size: "small",
|
|
164
|
+
clickable: true,
|
|
165
|
+
style: { marginRight: 4, marginBottom: 4 }
|
|
166
|
+
}
|
|
167
|
+
) }, tag.name)) })
|
|
168
|
+
] })
|
|
169
|
+
] }),
|
|
170
|
+
/* @__PURE__ */ jsx(Divider, {})
|
|
171
|
+
] });
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
export { StackOverflowSearchResultListItem };
|
|
175
|
+
//# sourceMappingURL=StackOverflowSearchResultListItem.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StackOverflowSearchResultListItem.esm.js","sources":["../../../src/components/StackOverflow/StackOverflowSearchResultListItem.tsx"],"sourcesContent":["/* \n * This specific component is a modified version of https://github.com/backstage/community-plugins/blob/main/workspaces/stack-overflow/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.tsx\n *\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Link } from '@backstage/core-components';\nimport Divider from '@material-ui/core/Divider';\nimport ListItem from '@material-ui/core/ListItem';\nimport ListItemText from '@material-ui/core/ListItemText';\nimport ListItemIcon from '@material-ui/core/ListItemIcon';\nimport Box from '@material-ui/core/Box';\nimport Chip from '@material-ui/core/Chip';\nimport { useAnalytics } from '@backstage/core-plugin-api';\nimport type { ResultHighlight } from '@backstage/plugin-search-common';\nimport { HighlightedSearchResultText } from '@backstage/plugin-search-react';\nimport { decodeHtml, getTimeAgo } from '../../utils';\nimport { Avatar, Typography } from '@material-ui/core';\n/**\n * Props for {@link StackOverflowSearchResultListItem}\n *\n * @public\n */\nexport type StackOverflowSearchResultListItemProps = {\n result?: any; // TODO(emmaindal): type to StackOverflowDocument.\n icon?: React.ReactNode;\n rank?: number;\n highlight?: ResultHighlight;\n};\nexport const StackOverflowSearchResultListItem = (\n props: StackOverflowSearchResultListItemProps,\n) => {\n const { result, highlight } = props;\n const analytics = useAnalytics();\n const handleClick = () => {\n analytics.captureEvent('discover', result.title, {\n attributes: { to: result.location },\n value: props.rank,\n });\n };\n if (!result) {\n return null;\n }\n const timeAgo = getTimeAgo(result.creationDate);\n // Recording role of the user\n const userRole = result.userRole;\n const isModerator = userRole === 'Moderator';\n const isAdmin = userRole === 'Admin';\n return (\n <>\n <ListItem alignItems=\"center\">\n {props.icon && <ListItemIcon>{props.icon}</ListItemIcon>}\n <Box\n display=\"flex\"\n flexDirection=\"column\"\n alignItems=\"center\"\n mr={2}\n minWidth=\"80px\"\n >\n <Typography variant=\"subtitle2\" color=\"textSecondary\">\n {result.score} votes\n </Typography>\n <Typography\n variant=\"subtitle2\"\n color={result.answers > 0 ? 'primary' : 'textSecondary'}\n style={{\n fontWeight: result.isAnswered ? 'bold' : 'normal',\n }}\n >\n {result.answers} answers\n </Typography>\n {result.isAnswered && (\n <Typography\n variant=\"subtitle2\"\n color=\"primary\"\n style={{ fontWeight: 'bold' }}\n >\n ✔ Accepted\n </Typography>\n )}\n </Box>\n <Box flexWrap=\"wrap\" flexGrow={1}>\n <ListItemText\n primaryTypographyProps={{ variant: 'h6' }}\n primary={\n // Currently, the backend send the referrer to fill out the questions index, however, this component is shared for both the questions that come from the index and also the question that are actively with a live API request, my solution for now is to add the referrer when it doesn't exist already until this is changed in the future.\n <Link\n to={\n result.location.includes('?r=')\n ? result.location\n : `${result.location}?r=Backstage_Plugin`\n }\n noTrack\n onClick={handleClick}\n >\n {highlight?.fields?.title ? (\n <HighlightedSearchResultText\n text={decodeHtml(highlight.fields.title)}\n preTag={highlight.preTag}\n postTag={highlight.postTag}\n />\n ) : (\n decodeHtml(result.title)\n )}\n </Link>\n }\n />\n \n <Box display=\"flex\" alignItems=\"center\" mt={1}>\n {/* Author Avatar */}\n {result.avatar && (\n <Link to={result.userProfile} noTrack>\n <Avatar\n src={result.avatar}\n alt={result.text}\n style={{ width: 20, height: 20, marginRight: 8 }}\n />\n </Link>\n )}\n {/* Author Name and Reputation */}\n <Link key={result.text} to={result.userProfile} noTrack>\n <Typography\n variant=\"body2\"\n color=\"textPrimary\"\n component=\"span\"\n >\n {decodeHtml(result.text)}\n </Typography>\n </Link>\n {/* User Reputation */}\n {result.userReputation && (\n <Typography\n variant=\"body2\"\n color=\"textSecondary\"\n component=\"span\"\n style={{ marginLeft: 4 }}\n >\n ({result.userReputation})\n </Typography>\n )}\n {(isModerator || isAdmin) && (\n <Chip\n label={isModerator ? 'Moderator' : 'Admin'}\n size=\"small\"\n style={{\n marginTop: 6,\n marginLeft: 8,\n backgroundColor: isModerator ? 'lightblue' : 'lightcoral',\n color: isModerator ? 'black' : '#fff',\n fontWeight: 'bold',\n }}\n />\n )}\n {/* Time Ago */}\n <Typography\n variant=\"body2\"\n color=\"textSecondary\"\n component=\"span\"\n style={{ marginLeft: 4 }}\n >\n asked {timeAgo}\n </Typography>\n </Box>\n\n {/* Tags section */}\n {result.tags && (\n <Box display=\"flex\" flexWrap=\"wrap\" mt={1}>\n {result.tags.map((tag: { name: string; location: string }) => (\n <Link key={tag.name} to={tag.location} noTrack>\n <Chip\n label={tag.name}\n size=\"small\"\n clickable\n style={{ marginRight: 4, marginBottom: 4 }}\n />\n </Link>\n ))}\n </Box>\n )}\n </Box>\n </ListItem>\n <Divider />\n </>\n );\n};"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
3
|
+
import { Progress, ResponseErrorPanel, Link } from '@backstage/core-components';
|
|
4
|
+
import { useStackOverflowData } from './hooks/useStackOverflowData.esm.js';
|
|
5
|
+
import { useApi } from '@backstage/core-plugin-api';
|
|
6
|
+
import { stackoverflowteamsApiRef } from '../../api/StackOverflowAPI.esm.js';
|
|
7
|
+
import './hooks/useStackOverflowStyles.esm.js';
|
|
8
|
+
import { Box, TextField, InputAdornment, Typography, Grid, Chip } from '@material-ui/core';
|
|
9
|
+
import SearchIcon from '@material-ui/icons/Search';
|
|
10
|
+
|
|
11
|
+
const StackOverflowTagList = ({
|
|
12
|
+
tags,
|
|
13
|
+
searchTerm,
|
|
14
|
+
isApiSearch = false,
|
|
15
|
+
isSearching = false
|
|
16
|
+
}) => {
|
|
17
|
+
if (isSearching) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
if (tags.length === 0) {
|
|
21
|
+
return /* @__PURE__ */ jsx(Box, { textAlign: "center", py: 4, children: /* @__PURE__ */ jsx(Typography, { variant: "body1", gutterBottom: true, children: isApiSearch ? `No tags found for "${searchTerm}" on your Stack Overflow Internal Team` : `No matching tags were found for "${searchTerm}"` }) });
|
|
22
|
+
}
|
|
23
|
+
return /* @__PURE__ */ jsx(Grid, { container: true, spacing: 1, children: tags.map((tag) => /* @__PURE__ */ jsx(Link, { to: tag.webUrl, noTrack: true, children: /* @__PURE__ */ jsx(
|
|
24
|
+
Chip,
|
|
25
|
+
{
|
|
26
|
+
label: `${tag.name}(${tag.postCount})`,
|
|
27
|
+
variant: "outlined",
|
|
28
|
+
clickable: true
|
|
29
|
+
}
|
|
30
|
+
) }, tag.name)) });
|
|
31
|
+
};
|
|
32
|
+
const StackOverflowTags = () => {
|
|
33
|
+
const { data, loading, error, fetchData } = useStackOverflowData("tags");
|
|
34
|
+
const [searchTerm, setSearchTerm] = useState("");
|
|
35
|
+
const [apiSearchResults, setApiSearchResults] = useState(null);
|
|
36
|
+
const [apiSearchLoading, setApiSearchLoading] = useState(false);
|
|
37
|
+
const [apiSearchError, setApiSearchError] = useState(null);
|
|
38
|
+
const [hasAttemptedApiSearch, setHasAttemptedApiSearch] = useState(false);
|
|
39
|
+
const stackOverflowTeamsApi = useApi(stackoverflowteamsApiRef);
|
|
40
|
+
const [baseUrl, setBaseUrl] = useState("");
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
stackOverflowTeamsApi.getBaseUrl().then((url) => setBaseUrl(url));
|
|
43
|
+
}, [stackOverflowTeamsApi]);
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
fetchData();
|
|
46
|
+
}, [fetchData]);
|
|
47
|
+
const searchTagsViaApi = useCallback(async (searchQuery) => {
|
|
48
|
+
if (!searchQuery.trim()) {
|
|
49
|
+
setApiSearchResults(null);
|
|
50
|
+
setHasAttemptedApiSearch(false);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
setApiSearchLoading(true);
|
|
54
|
+
setApiSearchError(null);
|
|
55
|
+
setHasAttemptedApiSearch(false);
|
|
56
|
+
try {
|
|
57
|
+
const response = await stackOverflowTeamsApi.getTags(searchQuery);
|
|
58
|
+
setApiSearchResults(response.items || []);
|
|
59
|
+
} catch (err) {
|
|
60
|
+
setApiSearchError(err);
|
|
61
|
+
setApiSearchResults([]);
|
|
62
|
+
} finally {
|
|
63
|
+
setApiSearchLoading(false);
|
|
64
|
+
setHasAttemptedApiSearch(true);
|
|
65
|
+
}
|
|
66
|
+
}, [stackOverflowTeamsApi]);
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
const timer = setTimeout(() => {
|
|
69
|
+
const localFilteredTags2 = (data?.tags || []).filter(
|
|
70
|
+
(tag) => tag.name.toLowerCase().includes(searchTerm.toLowerCase())
|
|
71
|
+
);
|
|
72
|
+
if (localFilteredTags2.length === 0 && searchTerm.trim()) {
|
|
73
|
+
searchTagsViaApi(searchTerm);
|
|
74
|
+
} else {
|
|
75
|
+
setApiSearchResults(null);
|
|
76
|
+
setApiSearchError(null);
|
|
77
|
+
setHasAttemptedApiSearch(false);
|
|
78
|
+
}
|
|
79
|
+
}, 300);
|
|
80
|
+
return () => clearTimeout(timer);
|
|
81
|
+
}, [searchTerm, data?.tags, searchTagsViaApi]);
|
|
82
|
+
const localFilteredTags = (data?.tags || []).filter(
|
|
83
|
+
(tag) => tag.name.toLowerCase().includes(searchTerm.toLowerCase())
|
|
84
|
+
);
|
|
85
|
+
const shouldShowApiResults = localFilteredTags.length === 0 && searchTerm.trim() && hasAttemptedApiSearch && apiSearchResults !== null;
|
|
86
|
+
const tagsToShow = shouldShowApiResults ? apiSearchResults : localFilteredTags;
|
|
87
|
+
const isShowingApiResults = shouldShowApiResults;
|
|
88
|
+
const currentLoading = apiSearchLoading;
|
|
89
|
+
const currentError = apiSearchError;
|
|
90
|
+
const shouldShowResults = !currentLoading && !currentError && // Show local results if we have them
|
|
91
|
+
(localFilteredTags.length > 0 || // Show API results if we have attempted API search and got results
|
|
92
|
+
hasAttemptedApiSearch && apiSearchResults !== null);
|
|
93
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
94
|
+
/* @__PURE__ */ jsx(Box, { mb: 2, children: /* @__PURE__ */ jsx(
|
|
95
|
+
TextField,
|
|
96
|
+
{
|
|
97
|
+
fullWidth: true,
|
|
98
|
+
variant: "outlined",
|
|
99
|
+
placeholder: "Filter tags...",
|
|
100
|
+
value: searchTerm,
|
|
101
|
+
onChange: (e) => setSearchTerm(e.target.value),
|
|
102
|
+
InputProps: {
|
|
103
|
+
startAdornment: /* @__PURE__ */ jsx(InputAdornment, { position: "start", children: /* @__PURE__ */ jsx(SearchIcon, {}) })
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
) }),
|
|
107
|
+
loading && /* @__PURE__ */ jsx(Progress, {}),
|
|
108
|
+
error && /* @__PURE__ */ jsx(ResponseErrorPanel, { error }),
|
|
109
|
+
!loading && !error && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
110
|
+
currentLoading && /* @__PURE__ */ jsx(Progress, {}),
|
|
111
|
+
currentError && /* @__PURE__ */ jsx(ResponseErrorPanel, { error: currentError }),
|
|
112
|
+
shouldShowResults && /* @__PURE__ */ jsx(
|
|
113
|
+
StackOverflowTagList,
|
|
114
|
+
{
|
|
115
|
+
tags: tagsToShow || [],
|
|
116
|
+
searchTerm,
|
|
117
|
+
baseUrl,
|
|
118
|
+
isApiSearch: !!isShowingApiResults,
|
|
119
|
+
isSearching: currentLoading
|
|
120
|
+
}
|
|
121
|
+
)
|
|
122
|
+
] })
|
|
123
|
+
] });
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export { StackOverflowTags, StackOverflowTags as default };
|
|
127
|
+
//# sourceMappingURL=StackOverflowTags.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StackOverflowTags.esm.js","sources":["../../../src/components/StackOverflow/StackOverflowTags.tsx"],"sourcesContent":["import { useEffect, useState, useCallback } from 'react';\nimport { Link, Progress, ResponseErrorPanel } from '@backstage/core-components';\nimport { useStackOverflowData } from './hooks/';\nimport {\n Chip,\n Grid,\n TextField,\n Box,\n Typography,\n InputAdornment,\n} from '@material-ui/core';\nimport { Tag } from '../../types';\nimport SearchIcon from '@material-ui/icons/Search';\nimport { stackoverflowteamsApiRef } from '../../api';\nimport { useApi } from '@backstage/core-plugin-api';\n\nconst StackOverflowTagList = ({\n tags,\n searchTerm,\n isApiSearch = false,\n isSearching = false,\n}: {\n tags: Tag[];\n searchTerm: string;\n baseUrl: string;\n isApiSearch?: boolean;\n isSearching?: boolean;\n}) => {\n if (isSearching) {\n return null; \n }\n\n if (tags.length === 0) {\n return (\n <Box textAlign=\"center\" py={4}>\n <Typography variant=\"body1\" gutterBottom>\n {isApiSearch \n ? `No tags found for \"${searchTerm}\" on your Stack Overflow Internal Team`\n : `No matching tags were found for \"${searchTerm}\"`\n }\n </Typography>\n </Box>\n );\n }\n\n return (\n <Grid container spacing={1}>\n {tags.map(tag => (\n <Link key={tag.name} to={tag.webUrl} noTrack>\n <Chip\n label={`${tag.name}(${tag.postCount})`}\n variant=\"outlined\"\n clickable\n />\n </Link>\n ))}\n </Grid>\n );\n};\n\nexport const StackOverflowTags = () => {\n const { data, loading, error, fetchData } = useStackOverflowData('tags');\n const [searchTerm, setSearchTerm] = useState('');\n const [apiSearchResults, setApiSearchResults] = useState<Tag[] | null>(null);\n const [apiSearchLoading, setApiSearchLoading] = useState(false);\n const [apiSearchError, setApiSearchError] = useState<Error | null>(null);\n const [hasAttemptedApiSearch, setHasAttemptedApiSearch] = useState(false);\n const stackOverflowTeamsApi = useApi(stackoverflowteamsApiRef);\n\n const [baseUrl, setBaseUrl] = useState<string>('');\n \n useEffect(() => {\n stackOverflowTeamsApi.getBaseUrl().then(url => setBaseUrl(url));\n }, [stackOverflowTeamsApi]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n // Debounced API search function\n const searchTagsViaApi = useCallback(async (searchQuery: string) => {\n if (!searchQuery.trim()) {\n setApiSearchResults(null);\n setHasAttemptedApiSearch(false);\n return;\n }\n\n setApiSearchLoading(true);\n setApiSearchError(null);\n setHasAttemptedApiSearch(false);\n \n try {\n const response = await stackOverflowTeamsApi.getTags(searchQuery);\n setApiSearchResults(response.items || []);\n } catch (err) {\n setApiSearchError(err as Error);\n setApiSearchResults([]);\n } finally {\n setApiSearchLoading(false);\n setHasAttemptedApiSearch(true);\n }\n }, [stackOverflowTeamsApi]);\n\n // Debounce the search to avoid too many API calls\n useEffect(() => {\n const timer = setTimeout(() => {\n const localFilteredTags = (data?.tags || []).filter(tag =>\n tag.name.toLowerCase().includes(searchTerm.toLowerCase()),\n );\n\n // If no local results and we have a search term, try API search\n if (localFilteredTags.length === 0 && searchTerm.trim()) {\n searchTagsViaApi(searchTerm);\n } else {\n // Reset API search results when we have local results or no search term\n setApiSearchResults(null);\n setApiSearchError(null);\n setHasAttemptedApiSearch(false);\n }\n }, 300); // 300ms debounce\n\n return () => clearTimeout(timer);\n }, [searchTerm, data?.tags, searchTagsViaApi]);\n\n const localFilteredTags = (data?.tags || []).filter(tag =>\n tag.name.toLowerCase().includes(searchTerm.toLowerCase()),\n );\n\n const shouldShowApiResults = localFilteredTags.length === 0 && searchTerm.trim() && hasAttemptedApiSearch && apiSearchResults !== null;\n const tagsToShow = shouldShowApiResults ? apiSearchResults : localFilteredTags;\n const isShowingApiResults = shouldShowApiResults;\n const currentLoading = apiSearchLoading;\n const currentError = apiSearchError;\n\n const shouldShowResults = !currentLoading && !currentError && (\n // Show local results if we have them\n localFilteredTags.length > 0 ||\n // Show API results if we have attempted API search and got results\n (hasAttemptedApiSearch && apiSearchResults !== null)\n );\n\n return (\n <div>\n <Box mb={2}>\n <TextField\n fullWidth\n variant=\"outlined\"\n placeholder=\"Filter tags...\"\n value={searchTerm}\n onChange={e => setSearchTerm(e.target.value)}\n InputProps={{\n startAdornment: (\n <InputAdornment position=\"start\">\n <SearchIcon />\n </InputAdornment>\n ),\n }}\n />\n </Box>\n\n {/* Show initial loading state */}\n {loading && <Progress />}\n \n {/* Show initial error state */}\n {error && <ResponseErrorPanel error={error} />}\n \n {/* Only show content when initial data is loaded */}\n {!loading && !error && (\n <>\n {/* Show API search loading */}\n {currentLoading && <Progress />}\n \n {/* Show API search error */}\n {currentError && <ResponseErrorPanel error={currentError} />}\n \n {/* Show results when appropriate */}\n {shouldShowResults && (\n <StackOverflowTagList\n tags={tagsToShow || []}\n searchTerm={searchTerm}\n baseUrl={baseUrl}\n isApiSearch={!!isShowingApiResults}\n isSearching={currentLoading}\n />\n )}\n </>\n )}\n </div>\n );\n};\n\nexport default StackOverflowTags;"],"names":["localFilteredTags"],"mappings":"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"}
|