feat: import people

Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
2026-06-22 21:59:27 -04:00
parent cee6c2924c
commit 5fbc217edb
19 changed files with 1321 additions and 73 deletions
+5 -1
View File
@@ -44,13 +44,17 @@ export interface ApiErrorResponse {
export type ApiResponse<T = any> = ApiSuccessResponse<T> | ApiErrorResponse;
/**
* Stream control start line
* Stream control start line.
*
* `total`, when present, is the expected number of data frames (the progress
* denominator). Streams that cannot cheaply know their size up front omit it.
*/
export interface ApiStreamStartResponse {
type: 'control';
status: 'start';
version: number;
transaction: string;
total?: number;
}
/**
+16
View File
@@ -11,6 +11,7 @@ import type {
import type { GroupInterface } from './group';
import type { IndividualInterface } from './individual';
import type { OrganizationInterface } from './organization';
import type { ImportDisposition, ImportFileOptions } from './import';
export type EntityPropertiesInterface = IndividualInterface | OrganizationInterface | GroupInterface;
@@ -167,3 +168,18 @@ export interface EntityMoveResponse {
error?: string;
};
}
/**
* Entity import
*/
export interface EntityImportRequest {
target: CollectionIdentifier;
data: string;
options: ImportFileOptions;
}
export interface EntityImportResponse {
identifier: string | null;
disposition: ImportDisposition;
errors: string[];
}
+74
View File
@@ -0,0 +1,74 @@
/**
* Types for the VCF / vCard contact import UI flow (file queue, options, and
* live session state).
*
* The wire request/response for the `entity.import` operation live alongside the
* other entity operations in `./entity` ({@link EntityImportRequest},
* {@link EntityImportResponse}).
*/
import type { CollectionIdentifier } from './common';
import type { EntityImportResponse } from './entity';
export type ImportDisposition = 'created' | 'updated' | 'exists' | 'error';
export type ImportSessionStage = 'idle' | 'preparing' | 'selecting' | 'importing' | 'completed' | 'error';
/**
* Per-file import options sent to the backend.
*/
export interface ImportFileOptions {
supersede: boolean;
}
/**
* A file queued for import (raw contents read from disk).
*/
export interface ImportFileSource {
id: number;
name: string;
contents: string;
size: number;
type: string;
}
/**
* Payload for queueing a file (id is assigned by the store).
*/
export type ImportFileAdd = Omit<ImportFileSource, 'id'>;
/**
* A queued file paired with its chosen target collection and options.
*/
export interface ImportFileEntry {
file: ImportFileSource;
collectionId: CollectionIdentifier | null;
options: ImportFileOptions;
}
/**
* Aggregate counters for an import run.
*/
export interface ImportCounters {
discovered: number;
processed: number;
created: number;
updated: number;
exists: number;
error: number;
}
/**
* Live state for one file's import session.
*/
export interface ImportSession {
fileId: number;
fileName: string;
targetDisplayName: string;
targetIdentifier: CollectionIdentifier | null;
status: 'pending' | 'importing' | 'completed' | 'error';
counters: ImportCounters;
/** Bounded rolling window of recent object results, capped (see RECENT_RESULTS_CAP). */
recentResults: EntityImportResponse[];
lastError: string | null;
}
+1
View File
@@ -2,6 +2,7 @@ export type * from './collection';
export type * from './common';
export type * from './entity';
export type * from './group';
export type * from './import';
export type * from './individual';
export type * from './organization';
export type * from './provider';