Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions config/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ export default [
path: paths.INFO,
component: "./pages/PersonalInfo",
},
{
path: `${paths.CREDENTIALS}/:editId?`,
component: "./pages/Credentials",
},
],
},
{
Expand Down
12 changes: 11 additions & 1 deletion public/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,15 @@
"find": "Find",
"edit_teams": "Edit teams",
"roles_and_access": "Roles and access",
"sql_api": "SQL API"
"sql_api": "SQL API",
"credentials": "Credentials",
"shared": "Shared",
"private": "Private",
"specific_users": "Specific users"
},
"form": {
"labels": {
"access_type": "Access type",
"data_source": "Data source",
"name": "Name",
"db_name": "Database Name",
Expand Down Expand Up @@ -149,6 +154,7 @@
"new_password": "New Password",
"old_password": "Old Password",
"team_member": "Team member",
"team_members": "Team members",
"auth_token": "Auth Token",
"json": "JSON",
"body": "Body",
Expand All @@ -157,6 +163,10 @@
},
"placeholders": {
"name": "Name",
"choose_access_type": "Choose access type",
"choose_data_source": "Choose data source",
"choose_team_members": "Choose team members",
"login": "Login",
"use_ssl": "I want use SSL",
"attach_file_credentials": "Attach the file credentials, please",
"schema": "schema",
Expand Down
17 changes: 17 additions & 0 deletions public/locales/en/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,23 @@
"attach_btn": "Attach SQL API"
}
},
"credentials": {
"title": "Manage Credentials",
"action": "Create now",
"created": "Credentials created",
"updated": "Credentials updated",
"deleted": "Credentials deleted",
"not_found": {
"title": "You have no Credentials",
"text": "Click \"Create Credentials\" to add one",
"create_btn": "Create Credentials"
},
"shared_access_type_description": "This credential will be available to all team members.",
"specific_users_access_type_description": "This credential will be available to the selected team members.",
"member_already_used": "One or more members already have access to this datasource. Please remove them from other credentials of this datasource.",
"member_has_access": "You already have access to this datasource. Please remove other credentials of this datasource or contact your administrator.",
"no_rights": "You don't have rights to delete this credential. Please contact your administrator."
},
"roles_and_access": {
"manage_roles": "Manage roles",
"create_now": "Create now",
Expand Down
11 changes: 11 additions & 0 deletions src/assets/credentials.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 1 addition & 2 deletions src/components/ApiSetup/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ const ApiSetup: FC<ApiSetupProps> = ({
connection = CONNECTION_DEFAULT,
host = connectionUrls[CONNECTION_DEFAULT],
user = initialValue?.db_username,
password = initialValue?.password,
database = initialValue?.db,
}) => {
const [hostname, port] = host.split(":");
Expand All @@ -117,7 +116,7 @@ const ApiSetup: FC<ApiSetupProps> = ({

return `psql --host=${hostname} ${psqlPortOption} --username=${user} --dbname=${database}`;
},
[initialValue?.password, initialValue?.db_username, initialValue?.db]
[initialValue?.db_username, initialValue?.db]
);

const onDownload = () => {
Expand Down
50 changes: 50 additions & 0 deletions src/components/CredentialCard/index.module.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
.btn {
padding: 0;
color: var(--color-primary);
span {
font-size: 12px;
}
}

.list {
padding: 0;
list-style: none;
}

.listItem {
display: flex;
gap: 5px;
align-items: center;
justify-content: space-between;
padding: 0;
font-size: 12px;
font-family: var(--font-manrope);
&:not(:last-child) {
margin-bottom: 12px;
}
}

.label {
font-weight: 500;
white-space: nowrap;
opacity: 0.5;
}

.value {
display: flex;
align-items: center;
font-weight: 600;
}

.paragraph {
margin-bottom: 0 !important;
&:extend(.value);
}

.deleteItem {
padding: 0 !important;
}

.deleteText {
padding: 5px 12px;
}
179 changes: 179 additions & 0 deletions src/components/CredentialCard/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import React from "react";
import { SettingOutlined } from "@ant-design/icons";
import { Card, Typography, Dropdown } from "antd";
import { useTranslation } from "react-i18next";
import cx from "classnames";

import Button from "@/components/Button";
import ConfirmModal from "@/components/ConfirmModal";
import formatTime from "@/utils/helpers/formatTime";
import type { CredentialsInfo } from "@/types/credential";
import DataSourceTag from "@/components/DataSourceTag";
import CurrentUserStore from "@/stores/CurrentUserStore";
import { Roles } from "@/types/team";

import styles from "./index.module.less";

import type { ItemType } from "antd/lib/menu/hooks/useItems";
import type { FC } from "react";

const { Paragraph } = Typography;

interface CredentialCardProps {
credential: CredentialsInfo;
onEdit?: (id: string) => void;
onDelete?: (id: string) => void;
}

const CredentialCard: FC<CredentialCardProps> = ({
credential,
onEdit = () => {},
onDelete = () => {},
}) => {
const { t } = useTranslation(["common"]);
const { currentUser, currentTeam } = CurrentUserStore();
const { id, username, updatedAt, createdAt, user, dataSource } = credential;

const isMember = currentTeam?.role === Roles.member;
const isOwner = currentUser?.id === credential.user.id;
const canDelete = !isMember || (isMember && isOwner);

return (
<div>
<Card
style={{ position: "static" }}
bodyStyle={{ padding: 16 }}
headStyle={{ padding: 16 }}
title={
<Button
block
type="link"
className={styles.btn}
style={{ textAlign: "left" }}
onClick={() => id && onEdit(id)}
>
<Paragraph
ellipsis
title={user?.displayName}
style={{ display: "inline-block", width: "95%" }}
className={cx(styles.paragraph, styles.btn)}
>
{user?.displayName}
</Paragraph>
</Button>
}
extra={
canDelete && (
<Dropdown
className={styles.btn}
trigger={["click"]}
menu={{
items: [
{
key: "edit",
label: t("common:words.edit"),
onClick: () => id && onEdit(id),
},
{
key: "delete",
className: styles.deleteItem,
label: (
<ConfirmModal
title={t("common:words.delete_datasource")}
className={styles.deleteText}
onConfirm={() => id && onDelete(id)}
>
{t("common:words.delete")}
</ConfirmModal>
),
},
],
}}
>
<SettingOutlined key="setting" />
</Dropdown>
)
}
>
<ul className={styles.list}>
<li className={styles.listItem}>
<span className={styles.label}>{t("common:words.type")}</span>
<DataSourceTag dataSource={dataSource.type} />
</li>

{dataSource?.name && (
<li className={styles.listItem}>
<span className={styles.label}>
{t("common:form.labels.data_source")}
</span>
<Paragraph
title={dataSource.name}
className={styles.paragraph}
style={{
display: "inline",
textAlign: "right",
width: "80%",
}}
ellipsis
>
{dataSource.name}
</Paragraph>
</li>
)}

{username && (
<li className={styles.listItem}>
<span className={styles.label}>{t("common:words.login")}</span>
<Paragraph
title={username}
className={styles.paragraph}
style={{
display: "inline",
textAlign: "right",
width: "80%",
}}
ellipsis
>
{username}
</Paragraph>
</li>
)}

<li className={styles.listItem}>
<span className={styles.label}>{t("common:words.updated_at")}</span>
<Paragraph
title={formatTime(updatedAt)}
className={styles.paragraph}
style={{
display: "inline",
textAlign: "right",
width: "80%",
}}
ellipsis
>
{formatTime(updatedAt)}{" "}
</Paragraph>
</li>

<li className={styles.listItem}>
<span className={styles.label}>{t("common:words.created_at")}</span>
<Paragraph
title={formatTime(createdAt)}
className={styles.paragraph}
style={{
display: "inline",
textAlign: "right",
width: "80%",
}}
ellipsis
>
{formatTime(createdAt)}{" "}
</Paragraph>
</li>
</ul>
</Card>
</div>
);
};

export default CredentialCard;
4 changes: 4 additions & 0 deletions src/components/CredentialsForm/index.module.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.form {
max-width: 400px;
margin: 0 auto;
}
Loading