mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
translate(frontend): update namespace names, move translate keys, translate some keys into korean
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
"simple-import-sort"
|
||||
],
|
||||
"rules": {
|
||||
"i18n-ally-translation-missing": "off",
|
||||
"react-hooks/exhaustive-deps": "off",
|
||||
"simple-import-sort/exports": "warn",
|
||||
"simple-import-sort/imports": [
|
||||
|
||||
6
frontend/.vscode/settings.json
vendored
Normal file
6
frontend/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"i18n-ally.localesPaths": [
|
||||
"locales",
|
||||
"public/locales"
|
||||
]
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Fragment, useState } from "react";
|
||||
import useTranslate from "next-translate/useTranslation";
|
||||
import { Dialog, Transition } from "@headlessui/react";
|
||||
|
||||
import addIncidentContact from "~/pages/api/organization/addIncidentContact";
|
||||
@@ -14,6 +15,7 @@ const AddIncidentContactDialog = ({
|
||||
setIncidentContacts,
|
||||
}) => {
|
||||
let [incidentContactEmail, setIncidentContactEmail] = useState("");
|
||||
const { t } = useTranslate();
|
||||
|
||||
const submit = () => {
|
||||
setIncidentContacts(
|
||||
@@ -59,17 +61,16 @@ const AddIncidentContactDialog = ({
|
||||
as="h3"
|
||||
className="text-lg font-medium leading-6 text-gray-400"
|
||||
>
|
||||
Add an Incident Contact
|
||||
{t("section-incident:add-dialog.title")}
|
||||
</Dialog.Title>
|
||||
<div className="mt-2 mb-2">
|
||||
<p className="text-sm text-gray-500">
|
||||
This contact will be notified in the unlikely event of a
|
||||
severe incident.
|
||||
{t("section-incident:add-dialog.description")}
|
||||
</p>
|
||||
</div>
|
||||
<div className="max-h-28">
|
||||
<InputField
|
||||
label="Email"
|
||||
label={t("common:email")}
|
||||
onChangeHandler={setIncidentContactEmail}
|
||||
type="varName"
|
||||
value={incidentContactEmail}
|
||||
@@ -81,7 +82,7 @@ const AddIncidentContactDialog = ({
|
||||
<Button
|
||||
onButtonPressed={submit}
|
||||
color="mineshaft"
|
||||
text="Add Incident Contact"
|
||||
text={t("section-incident.add-dialog.add-incident")}
|
||||
size="md"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -52,25 +52,25 @@ const AddProjectMemberDialog = ({
|
||||
as="h3"
|
||||
className="text-lg font-medium leading-6 text-gray-400 z-50"
|
||||
>
|
||||
{t("settings:add-member-dialog.add-member-to-project")}
|
||||
{t("section-members:add-dialog.add-member-to-project")}
|
||||
</Dialog.Title>
|
||||
) : (
|
||||
<Dialog.Title
|
||||
as="h3"
|
||||
className="text-lg font-medium leading-6 text-gray-400 z-50"
|
||||
>
|
||||
{t("settings:add-member-dialog.already-all-invited")}
|
||||
{t("section-members:add-dialog.already-all-invited")}
|
||||
</Dialog.Title>
|
||||
)}
|
||||
<div className="mt-2 mb-4">
|
||||
{data?.length > 0 ? (
|
||||
<div className="flex flex-col">
|
||||
<p className="text-sm text-gray-500">
|
||||
{t("settings:add-member-dialog.user-will-email")}
|
||||
{t("section-members:add-dialog.user-will-email")}
|
||||
</p>
|
||||
<div className="">
|
||||
<Trans
|
||||
i18nKey="settings:add-member-dialog.looking-add"
|
||||
i18nKey="section-members:add-dialog.looking-add"
|
||||
components={[
|
||||
// eslint-disable-next-line react/jsx-key
|
||||
<button
|
||||
@@ -93,16 +93,14 @@ const AddProjectMemberDialog = ({
|
||||
"?invite"
|
||||
)
|
||||
}
|
||||
>
|
||||
click here.
|
||||
</button>,
|
||||
/>,
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<p className="text-sm text-gray-500">
|
||||
{t("settings:add-member-dialog.add-user-org-first")}
|
||||
{t("section-members:add-dialog.add-user-org-first")}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
@@ -122,7 +120,7 @@ const AddProjectMemberDialog = ({
|
||||
<Button
|
||||
onButtonPressed={submitModal}
|
||||
color="mineshaft"
|
||||
text={t("settings:add-member-dialog.add-member")}
|
||||
text={t("section-members:add-member")}
|
||||
size="md"
|
||||
/>
|
||||
</div>
|
||||
@@ -132,7 +130,7 @@ const AddProjectMemberDialog = ({
|
||||
router.push("/settings/org/" + router.query.id)
|
||||
}
|
||||
color="mineshaft"
|
||||
text={t("settings:add-member-dialog.add-user-to-org")}
|
||||
text={t("section-members:add-dialog.add-user-to-org")}
|
||||
size="md"
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Fragment, useState } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import useTranslate from "next-translate/useTranslation";
|
||||
import { faCheck, faCopy } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Dialog, Transition } from "@headlessui/react";
|
||||
@@ -41,6 +42,7 @@ const AddServiceTokenDialog = ({
|
||||
const [serviceTokenEnv, setServiceTokenEnv] = useState("Development");
|
||||
const [serviceTokenExpiresIn, setServiceTokenExpiresIn] = useState("1 day");
|
||||
const [serviceTokenCopied, setServiceTokenCopied] = useState(false);
|
||||
const { t } = useTranslate();
|
||||
|
||||
const generateServiceToken = async () => {
|
||||
const latestFileKey = await getLatestFileKey(workspaceId);
|
||||
@@ -134,21 +136,20 @@ const AddServiceTokenDialog = ({
|
||||
as="h3"
|
||||
className="text-lg font-medium leading-6 text-gray-400 z-50"
|
||||
>
|
||||
Add a service token for {workspaceName}
|
||||
{t("section-token:add-dialog.title", {
|
||||
target: workspaceName,
|
||||
})}
|
||||
</Dialog.Title>
|
||||
<div className="mt-2 mb-4">
|
||||
<div className="flex flex-col">
|
||||
<p className="text-sm text-gray-500">
|
||||
Specify the name, environment, and expiry period. When
|
||||
a token is generated, you will only be able to see it
|
||||
once before it disappears. Make sure to save it
|
||||
somewhere.
|
||||
{t("section-token:add-dialog.description")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="max-h-28 mb-2">
|
||||
<InputField
|
||||
label="Service Token Name"
|
||||
label={t("section-token:add-dialog.name")}
|
||||
onChangeHandler={setServiceTokenName}
|
||||
type="varName"
|
||||
value={serviceTokenName}
|
||||
@@ -167,7 +168,7 @@ const AddServiceTokenDialog = ({
|
||||
"Testing",
|
||||
]}
|
||||
width="full"
|
||||
text="Environment: "
|
||||
text={`t("common:environment"): `}
|
||||
/>
|
||||
</div>
|
||||
<div className="max-h-28">
|
||||
@@ -176,7 +177,7 @@ const AddServiceTokenDialog = ({
|
||||
onChange={setServiceTokenExpiresIn}
|
||||
data={["1 day", "7 days", "1 month"]}
|
||||
width="full"
|
||||
text="Expires in: "
|
||||
text={`t("common:expired-in"): `}
|
||||
/>
|
||||
</div>
|
||||
<div className="max-w-max">
|
||||
@@ -184,8 +185,8 @@ const AddServiceTokenDialog = ({
|
||||
<Button
|
||||
onButtonPressed={() => generateServiceToken()}
|
||||
color="mineshaft"
|
||||
text="Add Service Token"
|
||||
textDisabled="Add Service Token"
|
||||
text={t("section-token:add-dialog.add")}
|
||||
textDisabled={t("section-token:add-dialog.add")}
|
||||
size="md"
|
||||
active={serviceTokenName == "" ? false : true}
|
||||
/>
|
||||
@@ -198,13 +199,14 @@ const AddServiceTokenDialog = ({
|
||||
as="h3"
|
||||
className="text-lg font-medium leading-6 text-gray-400 z-50"
|
||||
>
|
||||
Copy your service token
|
||||
{t("section-token:add-dialog.copy-service-token")}
|
||||
</Dialog.Title>
|
||||
<div className="mt-2 mb-4">
|
||||
<div className="flex flex-col">
|
||||
<p className="text-sm text-gray-500">
|
||||
Once you close this popup, you will never see your
|
||||
service token again
|
||||
{t(
|
||||
"section-token:add-dialog.copy-service-token-description"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -234,7 +236,7 @@ const AddServiceTokenDialog = ({
|
||||
)}
|
||||
</button>
|
||||
<span className="absolute hidden group-hover:flex group-hover:animate-popup duration-300 w-28 -left-8 -top-20 translate-y-full px-3 py-2 bg-chicago-900 rounded-md text-center text-gray-400 text-sm">
|
||||
Click to Copy
|
||||
{t("common.click-to-copy")}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,16 +1,27 @@
|
||||
const workaround = require("next-translate/lib/cjs/plugin/utils.js");
|
||||
|
||||
workaround.defaultLoader =
|
||||
"(l, n) => import(`@next-translate-root/locales/${l}.json`).then(m => m?.default[n] ?? {} )";
|
||||
"(l, n) => import(`@next-translate-root/locales/${l}.json`).then(m => m?.default[n] ?? {} )";
|
||||
|
||||
module.exports = {
|
||||
locales: ["en-US", "ko-KR"],
|
||||
defaultLocale: "en-US",
|
||||
pages: {
|
||||
"*": ["common", "nav"],
|
||||
"rgx:^/(login|signup)": ["auth"],
|
||||
"rgx:^/settings": ["settings"],
|
||||
"/dashboard/[id]": ["dashboard"],
|
||||
"/users/[id]": ["settings"],
|
||||
},
|
||||
locales: ["en-US", "ko-KR"],
|
||||
defaultLocale: "en-US",
|
||||
pages: {
|
||||
"*": ["common", "nav"],
|
||||
"/login": ["login"],
|
||||
"/signup": ["signup", "form-password"],
|
||||
"rgx:^/(login|signup)": ["auth"],
|
||||
"rgx:^/settings": ["settings"],
|
||||
"/dashboard/[id]": ["dashboard"],
|
||||
"/users/[id]": ["settings-members", "section-members"],
|
||||
"/settings/project/[id]": ["settings-project", "section-token"],
|
||||
"/settings/org/[id]": [
|
||||
"settings-org",
|
||||
"section-incident",
|
||||
"section-members",
|
||||
],
|
||||
"/settings/personal/[id]": ["settings-personal"],
|
||||
"/settings/billing/[id]": ["billing"],
|
||||
"/integrations/[id]": ["integrations"],
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
{
|
||||
"common": {
|
||||
"head-title": "{{title}} | Infiscal",
|
||||
"error_project-already-exists": "A project with this name already exists.",
|
||||
"no-mobile": " To use Infisical, please log in through a device with larger dimensions. ",
|
||||
"email": "Email",
|
||||
"password": "Password",
|
||||
"verify": "Verify",
|
||||
"first-name": "First Name",
|
||||
"last-name": "Last Name",
|
||||
"logout": "Log Out",
|
||||
"validate-required": "Please input your {{name}}",
|
||||
"password-validate": "Password should contain at least:",
|
||||
"password-validate-length": "14 characters",
|
||||
"password-validate-case": "1 lowercase character",
|
||||
"password-validate-number": "1 number",
|
||||
|
||||
"maintenance-alert": "We are experiencing minor technical difficulties. We are working on solving it right now. Please come back in a few minutes.",
|
||||
"click-to-copy": "Click to copy",
|
||||
"project-id": "Project ID",
|
||||
@@ -22,7 +19,29 @@
|
||||
"drop-zone-keys": "Drag and drop your .env file here to add more keys.",
|
||||
"role": "Role",
|
||||
"role_admin": "admin",
|
||||
"display-name": "Display Name"
|
||||
"display-name": "Display Name",
|
||||
"free": "Free",
|
||||
"starter": "Starter",
|
||||
"professional": "Professional",
|
||||
"enterprise": "Enterprise",
|
||||
"downgrade": "Downgrade",
|
||||
"upgrade": "Upgrade",
|
||||
"learn-more": "Learn More",
|
||||
"custom-pricing": "Custom Pricing",
|
||||
"schedule-demo": "Schedule a Demo",
|
||||
"environment": "Environment",
|
||||
"expired-in": "Expires in"
|
||||
},
|
||||
"form-password": {
|
||||
"password": "Password",
|
||||
"change": "Change password",
|
||||
"current": "Current password",
|
||||
"current-wrong": "The current password may be wrong",
|
||||
"new": "New password",
|
||||
"validate-base": "Password should contain at least:",
|
||||
"validate-length": "14 characters",
|
||||
"validate-case": "1 lowercase character",
|
||||
"validate-number": "1 number"
|
||||
},
|
||||
"nav": {
|
||||
"support": {
|
||||
@@ -46,25 +65,22 @@
|
||||
"project-settings": "Project Settings"
|
||||
}
|
||||
},
|
||||
"auth": {
|
||||
"meta": {
|
||||
"login": {
|
||||
"title": "Login | Infiscal",
|
||||
"og-title": "Log In to Infisical",
|
||||
"og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files."
|
||||
},
|
||||
"signup": {
|
||||
"title": "Sign Up | Infiscal",
|
||||
"og-title": "Replace .env files with 1 line of code. Sign Up for Infisical in 3 minutes.",
|
||||
"og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage API-keys and environemntal variables. Works with Node.js, Next.js, Gatsby, Nest.js..."
|
||||
}
|
||||
},
|
||||
"login": {
|
||||
"title": "Login",
|
||||
"og-title": "Log In to Infisical",
|
||||
"og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files.",
|
||||
"login": "Log In",
|
||||
"signup": "Sign Up",
|
||||
"need-account": "Need an Infisical account?",
|
||||
"create-account": "Create an account",
|
||||
"create-account": "Create an account"
|
||||
},
|
||||
"signup": {
|
||||
"title": "Sign Up",
|
||||
"og-title": "Replace .env files with 1 line of code. Sign Up for Infisical in 3 minutes.",
|
||||
"og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage API-keys and environemntal variables. Works with Node.js, Next.js, Gatsby, Nest.js...",
|
||||
"signup": "Sign Up",
|
||||
"already-have-account": "Have an account? Log in",
|
||||
"forgot-password": "Forgot your password?",
|
||||
"verify": "Verify",
|
||||
"step1-start": "Let's get started",
|
||||
"step1-privacy": "By creating an account, you agree to our Terms and have read and acknowledged the Privacy Policy.",
|
||||
"step1-submit": "Get Started",
|
||||
@@ -100,36 +116,105 @@
|
||||
"line2": "Here is how to connect them to your codebase."
|
||||
}
|
||||
},
|
||||
"settings-members": {
|
||||
"title": "Project Members",
|
||||
"description": "This pages shows the members of the selected project."
|
||||
},
|
||||
"settings-org": {
|
||||
"title": "Organization Settings",
|
||||
"description": "Manage members of your organization. These users could afterwards be formed into projects."
|
||||
},
|
||||
"settings-personal": {
|
||||
"title": "Personal Settings",
|
||||
"description": "View and manage your personal information here.",
|
||||
"emergency": {
|
||||
"name": "Emergency Kit",
|
||||
"text1": "Your Emergency Kit contains the information you’ll need to sign in to your Infisical account.",
|
||||
"text2": "Only the latest issued Emergency Kit remains valid. To get a new Emergency Kit, verify your password.",
|
||||
"download": "Download Emergency Kit"
|
||||
}
|
||||
},
|
||||
"settings-project": {
|
||||
"title": "Project Settings",
|
||||
"description": "These settings only apply to the currently selected Project.",
|
||||
"danger-zone": "Danger Zone",
|
||||
"delete-project": "Delete Project",
|
||||
"project-to-delete": "Project to be Deleted",
|
||||
"danger-zone-note": "As soon as you delete this project, you will not be able to undo it. This will immediately remove all the keys. If you still want to do that, please enter the name of the project below.",
|
||||
"delete-project-note": "Note: You can only delete a project in case you have more than one",
|
||||
"project-id-description": "To integrate Infisical into your code base and get automatic injection of environmental variables, you should use the following Project ID.",
|
||||
"project-id-description2": "For more guidance, including code snipets for various languages and frameworks, see ",
|
||||
"auto-generated": "This is your project's auto-generated unique identifier. It can't be changed.",
|
||||
"docs": "Infisical Docs"
|
||||
},
|
||||
"section-token": {
|
||||
"service-tokens": "Service Tokens",
|
||||
"service-tokens-description": "Every service token is specific to you, a certain project and a certain environment within this project.",
|
||||
"add-new": "Add New Token",
|
||||
"add-dialog": {
|
||||
"title": "Add a service token for {{target}}",
|
||||
"description": "Specify the name, environment, and expiry period. When a token is generated, you will only be able to see it once before it disappears. Make sure to save it somewhere.",
|
||||
"name": "Service Token Name",
|
||||
"add": "Add Service Token",
|
||||
"copy-service-token": "Copy your service token",
|
||||
"copy-service-token-description": "Once you close this popup, you will never see your service token again"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"meta": {
|
||||
"members": {
|
||||
"title": "Project Members",
|
||||
"head-title": "Project Settings | Infiscal",
|
||||
"description": "This pages shows the members of the selected project."
|
||||
},
|
||||
"org": {
|
||||
"title": "Organization Settings",
|
||||
"head-title": "Organization Settings | Infiscal",
|
||||
"description": "Manage members of your organization. These users could afterwards be formed into projects."
|
||||
}
|
||||
},
|
||||
"search-members": "Search members...",
|
||||
"search": "Search...",
|
||||
"delete-project": "Delete Project"
|
||||
},
|
||||
"billing": {
|
||||
"title": "Usage & Billing",
|
||||
"description": "View and manage your organization's subscription here",
|
||||
"subscription": "Subscription",
|
||||
"starter": {
|
||||
"price-explanation": "up to 5 team members",
|
||||
"text": "Manage any project with 5 members for free!",
|
||||
"subtext": "$5 per member/month afterwards."
|
||||
},
|
||||
"professional": {
|
||||
"price-explanation": "/member/month",
|
||||
"subtext": "Includes unlimited projects & members.",
|
||||
"text": "Keep up with key management as you grow."
|
||||
},
|
||||
"enterprise": {
|
||||
"text": "Keep up with key management as you grow."
|
||||
},
|
||||
"current-usage": "Current Usage"
|
||||
},
|
||||
"section-members": {
|
||||
"add-member": "Add Member",
|
||||
"org-members": "Organization Members",
|
||||
"org-members-description": "Manage members of your organization. These users could afterwards be formed into projects.",
|
||||
"incident-contacts": "Incident Contacts",
|
||||
"incident-contacts-description": "These contacts will be notified in the unlikely event of a severe incident.",
|
||||
"no-incident-contacts": "No incident contacts found.",
|
||||
"add-contact": "Add Contact",
|
||||
"add-member-dialog": {
|
||||
"search-members": "Search members...",
|
||||
"add-dialog": {
|
||||
"add-member-to-project": "Add a member to your project",
|
||||
"already-all-invited": "All the users in your organization are already invited.",
|
||||
"add-user-org-first": "Add more users to the organization first.",
|
||||
"user-will-email": "The user will receive an email with the instructions.",
|
||||
"looking-add": "<0>If you are looking to add users to your org,</0><1>click here</1>",
|
||||
"add-user-to-org": "Add Users to Organization",
|
||||
"add-member": "Add Member"
|
||||
"add-user-to-org": "Add Users to Organization"
|
||||
}
|
||||
},
|
||||
"section-incident": {
|
||||
"incident-contacts": "Incident Contacts",
|
||||
"incident-contacts-description": "These contacts will be notified in the unlikely event of a severe incident.",
|
||||
"no-incident-contacts": "No incident contacts found.",
|
||||
"add-contact": "Add Contact",
|
||||
"add-dialog": {
|
||||
"title": "Add an Incident Contact",
|
||||
"description": "This contact will be notified in the unlikely event of a severe incident.",
|
||||
"add-incident": "Add Incident Contact"
|
||||
}
|
||||
},
|
||||
"integrations": {
|
||||
"title": "Project Integrations",
|
||||
"description": "Manage your integrations of Infisical with third-party services.",
|
||||
"no-integrations1": "You don't have any integrations set up yet. When you do, they will appear here.",
|
||||
"no-integrations2": "To start, click on any of the options below. It takes 5 clicks to set up.",
|
||||
"available": "Available Integrations",
|
||||
"available-text1": "Click on the itegration you want to connect. This will let your environment variables flow automatically into selected third-party services.",
|
||||
"available-text2": " Note: during an integration with Heroku, for security reasons, it is impossible to maintain end-to-end encryption. In theory, this lets Infisical decrypt yor environment variables. In practice, we can assure you that this will never be done, and it allows us to protect your secrets from bad actors online. The core Infisical service will always stay end-to-end encrypted. With any questions, reach out support@infisical.com."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,189 @@
|
||||
{
|
||||
"common": {},
|
||||
"nav": {},
|
||||
"auth": {},
|
||||
"dashboard": {}
|
||||
"common": {
|
||||
"head-title": "{{title}} | Infiscal",
|
||||
"error_project-already-exists": "A project with this name already exists.",
|
||||
"no-mobile": " To use Infisical, please log in through a device with larger dimensions. ",
|
||||
"email": "Email",
|
||||
"password": "Password",
|
||||
"first-name": "First Name",
|
||||
"last-name": "Last Name",
|
||||
"logout": "Log Out",
|
||||
"validate-required": "Please input your {{name}}",
|
||||
"maintenance-alert": "We are experiencing minor technical difficulties. We are working on solving it right now. Please come back in a few minutes.",
|
||||
"click-to-copy": "Click to copy",
|
||||
"project-id": "Project ID",
|
||||
"project-id-description": "To integrate Infisical into your code base and get automatic injection of environmental variables, you should use the following Project ID.",
|
||||
"save-changes": "Save Changes",
|
||||
"saved": "Saved",
|
||||
"drop-zone": "Drag and drop your .env file here.",
|
||||
"drop-zone-keys": "Drag and drop your .env file here to add more keys.",
|
||||
"role": "Role",
|
||||
"role_admin": "admin",
|
||||
"display-name": "Display Name",
|
||||
"free": "Free",
|
||||
"starter": "Starter",
|
||||
"professional": "Professional",
|
||||
"enterprise": "Enterprise",
|
||||
"downgrade": "Downgrade",
|
||||
"upgrade": "Upgrade",
|
||||
"learn-more": "Learn More",
|
||||
"custom-pricing": "Custom Pricing",
|
||||
"schedule-demo": "Schedule a Demo"
|
||||
},
|
||||
"form-password": {
|
||||
"password": "비밀번호",
|
||||
"change": "비밀번호 변경",
|
||||
"current": "현재 비밀번호",
|
||||
"new": "새 비밀번호",
|
||||
"current-wrong": "현재 비밀번호가 잘못되었어요",
|
||||
"validate-base": "비밀번호는 다음 조건을 만족해야 합니다:",
|
||||
"validate-length": "14 글자 이상",
|
||||
"validate-case": "1개 이상의 소문자",
|
||||
"validate-number": "1개 이상의 숫자"
|
||||
},
|
||||
"nav": {
|
||||
"support": {
|
||||
"slack": "[NEW] 슬랙 포럼에 가입하기",
|
||||
"docs": "문서 보기",
|
||||
"issue": "깃허브 이슈 열기",
|
||||
"email": "Infisical팀에게 메일 보내기"
|
||||
},
|
||||
"user": {
|
||||
"signed-in-as": "다음으로 로그인됨",
|
||||
"current-organization": "현재 조직",
|
||||
"usage-billing": "요금제 & 결제",
|
||||
"invite": "맴버 초대하기",
|
||||
"other-organizations": "다른 조직"
|
||||
},
|
||||
"menu": {
|
||||
"project": "프로젝트",
|
||||
"secrets": "시크릿",
|
||||
"members": "맴버",
|
||||
"integrations": "연동",
|
||||
"project-settings": "프로젝트 설정"
|
||||
}
|
||||
},
|
||||
"login": {
|
||||
"title": "로그인",
|
||||
"og-title": "Infisical에 로그인하기",
|
||||
"og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files.",
|
||||
"login": "로그인",
|
||||
"need-account": "Infisical계정이 필요하신가요?",
|
||||
"create-account": "회원가입 하기"
|
||||
},
|
||||
"signup": {
|
||||
"title": "회원가입",
|
||||
"og-title": "Replace .env files with 1 line of code. Sign Up for Infisical in 3 minutes.",
|
||||
"og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage API-keys and environemntal variables. Works with Node.js, Next.js, Gatsby, Nest.js...",
|
||||
"signup": "회원가입",
|
||||
"already-have-account": "Have an account? Log in",
|
||||
"forgot-password": "Forgot your password?",
|
||||
"verify": "인증",
|
||||
"step1-start": "시작하기",
|
||||
"step1-privacy": "회원가입시 약관과 개인 정보 보호 정책을 읽고 동의한 것으로 간주합니다.",
|
||||
"step1-submit": "시작하기",
|
||||
"step2-message": "<email>{{email}}</email><wrapper>로 인증 메일을 전송하였습니다</wrapper><email>{{email}}</email>",
|
||||
"step2-code-error": "코드가 잘못된 것 같아요. 다시 시도해주세요.",
|
||||
"step2-spam-alert": "스팸함에 메일이 있지는 않은지 확인하세요",
|
||||
"step3-message": "거의다 끝났어요!",
|
||||
"step4-message": "긴급복구 키트 저장하기",
|
||||
"step4-description1": "계정이 잠겼을 경우 비상 키트를 사용하여 로그인할 수 있어요.",
|
||||
"step4-description2": "다운로드 후 안전한 곳에 보관하는 것을 추천합니다.",
|
||||
"step4-description3": "분실시 접근하거나 복구할 수 없는 시크릿 키가 포함되어 있어요.",
|
||||
"step4-download": "PDF 다운로드"
|
||||
},
|
||||
"dashboard": {
|
||||
"secrets": "시크릿",
|
||||
"meta": {
|
||||
"title": "Dashboard | Infiscal",
|
||||
"og-title": "Manage your .env files in seconds",
|
||||
"og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files."
|
||||
},
|
||||
"search-keys": "Search keys...",
|
||||
"add-key": "Add Key",
|
||||
"personal": "Personal",
|
||||
"personal-description": "Personal keys are only visible to you",
|
||||
"shared": "Shared",
|
||||
"shared-description": "Shared keys are visible to your whole team",
|
||||
"make-shared": "Make Shared",
|
||||
"make-personal": "Make Personal",
|
||||
"check-docs": {
|
||||
"button": "Check Docs",
|
||||
"title": "Good job!",
|
||||
"line1": "Congrats on adding more secrets.",
|
||||
"line2": "Here is how to connect them to your codebase."
|
||||
}
|
||||
},
|
||||
"settings-members": {
|
||||
"title": "맴버 설정",
|
||||
"description": "선택한 프로젝트의 맴버를 확인하세요."
|
||||
},
|
||||
"settings-org": {
|
||||
"title": "조직 설정",
|
||||
"description": "조직의 맴버를 관리하세요."
|
||||
},
|
||||
"settings-personal": {
|
||||
"title": "개인 설정",
|
||||
"description": "계정 및 기본적인 설정을 확인하고 변경하세요.",
|
||||
"emergency": {
|
||||
"name": "긴급복구 키트",
|
||||
"text1": "긴급복구 키트는 Infisical계정에 로그인 할 수 있는 정보를 가지고 있어요.",
|
||||
"text2": "오직 마지막으로 발급한 긴급복구 키트만 사용 가능해요. 새로운 긴급복구 키트를 받으려면, 비밀번호를 입력하세요.",
|
||||
"download": "긴급복구 키트 다운로드"
|
||||
}
|
||||
},
|
||||
"settings-project": {
|
||||
"title": "프로젝트 설정",
|
||||
"description": "현재 선택한 프로젝트에 대해서만 설정해요."
|
||||
},
|
||||
"settings": {
|
||||
"search-members": "Search members...",
|
||||
"search": "Search...",
|
||||
"add-member": "Add Member",
|
||||
"org-members": "Organization Members",
|
||||
"org-members-description": "Manage members of your organization. These users could afterwards be formed into projects.",
|
||||
"incident-contacts": "Incident Contacts",
|
||||
"incident-contacts-description": "These contacts will be notified in the unlikely event of a severe incident.",
|
||||
"no-incident-contacts": "No incident contacts found.",
|
||||
"add-contact": "Add Contact",
|
||||
"delete-project": "Delete Project",
|
||||
"delete-project-note": "Note: You can only delete a project in case you have more than one",
|
||||
"project-danger-zone-note": "As soon as you delete this project, you will not be able to undo it. This will immediately remove all the keys. If you still want to do that, please enter the name of the project below.",
|
||||
"danger-zone": "Danger Zone",
|
||||
"service-tokens": "Service Tokens",
|
||||
"service-tokens-description": "Every service token is specific to you, a certain project and a certain environment within this project."
|
||||
},
|
||||
"billing": {
|
||||
"title": "요금제 & 결제",
|
||||
"description": "이곳에서 조직의 구독을 확인하고 관리할 수 있어요.",
|
||||
"subscription": "구독",
|
||||
"starter": {
|
||||
"price-explanation": "5명의 팀 맴버까지",
|
||||
"text": "어떤 프로젝트든 다섯명의 맴버까지 무료로 이용할 수 있어요!",
|
||||
"subtext": "$5명/달 로 바뀔 예정입니다."
|
||||
},
|
||||
"professional": {
|
||||
"price-explanation": "/맴버/달",
|
||||
"subtext": "무제한의 프로젝트와 맴버",
|
||||
"text": "조직의 성장에 따라 유연하게 시크릿을 관리하세요."
|
||||
},
|
||||
"enterprise": {
|
||||
"text": "조직의 성장에 따라 유연하게 시크릿을 관리하세요."
|
||||
},
|
||||
"current-usage": "현재 요금제"
|
||||
},
|
||||
"section-members": {
|
||||
"add-member": "맴버 추가하기",
|
||||
"org-members": "조직 맴버",
|
||||
"search-members": "맴버를 검색하기...",
|
||||
"add-dialog": {
|
||||
"add-member-to-project": "프로젝트에 맴버 추가하기",
|
||||
"already-all-invited": "조직의 모든 유저가 이미 초대되었습니다.",
|
||||
"add-user-org-first": "유저를 먼저 조직에 추가해 주세요.",
|
||||
"user-will-email": "유저는 안내가 포함된 메일을 받게 됩니다.",
|
||||
"looking-add": "<0>조직에 유저를 추가하고 싶다면,</0><1>여기를 클릭하세요</1>",
|
||||
"add-user-to-org": "조직에 유저 추가하기"
|
||||
}
|
||||
},
|
||||
"integrations": {}
|
||||
}
|
||||
|
||||
@@ -65,4 +65,7 @@ module.exports = nextTranslate({
|
||||
},
|
||||
];
|
||||
},
|
||||
webpack: (config, { isServer, webpack }) => {
|
||||
return config;
|
||||
},
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { useEffect, useState } from "react";
|
||||
import Head from "next/head";
|
||||
import Image from "next/image";
|
||||
import { useRouter } from "next/router";
|
||||
import useTranslation from "next-translate/useTranslation";
|
||||
import {
|
||||
faArrowRight,
|
||||
faCheck,
|
||||
@@ -54,6 +55,8 @@ const Integration = ({ projectIntegration }) => {
|
||||
projectIntegration.app ? projectIntegration.app : apps[0]
|
||||
);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(async () => {
|
||||
const tempHerokuApps = await getIntegrationApps({
|
||||
integrationAuthId: projectIntegration.integrationAuth,
|
||||
@@ -179,6 +182,8 @@ export default function Integrations() {
|
||||
const router = useRouter();
|
||||
const [csrfToken, setCsrfToken] = useState("");
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(async () => {
|
||||
const tempCSRFToken = crypto.randomBytes(16).toString("hex");
|
||||
setCsrfToken(tempCSRFToken);
|
||||
@@ -205,24 +210,28 @@ export default function Integrations() {
|
||||
return integrations ? (
|
||||
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
|
||||
<Head>
|
||||
<title>Dashboard</title>
|
||||
<title>
|
||||
<title>
|
||||
{t("common:head-title", { title: t("integrations:title") })}
|
||||
</title>
|
||||
</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
<meta property="og:image" content="/images/message.png" />
|
||||
<meta property="og:title" content="Manage your .env files in seconds" />
|
||||
<meta
|
||||
name="og:description"
|
||||
content="Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files."
|
||||
/>
|
||||
<meta name="og:description" content={t("integrations:description")} />
|
||||
</Head>
|
||||
<div className="flex flex-row">
|
||||
<div className="w-full max-h-96 pb-2 h-screen max-h-[calc(100vh-10px)] overflow-y-scroll no-scrollbar no-scrollbar::-webkit-scrollbar">
|
||||
<NavHeader pageName="Project Integrations" isProjectRelated={true} />
|
||||
<NavHeader
|
||||
pageName={t("integrations:title")}
|
||||
isProjectRelated={true}
|
||||
/>
|
||||
<div className="flex flex-col justify-between items-start mx-4 mt-6 mb-4 text-xl max-w-5xl px-2">
|
||||
<div className="flex flex-row justify-start items-center text-3xl">
|
||||
<p className="font-semibold mr-4">Current Project Integrations</p>
|
||||
<p className="font-semibold mr-4">{t("integrations:title")}</p>
|
||||
</div>
|
||||
<p className="mr-4 text-base text-gray-400">
|
||||
Manage your integrations of Infisical with third-party services.
|
||||
{t("integrations:description")}
|
||||
</p>
|
||||
</div>
|
||||
{projectIntegrations.length > 0 ? (
|
||||
@@ -235,34 +244,22 @@ export default function Integrations() {
|
||||
) : (
|
||||
<div className="flex flex-col max-w-5xl justify-center bg-white/5 p-6 rounded-md mx-6 mt-8">
|
||||
<div className="relative px-4 flex flex-col text-gray-400 items-center justify-center">
|
||||
<div className="mb-1">
|
||||
You {"don't"} have any integrations set up yet. When you do,
|
||||
they will appear here.
|
||||
</div>
|
||||
<div className="">
|
||||
To start, click on any of the options below. It takes 5 clicks
|
||||
to set up.
|
||||
</div>
|
||||
<div className="mb-1">{t("integrations:no-integrations1")}</div>
|
||||
<div className="">{t("integrations:no-integrations2")}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-col justify-between items-start mx-4 mt-12 mb-4 text-xl max-w-5xl px-2">
|
||||
<div className="flex flex-row justify-start items-center text-3xl">
|
||||
<p className="font-semibold mr-4">Available Integrations</p>
|
||||
<p className="font-semibold mr-4">
|
||||
{t("integrations:available")}
|
||||
</p>
|
||||
</div>
|
||||
<p className="mr-4 text-base text-gray-400">
|
||||
Click on the itegration you want to connect. This will let your
|
||||
environment variables flow automatically into selected third-party
|
||||
services.
|
||||
{t("integrations:available-text1")}
|
||||
</p>
|
||||
<p className="mr-4 text-xs text-gray-600 mt-1">
|
||||
Note: during an integration with Heroku, for security reasons, it
|
||||
is impossible to maintain end-to-end encryption. In theory, this
|
||||
lets Infisical decrypt yor environment variables. In practice, we
|
||||
can assure you that this will never be done, and it allows us to
|
||||
protect your secrets from bad actors online. The core Infisical
|
||||
service will always stay end-to-end encrypted. With any questions,
|
||||
reach out support@infisical.com.
|
||||
{t("integrations:available-text2")}
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid gap-4 grid-cols-3 grid-rows-3 mx-6 mt-4 max-w-5xl">
|
||||
|
||||
@@ -55,14 +55,11 @@ export default function Login() {
|
||||
return (
|
||||
<div className="bg-bunker-800 h-screen flex flex-col justify-start px-6">
|
||||
<Head>
|
||||
<title>{t("auth:meta.login.title")}</title>
|
||||
<title>{t("common:head-title", { title: t("login:title") })}</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
<meta property="og:image" content="/images/message.png" />
|
||||
<meta property="og:title" content={t("auth:meta.login.og-title")} />
|
||||
<meta
|
||||
name="og:description"
|
||||
content={t("auth:meta.login.og-description")}
|
||||
/>
|
||||
<meta property="og:title" content={t("login:og-title")} />
|
||||
<meta name="og:description" content={t("login:og-description")} />
|
||||
</Head>
|
||||
<Link href="/">
|
||||
<div className="flex justify-center mb-8 mt-20 cursor-pointer">
|
||||
@@ -76,18 +73,18 @@ export default function Login() {
|
||||
</Link>
|
||||
<div className="bg-bunker w-full max-w-md mx-auto h-7/12 py-4 pt-8 px-6 rounded-xl drop-shadow-xl">
|
||||
<p className="text-4xl flex justify-center font-semibold text-transparent bg-clip-text bg-gradient-to-br from-sky-400 to-primary">
|
||||
{t("auth:login")}
|
||||
{t("login:login")}
|
||||
</p>
|
||||
<div className="flex flex-row items-center justify-center">
|
||||
<p className="text-md flex justify-center mt-2 text-gray-400">
|
||||
{t("auth:need-account")}
|
||||
{t("login:need-account")}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col items-center justify-center w-full md:pb-4 max-h-24 max-w-md mx-auto">
|
||||
<Link href="/signup">
|
||||
<button className="w-full pb-3 hover:opacity-90 duration-200">
|
||||
<u className="font-normal text-md text-sky-500">
|
||||
{t("auth:create-account")}
|
||||
{t("login:create-account")}
|
||||
</u>
|
||||
</button>
|
||||
</Link>
|
||||
@@ -116,7 +113,7 @@ export default function Login() {
|
||||
<div className="flex flex-col items-center justify-center w-full md:p-2 max-h-20 max-w-md mt-4 mx-auto text-sm">
|
||||
<div className="text-l mt-6 m-8 px-8 py-3 text-lg">
|
||||
<Button
|
||||
text={t("auth:login")}
|
||||
text={t("login:login")}
|
||||
onButtonPressed={loginCheck}
|
||||
loading={isLoading}
|
||||
size="lg"
|
||||
@@ -131,7 +128,7 @@ export default function Login() {
|
||||
<div className="w-full p-2 flex flex-row items-center bg-white/10 text-gray-300 rounded-md max-w-md mx-auto mt-4">
|
||||
<FontAwesomeIcon icon={faWarning} className="ml-2 mr-6 text-6xl" />
|
||||
|
||||
{t("auth:maintenance-alert")}
|
||||
{t("common:maintenance-alert")}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Head from "next/head";
|
||||
import useTranslation from "next-translate/useTranslation";
|
||||
|
||||
import Plan from "~/components/billing/Plan";
|
||||
import NavHeader from "~/components/navigation/NavHeader";
|
||||
@@ -12,36 +13,38 @@ export default function SettingsBilling() {
|
||||
let [currentPlan, setCurrentPlan] = useState("");
|
||||
let [numUsers, setNumUsers] = useState("");
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const plans = [
|
||||
{
|
||||
key: 1,
|
||||
name: "Starter",
|
||||
price: "Free",
|
||||
priceExplanation: "up to 5 team members",
|
||||
text: "Manage any project with 5 members for free!",
|
||||
subtext: "$5 per member/month afterwards.",
|
||||
buttonTextMain: "Downgrade",
|
||||
buttonTextSecondary: "Learn More",
|
||||
name: t("common:starter"),
|
||||
price: t("common:free"),
|
||||
priceExplanation: t("billing:starter.price-explanation"),
|
||||
text: t("billing:starter.text"),
|
||||
subtext: t("billing:starter.subtext"),
|
||||
buttonTextMain: t("common:downgrade"),
|
||||
buttonTextSecondary: t("common:learn-more"),
|
||||
current: currentPlan == STRIPE_PRODUCT_STARTER,
|
||||
},
|
||||
{
|
||||
key: 2,
|
||||
name: "Professional",
|
||||
name: t("common:professional"),
|
||||
price: "$9",
|
||||
priceExplanation: "/member/month",
|
||||
subtext: "Includes unlimited projects & members.",
|
||||
text: "Keep up with key management as you grow.",
|
||||
buttonTextMain: "Upgrade",
|
||||
buttonTextSecondary: "Learn More",
|
||||
priceExplanation: t("billing:professional.price-explanation"),
|
||||
subtext: t("billing:professional.subtext"),
|
||||
text: t("billing:professional.text"),
|
||||
buttonTextMain: t("common:upgrade"),
|
||||
buttonTextSecondary: t("common:learn-more"),
|
||||
current: currentPlan == STRIPE_PRODUCT_PRO,
|
||||
},
|
||||
{
|
||||
key: 3,
|
||||
name: "Enterprise",
|
||||
price: "Custom Pricing",
|
||||
text: "More control for advanced organizations.",
|
||||
buttonTextMain: "Schedule a Demo",
|
||||
buttonTextSecondary: "Learn More",
|
||||
name: t("common:enterprise"),
|
||||
price: t("common:custom-pricing"),
|
||||
text: t("billing:enterprise.text"),
|
||||
buttonTextMain: t("common:schedule-demo"),
|
||||
buttonTextSecondary: t("common:learn-more"),
|
||||
current: false,
|
||||
},
|
||||
];
|
||||
@@ -61,30 +64,32 @@ export default function SettingsBilling() {
|
||||
return (
|
||||
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
|
||||
<Head>
|
||||
<title>Settings - Billing</title>
|
||||
<title>{t("common:head-title", { title: t("billing:title") })}</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Head>
|
||||
<div className="flex flex-row">
|
||||
<div className="w-full max-h-screen pb-2 overflow-y-auto">
|
||||
<NavHeader pageName="Usage & Billing" />
|
||||
<NavHeader pageName={t("billing:title")} />
|
||||
<div className="flex flex-row justify-between items-center ml-6 my-8 text-xl max-w-5xl">
|
||||
<div className="flex flex-col justify-start items-start text-3xl">
|
||||
<p className="font-semibold mr-4 text-gray-200">
|
||||
Usage & Billing
|
||||
{t("billing:title")}
|
||||
</p>
|
||||
<p className="font-normal mr-4 text-gray-400 text-base">
|
||||
View and manage your {"organization's"} subscription here.
|
||||
{t("billing:description")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col ml-6 text-mineshaft-50">
|
||||
<p className="text-xl font-semibold">Subscription</p>
|
||||
<p className="text-xl font-semibold">{t("billing:subscription")}</p>
|
||||
<div className="flex flex-row mt-4 overflow-x-auto">
|
||||
{plans.map((plan) => (
|
||||
<Plan key={plan.name} plan={plan} />
|
||||
))}
|
||||
</div>
|
||||
<p className="text-xl font-bold mt-12">Current Usage</p>
|
||||
<p className="text-xl font-bold mt-12">
|
||||
{t("billing:current-usage")}
|
||||
</p>
|
||||
<div className="flex flex-row">
|
||||
<div className="mr-4 mt-8 text-gray-300 w-60 pt-6 pb-10 rounded-md bg-white/5 flex justify-center items-center flex flex-col">
|
||||
<p className="text-6xl font-bold">{numUsers}</p>
|
||||
|
||||
@@ -159,12 +159,14 @@ export default function SettingsOrg() {
|
||||
return (
|
||||
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
|
||||
<Head>
|
||||
<title>{t("settings:meta.org.head-title")}</title>
|
||||
<title>
|
||||
{t("common:head-title", { title: t("settings-org:title") })}
|
||||
</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Head>
|
||||
<div className="flex flex-row">
|
||||
<div className="w-full max-h-screen pb-2 overflow-y-auto">
|
||||
<NavHeader pageName={t("settings:meta.org.title")} />
|
||||
<NavHeader pageName={t("settings-org:title")} />
|
||||
<AddIncidentContactDialog
|
||||
isOpen={isAddIncidentContactOpen}
|
||||
closeModal={closeAddIncidentContactModal}
|
||||
@@ -175,10 +177,10 @@ export default function SettingsOrg() {
|
||||
<div className="flex flex-row justify-between items-center ml-6 my-8 text-xl max-w-5xl">
|
||||
<div className="flex flex-col justify-start items-start text-3xl">
|
||||
<p className="font-semibold mr-4 text-gray-200">
|
||||
{t("settings:meta.org.title")}
|
||||
{t("settings-org:title")}
|
||||
</p>
|
||||
<p className="font-normal mr-4 text-gray-400 text-base">
|
||||
{t("settings:meta.org.description")}
|
||||
{t("settings-org:description")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -278,15 +280,15 @@ export default function SettingsOrg() {
|
||||
<div className="flex flex-row max-w-5xl justify-between items-center w-full">
|
||||
<div className="flex flex-col justify-between w-full max-w-3xl">
|
||||
<p className="text-xl font-semibold mb-3 min-w-max">
|
||||
{t("settings:incident-contacts")}
|
||||
{t("section-incident:incident-contacts")}
|
||||
</p>
|
||||
<p className="text-xs text-gray-500 mb-2 min-w-max">
|
||||
{t("settings:incident-contacts-description")}
|
||||
{t("section-incident:incident-contacts-description")}
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-4 mb-2 min-w-max flex flex-row items-end justify-end justify-center">
|
||||
<Button
|
||||
text={t("common:add-contact")}
|
||||
text={t("section-incident:add-contact")}
|
||||
onButtonPressed={openAddIncidentContactModal}
|
||||
color="mineshaft"
|
||||
size="md"
|
||||
@@ -332,7 +334,7 @@ export default function SettingsOrg() {
|
||||
) : (
|
||||
<div className="w-full flex flex-row justify-center mt-6 max-w-4xl ml-6">
|
||||
<p className="text-gray-400">
|
||||
{t("settings:no-incident-contacts")}
|
||||
{t("section-incident:no-incident-contacts")}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Head from "next/head";
|
||||
import useTranslation from "next-translate/useTranslation";
|
||||
import { faCheck, faX } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
@@ -26,6 +27,8 @@ export default function PersonalSettings() {
|
||||
const [backupKeyIssued, setBackupKeyIssued] = useState(false);
|
||||
const [backupKeyError, setBackupKeyError] = useState(false);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(async () => {
|
||||
let user = await getUser();
|
||||
setPersonalEmail(user.email);
|
||||
@@ -35,19 +38,24 @@ export default function PersonalSettings() {
|
||||
return (
|
||||
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
|
||||
<Head>
|
||||
<title>Personal Settings</title>
|
||||
<title>
|
||||
{t("common:head-title", { title: t("settings-personal:title") })}
|
||||
</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Head>
|
||||
<div className="flex flex-row">
|
||||
<div className="w-full max-h-screen pb-2 overflow-y-auto">
|
||||
<NavHeader pageName="Personal Settings" isProjectRelated={false} />
|
||||
<NavHeader
|
||||
pageName={t("settings-personal:title")}
|
||||
isProjectRelated={false}
|
||||
/>
|
||||
<div className="flex flex-row justify-between items-center ml-6 mt-8 mb-6 text-xl max-w-5xl">
|
||||
<div className="flex flex-col justify-start items-start text-3xl">
|
||||
<p className="font-semibold mr-4 text-gray-200">
|
||||
Personal Settings
|
||||
{t("settings-personal:title")}
|
||||
</p>
|
||||
<p className="font-normal mr-4 text-gray-400 text-base">
|
||||
View and manage your personal information here.
|
||||
{t("settings-personal:description")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -104,13 +112,13 @@ export default function PersonalSettings() {
|
||||
<div className="flex flex-row max-w-5xl justify-between items-center w-full">
|
||||
<div className="flex flex-col justify-between w-full max-w-3xl">
|
||||
<p className="text-xl font-semibold mb-3 min-w-max">
|
||||
Change password
|
||||
{t("form-password:change")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="max-w-xl w-full">
|
||||
<InputField
|
||||
label="Current Password"
|
||||
label={t("form-password:current")}
|
||||
onChangeHandler={(password) => {
|
||||
setCurrentPassword(password);
|
||||
}}
|
||||
@@ -118,11 +126,11 @@ export default function PersonalSettings() {
|
||||
value={currentPassword}
|
||||
isRequired
|
||||
error={currentPasswordError}
|
||||
errorText="The current password may be wrong"
|
||||
errorText={t("form-password:current-wrong")}
|
||||
/>
|
||||
<div className="py-2"></div>
|
||||
<InputField
|
||||
label="New Password"
|
||||
label={t("form-password:new")}
|
||||
onChangeHandler={(password) => {
|
||||
setNewPassword(password);
|
||||
passwordCheck(
|
||||
@@ -148,7 +156,7 @@ export default function PersonalSettings() {
|
||||
passwordErrorNumber ? (
|
||||
<div className="w-full mt-3 bg-white/5 px-2 flex flex-col items-start py-2 rounded-md max-w-xl mb-2">
|
||||
<div className={`text-gray-400 text-sm mb-1`}>
|
||||
Password should contain at least:
|
||||
{t("form-password:validate-base")}
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
{passwordErrorLength ? (
|
||||
@@ -167,7 +175,7 @@ export default function PersonalSettings() {
|
||||
passwordErrorLength ? "text-gray-400" : "text-gray-600"
|
||||
} text-sm`}
|
||||
>
|
||||
14 characters
|
||||
{t("form-password:validate-length")}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
@@ -189,7 +197,7 @@ export default function PersonalSettings() {
|
||||
: "text-gray-600"
|
||||
} text-sm`}
|
||||
>
|
||||
1 lowercase character
|
||||
{t("form-password:validate-case")}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
@@ -209,7 +217,7 @@ export default function PersonalSettings() {
|
||||
passwordErrorNumber ? "text-gray-400" : "text-gray-600"
|
||||
} text-sm`}
|
||||
>
|
||||
1 number
|
||||
{t("form-password:validate-number")}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -247,7 +255,7 @@ export default function PersonalSettings() {
|
||||
passwordErrorNumber
|
||||
)
|
||||
}
|
||||
textDisabled="Change Password"
|
||||
textDisabled={t("password:change")}
|
||||
/>
|
||||
<FontAwesomeIcon
|
||||
icon={faCheck}
|
||||
@@ -262,32 +270,30 @@ export default function PersonalSettings() {
|
||||
<div className="flex flex-row max-w-5xl justify-between items-center w-full">
|
||||
<div className="flex flex-col justify-between w-full max-w-3xl">
|
||||
<p className="text-xl font-semibold mb-3 min-w-max">
|
||||
Emergency Kit
|
||||
{t("settings-personal:emergency.name")}
|
||||
</p>
|
||||
<p className="text-sm text-mineshaft-300 min-w-max">
|
||||
Your Emergency Kit contains the information you’ll need to
|
||||
sign in to your Infisical account.
|
||||
{t("settings-personal:emergency.text1")}
|
||||
</p>
|
||||
<p className="text-sm text-mineshaft-300 mb-5 min-w-max">
|
||||
Only the latest issued Emergency Kit remains valid. To get a
|
||||
new Emergency Kit, verify your password.
|
||||
{t("settings-personal:emergency.text2")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full max-w-xl mb-4">
|
||||
<InputField
|
||||
label="Current Password"
|
||||
label={t("password:current")}
|
||||
onChangeHandler={setBackupPassword}
|
||||
type="password"
|
||||
value={backupPassword}
|
||||
isRequired
|
||||
error={backupKeyError}
|
||||
errorText="The current password is wrong"
|
||||
errorText={t("password:current-wrong")}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-row items-center mt-3 w-full w-60">
|
||||
<Button
|
||||
text="Download Emergency Kit"
|
||||
text={t("settings-personal:emergency.download")}
|
||||
onButtonPressed={() => {
|
||||
issueBackupKey({
|
||||
email: personalEmail,
|
||||
@@ -300,7 +306,7 @@ export default function PersonalSettings() {
|
||||
color="mineshaft"
|
||||
size="md"
|
||||
active={backupPassword != ""}
|
||||
textDisabled="Download Emergency Kit"
|
||||
textDisabled={t("settings-personal:emergency.download")}
|
||||
/>
|
||||
<FontAwesomeIcon
|
||||
icon={faCheck}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import Head from "next/head";
|
||||
import { useRouter } from "next/router";
|
||||
import useTranslation from "next-translate/useTranslation";
|
||||
import { faCheck, faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
import Button from "~/components/basic/buttons/Button";
|
||||
@@ -25,6 +26,8 @@ export default function SettingsBasic() {
|
||||
let [isAddServiceTokenDialogOpen, setIsAddServiceTokenDialogOpen] =
|
||||
useState(false);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(async () => {
|
||||
let userWorkspaces = await getWorkspaces();
|
||||
userWorkspaces.map((userWorkspace) => {
|
||||
@@ -89,7 +92,9 @@ export default function SettingsBasic() {
|
||||
return (
|
||||
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
|
||||
<Head>
|
||||
<title>Settings</title>
|
||||
<title>
|
||||
{t("common:head-title", { title: t("settings-project:title") })}
|
||||
</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Head>
|
||||
<AddServiceTokenDialog
|
||||
@@ -100,14 +105,17 @@ export default function SettingsBasic() {
|
||||
/>
|
||||
<div className="flex flex-row mr-6 max-w-5xl">
|
||||
<div className="w-full max-h-screen pb-2 overflow-y-auto">
|
||||
<NavHeader pageName="Project Settings" isProjectRelated={true} />
|
||||
<NavHeader
|
||||
pageName={t("settings-project:title")}
|
||||
isProjectRelated={true}
|
||||
/>
|
||||
<div className="flex flex-row justify-between items-center ml-6 my-8 text-xl max-w-5xl">
|
||||
<div className="flex flex-col justify-start items-start text-3xl">
|
||||
<p className="font-semibold mr-4 text-gray-200">
|
||||
Project Settings
|
||||
{t("settings-project:title")}
|
||||
</p>
|
||||
<p className="font-normal mr-4 text-gray-400 text-base">
|
||||
These settings only apply to the currently selected Project.
|
||||
{t("settings-project:description")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -115,7 +123,9 @@ export default function SettingsBasic() {
|
||||
<div className="flex flex-col">
|
||||
<div className="min-w-md mt-2 flex flex-col items-start">
|
||||
<div className="bg-white/5 rounded-md px-6 pt-6 pb-4 flex flex-col items-start flex flex-col items-start w-full mb-6 pt-2">
|
||||
<p className="text-xl font-semibold mb-4">Display Name</p>
|
||||
<p className="text-xl font-semibold mb-4">
|
||||
{t("common:display-name")}
|
||||
</p>
|
||||
<div className="max-h-28 w-full max-w-md mr-auto">
|
||||
<InputField
|
||||
onChangeHandler={modifyWorkspaceName}
|
||||
@@ -128,7 +138,7 @@ export default function SettingsBasic() {
|
||||
<div className="flex justify-start w-full">
|
||||
<div className={`flex justify-start max-w-sm mt-4 mb-2`}>
|
||||
<Button
|
||||
text="Save Changes"
|
||||
text={t("common:save-changes")}
|
||||
onButtonPressed={() => submitChanges(workspaceName)}
|
||||
color="mineshaft"
|
||||
size="md"
|
||||
@@ -140,15 +150,14 @@ export default function SettingsBasic() {
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-white/5 rounded-md px-6 pt-6 pb-2 flex flex-col items-start flex flex-col items-start w-full mb-6 mt-4">
|
||||
<p className="text-xl font-semibold self-start">Project ID</p>
|
||||
<p className="text-xl font-semibold self-start">
|
||||
{t("common:project-id")}
|
||||
</p>
|
||||
<p className="text-base text-gray-400 font-normal self-start mt-4">
|
||||
To integrate Infisical into your code base and get automatic
|
||||
injection of environmental variables, you should use the
|
||||
following Project ID.
|
||||
{t("settings-project:project-id-description")}
|
||||
</p>
|
||||
<p className="text-base text-gray-400 font-normal self-start">
|
||||
For more guidance, including code snipets for various
|
||||
languages and frameworks, see{" "}
|
||||
{t("settings-project:project-id-description2")}
|
||||
{/* eslint-disable-next-line react/jsx-no-target-blank */}
|
||||
<a
|
||||
href="https://infisical.com/docs/getting-started/introduction"
|
||||
@@ -156,7 +165,7 @@ export default function SettingsBasic() {
|
||||
rel="noopener"
|
||||
className="text-primary hover:opacity-80 duration-200"
|
||||
>
|
||||
Infisical Docs.
|
||||
{t("settings-project:docs")}
|
||||
</a>
|
||||
</p>
|
||||
<div className="max-h-28 w-ful">
|
||||
@@ -166,7 +175,7 @@ export default function SettingsBasic() {
|
||||
placeholder=""
|
||||
isRequired
|
||||
static
|
||||
text="This is your project's auto-generated unique identifier. It can't be changed."
|
||||
text={t("settings-project:auto-generated")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -174,16 +183,15 @@ export default function SettingsBasic() {
|
||||
<div className="flex flex-row justify-between w-full">
|
||||
<div className="flex flex-col w-full">
|
||||
<p className="text-xl font-semibold mb-3">
|
||||
Service Tokens
|
||||
{t("section-token:service-tokens")}
|
||||
</p>
|
||||
<p className="text-base text-gray-400 mb-4">
|
||||
Every service token is specific to you, a certain
|
||||
project and a certain environment within this project.
|
||||
{t("section-token:service-tokens-description")}
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-48">
|
||||
<Button
|
||||
text="Add New Token"
|
||||
text={t("section-token:add-new")}
|
||||
onButtonPressed={() => {
|
||||
setIsAddServiceTokenDialogOpen(true);
|
||||
}}
|
||||
@@ -237,15 +245,15 @@ export default function SettingsBasic() {
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-white/5 rounded-md px-6 pt-6 pb-6 border-l border-red pl-6 flex flex-col items-start flex flex-col items-start w-full mb-6 mt-4 pb-4 pt-2">
|
||||
<p className="text-xl font-bold text-red">Danger Zone</p>
|
||||
<p className="text-xl font-bold text-red">
|
||||
{t("settings-project:danger-zone")}
|
||||
</p>
|
||||
<p className="mt-2 text-md text-gray-400">
|
||||
As soon as you delete this project, you will not be able to undo
|
||||
it. This will immediately remove all the keys. If you still want
|
||||
to do that, please enter the name of the project below.
|
||||
{t("settings-project:danger-zone-note")}
|
||||
</p>
|
||||
<div className="max-h-28 w-full max-w-md mr-auto mt-4">
|
||||
<InputField
|
||||
label="Project to be Deleted"
|
||||
label={t("settings-project:project-to-delete")}
|
||||
onChangeHandler={setWorkspaceToBeDeletedName}
|
||||
type="varName"
|
||||
value={workspaceToBeDeletedName}
|
||||
@@ -258,11 +266,10 @@ export default function SettingsBasic() {
|
||||
className="max-w-md mt-6 w-full inline-flex justify-center rounded-md border border-transparent bg-gray-800 px-4 py-2.5 text-sm font-medium text-gray-400 hover:bg-red hover:text-white hover:font-semibold hover:text-semibold duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
|
||||
onClick={executeDeletingWorkspace}
|
||||
>
|
||||
Delete Project
|
||||
{t("settings-project:delete-project")}
|
||||
</button>
|
||||
<p className="mt-0.5 ml-1 text-xs text-gray-500">
|
||||
Note: You can only delete a project in case you have more than
|
||||
one.
|
||||
{t("settings-project:delete-project-note")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -250,13 +250,13 @@ export default function SignUp() {
|
||||
const step1 = (
|
||||
<div className="bg-bunker w-full max-w-md mx-auto h-7/12 py-8 md:px-6 mx-1 mb-48 md:mb-16 rounded-xl drop-shadow-xl">
|
||||
<p className="text-4xl font-semibold flex justify-center text-transparent bg-clip-text bg-gradient-to-br from-sky-400 to-primary">
|
||||
{t("auth:step1-start")}
|
||||
{t("signup:step1-start")}
|
||||
</p>
|
||||
<div className="flex flex-col items-center justify-center w-full md:pb-2 max-h-24 max-w-md mx-auto pt-2">
|
||||
<Link href="/login">
|
||||
<button className="w-max pb-3 hover:opacity-90 duration-200">
|
||||
<u className="font-normal text-md text-sky-500">
|
||||
{t("auth:already-have-account")}
|
||||
{t("signup:already-have-account")}
|
||||
</u>
|
||||
</button>
|
||||
</Link>
|
||||
@@ -279,12 +279,11 @@ export default function SignUp() {
|
||||
</div> */}
|
||||
<div className="flex flex-col items-center justify-center w-5/6 md:w-full md:p-2 max-h-28 max-w-xs md:max-w-md mx-auto mt-4 md:mt-4 text-sm text-center md:text-left">
|
||||
<p className="text-gray-400 mt-2 md:mx-0.5">
|
||||
By creating an account, you agree to our Terms and have read and
|
||||
acknowledged the Privacy Policy.
|
||||
{t("signup:step1-privacy")}
|
||||
</p>
|
||||
<div className="text-l mt-6 m-2 md:m-8 px-8 py-1 text-lg">
|
||||
<Button
|
||||
text={t("auth:step1-submit")}
|
||||
text={t("signup:step1-submit")}
|
||||
onButtonPressed={emailCheck}
|
||||
size="lg"
|
||||
/>
|
||||
@@ -297,7 +296,7 @@ export default function SignUp() {
|
||||
const step2 = (
|
||||
<div className="bg-bunker w-max mx-auto h-7/12 pt-10 pb-4 px-8 rounded-xl drop-shadow-xl mb-64 md:mb-16">
|
||||
<Trans
|
||||
i18nKey="common:step2-message"
|
||||
i18nKey="signup:step2-message"
|
||||
components={{
|
||||
wrapper: <p className="text-l flex justify-center text-gray-400" />,
|
||||
email: (
|
||||
@@ -325,10 +324,10 @@ export default function SignUp() {
|
||||
className="mt-2 mb-6"
|
||||
/>
|
||||
</div>
|
||||
{codeError && <Error text={t("auth:step2-code-error")} />}
|
||||
{codeError && <Error text={t("signup:step2-code-error")} />}
|
||||
<div className="flex max-w-min flex-col items-center justify-center md:p-2 max-h-24 max-w-md mx-auto text-lg px-4 mt-4 mb-2">
|
||||
<Button
|
||||
text={t("auth:verify")}
|
||||
text={t("signup:verify")}
|
||||
onButtonPressed={incrementStep}
|
||||
size="lg"
|
||||
/>
|
||||
@@ -342,7 +341,7 @@ export default function SignUp() {
|
||||
</button>
|
||||
</Link> */}
|
||||
<p className="text-sm text-gray-500 pb-2">
|
||||
{t("auth:step2-spam-alert")}
|
||||
{t("signup:step2-spam-alert")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -352,7 +351,7 @@ export default function SignUp() {
|
||||
const step3 = (
|
||||
<div className="bg-bunker w-max mx-auto h-7/12 py-10 px-8 rounded-xl drop-shadow-xl mb-36 md:mb-16">
|
||||
<p className="text-4xl font-bold flex justify-center mb-6 text-gray-400 mx-8 md:mx-16 text-transparent bg-clip-text bg-gradient-to-br from-sky-400 to-primary">
|
||||
{t("auth:step3-message")}
|
||||
{t("signup:step3-message")}
|
||||
</p>
|
||||
<div className="relative z-0 flex items-center justify-end w-full md:p-2 rounded-lg max-h-24">
|
||||
<InputField
|
||||
@@ -382,7 +381,7 @@ export default function SignUp() {
|
||||
</div>
|
||||
<div className="mt-2 flex flex-col items-center justify-center w-full md:p-2 rounded-lg max-h-60">
|
||||
<InputField
|
||||
label={t("common:password")}
|
||||
label={t("form-password:password")}
|
||||
onChangeHandler={(password) => {
|
||||
setPassword(password);
|
||||
passwordCheck(
|
||||
@@ -405,7 +404,7 @@ export default function SignUp() {
|
||||
passwordErrorNumber ? (
|
||||
<div className="w-full mt-4 bg-white/5 px-2 flex flex-col items-start py-2 rounded-md">
|
||||
<div className={`text-gray-400 text-sm mb-1`}>
|
||||
{t("auth:password-validate")}
|
||||
{t("form-password:validate-base")}
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
{passwordErrorLength ? (
|
||||
@@ -424,7 +423,7 @@ export default function SignUp() {
|
||||
passwordErrorLength ? "text-gray-400" : "text-gray-600"
|
||||
} text-sm`}
|
||||
>
|
||||
{t("auth:password-validate-length")}
|
||||
{t("form-password:validate-length")}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
@@ -444,7 +443,7 @@ export default function SignUp() {
|
||||
passwordErrorLowerCase ? "text-gray-400" : "text-gray-600"
|
||||
} text-sm`}
|
||||
>
|
||||
{t("auth:password-validate-case")}
|
||||
{t("form-password:validate-case")}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
@@ -464,7 +463,7 @@ export default function SignUp() {
|
||||
passwordErrorNumber ? "text-gray-400" : "text-gray-600"
|
||||
} text-sm`}
|
||||
>
|
||||
{t("auth:password-validate-number")}
|
||||
{t("form-password:validate-number")}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -531,14 +530,11 @@ export default function SignUp() {
|
||||
return (
|
||||
<div className="bg-bunker-800 h-screen flex flex-col items-center justify-center">
|
||||
<Head>
|
||||
<title>{t("auth:meta.signup.title")}</title>
|
||||
<title>{t("common:head-title", { title: t("signup:title") })}</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
<meta property="og:image" content="/images/message.png" />
|
||||
<meta property="og:title" content={t("auth:meta.signup.og-title")} />
|
||||
<meta
|
||||
name="og:description"
|
||||
content={t("auth:meta.signup.og-description")}
|
||||
/>
|
||||
<meta property="og:title" content={t("signup:og-title")} />
|
||||
<meta name="og:description" content={t("signup:og-description")} />
|
||||
</Head>
|
||||
<div className="flex flex-col justify-center items-center">
|
||||
<Link href="/">
|
||||
|
||||
@@ -127,19 +127,21 @@ export default function Users() {
|
||||
return userList ? (
|
||||
<div className="bg-bunker-800 md:h-screen flex flex-col justify-start">
|
||||
<Head>
|
||||
<title>{t("settings:meta.members.head-title")}</title>
|
||||
<title>
|
||||
{t("common:head-title", { title: t("settings-members:title") })}
|
||||
</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Head>
|
||||
<NavHeader
|
||||
pageName={t("settings:meta.members.title")}
|
||||
pageName={t("settings-members:title")}
|
||||
isProjectRelated={true}
|
||||
/>
|
||||
<div className="flex flex-col justify-start items-start px-6 py-6 pb-4 text-3xl">
|
||||
<p className="font-semibold mr-4 text-white">
|
||||
{t("settings:meta.members.title")}
|
||||
{t("settings-members:title")}
|
||||
</p>
|
||||
<p className="mr-4 text-base text-gray-400">
|
||||
{t("settings:meta.members.description")}
|
||||
{t("settings-members:description")}
|
||||
</p>
|
||||
</div>
|
||||
<AddProjectMemberDialog
|
||||
@@ -167,12 +169,12 @@ export default function Users() {
|
||||
className="pl-2 text-gray-400 rounded-r-md bg-white/5 w-full h-full outline-none"
|
||||
value={searchUsers}
|
||||
onChange={(e) => setSearchUsers(e.target.value)}
|
||||
placeholder={t("settings:search-members")}
|
||||
placeholder={t("section-members:search-members")}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-2 ml-2 min-w-max flex flex-row items-start justify-start mr-4">
|
||||
<Button
|
||||
text={t("settings:add-member")}
|
||||
text={t("section-members:add-member")}
|
||||
onButtonPressed={openAddModal}
|
||||
color="mineshaft"
|
||||
size="md"
|
||||
|
||||
Reference in New Issue
Block a user