@@ -257,12 +257,12 @@ export function AuditLogs({ organizationId }: AuditLogsProps) {
257257 /**
258258 * Resolved, not merely present. Only the id lives in the URL, and the filter is
259259 * applied once it matches a workspace the organization actually owns — a stale id
260- * from an old link would otherwise silently narrow the feed to nothing under a
261- * chip labelled with the bare uuid.
260+ * from an old link would otherwise be shown under a chip labelled with a bare uuid.
262261 */
263- const orgWorkspaces = useOrganizationWorkspaces ( organizationId , Boolean ( urlFilters . workspace ) )
264- const filteredWorkspace = urlFilters . workspace
265- ? orgWorkspaces . data ?. find ( ( entry ) => entry . id === urlFilters . workspace )
262+ const workspaceScope = urlFilters . workspace
263+ const orgWorkspaces = useOrganizationWorkspaces ( organizationId , Boolean ( workspaceScope ) )
264+ const scopedWorkspace = workspaceScope
265+ ? orgWorkspaces . data ?. find ( ( entry ) => entry . id === workspaceScope )
266266 : undefined
267267
268268 const [ datePickerOpen , setDatePickerOpen ] = useState ( false )
@@ -289,7 +289,7 @@ export function AuditLogs({ organizationId }: AuditLogsProps) {
289289 const filters : AuditLogFilters = {
290290 search : debouncedSearch || undefined ,
291291 resourceType : selectedTypes . length > 0 ? selectedTypes . join ( ',' ) : undefined ,
292- workspaceId : filteredWorkspace ?. id ,
292+ workspaceId : scopedWorkspace ?. id ,
293293 startDate : getStartDateFromTimeRange ( timeRange , customStartDate ) ?. toISOString ( ) ,
294294 endDate : getEndDateFromTimeRange ( timeRange , customEndDate ) ?. toISOString ( ) ,
295295 }
@@ -300,7 +300,20 @@ export function AuditLogs({ organizationId }: AuditLogsProps) {
300300 * immediately refetches it narrowed — two requests, with a flash of rows the link
301301 * did not ask for in between.
302302 */
303- const isWorkspaceFilterPending = Boolean ( urlFilters . workspace ) && orgWorkspaces . isPending
303+ const isWorkspaceScopePending = Boolean ( workspaceScope ) && orgWorkspaces . isPending
304+
305+ /**
306+ * The link named a workspace this organization cannot resolve — deleted since, or
307+ * never one of ours.
308+ *
309+ * The feed stays closed rather than falling back to the organization. Every other
310+ * deep-linked id in the app degrades to the unfiltered view, but an audit feed is
311+ * the one place where widening is the dangerous direction: dropping the filter
312+ * would answer a request for one workspace's history with everybody's, under a URL
313+ * that still claims to be scoped, and the CSV export would follow.
314+ */
315+ const isWorkspaceScopeUnresolved =
316+ Boolean ( workspaceScope ) && ! isWorkspaceScopePending && ! scopedWorkspace
304317 const {
305318 data,
306319 isLoading,
@@ -309,7 +322,7 @@ export function AuditLogs({ organizationId }: AuditLogsProps) {
309322 hasNextPage,
310323 fetchNextPage,
311324 refetch,
312- } = useAuditLogs ( organizationId , filters , ! isWorkspaceFilterPending )
325+ } = useAuditLogs ( organizationId , filters , ! isWorkspaceScopePending && ! isWorkspaceScopeUnresolved )
313326
314327 const allEntries = useMemo ( ( ) => {
315328 if ( ! data ?. pages ) return [ ]
@@ -437,7 +450,7 @@ export function AuditLogs({ organizationId }: AuditLogsProps) {
437450 allOptionLabel = 'All types'
438451 align = 'start'
439452 />
440- { filteredWorkspace && (
453+ { workspaceScope && (
441454 /*
442455 A deep-linked scope, not a picker: the organization can hold hundreds of
443456 workspaces, so this narrows the feed only when a link asks it to and
@@ -448,11 +461,13 @@ export function AuditLogs({ organizationId }: AuditLogsProps) {
448461 < Chip
449462 rightIcon = { X }
450463 onClick = { ( ) => void setUrlFilters ( { workspace : null } ) }
451- aria-label = { ` Clear the ${ filteredWorkspace . name } workspace filter` }
464+ aria-label = ' Clear the workspace filter'
452465 className = 'max-w-[280px] shrink-0'
453466 >
467+ { /* Rendered for an unresolved scope too, or a bad link would leave the
468+ feed closed with no control to reopen it. */ }
454469 < OverflowText
455- label = { `Workspace: ${ filteredWorkspace . name } ` }
470+ label = { `Workspace: ${ scopedWorkspace ? .name ?? 'not found' } ` }
456471 className = 'block min-w-0'
457472 />
458473 </ Chip >
@@ -516,7 +531,11 @@ export function AuditLogs({ organizationId }: AuditLogsProps) {
516531 < ActivityLog
517532 entries = { allEntries . map ( toActivityEntry ) }
518533 emptyState = {
519- isLoading || isWorkspaceFilterPending ? undefined : debouncedSearch ? (
534+ isLoading || isWorkspaceScopePending ? undefined : isWorkspaceScopeUnresolved ? (
535+ < SettingsEmptyState >
536+ That workspace is not part of this organization.
537+ </ SettingsEmptyState >
538+ ) : debouncedSearch ? (
520539 < SettingsEmptyState variant = 'inline' >
521540 No results for "{ debouncedSearch } "
522541 </ SettingsEmptyState >
0 commit comments