Skip to content

Commit

Permalink
wip v1 secrets
Browse files Browse the repository at this point in the history
  • Loading branch information
leafty committed Nov 28, 2024
1 parent 1c1523f commit d2dc4b9
Show file tree
Hide file tree
Showing 19 changed files with 166 additions and 246 deletions.
13 changes: 8 additions & 5 deletions client/src/components/navbar/NavBarItems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -281,10 +281,14 @@ export function RenkuToolbarNotifications({
}

interface RenkuToolbarItemUserProps {
isV2?: boolean;
params: AppParams;
}

export function RenkuToolbarItemUser({ params }: RenkuToolbarItemUserProps) {
export function RenkuToolbarItemUser({
isV2,
params,
}: RenkuToolbarItemUserProps) {
const user = useLegacySelector<User>((state) => state.stateModel.user);

const { renku10Enabled } = useAppSelector(({ featureFlags }) => featureFlags);
Expand All @@ -305,6 +309,8 @@ export function RenkuToolbarItemUser({ params }: RenkuToolbarItemUserProps) {
);
}

const userSecretsUrl = isV2 ? ABSOLUTE_ROUTES.v2.secrets : "/secrets";

return (
<UncontrolledDropdown className="nav-item dropdown">
<DropdownToggle
Expand Down Expand Up @@ -333,7 +339,7 @@ export function RenkuToolbarItemUser({ params }: RenkuToolbarItemUserProps) {
/>
</DropdownItem>

<Link to="/secrets" className="dropdown-item">
<Link to={userSecretsUrl} className="dropdown-item">
User Secrets
</Link>

Expand All @@ -351,9 +357,6 @@ export function RenkuToolbarItemUser({ params }: RenkuToolbarItemUserProps) {
>
Renku 2.0 Settings
</Link>
<Link to={ABSOLUTE_ROUTES.v2.secrets} className="dropdown-item">
Renku 2.0 Secrets (temp)
</Link>
</>
)}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@
*/
import cx from "classnames";
import { useMemo, useRef } from "react";
import { Link, generatePath } from "react-router-dom-v5-compat";
import { Offcanvas, OffcanvasBody, UncontrolledTooltip } from "reactstrap";
import {
InfoCircleFill,
Folder,
Gear,
InfoCircleFill,
Key,
Lock,
PersonBadge,
} from "react-bootstrap-icons";
import { Link, generatePath } from "react-router-dom-v5-compat";
import { Offcanvas, OffcanvasBody, UncontrolledTooltip } from "reactstrap";

import { Clipboard } from "../../../components/clipboard/Clipboard";
import { Loader } from "../../../components/Loader";
Expand All @@ -38,15 +38,14 @@ import { CredentialMoreInfo } from "../../project/components/cloudStorage/CloudS
import { CLOUD_STORAGE_SENSITIVE_FIELD_TOKEN } from "../../project/components/cloudStorage/projectCloudStorage.constants";
import { getCredentialFieldDefinitions } from "../../project/utils/projectCloudStorage.utils";
import { useGetNamespacesByNamespaceSlugQuery } from "../../projectsV2/api/projectV2.enhanced-api";
import { storageSecretNameToFieldName } from "../../secretsV2/secrets.utils";
import UserAvatar from "../../usersV2/show/UserAvatar";

import type {
DataConnectorRead,
DataConnectorToProjectLink,
} from "../api/data-connectors.api";
import { useGetDataConnectorsByDataConnectorIdSecretsQuery } from "../api/data-connectors.enhanced-api";
import { storageSecretNameToFieldName } from "../../secrets/secrets.utils";

import UserAvatar from "../../usersV2/show/UserAvatar";

import DataConnectorActions from "./DataConnectorActions";
import useDataConnectorProjects from "./useDataConnectorProjects.hook";
Expand Down
2 changes: 1 addition & 1 deletion client/src/features/rootV2/NavbarV2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ export default function NavbarV2() {
<NavbarItemHelp />
</NavItem>
<NavItem>
<RenkuToolbarItemUser params={params!} />
<RenkuToolbarItemUser isV2 params={params!} />
</NavItem>
</Nav>
</Collapse>
Expand Down
105 changes: 28 additions & 77 deletions client/src/features/secrets/GeneralSecretNew.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,10 @@
import cx from "classnames";
import { useCallback, useEffect, useState } from "react";
import { PlusLg, XLg } from "react-bootstrap-icons";
import { Controller, useForm } from "react-hook-form";
import { useForm } from "react-hook-form";
import {
Button,
Form,
Input,
Label,
Modal,
ModalBody,
ModalFooter,
Expand All @@ -33,9 +31,10 @@ import {

import { RtkOrNotebooksError } from "../../components/errors/RtkErrorAlert";
import { Loader } from "../../components/Loader";
import FilenameField from "../secretsV2/fields/FilenameField";
import NameField from "../secretsV2/fields/NameField";
import SecretValueField from "../secretsV2/fields/SecretValueField";
import { usePostUserSecretMutation, usersApi } from "../usersV2/api/users.api";
import { AddSecretForm } from "./secrets.types";
import { SECRETS_VALUE_LENGTH_LIMIT } from "./secrets.utils";

export default function GeneralSecretNew() {
// Set up the modal
Expand All @@ -53,17 +52,24 @@ export default function GeneralSecretNew() {
} = useForm<AddSecretForm>({
defaultValues: {
name: "",
filename: "",
value: "",
kind: "general",
},
});

// Handle fetching/posting data
const [getSecrets, secrets] = usersApi.useLazyGetUserSecretsQuery();
const [addSecretMutation, result] = usePostUserSecretMutation();
const onSubmit = useCallback(
(newSecret: AddSecretForm) => {
addSecretMutation({ secretPost: newSecret });
(data: AddSecretForm) => {
const filename = data.filename.trim();
addSecretMutation({
secretPost: {
name: data.name,
value: data.value,
...(filename ? { default_filename: filename } : {}),
},
});
},
[addSecretMutation]
);
Expand Down Expand Up @@ -97,74 +103,9 @@ export default function GeneralSecretNew() {
data-cy="secrets-new-form"
onSubmit={handleSubmit(onSubmit)}
>
<div className="mb-3">
<Label className="form-label" for="new-secret-name">
Name
</Label>
<Controller
control={control}
name="name"
render={({ field }) => (
<Input
autoComplete="off"
className={cx(errors.name && "is-invalid")}
id="new-secret-name"
placeholder="Unique name"
type="text"
{...field}
/>
)}
rules={{
required: "Please provide a name.",
validate: (value) =>
secrets.data?.map((s) => s.name).includes(value)
? "This name is already used by another secret."
: value && value.startsWith(".")
? "Name cannot start with a dot."
: !/^[a-zA-Z0-9_.-]+$/.test(value)
? "Only letters, numbers, dots (.), underscores (_), and dashes (-)."
: undefined,
}}
/>
{errors.name && (
<div className="invalid-feedback">{errors.name.message}</div>
)}
</div>

<div className="mb-3">
<Label className="form-label" for="new-secret-value">
Value
</Label>
<Controller
control={control}
name="value"
render={({ field }) => (
<Input
id="new-secret-value"
type="textarea"
{...field}
autoComplete="off one-time-code"
className={cx(
"rounded-0",
"rounded-start",
errors.value && "is-invalid"
)}
spellCheck="false"
rows={6}
/>
)}
rules={{
required: "Please provide a value.",
validate: (value) =>
value.length > SECRETS_VALUE_LENGTH_LIMIT
? `Value cannot exceed ${SECRETS_VALUE_LENGTH_LIMIT} characters.`
: undefined,
}}
/>
{errors.value && (
<div className="invalid-feedback">{errors.value.message}</div>
)}
</div>
<NameField control={control} errors={errors} name="name" />
<FilenameField control={control} errors={errors} name="filename" />
<SecretValueField control={control} errors={errors} name="value" />
</Form>
</>
);
Expand Down Expand Up @@ -201,7 +142,11 @@ export default function GeneralSecretNew() {
onClick={handleSubmit(onSubmit)}
type="submit"
>
<PlusLg className={cx("bi", "me-1")} />
{result.isLoading ? (
<Loader inline className="me-1" size={16} />
) : (
<PlusLg className={cx("bi", "me-1")} />
)}
Add
</Button>
</ModalFooter>
Expand All @@ -219,3 +164,9 @@ export default function GeneralSecretNew() {
</>
);
}

interface AddSecretForm {
name: string;
filename: string;
value: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import {
import { RtkOrNotebooksError } from "../../components/errors/RtkErrorAlert";
import { usePatchUserSecretMutation } from "../usersV2/api/users.api";
import { EditSecretForm, SecretDetails } from "./secrets.types";
import { SECRETS_VALUE_LENGTH_LIMIT } from "./secrets.utils";
import { SECRETS_VALUE_LENGTH_LIMIT } from "./secrets.constants";

interface SecretsEditProps {
secret: SecretDetails;
Expand Down
29 changes: 2 additions & 27 deletions client/src/features/secrets/Secrets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ import WipBadge from "../projectsV2/shared/WipBadge";

import GeneralSecretNew from "./GeneralSecretNew";
import SecretsList from "./SecretsList";
// import StorageSecretsList from "./StorageSecretsList";
import { SECRETS_DOCS_URL } from "./secrets.utils";
import { SECRETS_DOCS_URL } from "./secrets.constants";

function GeneralSecretSection() {
return (
Expand All @@ -52,36 +51,13 @@ function GeneralSecretSection() {
</Row>
<Row>
<Col>
<SecretsList kind="general" />
<SecretsList />
</Col>
</Row>
</>
);
}

// function StorageSecretSection() {
// return (
// <>
// <Row className="mt-5">
// <Col>
// <div className={cx("d-flex", "justify-content-between")}>
// <h3>Storage Secrets</h3>
// </div>
// <p>
// Credentials used to access data connectors can be persisted as
// storage secrets.
// </p>
// </Col>
// </Row>
// <Row>
// <Col>
// <StorageSecretsList />
// </Col>
// </Row>
// </>
// );
// }

function SecretsPageInfo() {
return (
<>
Expand Down Expand Up @@ -130,7 +106,6 @@ export default function Secrets() {
</Col>
</Row>
{user.logged && <GeneralSecretSection />}
{/* {user.logged && <StorageSecretSection />} */}
</div>
);
}
24 changes: 9 additions & 15 deletions client/src/features/secrets/SecretsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,12 @@ import { Col, Container, Row } from "reactstrap";
import { RtkOrNotebooksError } from "../../components/errors/RtkErrorAlert";
import { Loader } from "../../components/Loader";
import { useGetUserSecretsQuery } from "../usersV2/api/users.api";
import type { SecretKind } from "./secrets.types";
import SecretsListItem from "./SecretsListItem";

interface SecretsListParams {
kind: SecretKind;
}

export default function SecretsList({ kind }: SecretsListParams) {
const secrets = useGetUserSecretsQuery({ userSecretsParams: { kind } });
export default function SecretsList() {
const secrets = useGetUserSecretsQuery({
userSecretsParams: { kind: "general" },
});

if (secrets.isLoading) return <Loader />;

Expand All @@ -39,17 +36,14 @@ export default function SecretsList({ kind }: SecretsListParams) {

if (secrets.data?.length === 0) return null;

const secretsList = secrets.data?.map((secret) => {
return (
<Col key={secret.id}>
<SecretsListItem kind={kind} secret={secret} />
</Col>
);
});
return (
<Container className={cx("p-0", "mt-2")} data-cy="secrets-list" fluid>
<Row className={cx("g-2", "row-cols-1", "row-cols-xl-2")}>
{secretsList}
{secrets.data?.map((secret) => (
<Col key={secret.id}>
<SecretsListItem secret={secret} />
</Col>
))}
</Row>
</Container>
);
Expand Down
Loading

0 comments on commit d2dc4b9

Please sign in to comment.