Tree search + click-rebuild; searchable relationship picker; gender dropdown

- Tree page: add a "Find a person" search box that jumps the chart to a
  match and rebuilds the hourglass (parents/grandparents/partner/children)
  around them. Clicking any card recenters via family-chart's default
  behavior (setAncestryDepth 3 / setProgenyDepth 2), syncing focus through
  setAfterUpdate for the "Open profile" link.
- Person detail: replace the relationship "add" <select> with a
  type-to-filter PersonCombobox so long people lists are searchable.
- Person detail: gender is now a Male/Female dropdown, not free text.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-07 09:58:45 -04:00
parent e0fb924a1d
commit f165ccb941
5 changed files with 966 additions and 26 deletions
+241 -5
View File
@@ -190,7 +190,8 @@ export interface paths {
delete: operations["delete_tree_api_v1_trees__tree_id__delete"];
options?: never;
head?: never;
patch?: never;
/** Update Tree */
patch: operations["update_tree_api_v1_trees__tree_id__patch"];
trace?: never;
};
"/api/v1/trees/{tree_id}/restore": {
@@ -366,7 +367,8 @@ export interface paths {
delete: operations["delete_relationship_api_v1_trees__tree_id__relationships__relationship_id__delete"];
options?: never;
head?: never;
patch?: never;
/** Update Relationship */
patch: operations["update_relationship_api_v1_trees__tree_id__relationships__relationship_id__patch"];
trace?: never;
};
"/api/v1/trees/{tree_id}/sources": {
@@ -402,7 +404,8 @@ export interface paths {
delete: operations["delete_source_api_v1_trees__tree_id__sources__source_id__delete"];
options?: never;
head?: never;
patch?: never;
/** Update Source */
patch: operations["update_source_api_v1_trees__tree_id__sources__source_id__patch"];
trace?: never;
};
"/api/v1/trees/{tree_id}/citations": {
@@ -437,7 +440,8 @@ export interface paths {
delete: operations["delete_citation_api_v1_trees__tree_id__citations__citation_id__delete"];
options?: never;
head?: never;
patch?: never;
/** Update Citation */
patch: operations["update_citation_api_v1_trees__tree_id__citations__citation_id__patch"];
trace?: never;
};
"/api/v1/trees/{tree_id}/media": {
@@ -489,7 +493,8 @@ export interface paths {
delete: operations["delete_media_api_v1_trees__tree_id__media__media_id__delete"];
options?: never;
head?: never;
patch?: never;
/** Update Media */
patch: operations["update_media_api_v1_trees__tree_id__media__media_id__patch"];
trace?: never;
};
"/api/v1/trees/{tree_id}/gedcom/import": {
@@ -610,6 +615,14 @@ export interface components {
*/
created_at: string;
};
/** CitationUpdate */
CitationUpdate: {
/** Page */
page?: string | null;
/** Detail */
detail?: string | null;
confidence?: components["schemas"]["CitationConfidence"] | null;
};
/** EventCreate */
EventCreate: {
/** Event Type */
@@ -756,6 +769,17 @@ export interface components {
/** Url */
url?: string | null;
};
/** MediaUpdate */
MediaUpdate: {
/** Title */
title?: string | null;
/** Person Id */
person_id?: string | null;
/** Event Id */
event_id?: string | null;
/** Source Id */
source_id?: string | null;
};
/**
* ParentChildQualifier
* @description Qualifies a parent_child edge so adoption/donor/blended families are
@@ -898,6 +922,12 @@ export interface components {
* @enum {string}
*/
RelationshipType: "parent_child" | "partnership" | "sibling";
/** RelationshipUpdate */
RelationshipUpdate: {
qualifier?: components["schemas"]["ParentChildQualifier"] | null;
/** Notes */
notes?: string | null;
};
/** SessionRead */
SessionRead: {
user: components["schemas"]["UserRead"];
@@ -962,6 +992,25 @@ export interface components {
*/
created_at: string;
};
/** SourceUpdate */
SourceUpdate: {
/** Title */
title?: string | null;
/** Author */
author?: string | null;
/** Source Type */
source_type?: string | null;
/** Repository */
repository?: string | null;
/** Url */
url?: string | null;
/** Citation Text */
citation_text?: string | null;
/** Publication Info */
publication_info?: string | null;
/** Quality Note */
quality_note?: string | null;
};
/** TokenRequest */
TokenRequest: {
/** Token */
@@ -999,6 +1048,14 @@ export interface components {
*/
created_at: string;
};
/** TreeUpdate */
TreeUpdate: {
/** Name */
name?: string | null;
/** Description */
description?: string | null;
visibility?: components["schemas"]["TreeVisibility"] | null;
};
/**
* TreeVisibility
* @enum {string}
@@ -1414,6 +1471,41 @@ export interface operations {
};
};
};
update_tree_api_v1_trees__tree_id__patch: {
parameters: {
query?: never;
header?: never;
path: {
tree_id: string;
};
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["TreeUpdate"];
};
};
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["TreeRead"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
restore_tree_api_v1_trees__tree_id__restore_post: {
parameters: {
query?: never;
@@ -1936,6 +2028,42 @@ export interface operations {
};
};
};
update_relationship_api_v1_trees__tree_id__relationships__relationship_id__patch: {
parameters: {
query?: never;
header?: never;
path: {
tree_id: string;
relationship_id: string;
};
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["RelationshipUpdate"];
};
};
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["RelationshipRead"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
list_sources_api_v1_trees__tree_id__sources_get: {
parameters: {
query?: never;
@@ -2064,6 +2192,42 @@ export interface operations {
};
};
};
update_source_api_v1_trees__tree_id__sources__source_id__patch: {
parameters: {
query?: never;
header?: never;
path: {
tree_id: string;
source_id: string;
};
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["SourceUpdate"];
};
};
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["SourceRead"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
list_citations_api_v1_trees__tree_id__citations_get: {
parameters: {
query?: never;
@@ -2160,6 +2324,42 @@ export interface operations {
};
};
};
update_citation_api_v1_trees__tree_id__citations__citation_id__patch: {
parameters: {
query?: never;
header?: never;
path: {
tree_id: string;
citation_id: string;
};
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["CitationUpdate"];
};
};
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["CitationRead"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
list_media_api_v1_trees__tree_id__media_get: {
parameters: {
query?: never;
@@ -2288,6 +2488,42 @@ export interface operations {
};
};
};
update_media_api_v1_trees__tree_id__media__media_id__patch: {
parameters: {
query?: never;
header?: never;
path: {
tree_id: string;
media_id: string;
};
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["MediaUpdate"];
};
};
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["MediaRead"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
import_gedcom_api_v1_trees__tree_id__gedcom_import_post: {
parameters: {
query?: never;