Skip to content

Commit

Permalink
feat: support document format
Browse files Browse the repository at this point in the history
  • Loading branch information
EiffelFly committed Nov 4, 2024
1 parent 43d1d2e commit 6bbc3d3
Show file tree
Hide file tree
Showing 10 changed files with 171 additions and 8 deletions.
15 changes: 15 additions & 0 deletions packages/toolkit/src/constant/pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,18 @@ version: v1beta
# Click "⌘O" to add a new component
# component:
`;

export const DocumentInputAcceptMimeTypes = [
"application/msword",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/vnd.ms-powerpoint",
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
"application/vnd.ms-excel",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"text/html",
"text/plain",
"text",
"text/markdown",
"text/csv",
"application/pdf",
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"use client";

import { Nullable } from "../../../type";
import { ComponentOutputFieldBaseProps } from "../../types";
import { FieldRoot } from "./FieldRoot";

export type DownloadableFileFieldProps = {
file: Nullable<string>;
} & ComponentOutputFieldBaseProps;

export const DownloadableFileField = (props: DownloadableFileFieldProps) => {
const { title, hideField, file } = props;

return (
<FieldRoot title={title} fieldKey={`${title}-field`}>
{!hideField && file ? (
<a
className="text-semantic-accent-default hover:text-semantic-accent-hover cursor-pointer underline font-sans text-xs font-medium"
download={`outout-${title}-download-file`}
href={file}
>
Download file
</a>
) : null}
</FieldRoot>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"use client";

import { Nullable } from "../../../type";
import { ComponentOutputFieldBaseProps } from "../../types";
import { FieldRoot } from "./FieldRoot";

export type DownloadableFilesFieldProps = {
files: Nullable<string>[];
} & ComponentOutputFieldBaseProps;

export const DownloadableFilesField = (props: DownloadableFilesFieldProps) => {
const { title, hideField, files } = props;

return (
<FieldRoot title={title} fieldKey={`${title}-field`}>
{!hideField ? (
<div className="flex flex-col gap-2 flex-wrap">
{files.map((file, index) => {
if (!file) return null;

return (
<a
key={`${title}-download-file-${index}`}
className="text-semantic-accent-default hover:text-semantic-accent-hover cursor-pointer underline font-sans text-xs font-medium"
download={`outout-${title}-download-file-${index}`}
href={file}
>
Download file
</a>
);
})}
</div>
) : null}
</FieldRoot>
);
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { AudioField } from "./AudioField";
import { AudiosField } from "./AudiosField";
import { DownloadableFileField } from "./DownloadableFileField";
import { DownloadableFilesField } from "./DownloadableFilesField";
import { ImageField } from "./ImageField";
import { ImagesField } from "./ImagesField";
import { NumberField } from "./NumberField";
Expand All @@ -24,4 +26,6 @@ export const ComponentOutputFields = {
TextsField,
VideoField,
VideosField,
DownloadableFileField,
DownloadableFilesField,
};
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ export const FileField = ({
disabledFieldControl,
disabledReferenceHint,
instillFormat,
}: StartOperatorFreeFormFieldBaseProps & AutoFormFieldBaseProps) => {
accept,
}: StartOperatorFreeFormFieldBaseProps &
AutoFormFieldBaseProps & { accept: string }) => {
const [uploadedFile, setUploadedFiles] = React.useState<Nullable<File>>();
const inputRef = React.useRef<HTMLInputElement>(null);

Expand Down Expand Up @@ -54,7 +56,7 @@ export const FileField = ({
ref={inputRef}
title="Upload file"
fieldKey={path}
accept="*/*"
accept={accept}
onChange={async (e) => {
const file = e.target.files?.[0];
if (file) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ export const FilesField = ({
disabledFieldControl,
disabledReferenceHint,
instillFormat,
}: StartOperatorFreeFormFieldBaseProps & AutoFormFieldBaseProps) => {
accept,
}: StartOperatorFreeFormFieldBaseProps &
AutoFormFieldBaseProps & {
accept: string;
}) => {
const [uploadedFiles, setUploadedFiles] = React.useState<File[]>([]);
const inputRef = React.useRef<HTMLInputElement>(null);

Expand Down Expand Up @@ -56,7 +60,7 @@ export const FilesField = ({
keyPrefix={keyPrefix}
title="Upload files"
fieldKey={path}
accept="*/*"
accept={accept}
multiple={true}
onChange={async (e) => {
if (e.target.files && e.target.files.length > 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ export function pickComponentOutputFieldsFromInstillFormTree(
if (tree.instillFormat.includes("array:")) {
const arrayType = tree.instillFormat.replaceAll("array:", "").split("/")[0];

if (arrayType?.includes("structured")) {
if (arrayType?.includes("structured") || arrayType === "json") {
// Some time even the type hint is array:semi-structured, backend will still be possible
// to return array of string or array of number. So we need to handle that case here
if (Array.isArray(propertyValue) && propertyValue.length > 0) {
Expand Down Expand Up @@ -309,7 +309,16 @@ export function pickComponentOutputFieldsFromInstillFormTree(
/>
);
}

case "document": {
return (
<ComponentOutputFields.DownloadableFilesField
mode={mode}
title={title}
files={propertyValue}
hideField={hideField}
/>
);
}
default: {
return (
<ComponentOutputFields.TextsField
Expand All @@ -328,7 +337,7 @@ export function pickComponentOutputFieldsFromInstillFormTree(
const singularType = tree.instillFormat.split("/")[0];

// Process structured type like semi-structured, structured/detection_object...etc
if (singularType?.includes("structured")) {
if (singularType?.includes("structured") || singularType === "json") {
return (
<ComponentOutputFields.ObjectField
mode={mode}
Expand Down Expand Up @@ -395,7 +404,8 @@ export function pickComponentOutputFieldsFromInstillFormTree(
/>
);
}
case "semi-structured": {
case "semi-structured":
case "json": {
return (
<ComponentOutputFields.ObjectField
mode={mode}
Expand All @@ -405,6 +415,16 @@ export function pickComponentOutputFieldsFromInstillFormTree(
/>
);
}
case "document": {
return (
<ComponentOutputFields.DownloadableFileField
mode={mode}
title={title}
file={propertyValue}
hideField={hideField}
/>
);
}
default: {
return (
<ComponentOutputFields.TextField
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { PipelineVariableFieldMap } from "instill-sdk";
import { UseFormReturn } from "react-hook-form";

import { DocumentInputAcceptMimeTypes } from "../../../constant/pipeline";
import { Nullable } from "../../type";
import { TriggerRequestFormFields } from "../components";
import { FieldMode, StartOperatorFreeFormFieldItem } from "../types";
Expand Down Expand Up @@ -374,6 +375,7 @@ export function pickPipelineTriggerRequestFormFields({
disabledFieldControl={disabledFieldControls}
disabledReferenceHint={disabledReferenceHint}
instillFormat={value.instillFormat}
accept="*/*"
/>
),
});
Expand All @@ -398,6 +400,55 @@ export function pickPipelineTriggerRequestFormFields({
disabledFieldControl={disabledFieldControls}
disabledReferenceHint={disabledReferenceHint}
instillFormat={value.instillFormat}
accept="*/*"
/>
),
});
break;
case "document":
items.push({
key,
instillUIOrder: value.instillUiOrder,
component: (
<TriggerRequestFormFields.FileField
mode={mode}
key={key}
form={form}
path={key}
title={value.title}
onDeleteField={onDeleteField}
onEditField={onEditField}
description={value.description ?? null}
disabled={disabledFields}
keyPrefix={keyPrefix}
disabledFieldControl={disabledFieldControls}
disabledReferenceHint={disabledReferenceHint}
instillFormat={value.instillFormat}
accept={DocumentInputAcceptMimeTypes.join(",")}
/>
),
});
break;
case "array:document":
items.push({
key,
instillUIOrder: value.instillUiOrder,
component: (
<TriggerRequestFormFields.FilesField
mode={mode}
key={key}
form={form}
path={key}
title={value.title}
onDeleteField={onDeleteField}
onEditField={onEditField}
description={value.description ?? null}
disabled={disabledFields}
keyPrefix={keyPrefix}
disabledFieldControl={disabledFieldControls}
disabledReferenceHint={disabledReferenceHint}
instillFormat={value.instillFormat}
accept={DocumentInputAcceptMimeTypes.join(",")}
/>
),
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,12 @@ export function transformPipelineTriggerRequestFieldsToZod(
break;
case "file":
case "*/*":
case "document":
zodSchema = zodSchema.setKey(key, z.string().nullable().optional());
break;
case "array:file":
case "array:*/*":
case "array:document":
zodSchema = zodSchema.setKey(
key,
z.array(z.string().nullable().optional()).nullable().optional(),
Expand Down
2 changes: 2 additions & 0 deletions packages/toolkit/src/view/recipe-editor/VscodeEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ const availableInstillFormats = [
"array:file",
"json",
"array:json",
"document",
"array:document",
];

const componentTopLevelKeys = ["type", "input", "setup", "condition", "task"];
Expand Down

0 comments on commit 6bbc3d3

Please sign in to comment.