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 vote down vote up
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 vote down vote up
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&apos;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 vote down vote up
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 vote down vote up
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>
  );
}