utils#callbackify TypeScript Examples
The following examples show how to use
utils#callbackify.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: ApiTypeSelector.tsx From one-platform with MIT License | 6 votes |
ApiTypeSelector = ({ value, onChange, errorMsg }: Props): JSX.Element => {
return (
<FormGroup fieldId="datasource-type" label="Datasource type" isRequired>
<Split hasGutter>
{apiOptions.map(({ title, desc, image, type }) => (
<SplitItem isFilled key={type}>
<CatalogBigButton
title={title}
desc={desc}
image={`${config.baseURL}/images/${image}`}
isSelected={value === type}
onClick={callbackify(onChange, type)}
/>
</SplitItem>
))}
</Split>
{errorMsg && (
<FormAlert>
<Alert variant="danger" title={errorMsg} aria-live="polite" isInline />
</FormAlert>
)}
</FormGroup>
);
}
Example #2
Source File: EnvironmentFormSection.tsx From one-platform with MIT License | 4 votes |
EnvironmentFormSection = ({
schemaPos,
handleSchemaValidation,
}: Props): JSX.Element => {
const [envNames, setEnvNames] = useState(['prod', 'stage', 'qa', 'dev']);
const { control, watch, getValues, setError, clearErrors, setValue } = useFormContext<FormData>();
const isGraphqlAPI = watch(`schemas.${schemaPos}.category`) === ApiCategory.GRAPHQL;
const { fields, append, remove } = useFieldArray({
control,
name: `schemas.${schemaPos}.environments`,
});
const handleAddNewEnvironment = () => {
append(
{
name: '',
apiBasePath: '',
headers: [{ key: '', value: '', id: undefined }],
schemaEndpoint: '',
isPublic: false,
},
{ shouldFocus: false }
);
};
const onEnvNameClear = (onChange: (...event: any[]) => void) => {
onChange('');
};
const onEnvNameSelect = (
onChange: (...event: any[]) => void,
event: React.MouseEventHandler,
selection: string,
isPlaceholder: boolean
) => {
if (isPlaceholder) onEnvNameClear(onChange);
else {
onChange(selection);
}
};
const onEnvNameCreate = (newSelection: string) => {
if (envNames.findIndex((envName) => envName === newSelection) === -1) {
setEnvNames((envState) => [...envState, newSelection]);
}
};
const onSetIntrospectionQuery = (envIndex: number) => {
const selectedEnv = `schemas.${schemaPos}.environments.${envIndex}` as const;
const value = getValues(selectedEnv);
setValue(`schemas.${schemaPos}.environments.${envIndex}.schemaEndpoint`, value.apiBasePath);
};
const setSchemaEndpointIsInvalid = (envIndex: number) => {
setError(`schemas.${schemaPos}.environments.${envIndex}.schemaEndpoint`, {
type: 'custom',
message: `Failed to get ${isGraphqlAPI ? 'introspection url' : 'api schema'}`,
});
};
const handleSchemaVerification = async (envIndex: number, schemaURL: string) => {
if (!schemaURL) return;
const isURL = isValidURL(schemaURL);
const selectedEnv = `schemas.${schemaPos}.environments.${envIndex}` as const;
if (isURL) {
const envData = getValues(selectedEnv) as ApiEnvironmentType;
const { slug, schemaEndpoint } = envData;
const category = isGraphqlAPI ? ApiCategory.GRAPHQL : ApiCategory.REST;
const headers = (envData?.headers || []).filter(({ key, value }) => key && value) as Header[];
const data = await handleSchemaValidation({
headers,
schemaEndpoint,
envSlug: slug,
category,
});
if (!data?.file) {
setSchemaEndpointIsInvalid(envIndex);
} else {
clearErrors(`schemas.${schemaPos}.environments.${envIndex}.schemaEndpoint`);
}
} else {
setSchemaEndpointIsInvalid(envIndex);
window.OpNotification.danger({ subject: 'Invalid schema url provided' });
}
};
return (
<Stack hasGutter className="pf-u-mt-md">
<StackItem>
<p className="pf-u-font-weight-bold">Environments</p>
</StackItem>
<StackItem>
<Stack hasGutter>
{fields.map((field, index) => (
<StackItem key={field.id}>
<Card id={field.id}>
<CardBody>
<Grid hasGutter>
<GridItem span={3}>
<Controller
name={`schemas.${schemaPos}.environments.${index}.name`}
control={control}
rules={{ required: true }}
defaultValue=""
render={({ field: controllerField, fieldState: { error } }) => (
<FormGroup
fieldId={`schemas.${schemaPos}.environments.${index}.name`}
label="Name"
isRequired
validated={error ? 'error' : 'success'}
helperTextInvalid={error?.message}
>
<Select
variant={SelectVariant.typeahead}
typeAheadAriaLabel="Select a state"
onSelect={callbackify(onEnvNameSelect, controllerField.onChange)}
onClear={callbackify(onEnvNameClear, controllerField.onChange)}
selections={controllerField.value}
aria-label="env link"
placeholder="Enter environment name"
isCreatable
onCreateOption={onEnvNameCreate}
placeholderText="Enter environment name"
>
{envNames.map((env, envIndex) => (
<SelectOption key={`${env}-${envIndex + 1}`} value={env} />
))}
</Select>
</FormGroup>
)}
/>
</GridItem>
<GridItem span={8}>
<Controller
name={`schemas.${schemaPos}.environments.${index}.apiBasePath`}
control={control}
rules={{ required: true }}
defaultValue=""
render={({ field: controllerField, fieldState: { error } }) => (
<FormGroup
fieldId={`schemas.${schemaPos}.environments.${index}.apiBasePath`}
label="API Base Path"
isRequired
validated={error ? 'error' : 'success'}
helperTextInvalid={error?.message}
>
<TextInput
aria-label="env link"
placeholder="Enter base path for the api"
{...controllerField}
/>
</FormGroup>
)}
/>
</GridItem>
<GridItem
span={1}
className="pf-u-display-flex pf-u-justify-content-center pf-u-align-items-flex-end"
>
<Button
variant="secondary"
aria-label="Remove"
onClick={callbackify(remove, index)}
className={styles['trash-button']}
>
<TrashIcon />
</Button>
</GridItem>
<GridItem span={12}>
<Controller
name={`schemas.${schemaPos}.environments.${index}.schemaEndpoint`}
control={control}
rules={{ required: true }}
defaultValue=""
render={({ field: { ...controllerField }, fieldState: { error } }) => (
<EnvSchemaField
isGraphqlAPI={isGraphqlAPI}
isError={Boolean(error)}
errorMessage={error?.message}
envIndex={index}
onCopyValue={() => onSetIntrospectionQuery(index)}
onRedoValidation={() =>
handleSchemaVerification(index, controllerField.value || '')
}
{...controllerField}
/>
)}
/>
</GridItem>
<GridItem span={12}>
<EnvHeaderFormSection schemaPos={schemaPos} envPos={index} />
</GridItem>
<GridItem span={12}>
<Controller
name={`schemas.${schemaPos}.environments.${index}.isPublic`}
defaultValue={false}
render={({ field: controllerField }) => (
<Checkbox
label="Is this API accessible from public?"
description="Tick this option if your environment can be accessed without VPN"
isChecked={controllerField.value}
id={`api-schema-${schemaPos}-env-${index}-internal`}
{...controllerField}
/>
)}
/>
</GridItem>
</Grid>
</CardBody>
</Card>
</StackItem>
))}
</Stack>
</StackItem>
<StackItem>
<Button
variant="link"
icon={<PlusIcon size="sm" />}
className="pf-u-p-0 pf-u-mb-lg"
onClick={handleAddNewEnvironment}
>
Add Environment
</Button>
</StackItem>
</Stack>
);
}
Example #3
Source File: EnvHeaderFormSection.tsx From one-platform with MIT License | 4 votes |
EnvHeaderFormSection = ({ schemaPos, envPos }: Props): JSX.Element => {
const { control, watch } = useFormContext<FormData>();
const { fields, append, remove } = useFieldArray({
control,
name: `schemas.${schemaPos}.environments.${envPos}.headers`,
});
const headerFields = watch(`schemas.${schemaPos}.environments.${envPos}.headers`);
const handleRemoveHeader = (indexToRemove: number) => {
remove(indexToRemove);
};
return (
<Stack hasGutter>
<StackItem style={{ marginBottom: 0 }}>
<Split>
<SplitItem isFilled>
<p className="pf-u-font-weight-bold" style={{ marginBottom: '-1rem' }}>
Headers
</p>
</SplitItem>
<SplitItem>
<Button
icon={<PlusIcon />}
variant="link"
isSmall
className="pf-u-mb-xs"
onClick={() => append({ id: undefined, value: '', key: '' })}
>
Add Header
</Button>
</SplitItem>
</Split>
</StackItem>
{fields.map((field, index) => (
<StackItem key={field.id}>
<Split hasGutter>
<SplitItem isFilled>
<Controller
name={`schemas.${schemaPos}.environments.${envPos}.headers.${index}.key`}
control={control}
defaultValue=""
render={({ field: controllerField, fieldState: { error } }) => (
<FormGroup
fieldId={`headers.${index}.key`}
isRequired
validated={error ? 'error' : 'success'}
helperTextInvalid={error?.message}
>
<TextInput
aria-label="header name"
placeholder="Content-Type"
{...controllerField}
/>
</FormGroup>
)}
/>
</SplitItem>
<SplitItem isFilled>
<Controller
name={`schemas.${schemaPos}.environments.${envPos}.headers.${index}.value`}
control={control}
defaultValue=""
render={({ field: controllerField, fieldState: { error } }) => (
<FormGroup
fieldId={`headers.${index}.value`}
isRequired
validated={error ? 'error' : 'success'}
helperTextInvalid={error?.message}
>
<TextInput
aria-label="header url"
isDisabled={Boolean(headerFields?.[index].id)}
placeholder="**********"
type="password"
{...controllerField}
/>
</FormGroup>
)}
/>
</SplitItem>
<SplitItem>
<Button
variant="secondary"
onClick={callbackify(handleRemoveHeader, index)}
className={styles['trash-button']}
>
<TrashIcon />
</Button>
</SplitItem>
</Split>
</StackItem>
))}
</Stack>
);
}
Example #4
Source File: APIListPage.tsx From one-platform with MIT License | 4 votes |
APIListPage = (): JSX.Element => {
const navigate = useNavigate();
// query param strings
const query = useQueryParams();
const mid = query.get('mid');
const defaultSearch = query.get('search');
// filters, search, sorting
const [isSortSelectOpen, setSortSelect] = useToggle();
const [sortOption, setSortOption] = useState(SortBy.RECENTLY_ADDED);
const [filters, setFilters] = useState<{ type: null | ApiCategory; search: string }>({
type: null,
search: defaultSearch || '',
});
const { pagination, onPerPageSelect, onSetPage, onResetPagination } = usePagination({
page: 1,
perPage: 20,
});
const debouncedSearch = useDebounce(filters.search);
// graphql query hooks
const { isLoading: isApiListLoading, data: namespaceList } = useGetNamespaceList({
limit: pagination.perPage,
offset: (pagination.page - 1) * pagination.perPage,
apiCategory: filters.type,
search: debouncedSearch,
sortBy: sortOption === SortBy.RECENTLY_ADDED ? 'CREATED_ON' : 'UPDATED_ON',
mid,
});
const { isLoading: isNamespaceStatLoading, data: namespaceStats } = useGetNamespaceStats({
search: debouncedSearch,
mid,
});
const handleApiOwnersRender = useCallback((owners: ApiOwnerType[]) => {
return owners.map((owner) =>
owner.group === ApiEmailGroup.USER ? owner.user.cn : owner.email
);
}, []);
const onStatCardClick = (cardType: 'total' | 'rest' | 'graphql') => {
onResetPagination();
if (cardType === 'total') {
setFilters((state) => ({ ...state, type: null }));
} else {
setFilters((state) => ({ ...state, type: cardType.toUpperCase() as ApiCategory }));
}
};
const onSearch = (search: string) => {
setFilters((state) => ({ ...state, search }));
};
const onSortSelect = (
event: React.MouseEvent | React.ChangeEvent,
value: string | SelectOptionObject,
isPlaceholder?: boolean
) => {
if (isPlaceholder) setSortOption(SortBy.RECENTLY_ADDED);
else setSortOption(value as SortBy);
setSortSelect.off(); // close the select
};
const onCardClick = (id: string) => {
navigate(id);
};
const namespaceCount = namespaceStats?.getApiCategoryCount;
const namespaces = namespaceList?.listNamespaces?.data;
const isNamespaceEmpty = !isApiListLoading && namespaces?.length === 0;
return (
<>
<Header />
<Divider />
<PageSection variant="light" isWidthLimited className="pf-m-align-center">
<Grid hasGutter>
<Grid hasGutter span={12}>
{stats.map(({ key, type, image }) => (
<GridItem
key={`api-select-${type}`}
span={4}
className={styles['api-list--stat-card']}
type={key}
>
<StatCard
value={namespaceCount?.[key]}
category={type}
isLoading={isNamespaceStatLoading}
onClick={callbackify(onStatCardClick, key)}
isSelected={filters.type ? filters.type.toLowerCase() === key : key === 'total'}
>
<img
src={`${config.baseURL}/images/${image}`}
alt={`api-select-${type}`}
style={{ height: '48px' }}
/>
</StatCard>
</GridItem>
))}
</Grid>
<GridItem className="pf-u-my-md">
<Split hasGutter className={styles['api-list--table-filter--container']}>
<SplitItem isFilled>
<Link to={ApiCatalogLinks.AddNewApiPage}>
<Button>Add API</Button>
</Link>
</SplitItem>
<SplitItem className="pf-u-w-33">
<Form>
<FormGroup fieldId="search">
<TextInput
aria-label="Search API"
placeholder="Search for APIs"
type="search"
iconVariant="search"
value={filters.search}
onChange={onSearch}
/>
</FormGroup>
</Form>
</SplitItem>
<SplitItem style={{ width: '180px' }}>
<Select
isOpen={isSortSelectOpen}
onToggle={setSortSelect.toggle}
selections={sortOption}
onSelect={onSortSelect}
>
{[
<SelectOption key="select-sort-placeholder" value="Sort by" isDisabled />,
<SelectOption
key={`select-sort:${SortBy.RECENTLY_ADDED}`}
value={SortBy.RECENTLY_ADDED}
/>,
<SelectOption
key={`select-sort:${SortBy.RECENTLY_MODIFIED}`}
value={SortBy.RECENTLY_MODIFIED}
/>,
]}
</Select>
</SplitItem>
</Split>
</GridItem>
{isApiListLoading ? (
<Bullseye className="pf-u-mt-lg">
<Spinner size="xl" />
</Bullseye>
) : (
namespaces?.map(({ id, name, updatedOn, owners, schemas, slug }) => (
<GridItem
span={12}
key={id}
className="catalog-nav-link"
onClick={callbackify(onCardClick, slug)}
>
<ApiDetailsCard
title={name}
owners={handleApiOwnersRender(owners)}
updatedAt={updatedOn}
schemas={schemas.map(({ name: schemaName, category }) => ({
name: schemaName,
type: category,
}))}
/>
</GridItem>
))
)}
{isNamespaceEmpty && (
<EmptyState>
<EmptyStateIcon icon={CubesIcon} />
<Title headingLevel="h4" size="lg">
No API found
</Title>
<EmptyStateBody>Add an API to fill this gap</EmptyStateBody>
</EmptyState>
)}
</Grid>
</PageSection>
<PageSection variant="light" isWidthLimited className="pf-m-align-center pf-u-pb-2xl">
<Pagination
itemCount={namespaceList?.listNamespaces?.count || 0}
widgetId="pagination-options-menu-bottom"
perPage={pagination.perPage}
page={pagination.page}
onSetPage={(_, page) => onSetPage(page)}
onPerPageSelect={(_, perPage) => onPerPageSelect(perPage)}
isCompact
/>
</PageSection>
</>
);
}