Ver código fonte

Add MetaData Tab (#3339)

sdess09 2 anos atrás
pai
commit
970f76f6ba

+ 3 - 0
dashboard/src/assets/copy-left.svg

@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M18 9.5999H20.4C21.0628 9.5999 21.6 10.1372 21.6 10.7999L21.6 19.5999C21.6 20.7045 20.7046 21.5999 19.6 21.5999L10.8 21.5999C10.1373 21.5999 9.60003 21.0626 9.60003 20.3999V17.9999M12 2.3999L4.80003 2.3999C3.47454 2.3999 2.40003 3.47442 2.40003 4.7999L2.40002 11.9999C2.40002 13.3254 3.47454 14.3999 4.80002 14.3999L12 14.3999C13.3255 14.3999 14.4 13.3254 14.4 11.9999L14.4 4.7999C14.4 3.47442 13.3255 2.3999 12 2.3999Z" stroke="white" stroke-width="2" stroke-linecap="round"/>
+</svg>

+ 16 - 17
dashboard/src/main/home/app-dashboard/expanded-app/env-vars/EnvGroupModal.tsx

@@ -66,11 +66,11 @@ const EnvGroupModal: React.FC<Props> = ({
           "<token>",
           {},
           {
-            id: currentProject.id,
-            cluster_id: currentCluster.id,
+            id: currentProject?.id,
+            cluster_id: currentCluster?.id,
           }
         )
-        .then((res) => res.data.environment_groups);
+        .then((res) => res.data?.environment_groups);
     } catch (error) {
       setLoading(false)
       setError(true);
@@ -114,27 +114,26 @@ const EnvGroupModal: React.FC<Props> = ({
         </LoadingWrapper>
       );
     } else {
-      const sortedEnvGroups = envGroups.slice().sort((a, b) => a.name.localeCompare(b.name));
-
-      return sortedEnvGroups
-        .filter((envGroup) => {
-          if (!Array.isArray(syncedEnvGroups)) {
-            return true;
-          }
-          return !syncedEnvGroups.find(
-            (syncedEnvGroup) => syncedEnvGroup.name === envGroup.name
-          );
-        })
+      const sortedEnvGroups = envGroups?.slice().sort((a, b) => a.name.localeCompare(b.name));
+
+      return sortedEnvGroups?.filter((envGroup) => {
+        if (!Array.isArray(syncedEnvGroups)) {
+          return true;
+        }
+        return !syncedEnvGroups?.find(
+          (syncedEnvGroup) => syncedEnvGroup?.name === envGroup?.name
+        );
+      })
         .map((envGroup: any, i: number) => {
           return (
             <EnvGroupRow
               key={i}
               isSelected={selectedEnvGroup === envGroup}
-              lastItem={i === envGroups.length - 1}
+              lastItem={i === envGroups?.length - 1}
               onClick={() => setSelectedEnvGroup(envGroup)}
             >
               <img src={sliders} />
-              {envGroup.name}
+              {envGroup?.name}
             </EnvGroupRow>
           );
         });
@@ -175,7 +174,7 @@ const EnvGroupModal: React.FC<Props> = ({
       <ColumnContainer>
 
         <ScrollableContainer>
-          {syncedEnvGroups.length != envGroups.length ? (<>
+          {syncedEnvGroups?.length != envGroups?.length ? (<>
             <Text color="helper">
               Select an Env Group to load into your application.
             </Text>

+ 124 - 0
dashboard/src/main/home/project-settings/Metadata.tsx

@@ -0,0 +1,124 @@
+import React, { useContext, useEffect, useState } from "react";
+import styled from "styled-components";
+
+import github from "assets/github.png";
+
+import { Context } from "../../../shared/Context";
+import api from "../../../shared/api";
+import Loading from "../../../components/Loading";
+import Heading from "components/form-components/Heading";
+import Helper from "components/form-components/Helper";
+
+import TabSelector from "components/TabSelector";
+import Link from "components/porter/Link";
+import Spacer from "components/porter/Spacer";
+import Text from "components/porter/Text";
+import CopyToClipboard from "components/CopyToClipboard";
+import copy from "assets/copy-left.svg"
+import Icon from "components/porter/Icon";
+import { ClusterType } from "shared/types";
+
+type Props = {
+};
+
+const Metadata: React.FC<Props> = ({
+}) => {
+    const [isExpanded, setIsExpanded] = useState(false);
+    const { currentProject } = useContext(Context);
+    const [clusters, setClusters] = useState<ClusterType[]>([]);
+    const [registries, setRegistries] = useState<any[]>(null);
+    // Add name as a property of the component
+    const IdTextWithCopy = ({ id, name }: { id: number, name: string }) => (
+        <IdContainer>
+            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
+                <span style={{ fontSize: '0.8em', marginRight: '10px' }}> {name}</span>
+                <div style={{ display: 'flex', alignItems: 'center' }}>
+                    <span style={{ fontSize: '0.8em', marginRight: '5px' }}>Id: {id}</span>
+                    <CopyToClipboard text={id.toString()}>
+                        <img src={copy} alt="copy" style={{ cursor: "pointer", marginLeft: "5px", marginRight: "5px", width: "10px", height: "10px" }} />
+                    </CopyToClipboard>
+                </div>
+            </div>
+        </IdContainer>
+    );
+
+
+    useEffect(() => {
+        if (currentProject) {
+            const project_id = currentProject.id;
+
+            api
+                .getProjectRegistries("<token>", {}, { id: project_id })
+                .then((res: any) => {
+                    setRegistries(res.data);
+                })
+                .catch((err: any) => console.log(err));
+
+            api
+                .getClusters("<token>", {}, { id: currentProject?.id })
+                .then((res) => {
+                    if (res.data) {
+                        let clusters = res.data;
+                        clusters.sort((a: any, b: any) => a.id - b.id);
+                        if (clusters.length > 0) {
+                            let options = clusters.map((item: { name: any; vanity_name: string; }) => ({
+                                label: (item.vanity_name ? item.vanity_name : item.name),
+                                value: item.name
+                            }));
+                            setClusters(clusters);
+                        }
+                    }
+                });
+        }
+    }, [currentProject]);
+
+    return (
+        <>
+            <Text>Project Id: </Text>
+            <IdTextWithCopy id={currentProject?.id} name={currentProject?.name} /> {/* Assuming currentProject has name field */}
+            <Spacer y={1} />
+            {clusters?.length > 0 && <>
+                <Text>Cluster Ids:</Text>
+                {clusters?.length > 0 &&
+                    clusters.map((cluster, index) =>
+                        <IdTextWithCopy key={index} id={cluster.id} name={cluster.name} />
+                    )
+                }
+            </>
+            }
+            <Spacer y={1} />
+
+            {registries?.length > 0 &&
+                <>
+                    <Text>Registry Ids:</Text>
+                    {registries?.length > 0 &&
+                        registries.map((registry, index) =>
+                            <IdTextWithCopy key={index} id={registry.id} name={registry.name} />
+                        )
+                    }
+                </>}
+
+        </>
+    );
+};
+
+export default Metadata;
+
+const IdContainer = styled.div`
+    color: #aaaabb;
+    border-radius: 5px;
+    padding: 5px;
+    display: block;
+    width: 100%;
+    border-radius: 5px;
+    border: 1px solid ${({ theme }) => theme.border};
+    margin-bottom: 10px;
+    margin-top: 5px;
+`;
+
+// const BoxContainer = styled.div`
+// color: #aaaabb;
+// border-radius: 5px;
+// background: ${({ theme }) => theme.fg}};
+// border: 1px solid ${({ theme }) => theme.border};
+// `;

+ 5 - 2
dashboard/src/main/home/project-settings/ProjectSettings.tsx

@@ -17,6 +17,7 @@ import _ from "lodash";
 import Link from "components/porter/Link";
 import Spacer from "components/porter/Spacer";
 import ProjectDeleteConsent from "./ProjectDeleteConsent";
+import Metadata from "./Metadata";
 
 type PropsType = RouteComponentProps & WithAuthProps & {};
 
@@ -74,7 +75,6 @@ class ProjectSettings extends Component<PropsType, StateType> {
     if (this.state.projectName !== currentProject.name) {
       this.setState({ projectName: currentProject.name });
     }
-
     const tabOptions = [];
     tabOptions.push({ value: "manage-access", label: "Manage access" });
     // ? Disabled for now https://discord.com/channels/542888846271184896/1059277393031856208/1059277395913351258
@@ -82,7 +82,7 @@ class ProjectSettings extends Component<PropsType, StateType> {
     //   value: "billing",
     //   label: "Billing",
     // });
-
+    tabOptions.push({ value: "metadata", label: "Metadata" });
     if (this.props.isAuthorized("settings", "", ["get", "delete"])) {
       // if (this.context?.hasBillingEnabled) {
       //   tabOptions.push({
@@ -128,6 +128,9 @@ class ProjectSettings extends Component<PropsType, StateType> {
 
     if (this.state.currentTab === "manage-access") {
       return <InvitePage />;
+    }
+    else if (this.state.currentTab == "metadata") {
+      return <Metadata />
     } else if (this.state.currentTab === "api-tokens") {
       return <APITokensSection />;
     } else if (this.state.currentTab === "billing") {