()
| 226 | // ============================================================ |
| 227 | |
| 228 | export function ProjectsPage() { |
| 229 | const { t } = useTranslation(); |
| 230 | const isLoggedIn = useAppStore((s) => s.isLoggedIn()); |
| 231 | |
| 232 | // Search state — managed as SearchParams (query + scopes) |
| 233 | const [searchParams, setSearchParams] = useState<SearchParams>(() => { |
| 234 | const currentRoute = router.currentRoute.value; |
| 235 | // Migrate old URL format |
| 236 | const queryState = currentRoute.query.state as string; |
| 237 | if (queryState === "archived" || queryState === "all") { |
| 238 | const stateValue = queryState === "archived" ? "DELETED" : "ALL"; |
| 239 | return { query: "", scopes: [{ id: "state", value: stateValue }] }; |
| 240 | } |
| 241 | const queryString = currentRoute.query.q as string; |
| 242 | if (queryString) { |
| 243 | const scopes: { id: string; value: string }[] = []; |
| 244 | const queryParts: string[] = []; |
| 245 | for (const token of queryString.split(/\s+/).filter(Boolean)) { |
| 246 | const colonIdx = token.indexOf(":"); |
| 247 | if (colonIdx > 0) { |
| 248 | const id = token.substring(0, colonIdx); |
| 249 | const value = token.substring(colonIdx + 1); |
| 250 | if (value && (id === "state" || id === "label")) { |
| 251 | scopes.push({ id, value }); |
| 252 | continue; |
| 253 | } |
| 254 | } |
| 255 | queryParts.push(token); |
| 256 | } |
| 257 | return { query: queryParts.join(" "), scopes }; |
| 258 | } |
| 259 | return { query: "", scopes: [] }; |
| 260 | }); |
| 261 | |
| 262 | // Scope options for the AdvancedSearch |
| 263 | const canUndelete = hasWorkspacePermissionV2("bb.projects.undelete"); |
| 264 | const scopeOptions: ScopeOption[] = useMemo(() => { |
| 265 | const stateOption: ScopeOption = { |
| 266 | id: "state", |
| 267 | title: t("common.state"), |
| 268 | description: t("issue.advanced-search.scope.state.description"), |
| 269 | options: [ |
| 270 | { value: "ACTIVE", keywords: ["active"] }, |
| 271 | ...(canUndelete |
| 272 | ? [ |
| 273 | { value: "DELETED", keywords: ["archived", "deleted"] }, |
| 274 | { value: "ALL", keywords: ["all"] }, |
| 275 | ] |
| 276 | : []), |
| 277 | ], |
| 278 | }; |
| 279 | const labelOption: ScopeOption = { |
| 280 | id: "label", |
| 281 | title: t("common.labels"), |
| 282 | description: t("issue.advanced-search.scope.label.description"), |
| 283 | allowMultiple: true, |
| 284 | }; |
| 285 | return [labelOption, stateOption]; |
nothing calls this directly
no test coverage detected