Skip to content

Commit

Permalink
Task/WP-694 : Provide mechanism to show UI for file selection on app …
Browse files Browse the repository at this point in the history
…arguments (#1450)

* FileSelection changes

* WP-694: Also allow file selection UI for app parameters

* Fix linting

---------

Co-authored-by: Sal Tijerina <[email protected]>
  • Loading branch information
chandra-tacc and rstijerina authored Oct 2, 2024
1 parent 1295c87 commit 37a4c36
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 30 deletions.
1 change: 1 addition & 0 deletions client/modules/_hooks/src/workspace/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export type TParameterSetNotes = {
isHidden?: boolean;
fieldType?: string;
inputType?: string;
validator?: {
regex: string;
message: string;
Expand Down
26 changes: 21 additions & 5 deletions client/modules/workspace/src/AppsWizard/AppsFormSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,7 @@ export type TField = {
parameterSet?: string;
description?: string;
options?: TFieldOptions[];
tapisFile?: boolean;
tapisFileSelectionMode?: string;
fileSettings?: TAppFileSettings;
placeholder?: string;
readOnly?: boolean;
};
Expand Down Expand Up @@ -96,7 +95,7 @@ export type TAppFormSchema = {
};
};

export const inputFileRegex = /^tapis:\/\/(?<storageSystem>[^/]+)/;
export const tapisInputFileRegex = /^tapis:\/\/(?<storageSystem>[^/]+)/;

export const fieldDisplayOrder: Record<string, string[]> = {
configuration: [
Expand All @@ -109,6 +108,14 @@ export const fieldDisplayOrder: Record<string, string[]> = {
outputs: ['name', 'archiveSystemId', 'archiveSystemDir'],
};

export type TAppFilePathRepresentation = 'FullTapisPath' | 'NameOnly';
export type TAppFileSelectionMode = 'both' | 'file' | 'directory';

export type TAppFileSettings = {
fileNameRepresentation: TAppFilePathRepresentation;
fileSelectionMode: TAppFileSelectionMode;
};

// See https://github.com/colinhacks/zod/issues/310 for Zod issue
const emptyStringToUndefined = z.literal('').transform(() => undefined);
function asOptionalField<T extends z.ZodTypeAny>(schema: T) {
Expand Down Expand Up @@ -316,6 +323,12 @@ const FormSchema = (
name: `parameters.${parameterSet}.${label}`,
key: paramId,
type: 'text',
...(param.notes?.inputType === 'fileInput' && {
fileSettings: {
fileNameRepresentation: 'NameOnly',
fileSelectionMode: 'file',
},
}),
};

if (param.notes?.enum_values) {
Expand Down Expand Up @@ -399,11 +412,14 @@ const FormSchema = (
required: input.inputMode === 'REQUIRED',
name: `inputs.${input.name}`,
key: `inputs.${input.name}`,
tapisFile: true,
type: 'text',
placeholder: 'Browse Data Files',
readOnly: input.inputMode === 'FIXED',
tapisFileSelectionMode: input.notes?.selectionMode ?? 'both',
fileSettings: {
fileNameRepresentation: 'FullTapisPath',
fileSelectionMode:
(input.notes?.selectionMode as TAppFileSelectionMode) ?? 'both',
},
};

appFields.fileInputs.schema[input.name] = z.string();
Expand Down
31 changes: 17 additions & 14 deletions client/modules/workspace/src/AppsWizard/FormField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,32 @@ import React, { useState, useEffect } from 'react';
import { Button, Form, Input, Select } from 'antd';
import { FormItem } from 'react-hook-form-antd';
import { useFormContext, useWatch } from 'react-hook-form';
import { TFieldOptions, inputFileRegex } from '../AppsWizard/AppsFormSchema';
import {
TFieldOptions,
tapisInputFileRegex,
TAppFileSettings,
} from '../AppsWizard/AppsFormSchema';
import { SecondaryButton } from '@client/common-components';
import { SelectModal } from '../SelectModal/SelectModal';

export const FormField: React.FC<{
name: string;
tapisFile?: boolean;
parameterSet?: string;
description?: string;
label: string;
required?: boolean;
type: string;
tapisFileSelectionMode?: string;
fileSettings?: TAppFileSettings;
placeholder?: string;
options?: TFieldOptions[];
}> = ({
name,
tapisFile = false,
parameterSet = null,
description,
label,
required = false,
type,
tapisFileSelectionMode = null,
fileSettings = null,
...props
}) => {
const { resetField, control, getValues, setValue, trigger } =
Expand All @@ -39,16 +41,17 @@ export const FormField: React.FC<{
setIsModalOpen(true);
};
useEffect(() => {
if (tapisFile) {
setStorageSystem(null);

if (fileSettings?.fileNameRepresentation === 'FullTapisPath') {
const inputFileValue = getValues(name);
const match = inputFileValue?.match(inputFileRegex);
if (match && match.groups) {
const match = inputFileValue?.match(tapisInputFileRegex);

if (match?.groups) {
setStorageSystem(match.groups.storageSystem);
} else {
setStorageSystem(null);
}
}
}, [tapisFile, name, fieldState]);
}, [fileSettings, name, fieldState]);

if (parameterSet) {
parameterSetLabel = (
Expand Down Expand Up @@ -89,7 +92,7 @@ export const FormField: React.FC<{
/>
) : (
<div style={{ display: 'flex', alignItems: 'center' }}>
{tapisFile && (
{fileSettings && (
<Form.Item name="prefix" noStyle>
<SecondaryButton onClick={handleSelectModalOpen}>
Select
Expand Down Expand Up @@ -133,11 +136,11 @@ export const FormField: React.FC<{
{/* Select Modal has Form and input which cause state sharing with above FormItem
So, SelectModal is outside FormItem.
*/}
{tapisFile && (
{fileSettings && (
<SelectModal
inputLabel={label}
system={storageSystem}
selectionMode={tapisFileSelectionMode ?? 'both'}
appFileSettings={fileSettings}
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
onSelect={(value: string) => {
Expand Down
32 changes: 21 additions & 11 deletions client/modules/workspace/src/SelectModal/SelectModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import {
TFileListing,
} from '@client/hooks';

import { TAppFileSettings } from '../AppsWizard/AppsFormSchema';

import {
BaseFileListingBreadcrumb,
FileListingTable,
Expand Down Expand Up @@ -152,7 +154,7 @@ const getParentFolder = (
function getFilesColumns(
api: string,
path: string,
selectionMode: string,
appFileSettings: TAppFileSettings,
searchTerm: string | null,
clearSearchTerm: () => void,
selectionCallback: (path: string) => void,
Expand Down Expand Up @@ -233,9 +235,11 @@ function getFilesColumns(
title: '',
render: (_, record, index) => {
const selectionModeAllowed =
(record.type === 'dir' && selectionMode === 'directory') ||
(record.type === 'file' && selectionMode === 'file') ||
selectionMode === 'both';
(record.type === 'dir' &&
appFileSettings.fileSelectionMode === 'directory') ||
(record.type === 'file' &&
appFileSettings.fileSelectionMode === 'file') ||
appFileSettings.fileSelectionMode === 'both';
const isNotRoot =
index > 0 ||
record.system.startsWith(projectPrefix) ||
Expand All @@ -244,9 +248,15 @@ function getFilesColumns(

return shouldRenderSelectButton ? (
<SecondaryButton
onClick={() =>
selectionCallback(`${api}://${record.system}${record.path}`)
}
onClick={() => {
const lastPartOfPath = record.path.split('/').pop() ?? '';
const filePath =
appFileSettings.fileNameRepresentation === 'FullTapisPath'
? `${api}://${record.system}${record.path}`
: lastPartOfPath;

selectionCallback(filePath);
}}
>
Select
</SecondaryButton>
Expand All @@ -259,11 +269,11 @@ function getFilesColumns(
export const SelectModal: React.FC<{
inputLabel: string;
system: string | null;
selectionMode: string;
appFileSettings: TAppFileSettings;
isOpen: boolean;
onClose: () => void;
onSelect: (value: string) => void;
}> = ({ inputLabel, system, selectionMode, isOpen, onClose, onSelect }) => {
}> = ({ inputLabel, system, appFileSettings, isOpen, onClose, onSelect }) => {
const [isModalOpen, setIsModalOpen] = useState(false);
const [searchTerm, setSearchTerm] = useState<string | null>(null);
const [form] = Form.useForm();
Expand Down Expand Up @@ -420,7 +430,7 @@ export const SelectModal: React.FC<{
getFilesColumns(
selectedApi,
selectedPath,
selectionMode,
appFileSettings,
searchTerm,
clearSearchTerm,
(selection: string) => selectCallback(selection),
Expand All @@ -435,7 +445,7 @@ export const SelectModal: React.FC<{
selectedSystem,
selectedPath,
systemLabel,
selectionMode,
appFileSettings,
selectCallback,
]
);
Expand Down

0 comments on commit 37a4c36

Please sign in to comment.