🏡 index : ~doyle/chartered.git

author Jordan Doyle <jordan@doyle.la> 2021-09-28 17:15:32.0 +01:00:00
committer Jordan Doyle <jordan@doyle.la> 2021-09-28 17:15:32.0 +01:00:00
commit
797ddfa046c70bea55313ee48e66bdb1c362608b [patch]
tree
230dc1b0f3eebbae8bb23d8ee6494c08171ef1e5
parent
9ef7e8c46391ffc3c53879ae40c72fc724780235
download
797ddfa046c70bea55313ee48e66bdb1c362608b.tar.gz

Less flashing from loading page on org/ssh key pages



Diff

 migrations/2021-08-31-214501_create_crates_table/up.sql          |   1 +
 chartered-frontend/src/pages/Loading.tsx                         |  12 +++++++++++-
 chartered-frontend/src/pages/organisations/ListOrganisations.tsx |  70 +++++++++++++++++++++++++++++++++++++++++++++-------------------------
 chartered-frontend/src/pages/ssh-keys/ListSshKeys.tsx            | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
 4 files changed, 123 insertions(+), 113 deletions(-)

diff --git a/migrations/2021-08-31-214501_create_crates_table/up.sql b/migrations/2021-08-31-214501_create_crates_table/up.sql
index fd57f0a..4f94311 100644
--- a/migrations/2021-08-31-214501_create_crates_table/up.sql
+++ a/migrations/2021-08-31-214501_create_crates_table/up.sql
@@ -5,6 +5,7 @@
);

INSERT INTO users (id, uuid, username) VALUES (1, X'936DA01F9ABD4D9D80C702AF85C822A8', "admin");
INSERT INTO users (id, uuid, username) VALUES (2, X'936DA01F9ABD4D9D80C702AF85C822A9', "billy");

CREATE TABLE organisations (
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
diff --git a/chartered-frontend/src/pages/Loading.tsx b/chartered-frontend/src/pages/Loading.tsx
index 90055d1..a92e405 100644
--- a/chartered-frontend/src/pages/Loading.tsx
+++ a/chartered-frontend/src/pages/Loading.tsx
@@ -1,6 +1,16 @@
import React = require("react");

export default function Loading() {
export function LoadingSpinner() {
  return (
    <div className="p-4 d-flex justify-content-center align-items-center">
      <div className="spinner-border text-primary" role="status">
        <span className="visually-hidden">Loading...</span>
      </div>
    </div>
  );
}

export default function LoadingPage() {
  return (
    <div className="min-vh-100 bg-primary d-flex justify-content-center align-items-center">
      <div className="spinner-border text-light" role="status">
diff --git a/chartered-frontend/src/pages/organisations/ListOrganisations.tsx b/chartered-frontend/src/pages/organisations/ListOrganisations.tsx
index bcafc46..7e00c09 100644
--- a/chartered-frontend/src/pages/organisations/ListOrganisations.tsx
+++ a/chartered-frontend/src/pages/organisations/ListOrganisations.tsx
@@ -6,7 +6,7 @@
import { useAuth } from "../../useAuth";
import { RoundedPicture, useAuthenticatedRequest } from "../../util";
import ErrorPage from "../ErrorPage";
import Loading from "../Loading";
import { LoadingSpinner } from "../Loading";

interface Response {
  organisations: ResponseOrganisations[];
@@ -27,8 +27,6 @@

  if (error) {
    return <ErrorPage message={error} />;
  } else if (!list) {
    return <Loading />;
  }

  return (
@@ -39,38 +37,40 @@
        <h1>Your Organisations</h1>

        <div className="card border-0 shadow-sm text-black">
          {list.organisations.length === 0 ? (
            <div className="card-body">
              You don't belong to any organisations yet.
            </div>
          ) : (
            <table className="table table-striped">
              <tbody>
                {list.organisations.map((v, i) => (
                  <tr key={i}>
                    <td className="align-middle fit">
                      <RoundedPicture
                        src="http://placekitten.com/48/48"
                        height="48px"
                        width="48px"
                      />
                    </td>

                    <td className="align-middle" style={{ lineHeight: "1.1" }}>
                      <div>
                        <Link to={`/crates/${v.name}`}>{v.name}</Link>
                      </div>
                      <div>
                        <small style={{ fontSize: "0.75rem" }}>
                          {v.description}
                        </small>
                      </div>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          )}
          {!list ? <LoadingSpinner /> : <>
            {list.organisations.length === 0 ? (
                <div className="card-body">
                You don't belong to any organisations yet.
                </div>
            ) : (
                <table className="table table-striped">
                <tbody>
                    {list.organisations.map((v, i) => (
                    <tr key={i}>
                        <td className="align-middle fit">
                        <RoundedPicture
                            src="http://placekitten.com/48/48"
                            height="48px"
                            width="48px"
                        />
                        </td>

                        <td className="align-middle" style={{ lineHeight: "1.1" }}>
                        <div>
                            <Link to={`/crates/${v.name}`}>{v.name}</Link>
                        </div>
                        <div>
                            <small style={{ fontSize: "0.75rem" }}>
                            {v.description}
                            </small>
                        </div>
                        </td>
                    </tr>
                    ))}
                </tbody>
                </table>
            )}
          </>}
        </div>

        <Link
diff --git a/chartered-frontend/src/pages/ssh-keys/ListSshKeys.tsx b/chartered-frontend/src/pages/ssh-keys/ListSshKeys.tsx
index 48938c2..e446ec8 100644
--- a/chartered-frontend/src/pages/ssh-keys/ListSshKeys.tsx
+++ a/chartered-frontend/src/pages/ssh-keys/ListSshKeys.tsx
@@ -10,7 +10,7 @@
import { Button, Modal, OverlayTrigger, Tooltip } from "react-bootstrap";
import HumanTime from "react-human-time";
import ErrorPage from "../ErrorPage";
import Loading from "../Loading";
import Loading, { LoadingSpinner } from "../Loading";

interface SshKeysResponse {
  keys: SshKeysResponseKey[];
@@ -42,8 +42,6 @@

  if (loadError) {
    return <ErrorPage message={loadError} />;
  } else if (!sshKeys) {
    return <Loading />;
  }

  const deleteKey = async () => {
@@ -99,81 +97,82 @@
        </div>

        <div className="card border-0 shadow-sm text-black">
          {sshKeys.keys.length == 0 ? (
            <div className="card-body">You haven't added any SSH keys yet</div>
          ) : (
            <></>
          )}
          <div className="table-responsive">
            <table className="table table-striped">
              <tbody>
                {sshKeys.keys.map((key) => (
                  <tr key={key.uuid}>
                    <td className="align-middle">
                      <h6 className="m-0 lh-sm">{key.name}</h6>
                      <pre className="m-0">{key.fingerprint}</pre>
                      <div className="lh-sm" style={{ fontSize: ".75rem" }}>
                        <div className="text-muted d-inline-block me-3">
                          Added{" "}
                          <OverlayTrigger
                            overlay={
                              <Tooltip id={`${key.uuid}-created-at`}>
                                {new Date(key.created_at).toLocaleString()}
                              </Tooltip>
                            }
                          >
                            <span className="text-decoration-underline-dotted">
                              <HumanTime
                                time={new Date(key.created_at).getTime()}
                              />
                            </span>
                          </OverlayTrigger>
                        </div>
                        <span
                          className={`text-${
                            key.last_used_at
                              ? new Date(key.last_used_at) > dateMonthAgo
                                ? "success"
                                : "danger"
                              : "muted"
                          }`}
                        >
                          Last used{" "}
                          {key.last_used_at ? (
                            <OverlayTrigger
                              overlay={
                                <Tooltip id={`${key.uuid}-last-used`}>
                                  {new Date(key.last_used_at).toLocaleString()}
                                </Tooltip>
                              }
          {!sshKeys ? <LoadingSpinner /> : <>
            {sshKeys.keys.length == 0 ? (
              <div className="card-body">You haven't added any SSH keys yet.</div>
            ) : (
              <div className="table-responsive">
                <table className="table table-striped">
                  <tbody>
                    {sshKeys.keys.map((key) => (
                      <tr key={key.uuid}>
                        <td className="align-middle">
                          <h6 className="m-0 lh-sm">{key.name}</h6>
                          <pre className="m-0">{key.fingerprint}</pre>
                          <div className="lh-sm" style={{ fontSize: ".75rem" }}>
                            <div className="text-muted d-inline-block me-3">
                              Added{" "}
                              <OverlayTrigger
                                overlay={
                                  <Tooltip id={`${key.uuid}-created-at`}>
                                    {new Date(key.created_at).toLocaleString()}
                                  </Tooltip>
                                }
                              >
                                <span className="text-decoration-underline-dotted">
                                  <HumanTime
                                    time={new Date(key.created_at).getTime()}
                                  />
                                </span>
                              </OverlayTrigger>
                            </div>
                            <span
                              className={`text-${
                                key.last_used_at
                                  ? new Date(key.last_used_at) > dateMonthAgo
                                    ? "success"
                                    : "danger"
                                  : "muted"
                              }`}
                            >
                              <span className="text-decoration-underline-dotted">
                                <HumanTime
                                  time={new Date(key.last_used_at).getTime()}
                                />
                              </span>
                            </OverlayTrigger>
                          ) : (
                            <>never</>
                          )}
                        </span>
                      </div>
                    </td>

                    <td className="align-middle fit">
                      <button
                        type="button"
                        className="btn text-danger"
                        onClick={() => setDeleting(key)}
                      >
                        <Trash />
                      </button>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
                              Last used{" "}
                              {key.last_used_at ? (
                                <OverlayTrigger
                                  overlay={
                                    <Tooltip id={`${key.uuid}-last-used`}>
                                      {new Date(key.last_used_at).toLocaleString()}
                                    </Tooltip>
                                  }
                                >
                                  <span className="text-decoration-underline-dotted">
                                    <HumanTime
                                      time={new Date(key.last_used_at).getTime()}
                                    />
                                  </span>
                                </OverlayTrigger>
                              ) : (
                                <>never</>
                              )}
                            </span>
                          </div>
                        </td>

                        <td className="align-middle fit">
                          <button
                            type="button"
                            className="btn text-danger"
                            onClick={() => setDeleting(key)}
                          >
                            <Trash />
                          </button>
                        </td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            )}
          </>}
        </div>

        <Link