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:
@@ -9,6 +9,7 @@ import type { components } from "@/lib/api/schema";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { PersonCombobox } from "@/components/person-combobox";
|
||||
|
||||
type Person = components["schemas"]["PersonRead"];
|
||||
type Event = components["schemas"]["EventRead"];
|
||||
@@ -431,7 +432,11 @@ export default function PersonDetailPage() {
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Input className="w-40" placeholder="Given name" value={pGiven} onChange={(e) => setPGiven(e.target.value)} />
|
||||
<Input className="w-40" placeholder="Surname" value={pSurname} onChange={(e) => setPSurname(e.target.value)} />
|
||||
<Input className="w-32" placeholder="Gender" value={pGender} onChange={(e) => setPGender(e.target.value)} />
|
||||
<select className={fieldCls} value={pGender} onChange={(e) => setPGender(e.target.value)}>
|
||||
<option value="">Gender: —</option>
|
||||
<option value="male">Male</option>
|
||||
<option value="female">Female</option>
|
||||
</select>
|
||||
<select className={fieldCls} value={pLiving} onChange={(e) => setPLiving(e.target.value)}>
|
||||
<option value="unknown">Status: unknown</option>
|
||||
<option value="living">Living</option>
|
||||
@@ -672,14 +677,12 @@ export default function PersonDetailPage() {
|
||||
<option value="partner">partner</option>
|
||||
<option value="sibling">sibling</option>
|
||||
</select>
|
||||
<select className={fieldCls} value={relOther} onChange={(e) => setRelOther(e.target.value)}>
|
||||
<option value="">— person —</option>
|
||||
{others.map((p) => (
|
||||
<option key={p.id} value={p.id}>
|
||||
{p.primary_name ?? "Unnamed"}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<PersonCombobox
|
||||
people={others}
|
||||
value={relOther}
|
||||
onChange={setRelOther}
|
||||
placeholder="Search for a person…"
|
||||
/>
|
||||
{(relKind === "parent" || relKind === "child") && (
|
||||
<select className={fieldCls} value={relQual} onChange={(e) => setRelQual(e.target.value as Qualifier)}>
|
||||
{QUALIFIERS.map((q) => (
|
||||
|
||||
@@ -10,6 +10,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { api } from "@/lib/api/client";
|
||||
import type { components } from "@/lib/api/schema";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { FanChart } from "@/components/fan-chart";
|
||||
|
||||
type Person = components["schemas"]["PersonRead"];
|
||||
@@ -28,6 +29,9 @@ export default function TreePage() {
|
||||
const params = useParams<{ id: string }>();
|
||||
const treeId = params.id;
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const chartRef = useRef<any>(null);
|
||||
const [query, setQuery] = useState("");
|
||||
|
||||
const [people, setPeople] = useState<Person[]>([]);
|
||||
const [rels, setRels] = useState<Relationship[]>([]);
|
||||
@@ -117,19 +121,20 @@ export default function TreePage() {
|
||||
if (cancelled || !containerRef.current) return;
|
||||
containerRef.current.innerHTML = "";
|
||||
const chart = f3.createChart(containerRef.current, data);
|
||||
chart
|
||||
.setCardHtml()
|
||||
.setCardDisplay([["first name", "last name"], ["birthday"]])
|
||||
.setOnCardClick((_e: unknown, d: { data?: { id?: string } }) => {
|
||||
const id = d?.data?.id;
|
||||
if (id) {
|
||||
setFocusId(id);
|
||||
chart.updateMainId(id);
|
||||
chart.updateTree();
|
||||
}
|
||||
});
|
||||
chart.setCardHtml().setCardDisplay([["first name", "last name"], ["birthday"]]);
|
||||
if (mode === "portrait") chart.setOrientationVertical();
|
||||
else chart.setOrientationHorizontal();
|
||||
// Show enough generations that a recenter reveals grandparents + children.
|
||||
chart.setAncestryDepth?.(3);
|
||||
chart.setProgenyDepth?.(2);
|
||||
// Default card click recenters the whole hourglass; sync focus for the
|
||||
// "Open profile" link after every (re)build.
|
||||
chart.setAfterUpdate?.(() => {
|
||||
const md = chart.getMainDatum?.();
|
||||
const id = md?.id ?? md?.data?.id;
|
||||
if (id) setFocusId(id);
|
||||
});
|
||||
chartRef.current = chart;
|
||||
if (focusId) chart.updateMainId(focusId);
|
||||
chart.updateTree({ initial: true });
|
||||
})();
|
||||
@@ -139,6 +144,27 @@ export default function TreePage() {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [status, mode, people, rels, events]);
|
||||
|
||||
// Jump the tree (or fan) to a person and rebuild the hourglass around them.
|
||||
const goTo = useCallback(
|
||||
(id: string) => {
|
||||
setFocusId(id);
|
||||
setQuery("");
|
||||
if (mode !== "fan" && chartRef.current) {
|
||||
chartRef.current.updateMainId?.(id);
|
||||
chartRef.current.updateTree?.();
|
||||
}
|
||||
},
|
||||
[mode],
|
||||
);
|
||||
|
||||
const matches = useMemo(() => {
|
||||
const q = query.trim().toLowerCase();
|
||||
if (!q) return [];
|
||||
return people
|
||||
.filter((p) => (p.primary_name ?? "").toLowerCase().includes(q))
|
||||
.slice(0, 8);
|
||||
}, [query, people]);
|
||||
|
||||
const ModeButton = ({ m, label }: { m: Mode; label: string }) => (
|
||||
<button
|
||||
onClick={() => setMode(m)}
|
||||
@@ -153,7 +179,34 @@ export default function TreePage() {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex flex-wrap items-center justify-between gap-3">
|
||||
<h1 className="text-2xl font-semibold">Tree</h1>
|
||||
<div className="flex items-center gap-3">
|
||||
<h1 className="text-2xl font-semibold">Tree</h1>
|
||||
<div className="relative">
|
||||
<Input
|
||||
value={query}
|
||||
onChange={(e) => setQuery(e.target.value)}
|
||||
placeholder="Find a person…"
|
||||
className="w-56"
|
||||
/>
|
||||
{matches.length > 0 && (
|
||||
<ul className="absolute z-20 mt-1 w-72 overflow-hidden rounded-lg border border-[var(--border)] bg-[var(--surface)] shadow-lg">
|
||||
{matches.map((p) => (
|
||||
<li key={p.id}>
|
||||
<button
|
||||
onClick={() => goTo(p.id)}
|
||||
className="flex w-full items-center justify-between gap-3 px-3 py-2 text-left text-sm hover:bg-[var(--muted-bg,rgba(0,0,0,0.04))]"
|
||||
>
|
||||
<span>{p.primary_name ?? "Unnamed"}</span>
|
||||
{yearOf(p.id) && (
|
||||
<span className="text-xs text-[var(--muted)]">{yearOf(p.id)}</span>
|
||||
)}
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center rounded-lg border border-[var(--border)] p-0.5">
|
||||
<ModeButton m="landscape" label="Landscape" />
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
|
||||
import type { components } from "@/lib/api/schema";
|
||||
|
||||
type Person = components["schemas"]["PersonRead"];
|
||||
|
||||
/**
|
||||
* A type-to-filter person picker. Shows a text input; as you type, a dropdown
|
||||
* of matching people appears. Selecting one sets `value` (a person id) and
|
||||
* fills the input with their name. Replaces a plain <select> when the list is
|
||||
* long enough that scanning it by hand is painful.
|
||||
*/
|
||||
export function PersonCombobox({
|
||||
people,
|
||||
value,
|
||||
onChange,
|
||||
placeholder = "Search for a person…",
|
||||
className,
|
||||
}: {
|
||||
people: Person[];
|
||||
value: string;
|
||||
onChange: (id: string) => void;
|
||||
placeholder?: string;
|
||||
className?: string;
|
||||
}) {
|
||||
const [query, setQuery] = useState("");
|
||||
const [open, setOpen] = useState(false);
|
||||
const wrapRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const nameOf = useMemo(
|
||||
() => new Map(people.map((p) => [p.id, p.primary_name ?? "Unnamed"])),
|
||||
[people],
|
||||
);
|
||||
|
||||
// Keep the input text in sync when the selection changes externally
|
||||
// (e.g. cleared to "" after a successful add).
|
||||
useEffect(() => {
|
||||
if (!value) {
|
||||
setQuery("");
|
||||
} else if (!open) {
|
||||
setQuery(nameOf.get(value) ?? "");
|
||||
}
|
||||
}, [value, open, nameOf]);
|
||||
|
||||
// Close on outside click.
|
||||
useEffect(() => {
|
||||
function onDoc(e: MouseEvent) {
|
||||
if (wrapRef.current && !wrapRef.current.contains(e.target as Node)) setOpen(false);
|
||||
}
|
||||
document.addEventListener("mousedown", onDoc);
|
||||
return () => document.removeEventListener("mousedown", onDoc);
|
||||
}, []);
|
||||
|
||||
const matches = useMemo(() => {
|
||||
const q = query.trim().toLowerCase();
|
||||
const pool = q
|
||||
? people.filter((p) => (p.primary_name ?? "").toLowerCase().includes(q))
|
||||
: people;
|
||||
return pool.slice(0, 10);
|
||||
}, [query, people]);
|
||||
|
||||
const base =
|
||||
"h-9 w-56 rounded-md border border-[var(--border)] bg-[var(--surface)] px-2 text-sm placeholder:text-[var(--muted)] focus-visible:border-bronze focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-bronze/40";
|
||||
|
||||
return (
|
||||
<div ref={wrapRef} className="relative">
|
||||
<input
|
||||
className={`${base} ${className ?? ""}`}
|
||||
value={query}
|
||||
placeholder={placeholder}
|
||||
onFocus={() => setOpen(true)}
|
||||
onChange={(e) => {
|
||||
setQuery(e.target.value);
|
||||
setOpen(true);
|
||||
if (value) onChange(""); // typing invalidates the prior pick
|
||||
}}
|
||||
/>
|
||||
{open && matches.length > 0 && (
|
||||
<ul className="absolute z-30 mt-1 max-h-64 w-72 overflow-auto rounded-lg border border-[var(--border)] bg-[var(--surface)] shadow-lg">
|
||||
{matches.map((p) => (
|
||||
<li key={p.id}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
onChange(p.id);
|
||||
setQuery(p.primary_name ?? "Unnamed");
|
||||
setOpen(false);
|
||||
}}
|
||||
className={`block w-full px-3 py-2 text-left text-sm hover:bg-[var(--muted-bg,rgba(0,0,0,0.04))] ${
|
||||
p.id === value ? "text-bronze" : ""
|
||||
}`}
|
||||
>
|
||||
{p.primary_name ?? "Unnamed"}
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Vendored
+241
-5
@@ -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;
|
||||
|
||||
@@ -408,6 +408,57 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"patch": {
|
||||
"tags": [
|
||||
"trees"
|
||||
],
|
||||
"summary": "Update Tree",
|
||||
"operationId": "update_tree_api_v1_trees__tree_id__patch",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "tree_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"title": "Tree Id"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/TreeUpdate"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/TreeRead"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": [
|
||||
"trees"
|
||||
@@ -1239,6 +1290,67 @@
|
||||
}
|
||||
},
|
||||
"/api/v1/trees/{tree_id}/relationships/{relationship_id}": {
|
||||
"patch": {
|
||||
"tags": [
|
||||
"relationships"
|
||||
],
|
||||
"summary": "Update Relationship",
|
||||
"operationId": "update_relationship_api_v1_trees__tree_id__relationships__relationship_id__patch",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "tree_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"title": "Tree Id"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "relationship_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"title": "Relationship Id"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/RelationshipUpdate"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/RelationshipRead"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": [
|
||||
"relationships"
|
||||
@@ -1434,6 +1546,67 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"patch": {
|
||||
"tags": [
|
||||
"sources"
|
||||
],
|
||||
"summary": "Update Source",
|
||||
"operationId": "update_source_api_v1_trees__tree_id__sources__source_id__patch",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "tree_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"title": "Tree Id"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "source_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"title": "Source Id"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SourceUpdate"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SourceRead"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": [
|
||||
"sources"
|
||||
@@ -1578,6 +1751,67 @@
|
||||
}
|
||||
},
|
||||
"/api/v1/trees/{tree_id}/citations/{citation_id}": {
|
||||
"patch": {
|
||||
"tags": [
|
||||
"citations"
|
||||
],
|
||||
"summary": "Update Citation",
|
||||
"operationId": "update_citation_api_v1_trees__tree_id__citations__citation_id__patch",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "tree_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"title": "Tree Id"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "citation_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"title": "Citation Id"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/CitationUpdate"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/CitationRead"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": [
|
||||
"citations"
|
||||
@@ -1773,6 +2007,67 @@
|
||||
}
|
||||
},
|
||||
"/api/v1/trees/{tree_id}/media/{media_id}": {
|
||||
"patch": {
|
||||
"tags": [
|
||||
"media"
|
||||
],
|
||||
"summary": "Update Media",
|
||||
"operationId": "update_media_api_v1_trees__tree_id__media__media_id__patch",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "tree_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"title": "Tree Id"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "media_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"title": "Media Id"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/MediaUpdate"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/MediaRead"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": [
|
||||
"media"
|
||||
@@ -2212,6 +2507,44 @@
|
||||
],
|
||||
"title": "CitationRead"
|
||||
},
|
||||
"CitationUpdate": {
|
||||
"properties": {
|
||||
"page": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Page"
|
||||
},
|
||||
"detail": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Detail"
|
||||
},
|
||||
"confidence": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/CitationConfidence"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"title": "CitationUpdate"
|
||||
},
|
||||
"EventCreate": {
|
||||
"properties": {
|
||||
"event_type": {
|
||||
@@ -2754,6 +3087,59 @@
|
||||
],
|
||||
"title": "MediaRead"
|
||||
},
|
||||
"MediaUpdate": {
|
||||
"properties": {
|
||||
"title": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Title"
|
||||
},
|
||||
"person_id": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Person Id"
|
||||
},
|
||||
"event_id": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Event Id"
|
||||
},
|
||||
"source_id": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Source Id"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"title": "MediaUpdate"
|
||||
},
|
||||
"ParentChildQualifier": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
@@ -3159,6 +3545,33 @@
|
||||
],
|
||||
"title": "RelationshipType"
|
||||
},
|
||||
"RelationshipUpdate": {
|
||||
"properties": {
|
||||
"qualifier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ParentChildQualifier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"notes": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Notes"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"title": "RelationshipUpdate"
|
||||
},
|
||||
"SessionRead": {
|
||||
"properties": {
|
||||
"user": {
|
||||
@@ -3387,6 +3800,100 @@
|
||||
],
|
||||
"title": "SourceRead"
|
||||
},
|
||||
"SourceUpdate": {
|
||||
"properties": {
|
||||
"title": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Title"
|
||||
},
|
||||
"author": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Author"
|
||||
},
|
||||
"source_type": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Source Type"
|
||||
},
|
||||
"repository": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Repository"
|
||||
},
|
||||
"url": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Url"
|
||||
},
|
||||
"citation_text": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Citation Text"
|
||||
},
|
||||
"publication_info": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Publication Info"
|
||||
},
|
||||
"quality_note": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Quality Note"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"title": "SourceUpdate"
|
||||
},
|
||||
"TokenRequest": {
|
||||
"properties": {
|
||||
"token": {
|
||||
@@ -3475,6 +3982,44 @@
|
||||
],
|
||||
"title": "TreeRead"
|
||||
},
|
||||
"TreeUpdate": {
|
||||
"properties": {
|
||||
"name": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Name"
|
||||
},
|
||||
"description": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Description"
|
||||
},
|
||||
"visibility": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/TreeVisibility"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"title": "TreeUpdate"
|
||||
},
|
||||
"TreeVisibility": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
|
||||
Reference in New Issue
Block a user