@haneinfo/frontend-instances 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +14 -0
- package/README.md +68 -2
- package/agent-guide.md +35 -0
- package/dist/client.d.ts +62 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +463 -0
- package/dist/client.js.map +1 -0
- package/dist/contracts.d.ts +237 -0
- package/dist/contracts.d.ts.map +1 -0
- package/dist/contracts.js +102 -0
- package/dist/contracts.js.map +1 -0
- package/dist/query.d.ts +20 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +73 -0
- package/dist/query.js.map +1 -0
- package/dist/server.d.ts +41 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +189 -0
- package/dist/server.js.map +1 -0
- package/package.json +57 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Copyright (c) 2026 Haneinfo. All Rights Reserved.
|
|
2
|
+
|
|
3
|
+
This software and associated documentation files (the "Software") are the proprietary and
|
|
4
|
+
confidential property of Haneinfo. No part of the Software may be copied, modified, merged,
|
|
5
|
+
published, distributed, sublicensed, or sold without the prior written permission of Haneinfo.
|
|
6
|
+
|
|
7
|
+
The Software is provided for internal use by Haneinfo and its authorized personnel only, and is
|
|
8
|
+
NOT licensed for external distribution or open-source use.
|
|
9
|
+
|
|
10
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
|
11
|
+
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
12
|
+
NONINFRINGEMENT. IN NO EVENT SHALL HANEINFO BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
13
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
|
14
|
+
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,69 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @haneinfo/frontend-instances
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Reusable instance lists, collaboration and import/export pages for React 19 / Next 16.
|
|
4
|
+
Backend packages stay free of React and NestJS is not a dependency of this package.
|
|
5
|
+
|
|
6
|
+
## Mounting
|
|
7
|
+
|
|
8
|
+
Import `renderInstanceListPage`, `renderInstanceDetailPage` and `renderImportPage` from
|
|
9
|
+
`@haneinfo/frontend-instances/server`. Each returns a server-renderable React tree. Supply:
|
|
10
|
+
|
|
11
|
+
- `apiFetch<T>(path, init?)`, using the current authenticated session and an App-owned API URL.
|
|
12
|
+
- `LinkComponent`, `t(LabelKey)`, `getCurrentUser()`, and `basePath`.
|
|
13
|
+
- An App Server Action calling `performInstanceRequest(apiFetch, request)` and returning
|
|
14
|
+
`{ data }` or `{ error: instanceError(error) }` after checking the session.
|
|
15
|
+
- For imports, an authenticated `uploadAction(FormData)` calling `readImportUpload`, plus
|
|
16
|
+
the App's `{ code, label }[]` machine choices.
|
|
17
|
+
|
|
18
|
+
The list additionally takes `machineCode` and promised `searchParams: { query?: string }`.
|
|
19
|
+
The detail takes `id`. The import takes `machines` and `uploadAction`.
|
|
20
|
+
All UI labels are injected. System field labels use `t`; Form labels stay verbatim from the API.
|
|
21
|
+
See `LabelKey` and the complete English/zh-TW mounting examples in
|
|
22
|
+
`validation/equipment-loan/instance-frontend/app/` in the source repository.
|
|
23
|
+
|
|
24
|
+
Add `@source "../../node_modules/@haneinfo/frontend-instances/dist";` to the App's Tailwind
|
|
25
|
+
CSS source declarations. Mount navigation in the App's sidebar, not generated plugin files.
|
|
26
|
+
Set the App's Server Action body limit to allow multipart uploads (the example uses 16 MB).
|
|
27
|
+
The backend HTTP body limit remains App-owned; API rejections are shown in the UI.
|
|
28
|
+
|
|
29
|
+
## Client components and contracts
|
|
30
|
+
|
|
31
|
+
`@haneinfo/frontend-instances/client` exports `ListClient`, `DetailClient`, `ImportClient`,
|
|
32
|
+
`FilterEditor`, `JobStatus`, `JobReport`, `ImportConfirmation` and `prepareFilter`.
|
|
33
|
+
Use the server renderers for normal mounting. `@haneinfo/frontend-instances/contracts` exports
|
|
34
|
+
HTTP-only types and `labelKeys`. The server entry also exports the contracts, `dateRange`,
|
|
35
|
+
`importMapping`, `normalizeQuery`, `performInstanceRequest`, `readImportUpload` and `instanceError`.
|
|
36
|
+
|
|
37
|
+
Lists support PREDICATE/GROUP AND/OR, all eight operators, inclusive date ranges, up to eight
|
|
38
|
+
sort keys, selected columns and offset/limit pagination (1–500). IN uses one literal per line.
|
|
39
|
+
Datetime-local controls are explicitly UTC. Exports use the last applied query, not unapplied
|
|
40
|
+
editor changes. Saved views default to private; sharing controls depend only on `canShare`.
|
|
41
|
+
|
|
42
|
+
Details use pinned subject Form labels and the merged timeline; mentions come only from the
|
|
43
|
+
instance-specific mentionable API. Following comes from the timeline or mutation response.
|
|
44
|
+
Comments are append-only plain text and AI comments have a visible attribution.
|
|
45
|
+
|
|
46
|
+
CSV and xlsx headers are read using csv-parse and ExcelJS on the server, with a 10 MB upload
|
|
47
|
+
bound. The backend performs the complete preflight and authorization. Duplicate keys are
|
|
48
|
+
optional, mapped top-level keys with a five-key maximum. Preflight never confirms an import.
|
|
49
|
+
Confirmation requires a separate button click; global errors and zero valid rows disable it.
|
|
50
|
+
Re-upload to change a completed preflight's mapping.
|
|
51
|
+
|
|
52
|
+
`JobStatus` polls every two seconds, stops on terminal status or failure, and bounds automatic
|
|
53
|
+
polling to 90 requests. A manual refresh resumes polling. Job state is owner-authorized by the
|
|
54
|
+
backend. Binary result bytes and uploaded job params are removed before returning jobs to clients.
|
|
55
|
+
|
|
56
|
+
## Downloads and safety
|
|
57
|
+
|
|
58
|
+
Mount `${basePath}/download?path=...` as an authenticated, no-store streaming GET proxy. Constrain
|
|
59
|
+
the path to `/import-export/(imports|exports)/<id>/file`, forward the current session token to
|
|
60
|
+
that exact backend-provided `downloadPath`, and forward its disposition/type. Never synthesize
|
|
61
|
+
job download paths or put file bytes/tokens in the URL. The App example includes this route.
|
|
62
|
+
|
|
63
|
+
Use real Next Server Actions so same-origin CSRF checks apply. All mutations have an immediate
|
|
64
|
+
in-memory submission lock and disabled pending buttons. The backend remains authoritative for
|
|
65
|
+
authorization and validation; the UI does not recreate RBAC. 401/403/404 display generic localized
|
|
66
|
+
messages without raw API details. All user content is rendered as text nodes, including errors,
|
|
67
|
+
field values, names, and timeline details. No HTML or Markdown rendering is used.
|
|
68
|
+
|
|
69
|
+
No instance creation, submission, approval, rejection or transition controls are included.
|
package/agent-guide.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Instance frontend agent guide
|
|
2
|
+
|
|
3
|
+
Use this package to mount shared instance lists, read-only details with collaboration, and
|
|
4
|
+
human-confirmed bulk imports. Read the README for exact entry points and injected dependencies.
|
|
5
|
+
Do not add React or Next dependencies to list-view, collaboration, import-export or background-jobs.
|
|
6
|
+
|
|
7
|
+
## HTTP contracts
|
|
8
|
+
|
|
9
|
+
- List metadata: GET `/list-view/machines/:code/fields`; query: POST the same machine's `/query`.
|
|
10
|
+
- Views: GET/POST `/list-view/views`; PATCH `/list-view/views/:id/sharing`. Preserve `canShare`.
|
|
11
|
+
- Details: GET `/state-machine-instances/:id` uses the pinned subject Form bundle.
|
|
12
|
+
- Timeline: GET `/state-machine-instances/:id/timeline?offset=&limit=50`, including `following`.
|
|
13
|
+
- People: GET `/state-machine-instances/:id/mentionable?q=`, at most twenty eligible people.
|
|
14
|
+
- Collaboration: POST `comments` with `{ body }`, using `@{id}` from the people picker;
|
|
15
|
+
POST/DELETE `follow`. There are no comment edit/delete controls.
|
|
16
|
+
- Imports: GET `/import-export/machines/:code/fields`; POST `/import-export/imports/preflight`
|
|
17
|
+
with file format/base64, header-to-key mapping, and optional duplicateKey (one to five keys).
|
|
18
|
+
- Human confirmation: POST `/import-export/imports/:id/confirm` with `{ confirmed: true }` only
|
|
19
|
+
from an explicit button event, never from polling, render, an effect, or an AI tool.
|
|
20
|
+
- Exports: POST `/import-export/exports` with `{ format, source: { machineCode, query } }`.
|
|
21
|
+
- Jobs: GET `/background-jobs/:id`; downloads use the result's exact `downloadPath` through
|
|
22
|
+
an App-owned authenticated streaming proxy. The API alone decides job ownership and expiry.
|
|
23
|
+
|
|
24
|
+
The minimal types are local HTTP contracts; never import backend runtime packages for types.
|
|
25
|
+
Keep the API adapter and authentication in the App, with Server Action CSRF protection.
|
|
26
|
+
Keep API error values and all user-controlled content as plain text. Do not inspect role names
|
|
27
|
+
to decide sharing or visibility. Use both English and zh-TW translations for new UI text.
|
|
28
|
+
|
|
29
|
+
## Validation
|
|
30
|
+
|
|
31
|
+
Run package build/typecheck/tests and workspace build:graph, lint, specs:lint. Component tests
|
|
32
|
+
render actual HTML, test authorization and escaping, and verify confirmation and parameters.
|
|
33
|
+
Use the equipment-loan validation overlay for full production-build/browser acceptance. Always
|
|
34
|
+
restore and finish it, including original manifest/lockfile bytes and dependency installation.
|
|
35
|
+
Do not release, version, approve a decision, or commit as part of frontend validation.
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type Condition, type FormField, type ImportField, type InstanceAction, type InstanceQuery, type Job, type JobResult, type Labels, type ListResult, type QueryField, type SavedView, type Timeline, type UploadAction } from './contracts.js';
|
|
2
|
+
export declare function FilterEditor({ condition, fields, labels, onChange, depth, }: {
|
|
3
|
+
condition: Condition;
|
|
4
|
+
fields: QueryField[];
|
|
5
|
+
labels: Labels;
|
|
6
|
+
onChange: (value: Condition) => void;
|
|
7
|
+
depth?: number;
|
|
8
|
+
}): import("react").JSX.Element;
|
|
9
|
+
declare function prepareFilter(condition: Condition, fields: QueryField[]): Condition | undefined;
|
|
10
|
+
export { prepareFilter };
|
|
11
|
+
export declare function ListClient({ fields, initial, initialQuery, views: initialViews, machineCode, basePath, labels: t, action, }: {
|
|
12
|
+
fields: QueryField[];
|
|
13
|
+
initial: ListResult;
|
|
14
|
+
initialQuery: InstanceQuery;
|
|
15
|
+
views: SavedView[];
|
|
16
|
+
machineCode: string;
|
|
17
|
+
basePath: string;
|
|
18
|
+
labels: Labels;
|
|
19
|
+
action: InstanceAction;
|
|
20
|
+
}): import("react").JSX.Element;
|
|
21
|
+
export declare function DetailClient({ id, data, fields, state, submitterId, createdAt, initial, initialNumbers, labels: t, action, }: {
|
|
22
|
+
id: string;
|
|
23
|
+
data: Record<string, unknown>;
|
|
24
|
+
fields: FormField[];
|
|
25
|
+
state: string;
|
|
26
|
+
submitterId: string | null;
|
|
27
|
+
createdAt: string;
|
|
28
|
+
initial: Timeline;
|
|
29
|
+
initialNumbers?: string[];
|
|
30
|
+
labels: Labels;
|
|
31
|
+
action: InstanceAction;
|
|
32
|
+
}): import("react").JSX.Element;
|
|
33
|
+
export declare function JobStatus({ initial, labels: t, action, downloadBase, onComplete, }: {
|
|
34
|
+
initial: Job;
|
|
35
|
+
labels: Labels;
|
|
36
|
+
action: InstanceAction;
|
|
37
|
+
downloadBase: string;
|
|
38
|
+
onComplete?: (job: Job) => void;
|
|
39
|
+
}): import("react").JSX.Element;
|
|
40
|
+
export declare function JobReport({ result, labels: t, downloadBase, }: {
|
|
41
|
+
result: JobResult;
|
|
42
|
+
labels: Labels;
|
|
43
|
+
downloadBase: string;
|
|
44
|
+
}): import("react").JSX.Element;
|
|
45
|
+
export declare function ImportClient({ machines, fields: initialFields, labels: t, action, uploadAction, downloadBase, }: {
|
|
46
|
+
machines: {
|
|
47
|
+
code: string;
|
|
48
|
+
label: string;
|
|
49
|
+
}[];
|
|
50
|
+
fields: ImportField[];
|
|
51
|
+
labels: Labels;
|
|
52
|
+
action: InstanceAction;
|
|
53
|
+
uploadAction: UploadAction;
|
|
54
|
+
downloadBase: string;
|
|
55
|
+
}): import("react").JSX.Element;
|
|
56
|
+
export declare function ImportConfirmation({ job, labels: t, pending, onConfirm, }: {
|
|
57
|
+
job: Job;
|
|
58
|
+
labels: Labels;
|
|
59
|
+
pending: boolean;
|
|
60
|
+
onConfirm: () => void;
|
|
61
|
+
}): import("react").JSX.Element | null;
|
|
62
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.tsx"],"names":[],"mappings":"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"}
|