components#ReadMore TypeScript Examples
The following examples show how to use
components#ReadMore.
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: APIReview.tsx From one-platform with MIT License | 4 votes |
APIReview = (): JSX.Element => {
const { getValues } = useFormContext<FormData>();
const [formData] = useState(getValues());
return (
<Stack hasGutter>
<StackItem>
<Card>
<CardTitle>
<Title headingLevel="h2">API Details</Title>
</CardTitle>
<CardBody>
<Stack hasGutter>
<StackItem>
<Description title="Name" isRequired>
<Title headingLevel="h6">{formData.name}</Title>
</Description>
</StackItem>
<StackItem>
<Description title="Description" isRequired>
<Title headingLevel="h6">
<ReadMore>{formData.description}</ReadMore>
</Title>
</Description>
</StackItem>
<StackItem>
<Description title="Owners">
<Title headingLevel="h6">
<List isPlain isBordered>
{formData.owners.map(({ email }) => (
<ListItem key={email}>{email}</ListItem>
))}
</List>
</Title>
</Description>
</StackItem>
</Stack>
</CardBody>
</Card>
</StackItem>
{formData.schemas?.map((schema, schemaIndex) => (
<StackItem key={schema.name}>
<Card>
<CardTitle>
<Title headingLevel="h2">{`API Schema #${schemaIndex + 1}`}</Title>
</CardTitle>
<CardBody>
<Stack hasGutter>
<StackItem>
<Description title="Schema Name" isRequired>
<Title headingLevel="h6">{schema.name}</Title>
</Description>
</StackItem>
<StackItem>
<Description title="Description" isRequired>
<Title headingLevel="h6">
<ReadMore>{schema.description}</ReadMore>
</Title>
</Description>
</StackItem>
<StackItem>
<Description title="Type" isRequired>
<CatalogBigButton
title={apiOptions[schema.category].title}
desc={apiOptions[schema.category].desc}
image={`${config.baseURL}/images/${apiOptions[schema.category].image}`}
/>
</Description>
</StackItem>
<StackItem>
<Split hasGutter>
<SplitItem isFilled>
<Description title="App URL" isRequired>
<Title headingLevel="h6">{schema.appURL}</Title>
</Description>
</SplitItem>
<SplitItem isFilled>
<Description title="App Documentation URL" isRequired>
<Title headingLevel="h6">{schema.docURL}</Title>
</Description>
</SplitItem>
</Split>
</StackItem>
<StackItem>
<Description title="Environments">
{schema.environments.map((env, envIndex) => (
<div
style={{ border: '1px solid #d2d2d2' }}
className="pf-u-p-lg pf-u-mb-md"
key={`schema-${schemaIndex + 1}-env-${envIndex + 1}`}
>
<Grid hasGutter>
<GridItem span={6}>
<Description title="Name" isRequired>
<Title headingLevel="h6" className="uppercase">
{env.name}
</Title>
</Description>
</GridItem>
<GridItem span={6}>
<Description title="API Base Path" isRequired>
<Title headingLevel="h6">{env.apiBasePath}</Title>
</Description>
</GridItem>
<GridItem span={6}>
<Description title="API Schema Endpoint" isRequired>
<Title headingLevel="h6">{env.schemaEndpoint}</Title>
</Description>
</GridItem>
<GridItem span={12}>
<Description title="Headers" isRequired>
<DataList aria-label="header-list" isCompact>
{env.headers?.map(
({ key }, index) =>
key && (
<DataListItem key={`${key}-${index + 1}`}>
<DataListItemRow>
<DataListItemCells
dataListCells={[
<DataListCell key={`${key}-${index + 1}-cell-1`}>
<span>{key}</span>
</DataListCell>,
<DataListCell key={`${key}-${index + 1}-cell-2`}>
<span>********</span>
</DataListCell>,
]}
/>
</DataListItemRow>
</DataListItem>
)
)}
</DataList>
</Description>
</GridItem>
<GridItem span={12}>
<Checkbox
isChecked={env.isPublic}
isDisabled
id={`schema-${schemaIndex}-env-${envIndex}-isPublic`}
label="Is this API accessible from public?"
/>
</GridItem>
</Grid>
</div>
))}
</Description>
</StackItem>
</Stack>
</CardBody>
</Card>
</StackItem>
))}
</Stack>
);
}
Example #2
Source File: APIDescriptionPage.tsx From one-platform with MIT License | 4 votes |
APIDescriptionPage = (): JSX.Element => {
const { slug } = useParams();
const navigate = useNavigate();
const { handleDynamicCrumbs } = useBreadcrumb();
const urlParser = useURLParser();
const [selectedSchemaIndex, setSelectedSchemaIndex] = useState(0);
const [isSubscriptionOptionOpen, setIsSubscriptionOptionOpen] = useToggle();
const [isSchemaDropdownOpen, setIsSchemaDropdownOpen] = useToggle();
const [selectedSubscriptonEnv, setSelectedSubscriptionEnv] = useState<Record<
string,
boolean
> | null>(null);
const userInfo = opcBase.auth?.getUserInfo();
const [{ fetching: isSubscribing, data: subscribedNamespace }, handleSubscribeSchemaGQL] =
useSubscribeSchema();
const { isLoading: isNamespaceLoading, data: fetchedNamespace } = useGetANamespaceBySlug({
slug,
});
const namespace = subscribedNamespace?.subscribeApiSchema || fetchedNamespace?.getNamespaceBySlug;
const id = namespace?.id;
const schemas = namespace?.schemas || [];
const selectedSchema = namespace?.schemas[selectedSchemaIndex];
// effect to add breadcrumb data
useEffect(() => {
if (!isNamespaceLoading && namespace?.name && namespace?.id) {
handleDynamicCrumbs({
'api-name': { label: namespace.name, url: `/apis/${namespace?.slug}` },
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isNamespaceLoading, namespace?.name, namespace?.id]);
const hasEditAccess = useMemo(() => {
const userUuid = userInfo?.rhatUUID;
return hasUserApiEditAccess(userUuid as string, namespace);
}, [namespace, userInfo?.rhatUUID]);
const onMenuClick = (schemaId: string) => {
const index = namespace?.schemas.findIndex(({ id: sid }) => sid === schemaId);
if (index !== -1) {
setSelectedSchemaIndex(index || 0);
}
setIsSchemaDropdownOpen.off();
};
const hasSubscribed = selectedSchema?.environments.some(({ isSubscribed }) => isSubscribed);
const handleSchemaSubscription = async (envIDs?: string[]) => {
const subscribedIds =
envIDs ||
(hasSubscribed ? [] : (selectedSchema?.environments || []).map(({ id: sID }) => sID));
const subscriptionConfig = {
namespaceID: id as string,
schemaID: selectedSchema?.id || '',
envIDs: subscribedIds,
email: userInfo?.email || '',
};
try {
const res = await handleSubscribeSchemaGQL({ config: subscriptionConfig });
if (res.error) {
opcBase.toast.danger({
subject: `Failed to ${hasSubscribed ? 'unsubscribe' : 'subscribe'} api`,
body: res?.error?.message,
});
} else {
const subject = `${hasSubscribed ? 'Unsubscribed' : 'Subscribed'} to ${namespace?.name}`;
const body = `You will ${
hasSubscribed ? 'not be' : 'be'
} be notified regarding updates on this API`;
opcBase.toast.info({ subject, body });
}
} catch (error) {
opcBase.toast.danger({
subject: `Failed to ${hasSubscribed ? 'unsubscribe' : 'subscribe'} api`,
});
}
};
const onInitializeSelect = () => {
if (!isSubscriptionOptionOpen) {
const alreadySubscripedEnv = (selectedSchema?.environments || []).reduce<
Record<string, boolean>
>(
(prev, { isSubscribed, id: eId }) =>
isSubscribed ? { ...prev, [eId]: true } : { ...prev },
{}
);
setSelectedSubscriptionEnv(alreadySubscripedEnv);
}
setIsSubscriptionOptionOpen.toggle();
};
const onEnvSelect = (env: string) => {
const isEnvPresent = Boolean(selectedSubscriptonEnv?.[env]);
const state = { ...selectedSubscriptonEnv };
if (isEnvPresent) {
delete state[env];
setSelectedSubscriptionEnv(state);
} else {
state[env] = true;
setSelectedSubscriptionEnv(state);
}
};
const onEnvSelectBlur = async () => {
if (selectedSubscriptonEnv) {
await handleSchemaSubscription(Object.keys(selectedSubscriptonEnv));
}
setIsSubscriptionOptionOpen.off();
setSelectedSubscriptionEnv(null);
};
if (isNamespaceLoading) {
return (
<Bullseye>
<Spinner size="xl" />
</Bullseye>
);
}
if (!namespace) {
return (
<Bullseye>
<EmptyState>
<EmptyStateIcon icon={CubesIcon} />
<Title headingLevel="h4" size="lg">
Sorry, Couldn't find this API
</Title>
<Button variant="primary" onClick={() => navigate('../')}>
Go Back
</Button>
</EmptyState>
</Bullseye>
);
}
return (
<Stack>
<StackItem>
<PageSection isWidthLimited isCenterAligned>
<Grid hasGutter>
<GridItem span={8}>
<DetailsSection namespace={namespace} id={slug} hasEditAccess={hasEditAccess} />
</GridItem>
<GridItem span={4}>
<ApiSchemaList
schemas={namespace?.schemas}
onClick={onMenuClick}
selectedSchemaID={selectedSchema?.id}
/>
</GridItem>
</Grid>
</PageSection>
</StackItem>
<StackItem>
<PageSection
isWidthLimited
isCenterAligned
padding={{ default: 'noPadding' }}
className="pf-u-py-sm pf-u-px-md"
>
<Text component={TextVariants.small} className="pf-u-color-400">
API Schema
</Text>
</PageSection>
</StackItem>
<StackItem>
<Divider />
</StackItem>
<StackItem>
<PageSection isWidthLimited isCenterAligned className="pf-u-pb-4xl">
<Grid hasGutter>
{selectedSchema?.flags.isDeprecated && (
<Grid span={12}>
<Alert variant="danger" isInline title={`${selectedSchema.name} is deprecated`} />
</Grid>
)}
<GridItem span={8}>
<Stack
hasGutter
style={{ '--pf-l-stack--m-gutter--MarginBottom': '1.5rem' } as CSSProperties}
>
<StackItem className={styles.schemaContainer}>
<Split>
<SplitItem isFilled>
<Button
variant="link"
icon={<CaretDownIcon />}
onClick={setIsSchemaDropdownOpen.toggle}
iconPosition="right"
style={{ color: 'black' }}
className={styles.schemaDropdownTitle}
>
{selectedSchema?.name}
</Button>
</SplitItem>
<SplitItem className="pf-u-mr-lg">
<Label color={selectedSchema?.flags?.isInternal ? 'blue' : 'green'} isCompact>
{selectedSchema?.flags?.isInternal ? 'Internal API' : 'External API'}
</Label>
</SplitItem>
</Split>
<CSSTransition
in={isSchemaDropdownOpen}
timeout={200}
classNames="fade-in"
unmountOnExit
>
<Menu className={styles.schemaMenu}>
<MenuContent>
<MenuList className="pf-u-py-0">
{schemas.map((schema, index) => (
<Fragment key={schema.id}>
<MenuItem
className={css({
'menu-selected': schema.id === selectedSchema?.id,
})}
icon={
<Avatar
src={`${config.baseURL}/images/${
schema.category === 'REST'
? 'swagger-black-logo.svg'
: 'graphql-logo.svg'
}`}
alt="api-type"
size="sm"
style={{ width: '1.25rem', height: '1.25rem' }}
className="pf-u-mt-sm"
/>
}
onClick={() => onMenuClick(schema.id)}
>
<Split>
<SplitItem isFilled>{schema.name}</SplitItem>
<SplitItem>
<Label
color={schema.flags.isInternal ? 'blue' : 'green'}
isCompact
className="pf-u-ml-sm"
>
{schema.flags.isInternal ? 'Internal' : 'External'}
</Label>
</SplitItem>
</Split>
</MenuItem>
{schemas.length - 1 !== index && (
<Divider component="li" className="pf-u-my-0" />
)}
</Fragment>
))}
</MenuList>
</MenuContent>
</Menu>
</CSSTransition>
</StackItem>
<StackItem>
<ReadMore>{selectedSchema?.description || ''}</ReadMore>
</StackItem>
<StackItem>
<Split hasGutter>
<SplitItem isFilled>
<Title headingLevel="h3">Application URL</Title>
<a href={selectedSchema?.appURL} target="_blank" rel="noopener noreferrer">
<Text className="pf-u-color-400">
{urlParser(selectedSchema?.appURL || '')}
</Text>
</a>
</SplitItem>
<SplitItem isFilled>
<Title headingLevel="h3">Documentation URL</Title>
<a href={selectedSchema?.docURL} target="_blank" rel="noopener noreferrer">
<Text className="pf-u-color-400">
{urlParser(selectedSchema?.docURL || '')}
</Text>
</a>
</SplitItem>
</Split>
</StackItem>
<StackItem className="pf-u-mt-md">
<ApiEnvironmentSection
environments={selectedSchema?.environments}
category={selectedSchema?.category}
/>
</StackItem>
</Stack>
</GridItem>
<GridItem span={1} />
<GridItem span={3}>
<Stack hasGutter>
<StackItem className={styles.subscriptionContainer}>
<Split>
<SplitItem isFilled>
<Button
icon={<BellIcon />}
variant={hasSubscribed ? 'primary' : 'secondary'}
iconPosition="right"
isBlock
isLoading={isSubscribing}
className={css(hasSubscribed ? styles.subscriptionDropdownBtn : null)}
onClick={() => handleSchemaSubscription()}
>
{hasSubscribed ? 'Subscribed' : 'Subscribe'}
</Button>
</SplitItem>
<CSSTransition
in={hasSubscribed}
timeout={200}
classNames="fade-in"
unmountOnExit
>
<SplitItem>
<Button
icon={<CaretDownIcon />}
onClick={onInitializeSelect}
className={css('ignore-blur', styles.subscriptionDropdownArrow)}
/>
</SplitItem>
</CSSTransition>
</Split>
<CSSTransition
in={isSubscriptionOptionOpen}
timeout={200}
classNames="fade-in"
unmountOnExit
>
<Menu
className={styles.subscriptionMenu}
onBlur={(e) => {
if (!e.relatedTarget?.className?.includes('ignore-blur')) {
onEnvSelectBlur();
}
}}
>
<MenuContent>
<MenuList className="pf-u-py-0">
{selectedSchema?.environments.map(({ name, isSubscribed, id: envId }) => (
<MenuItem
className="uppercase ignore-blur"
isSelected={
selectedSubscriptonEnv
? selectedSubscriptonEnv[envId]
: isSubscribed
}
key={`subscription-${envId}`}
itemId={envId}
onClick={() => onEnvSelect(envId)}
>
{name}
</MenuItem>
))}
</MenuList>
</MenuContent>
</Menu>
</CSSTransition>
</StackItem>
<StackItem>
<ApiTypeCard category={selectedSchema?.category} />
</StackItem>
</Stack>
</GridItem>
</Grid>
</PageSection>
</StackItem>
</Stack>
);
}
Example #3
Source File: ApiDetailsCard.tsx From one-platform with MIT License | 4 votes |
ApiDetailsCard = ({
title,
owners = [],
schemas = [],
updatedAt,
}: Props): JSX.Element => {
const formatUpdatedAt = useCallback(
(apiUpdatedAt: string) => `modified on: ${dayjs(apiUpdatedAt).format('DD MMM YYYY hh:mm a')}`,
[]
);
const stopOnClickPropogation: DOMAttributes<HTMLDivElement>['onClick'] = (event) => {
event.stopPropagation();
};
return (
<Card className="catalog-card-hover-effect cursor-pointer">
<CardBody className="pf-u-px-md">
<Stack hasGutter>
<StackItem>
<Split hasGutter className="pf-l-flex pf-m-align-items-flex-end">
<SplitItem isFilled>
<Title headingLevel="h4" size={TitleSizes['2xl']}>
{title}
</Title>
</SplitItem>
<SplitItem>
<Text component={TextVariants.small} className="pf-u-color-400">
{formatUpdatedAt(updatedAt)}
</Text>
</SplitItem>
</Split>
</StackItem>
<StackItem>
<Split hasGutter>
<SplitItem>
<Split isWrappable onClick={stopOnClickPropogation}>
<SplitItem className="pf-u-mr-xs">
<Text>Owned by:</Text>
</SplitItem>
<ReadMore
limit={MAX_LOADED}
showMoreText={`+${(owners || []).length - MAX_LOADED} more`}
>
{owners.map((owner) => (
<SplitItem className="pf-u-ml-xs" key={owner}>
<Label isCompact color="cyan">
{owner}
</Label>
</SplitItem>
))}
</ReadMore>
</Split>
</SplitItem>
<SplitItem isFilled />
<SplitItem>
<Split onClick={stopOnClickPropogation} isWrappable>
<SplitItem className="pf-u-mr-sm">
<Text>Schema(s): </Text>
</SplitItem>
<ReadMore
limit={MAX_LOADED}
showMoreText={`+${(schemas || []).length - MAX_LOADED} more`}
>
{schemas.map(({ name, type }) => (
<SplitItem style={{ marginTop: '0.1rem' }} key={name}>
<Label
color="blue"
className="pf-u-mr-xs"
isCompact
icon={
<img
src={`${config.baseURL}/images/${
type === 'REST' ? 'swagger-black-logo.svg' : 'graphql-logo.svg'
}`}
alt="api-type"
className="pf-u-mt-xs"
style={{ height: '0.8rem', width: '0.8rem' }}
/>
}
>
{name}
</Label>
</SplitItem>
))}
</ReadMore>
</Split>
</SplitItem>
</Split>
</StackItem>
</Stack>
</CardBody>
</Card>
);
}
Example #4
Source File: FeedbackDetailCard.tsx From one-platform with MIT License | 4 votes |
FeedbackDetailCard = ({ feedback, isLoading }: Props): JSX.Element => {
const formatDate = useCallback((date: string) => {
return dayjs(date).format('DD MMMM YYYY');
}, []);
if (!feedback || isLoading) {
return (
<EmptyState>
<EmptyStateIcon
variant={isLoading ? 'container' : 'icon'}
component={isLoading ? Spinner : undefined}
icon={CubesIcon}
/>
<Title size="lg" headingLevel="h4">
{isLoading ? 'Loading' : 'No feedback found!!!'}
</Title>
</EmptyState>
);
}
const {
createdBy,
createdOn,
summary,
description,
error,
experience,
state,
module,
category,
assignee,
} = feedback;
return (
<Stack>
<StackItem>
<Stack hasGutter>
<StackItem>
<Title headingLevel="h6">
{(createdBy as FeedbackUserProfileAPI)?.cn} at {formatDate(createdOn)}
</Title>
<ReadMore>{summary}</ReadMore>
</StackItem>
<StackItem style={{ whiteSpace: 'pre-line', lineHeight: 1.75 }}>
<Title headingLevel="h6">Description</Title>
{/* // regex in html to remove <br/> tag */}
<ReadMore>{description.replace(/<br\/>/gi, '')}</ReadMore>
</StackItem>
<StackItem>
<Stack hasGutter>
<StackItem>
<Title headingLevel="h6">Details</Title>
<Divider />
</StackItem>
<StackItem>
<List isPlain isBordered>
<ListItem>
<Split hasGutter>
<SplitItem isFilled>Issue raised for</SplitItem>
<SplitItem>
<Label color="red" isCompact>
{module}
</Label>
</SplitItem>
</Split>
</ListItem>
<ListItem>
<Split hasGutter>
<SplitItem isFilled>Type</SplitItem>
<SplitItem>
<Label
color={category === FeedbackCategoryAPI.BUG ? 'red' : 'green'}
isCompact
>
{category}
</Label>
</SplitItem>
<SplitItem>
<Label color={error ? 'red' : 'green'} isCompact>
{error || experience}
</Label>
</SplitItem>
</Split>
</ListItem>
<ListItem>
<Split hasGutter>
<SplitItem isFilled>Status</SplitItem>
<SplitItem>
<Label color="red" isCompact>
{state}
</Label>
</SplitItem>
</Split>
</ListItem>
<ListItem>
<Split hasGutter>
<SplitItem isFilled>Assignee(s)</SplitItem>
{assignee?.name && (
<SplitItem>
<Label color="green" isCompact>
{assignee?.name}
</Label>
</SplitItem>
)}
</Split>
</ListItem>
</List>
</StackItem>
</Stack>
</StackItem>
</Stack>
</StackItem>
</Stack>
);
}