github.com/freiheit-com/kuberpult@v1.24.2-0.20240328135542-315d5630abe6/services/frontend-service/src/ui/utils/Links.tsx (about)

     1  /*This file is part of kuberpult.
     2  
     3  Kuberpult is free software: you can redistribute it and/or modify
     4  it under the terms of the Expat(MIT) License as published by
     5  the Free Software Foundation.
     6  
     7  Kuberpult is distributed in the hope that it will be useful,
     8  but WITHOUT ANY WARRANTY; without even the implied warranty of
     9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    10  MIT License for more details.
    11  
    12  You should have received a copy of the MIT License
    13  along with kuberpult. If not, see <https://directory.fsf.org/wiki/License:Expat>.
    14  
    15  Copyright 2023 freiheit.com*/
    16  
    17  import React from 'react';
    18  import { useArgoCdBaseUrl, useSourceRepoUrl, useBranch, useManifestRepoUrl } from './store';
    19  
    20  export const deriveArgoAppLink = (baseUrl: string | undefined, app: string): string | undefined => {
    21      if (baseUrl) {
    22          const baseUrlSlash = baseUrl.endsWith('/') ? baseUrl : baseUrl + '/';
    23          return baseUrlSlash + 'applications?search=-' + app;
    24      }
    25      return undefined;
    26  };
    27  
    28  export const deriveArgoAppEnvLink = (
    29      baseUrl: string | undefined,
    30      app: string,
    31      env: string,
    32      namespace: string
    33  ): string | undefined => {
    34      if (baseUrl) {
    35          const baseUrlSlash = baseUrl.endsWith('/') ? baseUrl : baseUrl + '/';
    36          return `${baseUrlSlash}applications/${namespace}/${env}-${app}`;
    37      }
    38      return undefined;
    39  };
    40  
    41  export const deriveArgoTeamLink = (baseUrl: string | undefined, team: string): string | undefined => {
    42      if (baseUrl) {
    43          const baseUrlSlash = baseUrl.endsWith('/') ? baseUrl : baseUrl + '/';
    44          return baseUrlSlash + 'applications?&labels=' + encodeURIComponent('com.freiheit.kuberpult/team=') + team;
    45      }
    46      return undefined;
    47  };
    48  
    49  export const deriveSourceCommitLink = (
    50      baseUrl: string | undefined,
    51      branch: string | undefined,
    52      commit: string
    53  ): string | undefined => {
    54      if (baseUrl && branch) {
    55          baseUrl = baseUrl.replace(/{branch}/gi, branch);
    56          baseUrl = baseUrl.replace(/{commit}/gi, commit);
    57          return baseUrl;
    58      }
    59      return undefined;
    60  };
    61  
    62  export const deriveReleaseDirLink = (
    63      baseUrl: string | undefined,
    64      branch: string | undefined,
    65      app: string,
    66      version: number
    67  ): string | undefined => {
    68      if (baseUrl && branch) {
    69          baseUrl = baseUrl.replace(/{branch}/gi, branch);
    70          baseUrl = baseUrl.replace(/{dir}/gi, 'applications/' + app + '/releases/' + version);
    71          return baseUrl;
    72      }
    73      return undefined;
    74  };
    75  
    76  export const getCommitHistoryLink = (commitId: string | undefined): string | undefined => {
    77      if (commitId) {
    78          return '/ui/commits/' + commitId;
    79      }
    80      return undefined;
    81  };
    82  
    83  export const ArgoTeamLink: React.FC<{ team: string | undefined }> = (props): JSX.Element | null => {
    84      const { team } = props;
    85      const argoBaseUrl = useArgoCdBaseUrl();
    86      if (!team) {
    87          return null;
    88      }
    89      if (!argoBaseUrl) {
    90          // just render as text, because we do not have a base url:
    91          return <span>{team}</span>;
    92      }
    93      return (
    94          <span>
    95              {' | Team: '}
    96              <a title={'Opens the team in ArgoCd'} href={deriveArgoTeamLink(argoBaseUrl, team)}>
    97                  {team}
    98              </a>
    99          </span>
   100      );
   101  };
   102  
   103  export const ArgoAppLink: React.FC<{ app: string }> = (props): JSX.Element => {
   104      const { app } = props;
   105      const argoBaseUrl = useArgoCdBaseUrl();
   106      if (!argoBaseUrl) {
   107          // just render as text, because we do not have a base url:
   108          return <span>{app}</span>;
   109      }
   110      return (
   111          <a title={'Opens this app in ArgoCd for all environments'} href={deriveArgoAppLink(argoBaseUrl, app)}>
   112              {app}
   113          </a>
   114      );
   115  };
   116  
   117  export const ArgoAppEnvLink: React.FC<{ app: string; env: string; namespace: string | undefined }> = (
   118      props
   119  ): JSX.Element => {
   120      const { app, env, namespace } = props;
   121      const argoBaseUrl = useArgoCdBaseUrl();
   122      if (!argoBaseUrl) {
   123          // just render as text, because we do not have a base url:
   124          return <span>{env}</span>;
   125      }
   126      return (
   127          <a
   128              title={'Opens the app in ArgoCd for this environment'}
   129              href={namespace ? deriveArgoAppEnvLink(argoBaseUrl, app, env, namespace) : undefined}>
   130              {env}
   131          </a>
   132      );
   133  };
   134  
   135  export const DisplaySourceLink: React.FC<{ displayString: string; commitId: string }> = (props): JSX.Element | null => {
   136      const { commitId, displayString } = props;
   137      const sourceRepo = useSourceRepoUrl();
   138      const branch = useBranch();
   139      const sourceLink = deriveSourceCommitLink(sourceRepo, branch, commitId);
   140      if (sourceLink) {
   141          return (
   142              <a title={'Opens the commit for this release in the source repository'} href={sourceLink}>
   143                  {displayString}
   144              </a>
   145          );
   146      }
   147      return null;
   148  };
   149  
   150  export const DisplayManifestLink: React.FC<{ displayString: string; app: string; version: number }> = (
   151      props
   152  ): JSX.Element | null => {
   153      const { displayString, app, version } = props;
   154      const manifestRepo = useManifestRepoUrl();
   155      const branch = useBranch();
   156      const manifestLink = deriveReleaseDirLink(manifestRepo, branch, app, version);
   157      if (manifestLink && version) {
   158          return (
   159              <a title={'Opens the release directory in the manifest repository for this release'} href={manifestLink}>
   160                  {displayString}
   161              </a>
   162          );
   163      }
   164      return null;
   165  };
   166  
   167  export const DisplayCommitHistoryLink: React.FC<{ displayString: string; commitId: string }> = (
   168      props
   169  ): JSX.Element | null => {
   170      const { displayString, commitId } = props;
   171      if (commitId) {
   172          const listLink = getCommitHistoryLink(commitId);
   173          return (
   174              <a title={'Opens the commit history'} href={listLink}>
   175                  {displayString}
   176              </a>
   177          );
   178      }
   179  
   180      return null;
   181  };
   182  
   183  type Query = {
   184      key: string;
   185      value: string | null;
   186  };
   187  
   188  const toQueryString = (queries: Query[]): string => {
   189      const str: string[] = [];
   190      queries.forEach((q: Query) => {
   191          if (q.value) {
   192              str.push(encodeURIComponent(q.key) + '=' + encodeURIComponent(q.value));
   193          }
   194      });
   195      return str.join('&');
   196  };
   197  
   198  export const ProductVersionLink: React.FC<{ env: string; groupName: string }> = (props): JSX.Element | null => {
   199      const { env, groupName } = props;
   200  
   201      const separator = groupName === '' ? '' : '/';
   202  
   203      const urlParams = new URLSearchParams(window.location.search);
   204      const teams = urlParams.get('teams');
   205      const queryString = toQueryString([
   206          { key: 'env', value: groupName + separator + env },
   207          { key: 'teams', value: teams },
   208      ]);
   209  
   210      const currentLink = window.location.href;
   211      const addParam = currentLink.split('?');
   212      return (
   213          <a
   214              title={'Opens the release directory in the manifest repository for this release'}
   215              href={addParam[0] + '/productVersion?' + queryString}>
   216              Display Version for {env}
   217          </a>
   218      );
   219  };
   220  
   221  export const KuberpultGitHubLink: React.FC<{ version: string }> = (props): JSX.Element | null => {
   222      const { version } = props;
   223      return (
   224          <a
   225              title={'Opens the Kuberpult Readme for the current version ' + version}
   226              href={'https://github.com/freiheit-com/kuberpult/blob/' + version + '/README.md'}>
   227              {version}
   228          </a>
   229      );
   230  };
   231  
   232  const hideWithoutWarningsParamName = 'hideWithoutWarnings';
   233  const hideWithoutWarningsParamEnabledValue = 'Y';
   234  export const hideWithoutWarnings = (params: URLSearchParams): boolean => {
   235      const hideWithoutWarningsParam = params.get(hideWithoutWarningsParamName) || '';
   236      return hideWithoutWarningsParam === hideWithoutWarningsParamEnabledValue;
   237  };
   238  export const setHideWithoutWarnings = (params: URLSearchParams, newValue: boolean): void => {
   239      if (newValue) {
   240          params.set(hideWithoutWarningsParamName, hideWithoutWarningsParamEnabledValue);
   241      } else {
   242          params.delete(hideWithoutWarningsParamName);
   243      }
   244  };
   245  
   246  const envConfigDialogParamName = 'dialog-env-config';
   247  export const getOpenEnvironmentConfigDialog = (params: URLSearchParams): string =>
   248      params.get(envConfigDialogParamName) || '';
   249  export const setOpenEnvironmentConfigDialog = (params: URLSearchParams, envName: string): void => {
   250      if (envName.length > 0) {
   251          params.set(envConfigDialogParamName, envName);
   252      } else {
   253          params.delete(envConfigDialogParamName);
   254      }
   255  };