Просмотр исходного кода

Improved some styles and implemented delete

jnfrati 3 лет назад
Родитель
Сommit
93dde562c9

+ 82 - 258
dashboard/src/main/home/cluster-dashboard/stacks/_StackList.tsx

@@ -5,8 +5,9 @@ import api from "shared/api";
 import { Context } from "shared/Context";
 import Placeholder from "components/Placeholder";
 import styled from "styled-components";
-import { GetStacksResponse, Stack } from "./types";
+import { Stack } from "./types";
 import { readableDate } from "shared/string_utils";
+import { CardGrid, Card } from "./launch/components/styles";
 
 const StackList = ({ namespace }: { namespace: string }) => {
   const { currentProject, currentCluster, setCurrentError } = useContext(
@@ -14,6 +15,31 @@ const StackList = ({ namespace }: { namespace: string }) => {
   );
   const [stacks, setStacks] = useState<Stack[]>(null);
   const [isLoading, setIsLoading] = useState(true);
+  const [deleting, setDeleting] = useState<string | null>(null);
+
+  const handleDelete = (stack: Stack) => {
+    setDeleting(stack.id);
+    api
+      .deleteStack(
+        "<token>",
+        {},
+        {
+          namespace,
+          project_id: currentProject.id,
+          cluster_id: currentCluster.id,
+          stack_id: stack.id,
+        }
+      )
+      .then(() => {
+        setStacks((prev) => prev.filter((s) => s.id !== stack.id));
+      })
+      .catch((err) => {
+        setCurrentError(err);
+      })
+      .finally(() => {
+        setDeleting(null);
+      });
+  };
 
   useEffect(() => {
     let isSubscribed = true;
@@ -53,12 +79,10 @@ const StackList = ({ namespace }: { namespace: string }) => {
 
   if (stacks?.length === 0) {
     return (
-      <Placeholder
-        height="250px"
-      >
+      <Placeholder height="250px">
         <div>
-        <h3>No stacks found</h3>
-        <p>You can create a stack by clicking the "Create Stack" button.</p>
+          <h3>No stacks found</h3>
+          <p>You can create a stack by clicking the "Create Stack" button.</p>
         </div>
       </Placeholder>
     );
@@ -66,53 +90,66 @@ const StackList = ({ namespace }: { namespace: string }) => {
 
   return (
     <>
-      {stacks.map((stack) => (
-        <StackCard key={stack?.id}>
-          <LinkMask to={`/stacks/${namespace}/${stack?.id}`}  />
-          <DataContainer>
-            <StackName>
-              <StackIcon>
-                <i className="material-icons-outlined">lan</i>
-              </StackIcon>
-              <span>
-                {stack.name}
-              </span>
-            </StackName>
-
+      <CardGrid>
+        {stacks.map((stack) => (
+          <StackCard
+            as={DynamicLink}
+            key={stack?.id}
+            to={`/stacks/${namespace}/${stack?.id}`}
+          >
+            <DataContainer>
+              <StackName>
+                <StackIcon>
+                  <i className="material-icons-outlined">lan</i>
+                </StackIcon>
+                <span>{stack.name}</span>
+              </StackName>
+
+              <Flex>
+                <DeploymentImageContainer>
+                  <InfoWrapper>
+                    <LastDeployed>
+                      <Revision>
+                        {!stack.latest_revision?.id
+                          ? `No version found`
+                          : `v${stack.latest_revision.id}`}
+                      </Revision>
+                      <SepDot>•</SepDot>
+                      Last updated {readableDate(stack.updated_at)}
+                    </LastDeployed>
+                  </InfoWrapper>
+                </DeploymentImageContainer>
+              </Flex>
+            </DataContainer>
             <Flex>
-              <DeploymentImageContainer>
-                <InfoWrapper>
-                  <LastDeployed>
-                    <Revision>
-                    {!stack.latest_revision?.id
-                    ? `No version found`
-                    : `v${stack.latest_revision.id}`}
-                    </Revision>
-                    <SepDot>•</SepDot>
-                    Last updated {readableDate(stack.updated_at)}
-                  </LastDeployed>
-                </InfoWrapper>
-              </DeploymentImageContainer>
+              <RowButton
+                onClick={(e) => {
+                  e.preventDefault();
+                  e.stopPropagation();
+                  handleDelete(stack);
+                }}
+                disabled={
+                  deleting === stack.id || (deleting && deleting === stack.id)
+                }
+              >
+                <i className="material-icons">delete</i>
+
+                {deleting === stack.id ? <Loading /> : "Delete"}
+              </RowButton>
             </Flex>
-          </DataContainer>
-          <MinFlex>
-            <RowButton>
-              <i className="material-icons">delete</i>
-              Delete
-            </RowButton>
-          </MinFlex>
-        </StackCard>
-      ))}
+          </StackCard>
+        ))}
+      </CardGrid>
     </>
   );
 };
 
 export default StackList;
 
-const RowButton = styled.div`
+const RowButton = styled.button`
+  min-width: 82px;
   white-space: nowrap;
   font-size: 12px;
-  z-index: 999;
   padding: 8px 10px;
   font-weight: 400;
   height: 32px;
@@ -199,11 +236,6 @@ const Flex = styled.div`
   align-items: center;
 `;
 
-const MinFlex = styled.div`
-  display: flex;
-  align-items: center;
-`;
-
 const DataContainer = styled.div`
   display: flex;
   flex-direction: column;
@@ -212,215 +244,7 @@ const DataContainer = styled.div`
   overflow: hidden;
 `;
 
-const LinkMask = styled(DynamicLink)`
-  width: 100%;
-  height: 100%;
-  position: absolute;
-  top: 0;
-  left: 0;
-  z-index: 1;
-`;
-
-const StackCard = styled.div`
-  color: #ffffff;
-  display: flex;
-  font-weight: 500;
-  position: relative;
-  background: #2b2e3699;
-  justify-content: space-between;
-  border-radius: 5px;
+const StackCard = styled(Card)`
   font-size: 13px;
-  height: 75px;
-  padding: 12px;
-  padding-left: 14px;
-  border: 1px solid #ffffff2f;
-
-  animation: fadeIn 0.5s;
-  @keyframes fadeIn {
-    from {
-      opacity: 0;
-    }
-    to {
-      opacity: 1;
-    }
-  }
+  font-weight: 500;
 `;
-
-const mockApi = () =>
-  new Promise<{ data: GetStacksResponse }>((res) =>
-    setTimeout(() => res({ data: StacksMock }), 500)
-  );
-
-const StacksMock: GetStacksResponse = [
-  {
-    created_at: "2022-06-09T11:59:27.729463-04:00",
-    updated_at: "2022-06-09T11:59:27.729463-04:00",
-    name: "string",
-    id: "5433422f46f3ba52e49bb46dd1e12ab5",
-    latest_revision: {
-      created_at: "2022-06-09T11:59:27.731416-04:00",
-      id: 1,
-      status: "deploying",
-      stack_id: "5433422f46f3ba52e49bb46dd1e12ab5",
-      resources: [
-        {
-          created_at: "2022-06-09T11:59:27.732213-04:00",
-          updated_at: "2022-06-09T11:59:27.732213-04:00",
-          stack_id: "5433422f46f3ba52e49bb46dd1e12ab5",
-          stack_revision_id: 1,
-          name: "string",
-          id: "4b2cae112ca29203acdef784392e7ac0",
-          stack_app_data: {
-            template_repo_url: "",
-            template_name: "string",
-            template_version: "string",
-          },
-          stack_source_config: {
-            created_at: "2022-06-09T11:59:27.732334-04:00",
-            updated_at: "2022-06-09T11:59:27.732334-04:00",
-            stack_id: "5433422f46f3ba52e49bb46dd1e12ab5",
-            stack_revision_id: 1,
-            name: "my-source-config",
-            id: "0d6aa05dcb37e5a0a4e8febd4854dac2",
-            image_repo_uri: "image-repo-uri",
-            image_tag: "tag",
-          },
-        },
-      ],
-      source_configs: [
-        {
-          created_at: "2022-06-09T11:59:27.732334-04:00",
-          updated_at: "2022-06-09T11:59:27.732334-04:00",
-          stack_id: "5433422f46f3ba52e49bb46dd1e12ab5",
-          stack_revision_id: 1,
-          name: "my-source-config",
-          id: "0d6aa05dcb37e5a0a4e8febd4854dac2",
-          image_repo_uri: "image-repo-uri",
-          image_tag: "tag",
-        },
-      ],
-    },
-    revisions: [
-      {
-        created_at: "2022-06-09T11:59:27.731416-04:00",
-        id: 1,
-        status: "deploying",
-        stack_id: "5433422f46f3ba52e49bb46dd1e12ab5",
-      },
-    ],
-  },
-  {
-    created_at: "2022-06-09T11:59:27.729463-04:00",
-    updated_at: "2022-06-09T11:59:27.729463-04:00",
-    name: "string",
-    id: "9873422f46f3ba52e49bb46dd1e12ab5",
-    latest_revision: {
-      created_at: "2022-06-09T11:59:27.731416-04:00",
-      id: 1,
-      status: "deploying",
-      stack_id: "9873422f46f3ba52e49bb46dd1e12ab5",
-      resources: [
-        {
-          created_at: "2022-06-09T11:59:27.732213-04:00",
-          updated_at: "2022-06-09T11:59:27.732213-04:00",
-          stack_id: "9873422f46f3ba52e49bb46dd1e12ab5",
-          stack_revision_id: 1,
-          name: "string",
-          id: "4b2cae112ca29203acdef784392e7ac0",
-          stack_app_data: {
-            template_repo_url: "",
-            template_name: "string",
-            template_version: "string",
-          },
-          stack_source_config: {
-            created_at: "2022-06-09T11:59:27.732334-04:00",
-            updated_at: "2022-06-09T11:59:27.732334-04:00",
-            stack_id: "9873422f46f3ba52e49bb46dd1e12ab5",
-            stack_revision_id: 1,
-            name: "my-source-config",
-            id: "0d6aa05dcb37e5a0a4e8febd4854dac2",
-            image_repo_uri: "image-repo-uri",
-            image_tag: "tag",
-          },
-        },
-      ],
-      source_configs: [
-        {
-          created_at: "2022-06-09T11:59:27.732334-04:00",
-          updated_at: "2022-06-09T11:59:27.732334-04:00",
-          stack_id: "9873422f46f3ba52e49bb46dd1e12ab5",
-          stack_revision_id: 1,
-          name: "my-source-config",
-          id: "0d6aa05dcb37e5a0a4e8febd4854dac2",
-          image_repo_uri: "image-repo-uri",
-          image_tag: "tag",
-        },
-      ],
-    },
-    revisions: [
-      {
-        created_at: "2022-06-09T11:59:27.731416-04:00",
-        id: 1,
-        status: "deploying",
-        stack_id: "9873422f46f3ba52e49bb46dd1e12ab5",
-      },
-    ],
-  },
-  {
-    created_at: "2022-06-09T11:59:27.729463-04:00",
-    updated_at: "2022-06-09T11:59:27.729463-04:00",
-    name: "string",
-    id: "1753422f46f3ba52e49bb46dd1e12ab5",
-    latest_revision: {
-      created_at: "2022-06-09T11:59:27.731416-04:00",
-      id: 1,
-      status: "deploying",
-      stack_id: "1753422f46f3ba52e49bb46dd1e12ab5",
-      resources: [
-        {
-          created_at: "2022-06-09T11:59:27.732213-04:00",
-          updated_at: "2022-06-09T11:59:27.732213-04:00",
-          stack_id: "1753422f46f3ba52e49bb46dd1e12ab5",
-          stack_revision_id: 1,
-          name: "string",
-          id: "4b2cae112ca29203acdef784392e7ac0",
-          stack_app_data: {
-            template_repo_url: "",
-            template_name: "string",
-            template_version: "string",
-          },
-          stack_source_config: {
-            created_at: "2022-06-09T11:59:27.732334-04:00",
-            updated_at: "2022-06-09T11:59:27.732334-04:00",
-            stack_id: "1753422f46f3ba52e49bb46dd1e12ab5",
-            stack_revision_id: 1,
-            name: "my-source-config",
-            id: "0d6aa05dcb37e5a0a4e8febd4854dac2",
-            image_repo_uri: "image-repo-uri",
-            image_tag: "tag",
-          },
-        },
-      ],
-      source_configs: [
-        {
-          created_at: "2022-06-09T11:59:27.732334-04:00",
-          updated_at: "2022-06-09T11:59:27.732334-04:00",
-          stack_id: "1753422f46f3ba52e49bb46dd1e12ab5",
-          stack_revision_id: 1,
-          name: "my-source-config",
-          id: "0d6aa05dcb37e5a0a4e8febd4854dac2",
-          image_repo_uri: "image-repo-uri",
-          image_tag: "tag",
-        },
-      ],
-    },
-    revisions: [
-      {
-        created_at: "2022-06-09T11:59:27.731416-04:00",
-        id: 1,
-        status: "deploying",
-        stack_id: "1753422f46f3ba52e49bb46dd1e12ab5",
-      },
-    ],
-  },
-];

+ 6 - 8
dashboard/src/main/home/cluster-dashboard/stacks/launch/components/AppCard.tsx

@@ -5,8 +5,6 @@ import { hardcodedIcons } from "shared/hardcodedNameDict";
 
 import styled from "styled-components";
 
-const DeleteButton = ButtonWithIcon;
-
 export const AppCard = ({
   app,
 }: {
@@ -21,12 +19,12 @@ export const AppCard = ({
   return (
     <UnclickableCard>
       <Flex>
-      <Icon src={hardcodedIcons[app.template_name]} />
-      {app.name}
+        <Icon src={hardcodedIcons[app.template_name]} />
+        {app.name}
       </Flex>
-      <Delete onClick={handleDelete}>
+      <DeleteButton onClick={handleDelete}>
         <i className="material-icons-outlined">close</i>
-      </Delete>
+      </DeleteButton>
     </UnclickableCard>
   );
 };
@@ -38,7 +36,7 @@ const UnclickableCard = styled(Card)`
   }
 `;
 
-const Delete = styled(DeleteButton)`
+const DeleteButton = styled(ButtonWithIcon)`
   margin-right: 5px;
 `;
 
@@ -53,4 +51,4 @@ const Icon = styled.img`
   height: 30px;
   margin-right: 15px;
   margin-left: 5px;
-`;
+`;

+ 15 - 0
dashboard/src/shared/api.tsx

@@ -1995,6 +1995,20 @@ const rollbackStack = baseApi<
     `/api/v1/projects/${project_id}/clusters/${cluster_id}/namespaces/${namespace}/stacks/${stack_id}/rollback`
 );
 
+const deleteStack = baseApi<
+  {},
+  {
+    project_id: number;
+    cluster_id: number;
+    namespace: string;
+    stack_id: string;
+  }
+>(
+  "DELETE",
+  ({ project_id, cluster_id, namespace, stack_id }) =>
+    `/api/v1/projects/${project_id}/clusters/${cluster_id}/namespaces/${namespace}/stacks/${stack_id}`
+);
+
 // Bundle export to allow default api import (api.<method> is more readable)
 export default {
   checkAuth,
@@ -2184,4 +2198,5 @@ export default {
   getStackRevision,
   createStack,
   rollbackStack,
+  deleteStack,
 };