feat(person): migrate birth/death year to LocalDate + DatePrecision (#773) #812
@@ -2381,6 +2381,14 @@ export interface components {
|
|||||||
documentCount?: number;
|
documentCount?: number;
|
||||||
alias?: string;
|
alias?: string;
|
||||||
notes?: string;
|
notes?: string;
|
||||||
|
/** Format: date */
|
||||||
|
birthDate?: string;
|
||||||
|
/** @enum {string} */
|
||||||
|
birthDatePrecision?: "DAY" | "MONTH" | "SEASON" | "YEAR" | "RANGE" | "APPROX" | "UNKNOWN";
|
||||||
|
/** Format: date */
|
||||||
|
deathDate?: string;
|
||||||
|
/** @enum {string} */
|
||||||
|
deathDatePrecision?: "DAY" | "MONTH" | "SEASON" | "YEAR" | "RANGE" | "APPROX" | "UNKNOWN";
|
||||||
personType?: string;
|
personType?: string;
|
||||||
familyMember?: boolean;
|
familyMember?: boolean;
|
||||||
provisional?: boolean;
|
provisional?: boolean;
|
||||||
@@ -2490,10 +2498,10 @@ export interface components {
|
|||||||
/** Format: int32 */
|
/** Format: int32 */
|
||||||
number?: number;
|
number?: number;
|
||||||
sort?: components["schemas"]["SortObject"];
|
sort?: components["schemas"]["SortObject"];
|
||||||
first?: boolean;
|
|
||||||
last?: boolean;
|
|
||||||
/** Format: int32 */
|
/** Format: int32 */
|
||||||
numberOfElements?: number;
|
numberOfElements?: number;
|
||||||
|
first?: boolean;
|
||||||
|
last?: boolean;
|
||||||
empty?: boolean;
|
empty?: boolean;
|
||||||
};
|
};
|
||||||
PageableObject: {
|
PageableObject: {
|
||||||
|
|||||||
@@ -15,7 +15,9 @@ import { m } from '$lib/paraglide/messages.js';
|
|||||||
// — see Felix #3 on PR #629.
|
// — see Felix #3 on PR #629.
|
||||||
import { MAX_QUERY_LENGTH } from './mentionConstants';
|
import { MAX_QUERY_LENGTH } from './mentionConstants';
|
||||||
|
|
||||||
type Person = components['schemas']['Person'];
|
// PersonSummaryDTO, not Person: /api/persons list items are the summary projection.
|
||||||
|
// Typing them as the full entity hid a runtime bug (missing date fields, #812).
|
||||||
|
type Person = components['schemas']['PersonSummaryDTO'];
|
||||||
|
|
||||||
// The dropdown receives a single reactive state object. PersonMentionEditor
|
// The dropdown receives a single reactive state object. PersonMentionEditor
|
||||||
// mutates fields on this object (model.items = ..., etc.) and Svelte's $state
|
// mutates fields on this object (model.items = ..., etc.) and Svelte's $state
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ import MentionDropdownFixture from './MentionDropdown.test-fixture.svelte';
|
|||||||
import { m } from '$lib/paraglide/messages.js';
|
import { m } from '$lib/paraglide/messages.js';
|
||||||
import type { components } from '$lib/generated/api';
|
import type { components } from '$lib/generated/api';
|
||||||
|
|
||||||
type Person = components['schemas']['Person'];
|
// PersonSummaryDTO mirrors the real runtime shape: /api/persons list items are
|
||||||
|
// the summary projection, not the full entity (#812).
|
||||||
|
type Person = components['schemas']['PersonSummaryDTO'];
|
||||||
|
|
||||||
afterEach(cleanup);
|
afterEach(cleanup);
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { untrack } from 'svelte';
|
|||||||
import MentionDropdown from './MentionDropdown.svelte';
|
import MentionDropdown from './MentionDropdown.svelte';
|
||||||
import type { components } from '$lib/generated/api';
|
import type { components } from '$lib/generated/api';
|
||||||
|
|
||||||
type Person = components['schemas']['Person'];
|
type Person = components['schemas']['PersonSummaryDTO'];
|
||||||
type DropdownState = {
|
type DropdownState = {
|
||||||
items: Person[];
|
items: Person[];
|
||||||
command: (item: Person) => void;
|
command: (item: Person) => void;
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ import MentionDropdown from './MentionDropdown.svelte';
|
|||||||
import { createMentionNodeView } from './mentionNodeView';
|
import { createMentionNodeView } from './mentionNodeView';
|
||||||
import { MAX_QUERY_LENGTH, SEARCH_DEBOUNCE_MS, SEARCH_RESULT_LIMIT } from './mentionConstants';
|
import { MAX_QUERY_LENGTH, SEARCH_DEBOUNCE_MS, SEARCH_RESULT_LIMIT } from './mentionConstants';
|
||||||
|
|
||||||
type Person = components['schemas']['Person'];
|
// PersonSummaryDTO, not Person: /api/persons list items are the summary projection.
|
||||||
|
// Typing them as the full entity hid a runtime bug (missing date fields, #812).
|
||||||
|
type Person = components['schemas']['PersonSummaryDTO'];
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
value: string;
|
value: string;
|
||||||
@@ -216,14 +218,15 @@ const controller = createMentionController();
|
|||||||
// reflected data-person-id or the search input).
|
// reflected data-person-id or the search input).
|
||||||
function commitRelink(pos: number): CommitFn {
|
function commitRelink(pos: number): CommitFn {
|
||||||
return (item: Person) => {
|
return (item: Person) => {
|
||||||
if (!editor) return;
|
if (!editor || !item.id) return;
|
||||||
|
const personId = item.id;
|
||||||
editor
|
editor
|
||||||
.chain()
|
.chain()
|
||||||
.focus()
|
.focus()
|
||||||
.command(({ tr, state }) => {
|
.command(({ tr, state }) => {
|
||||||
const node = state.doc.nodeAt(pos);
|
const node = state.doc.nodeAt(pos);
|
||||||
if (!node || node.type.name !== 'mention') return false;
|
if (!node || node.type.name !== 'mention') return false;
|
||||||
tr.setNodeMarkup(pos, undefined, { ...node.attrs, personId: item.id });
|
tr.setNodeMarkup(pos, undefined, { ...node.attrs, personId });
|
||||||
return true;
|
return true;
|
||||||
})
|
})
|
||||||
.run();
|
.run();
|
||||||
@@ -364,8 +367,10 @@ onMount(() => {
|
|||||||
render() {
|
render() {
|
||||||
const buildFreshCommit = (loose: LooseRenderProps): CommitFn => {
|
const buildFreshCommit = (loose: LooseRenderProps): CommitFn => {
|
||||||
const clippedQuery = loose.query.slice(0, MAX_QUERY_LENGTH);
|
const clippedQuery = loose.query.slice(0, MAX_QUERY_LENGTH);
|
||||||
return (item: Person) =>
|
return (item: Person) => {
|
||||||
|
if (!item.id) return;
|
||||||
loose.command({ personId: item.id, displayName: clippedQuery });
|
loose.command({ personId: item.id, displayName: clippedQuery });
|
||||||
|
};
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
onStart(renderProps) {
|
onStart(renderProps) {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { m } from '$lib/paraglide/messages.js';
|
|||||||
// module so the test cannot drift from production. Sara on PR #629 round 3.
|
// module so the test cannot drift from production. Sara on PR #629 round 3.
|
||||||
import { SEARCH_DEBOUNCE_MS } from './mentionConstants';
|
import { SEARCH_DEBOUNCE_MS } from './mentionConstants';
|
||||||
|
|
||||||
type Person = components['schemas']['Person'];
|
type Person = components['schemas']['PersonSummaryDTO'];
|
||||||
type PersonMention = components['schemas']['PersonMention'];
|
type PersonMention = components['schemas']['PersonMention'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user