Highly ambitious ATProtocol AppView service and sdks
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix lexicon getRecords weirdness, fix lexicon delete handlers and add oob for count

+62 -58
+4 -28
api/src/database/records.rs
··· 221 221 let mut where_clauses = Vec::new(); 222 222 let mut param_count = 1; 223 223 224 - let is_lexicon = where_clause 225 - .as_ref() 226 - .and_then(|wc| wc.conditions.get("collection")) 227 - .and_then(|c| c.eq.as_ref()) 228 - .and_then(|v| v.as_str()) 229 - == Some("network.slices.lexicon"); 230 - 231 224 // Extract collection name from where clause for lexicon lookup 232 225 let collection = where_clause 233 226 .as_ref() ··· 262 255 // Build ORDER BY clause with datetime field information 263 256 let order_by = build_order_by_clause_with_field_info(sort_by, primary_field_is_datetime); 264 257 265 - if is_lexicon { 266 - where_clauses.push(format!("json->>'slice' = ${}", param_count)); 267 - } else { 268 - where_clauses.push(format!("slice_uri = ${}", param_count)); 269 - } 258 + where_clauses.push(format!("slice_uri = ${}", param_count)); 270 259 param_count += 1; 271 260 272 261 // Build all other WHERE conditions first (including collection filter) 273 - // For non-lexicon records, exclude the 'slice' field since we handle it via slice_uri 262 + // Exclude the 'slice' field since we handle it via slice_uri 274 263 let mut filtered_where_clause = None; 275 264 let filtered_clause; 276 265 277 - if is_lexicon { 278 - filtered_where_clause = where_clause; 279 - } else if let Some(wc) = where_clause { 266 + if let Some(wc) = where_clause { 280 267 let mut filtered_conditions = std::collections::HashMap::new(); 281 268 for (field, condition) in &wc.conditions { 282 269 if field != "slice" { ··· 372 359 let mut where_clauses = Vec::new(); 373 360 let mut param_count = 1; 374 361 375 - let is_lexicon = where_clause 376 - .as_ref() 377 - .and_then(|wc| wc.conditions.get("collection")) 378 - .and_then(|c| c.eq.as_ref()) 379 - .and_then(|v| v.as_str()) 380 - == Some("network.slices.lexicon"); 381 - 382 - if is_lexicon { 383 - where_clauses.push(format!("json->>'slice' = ${}", param_count)); 384 - } else { 385 - where_clauses.push(format!("slice_uri = ${}", param_count)); 386 - } 362 + where_clauses.push(format!("slice_uri = ${}", param_count)); 387 363 param_count += 1; 388 364 389 365 let (and_conditions, or_conditions) =
+53 -25
frontend/src/features/slices/lexicon/handlers.tsx
··· 12 12 import { LexiconsList } from "./templates/fragments/LexiconsList.tsx"; 13 13 import { LexiconFormModal } from "./templates/fragments/LexiconFormModal.tsx"; 14 14 import { Badge } from "../../../shared/fragments/Badge.tsx"; 15 + import { Card } from "../../../shared/fragments/Card.tsx"; 15 16 import { FileCode } from "lucide-preact"; 16 17 import { buildSliceUrl } from "../../../utils/slice-params.ts"; 17 18 import type { NetworkSlicesLexicon } from "../../../client.ts"; 18 19 import type { RecordResponse } from "@slices/client"; 20 + import { publicClient } from "../../../config.ts"; 19 21 20 22 async function handleListLexicons( 21 23 req: Request, ··· 287 289 const remainingLexicons = 288 290 await sliceClient.network.slices.lexicon.getRecords(); 289 291 292 + const countHeader = ( 293 + <Card.Header 294 + title={`${remainingLexicons.records.length} ${ 295 + remainingLexicons.records.length === 1 ? "Lexicon" : "Lexicons" 296 + }`} 297 + id="lexicon-count-header" 298 + hx-swap-oob="true" 299 + /> 300 + ); 301 + 290 302 if (remainingLexicons.records.length === 0) { 291 303 return renderHTML( 292 - <EmptyState 293 - icon={<FileCode size={64} strokeWidth={1} />} 294 - title="No lexicons uploaded" 295 - description="Upload lexicon definitions to define custom schemas for this slice." 296 - withPadding 297 - />, 304 + <div> 305 + <EmptyState 306 + icon={<FileCode size={64} strokeWidth={1} />} 307 + title="No lexicons uploaded" 308 + description="Upload lexicon definitions to define custom schemas for this slice." 309 + withPadding 310 + /> 311 + {countHeader} 312 + </div>, 298 313 { 299 314 headers: { 300 315 "HX-Retarget": "#lexicon-list", ··· 302 317 } 303 318 ); 304 319 } else { 305 - return new Response("", { 306 - status: 200, 307 - headers: { "content-type": "text/html" }, 308 - }); 320 + return renderHTML(countHeader); 309 321 } 310 322 } catch (error) { 311 323 console.error("Failed to delete lexicon:", error); ··· 414 426 const remainingLexicons = 415 427 await sliceClient.network.slices.lexicon.getRecords(); 416 428 429 + const countHeader = ( 430 + <Card.Header 431 + title={`${remainingLexicons.records.length} ${ 432 + remainingLexicons.records.length === 1 ? "Lexicon" : "Lexicons" 433 + }`} 434 + id="lexicon-count-header" 435 + hx-swap-oob="true" 436 + /> 437 + ); 438 + 417 439 if (remainingLexicons.records.length === 0) { 418 440 return renderHTML( 419 - <EmptyState 420 - icon={<FileCode size={64} strokeWidth={1} />} 421 - title="No lexicons uploaded" 422 - description="Upload lexicon definitions to define custom schemas for this slice." 423 - withPadding 424 - /> 441 + <div> 442 + <EmptyState 443 + icon={<FileCode size={64} strokeWidth={1} />} 444 + title="No lexicons uploaded" 445 + description="Upload lexicon definitions to define custom schemas for this slice." 446 + withPadding 447 + /> 448 + {countHeader} 449 + </div> 425 450 ); 426 451 } else { 427 452 // Get slice info for domain comparison 428 453 const sliceUri = buildSliceUri(context.currentUser.sub!, sliceId); 429 - const sliceResponse = await sliceClient.network.slices.slice.getRecord({ 454 + const sliceResponse = await publicClient.network.slices.slice.getRecord({ 430 455 uri: sliceUri, 431 456 }); 432 457 const sliceDomain = sliceResponse.value.domain; 433 458 434 459 return renderHTML( 435 - <LexiconsList 436 - records={remainingLexicons.records} 437 - sliceId={sliceId} 438 - handle={handle || undefined} 439 - sliceDomain={sliceDomain} 440 - hasSliceAccess 441 - /> 460 + <div> 461 + <LexiconsList 462 + records={remainingLexicons.records} 463 + sliceId={sliceId} 464 + handle={handle || undefined} 465 + sliceDomain={sliceDomain} 466 + hasSliceAccess 467 + /> 468 + {countHeader} 469 + </div> 442 470 ); 443 471 } 444 472 } catch (error) { ··· 548 576 549 577 // Get the current lexicon record using the URI 550 578 const currentRecord = await sliceClient.network.slices.lexicon.getRecord({ 551 - uri 579 + uri, 552 580 }); 553 581 554 582 // Update the record with the new exclusion status
+1
frontend/src/features/slices/lexicon/templates/SliceLexiconPage.tsx
··· 72 72 title={`${lexicons.length} ${ 73 73 lexicons.length === 1 ? "Lexicon" : "Lexicons" 74 74 }`} 75 + id="lexicon-count-header" 75 76 /> 76 77 <Card.Content id="lexicon-list"> 77 78 {lexicons.length > 0 ? (
+4 -5
frontend/src/shared/fragments/Card.tsx
··· 11 11 children: ComponentChildren; 12 12 } 13 13 14 - interface CardHeaderProps { 14 + type CardHeaderProps = JSX.IntrinsicElements['div'] & { 15 15 title: string; 16 16 action?: JSX.Element; 17 - className?: string; 18 - } 17 + }; 19 18 20 19 interface CardContentProps extends JSX.HTMLAttributes<HTMLDivElement> { 21 20 children: ComponentChildren; ··· 55 54 ); 56 55 } 57 56 58 - Card.Header = function CardHeader({ title, action, className }: CardHeaderProps): JSX.Element { 57 + Card.Header = function CardHeader({ title, action, className, ...props }: CardHeaderProps): JSX.Element { 59 58 return ( 60 - <div className={cn("bg-zinc-50 dark:bg-zinc-800 px-6 py-3 border-b border-zinc-200 dark:border-zinc-700 rounded-t-sm", className)}> 59 + <div className={cn("bg-zinc-50 dark:bg-zinc-800 px-6 py-3 border-b border-zinc-200 dark:border-zinc-700 rounded-t-sm", className)} {...props}> 61 60 <div className="flex items-center justify-between"> 62 61 <Text as="h2" size="base" className="font-semibold"> 63 62 {title}