utils#hasUserApiEditAccess TypeScript Examples

The following examples show how to use utils#hasUserApiEditAccess. 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: 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>
  );
}