Add eslint rule and fix as many issues as possible

This commit is contained in:
Khoa Le
2023-06-19 23:32:35 -04:00
parent e9eacc445d
commit 9d33e4756b
689 changed files with 9446 additions and 21821 deletions

View File

@@ -10,66 +10,68 @@ module.exports = {
es2021: true
},
extends: [
'airbnb',
'airbnb-typescript',
'airbnb/hooks',
'plugin:react/recommended',
'prettier',
'plugin:storybook/recommended'
"airbnb",
"airbnb-typescript",
"airbnb/hooks",
"plugin:react/recommended",
"prettier",
"plugin:storybook/recommended"
],
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
project: './tsconfig.json',
ecmaVersion: "latest",
sourceType: "module",
project: "./tsconfig.json",
ecmaFeatures: {
jsx: true
},
tsconfigRootDir: __dirname
},
plugins: ['react', 'prettier', 'simple-import-sort', 'import'],
plugins: ["react", "prettier", "simple-import-sort", "import"],
rules: {
'react/react-in-jsx-scope': 'off',
'import/prefer-default-export': 'off',
'react-hooks/exhaustive-deps': 'off',
'@typescript-eslint/ban-ts-comment': 'warn',
'react/jsx-props-no-spreading': 'off', // switched off for component building
quotes: ["error", "double", { avoidEscape: true }],
"comma-dangle": ["error", "only-multiline"],
"react/react-in-jsx-scope": "off",
"import/prefer-default-export": "off",
"react-hooks/exhaustive-deps": "off",
"@typescript-eslint/ban-ts-comment": "warn",
"react/jsx-props-no-spreading": "off", // switched off for component building
// TODO: This rule will be switched ON after complete revamp of frontend
'@typescript-eslint/no-explicit-any': 'off',
'no-console': 'off',
'arrow-body-style': 'off',
'no-underscore-dangle': [
'error',
"@typescript-eslint/no-explicit-any": "off",
"no-console": "off",
"arrow-body-style": "off",
"no-underscore-dangle": [
"error",
{
allow: ['_id']
allow: ["_id"]
}
],
'jsx-a11y/anchor-is-valid': 'off',
"jsx-a11y/anchor-is-valid": "off",
// all those <a> tags must be converted to label or a p component
//
'react/require-default-props': 'off',
'react/jsx-filename-extension': [
"react/require-default-props": "off",
"react/jsx-filename-extension": [
1,
{
extensions: ['.tsx', '.ts']
extensions: [".tsx", ".ts"]
}
],
// TODO: turn this rule ON after migration. everything should use arrow functions
'react/function-component-definition': [
"react/function-component-definition": [
0,
{
namedComponents: 'arrow-function'
namedComponents: "arrow-function"
}
],
'react/no-unknown-property': [
'error',
"react/no-unknown-property": [
"error",
{
ignore: ['jsx']
ignore: ["jsx"]
}
],
'@typescript-eslint/no-non-null-assertion': 'off',
'simple-import-sort/exports': 'warn',
'simple-import-sort/imports': [
'warn',
"@typescript-eslint/no-non-null-assertion": "off",
"simple-import-sort/exports": "warn",
"simple-import-sort/imports": [
"warn",
{
groups: [
// Node.js builtins. You could also generate this regex if you use a `.js` config.
@@ -77,26 +79,26 @@ module.exports = {
// Note that if you use the `node:` prefix for Node.js builtins,
// you can avoid this complexity: You can simply use "^node:".
[
'^(assert|buffer|child_process|cluster|console|constants|crypto|dgram|dns|domain|events|fs|http|https|module|net|os|path|punycode|querystring|readline|repl|stream|string_decoder|sys|timers|tls|tty|url|util|vm|zlib|freelist|v8|process|async_hooks|http2|perf_hooks)(/.*|$)'
"^(assert|buffer|child_process|cluster|console|constants|crypto|dgram|dns|domain|events|fs|http|https|module|net|os|path|punycode|querystring|readline|repl|stream|string_decoder|sys|timers|tls|tty|url|util|vm|zlib|freelist|v8|process|async_hooks|http2|perf_hooks)(/.*|$)"
],
// Packages `react` related packages
['^react', '^next', '^@?\\w'],
['^@app'],
["^react", "^next", "^@?\\w"],
["^@app"],
// Internal packages.
['^~(/.*|$)'],
["^~(/.*|$)"],
// Relative imports
['^\\.\\.(?!/?$)', '^\\.\\./?$', '^\\./(?=.*/)(?!/?$)', '^\\.(?!/?$)', '^\\./?$'],
["^\\.\\.(?!/?$)", "^\\.\\./?$", "^\\./(?=.*/)(?!/?$)", "^\\.(?!/?$)", "^\\./?$"],
// Style imports.
['^.+\\.?(css|scss)$']
["^.+\\.?(css|scss)$"]
]
}
]
},
ignorePatterns: ['next.config.js'],
ignorePatterns: ["next.config.js"],
settings: {
'import/resolver': {
"import/resolver": {
typescript: {
project: ['./tsconfig.json']
project: ["./tsconfig.json"]
}
}
}

View File

@@ -1,5 +1,5 @@
{
"singleQuote": true,
"singleQuote": false,
"printWidth": 100,
"trailingComma": "none",
"tabWidth": 2,

View File

@@ -6,7 +6,8 @@
"build": "next build",
"start": "next start",
"start:docker": "next build && next start",
"lint": "eslint --fix --ext js,ts,tsx ./src",
"lint": "eslint --ext js,ts,tsx ./src",
"lint-and-fix": "eslint --fix --ext js,ts,tsx ./src",
"type-check": "tsc --project tsconfig.json",
"storybook": "storybook dev -p 6006 -s ./public",
"build-storybook": "storybook build"

View File

@@ -1,8 +1,8 @@
import { ReactNode, useEffect, useState } from 'react';
import { useRouter } from 'next/router';
import { ReactNode, useEffect, useState } from "react";
import { useRouter } from "next/router";
import { publicPaths } from '@app/const';
import checkAuth from '@app/pages/api/auth/CheckAuth';
import { publicPaths } from "@app/const";
import checkAuth from "@app/pages/api/auth/CheckAuth";
// #TODO: finish spinner only when the data loads fully
// #TODO: Redirect somewhere if the page does not exist
@@ -21,7 +21,7 @@ export default function RouteGuard({ children }: Prop): JSX.Element {
*/
async function authCheck(url: string) {
// Make sure that we don't redirect when the user is on the following pages.
const path = `/${url.split('?')[0].split('/')[1]}`;
const path = `/${url.split("?")[0].split("/")[1]}`;
// Check if the user is authenticated
const response = await checkAuth();
@@ -30,15 +30,15 @@ export default function RouteGuard({ children }: Prop): JSX.Element {
if (!publicPaths.includes(path)) {
try {
if (response.status !== 200) {
router.push('/login');
console.log('Unauthorized to access.');
router.push("/login");
console.log("Unauthorized to access.");
setAuthorized(false);
} else {
setAuthorized(true);
console.log('Authorized to access.');
console.log("Authorized to access.");
}
} catch (error) {
console.log('Error (probably the authCheck route is stuck again...):', error);
console.log("Error (probably the authCheck route is stuck again...):", error);
}
}
}
@@ -53,16 +53,16 @@ export default function RouteGuard({ children }: Prop): JSX.Element {
// #TODO: add the loading page when not yet authorized.
const hideContent = () => setAuthorized(false);
// const onError = () => setAuthorized(true)
router.events.on('routeChangeStart', hideContent);
router.events.on("routeChangeStart", hideContent);
// router.events.on("routeChangeError", onError);
// on route change complete - run auth check
router.events.on('routeChangeComplete', authCheck);
router.events.on("routeChangeComplete", authCheck);
// unsubscribe from events in useEffect return function
return () => {
router.events.off('routeChangeStart', hideContent);
router.events.off('routeChangeComplete', authCheck);
router.events.off("routeChangeStart", hideContent);
router.events.off("routeChangeComplete", authCheck);
// router.events.off("routeChangeError", onError);
};
// eslint-disable-next-line react-hooks/exhaustive-deps

View File

@@ -1,16 +1,16 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
/* eslint-disable no-undef */
import posthog from 'posthog-js';
import posthog from "posthog-js";
import { ENV, POSTHOG_API_KEY, POSTHOG_HOST } from '../utilities/config';
import { ENV, POSTHOG_API_KEY, POSTHOG_HOST } from "../utilities/config";
export const initPostHog = () => {
// @ts-ignore
console.log("Hi there 👋")
try {
if (typeof window !== 'undefined') {
if (typeof window !== "undefined") {
// @ts-ignore
if (ENV === 'production' && TELEMETRY_CAPTURING_ENABLED) {
if (ENV === "production" && TELEMETRY_CAPTURING_ENABLED) {
posthog.init(POSTHOG_API_KEY, {
api_host: POSTHOG_HOST
});

View File

@@ -1,5 +1,5 @@
import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faExclamationTriangle } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
const Error = ({ text }: { text: string }): JSX.Element => {
return (

View File

@@ -1,5 +1,5 @@
import React, { Fragment } from 'react';
import { useTranslation } from 'react-i18next';
import React, { Fragment } from "react";
import { useTranslation } from "react-i18next";
import {
faAngleDown,
faEye,
@@ -7,9 +7,9 @@ import {
faShuffle,
faTrash,
faX
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Listbox, Transition } from '@headlessui/react';
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Listbox, Transition } from "@headlessui/react";
interface ListBoxProps {
selected: string;
@@ -18,19 +18,19 @@ interface ListBoxProps {
const eventOptions = [
{
name: 'addSecrets',
name: "addSecrets",
icon: faPlus
},
{
name: 'readSecrets',
name: "readSecrets",
icon: faEye
},
{
name: 'updateSecrets',
name: "updateSecrets",
icon: faShuffle
},
{
name: 'deleteSecrets',
name: "deleteSecrets",
icon: faTrash
}
];
@@ -48,13 +48,13 @@ const EventFilter = ({ selected, select }: ListBoxProps): JSX.Element => {
<Listbox value={t(`activity.event.${selected}`)} onChange={select}>
<div className="relative">
<Listbox.Button className="flex h-10 w-52 cursor-pointer items-center justify-between rounded-md bg-mineshaft-800 pl-4 pr-2 text-sm text-bunker-200 duration-200 hover:bg-mineshaft-700">
{selected !== '' ? (
{selected !== "" ? (
<p className="select-none text-bunker-100">{t(`activity.event.${selected}`)}</p>
) : (
<p className="select-none">{String(t('common.select-event'))}</p>
<p className="select-none">{String(t("common.select-event"))}</p>
)}
{selected !== '' ? (
<FontAwesomeIcon icon={faX} className="w-2 p-2 pl-2" onClick={() => select('')} />
{selected !== "" ? (
<FontAwesomeIcon icon={faX} className="w-2 p-2 pl-2" onClick={() => select("")} />
) : (
<FontAwesomeIcon icon={faAngleDown} className="pl-4 pr-2" />
)}
@@ -70,15 +70,15 @@ const EventFilter = ({ selected, select }: ListBoxProps): JSX.Element => {
<Listbox.Option
key={`${event.name}.${id + 1}`}
className={`flex h-10 cursor-pointer items-center rounded-md px-4 text-sm text-bunker-200 hover:bg-mineshaft-700 ${
selected === t(`activity.event.${event.name}`) && 'bg-mineshaft-700'
selected === t(`activity.event.${event.name}`) && "bg-mineshaft-700"
}`}
value={event.name}
>
{({ selected: isSelected }) => (
<span
className={`block truncate ${isSelected ? 'font-semibold' : 'font-normal'}`}
className={`block truncate ${isSelected ? "font-semibold" : "font-normal"}`}
>
<FontAwesomeIcon icon={event.icon} className="pr-4" />{' '}
<FontAwesomeIcon icon={event.icon} className="pr-4" />{" "}
{t(`activity.event.${event.name}`)}
</span>
)}

View File

@@ -1,8 +1,8 @@
import { memo, useState } from 'react';
import { faCircle, faEye, faEyeSlash } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { memo, useState } from "react";
import { faCircle, faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import guidGenerator from '../utilities/randomId';
import guidGenerator from "../utilities/randomId";
interface InputFieldProps {
isStatic?: boolean;
@@ -34,7 +34,7 @@ const InputField = ({
placeholder,
isStatic,
text
}: InputFieldProps & Pick<JSX.IntrinsicElements['input'], 'autoComplete' | 'id'>) => {
}: InputFieldProps & Pick<JSX.IntrinsicElements["input"], "autoComplete" | "id">) => {
const [passwordVisible, setPasswordVisible] = useState(false);
if (isStatic === true) {
@@ -64,28 +64,28 @@ const InputField = ({
</div>
<div
className={`group relative flex flex-col justify-center w-full max-w-2xl border ${
error ? 'border-red' : 'border-mineshaft-500'
error ? "border-red" : "border-mineshaft-500"
} rounded-md`}
>
<input
onChange={(e) => onChangeHandler(e.target.value)}
type={passwordVisible === false ? type : 'text'}
type={passwordVisible === false ? type : "text"}
placeholder={placeholder}
value={value}
required={isRequired}
className={`${
blurred
? 'text-bunker-800 group-hover:text-gray-400 focus:text-gray-400 active:text-gray-400'
: ''
? "text-bunker-800 group-hover:text-gray-400 focus:text-gray-400 active:text-gray-400"
: ""
} ${
error ? 'focus:ring-red/50' : 'focus:ring-primary/50'
error ? "focus:ring-red/50" : "focus:ring-primary/50"
} relative peer bg-mineshaft-900 rounded-md text-gray-400 text-md p-2 w-full min-w-16 outline-none focus:ring-4 duration-200`}
name={name}
spellCheck="false"
autoComplete={autoComplete}
id={id}
/>
{label?.includes('Password') && (
{label?.includes("Password") && (
<button
type="button"
onClick={() => {
@@ -104,7 +104,7 @@ const InputField = ({
<div className="peer group-hover:hidden peer-hover:hidden peer-focus:hidden peer-active:invisible absolute h-10 w-fit max-w-xl rounded-md flex items-center text-gray-400/50 text-clip overflow-hidden">
<p className="ml-2" />
{value
.split('')
.split("")
.slice(0, 54)
.map(() => (
<FontAwesomeIcon

View File

@@ -1,12 +1,12 @@
/* eslint-disable no-nested-ternary */
/* eslint-disable no-unexpected-multiline */
/* eslint-disable react-hooks/exhaustive-deps */
import crypto from 'crypto';
import crypto from "crypto";
import { useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import Link from 'next/link';
import { useRouter } from 'next/router';
import { useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import Link from "next/link";
import { useRouter } from "next/router";
import {
faBookOpen,
faFileLines,
@@ -16,25 +16,25 @@ import {
faPlug,
faPlus,
faUser
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import getOrganizations from '@app/pages/api/organization/getOrgs';
import getOrganizationUserProjects from '@app/pages/api/organization/GetOrgUserProjects';
import getOrganizationUsers from '@app/pages/api/organization/GetOrgUsers';
import getUser from '@app/pages/api/user/getUser';
import addUserToWorkspace from '@app/pages/api/workspace/addUserToWorkspace';
import createWorkspace from '@app/pages/api/workspace/createWorkspace';
import getWorkspaces from '@app/pages/api/workspace/getWorkspaces';
import uploadKeys from '@app/pages/api/workspace/uploadKeys';
import getOrganizations from "@app/pages/api/organization/getOrgs";
import getOrganizationUserProjects from "@app/pages/api/organization/GetOrgUserProjects";
import getOrganizationUsers from "@app/pages/api/organization/GetOrgUsers";
import getUser from "@app/pages/api/user/getUser";
import addUserToWorkspace from "@app/pages/api/workspace/addUserToWorkspace";
import createWorkspace from "@app/pages/api/workspace/createWorkspace";
import getWorkspaces from "@app/pages/api/workspace/getWorkspaces";
import uploadKeys from "@app/pages/api/workspace/uploadKeys";
import NavBarDashboard from '../navigation/NavBarDashboard';
import onboardingCheck from '../utilities/checks/OnboardingCheck';
import { tempLocalStorage } from '../utilities/checks/tempLocalStorage';
import { decryptAssymmetric, encryptAssymmetric } from '../utilities/cryptography/crypto';
import Button from './buttons/Button';
import AddWorkspaceDialog from './dialog/AddWorkspaceDialog';
import Listbox from './Listbox';
import NavBarDashboard from "../navigation/NavBarDashboard";
import onboardingCheck from "../utilities/checks/OnboardingCheck";
import { tempLocalStorage } from "../utilities/checks/tempLocalStorage";
import { decryptAssymmetric, encryptAssymmetric } from "../utilities/cryptography/crypto";
import Button from "./buttons/Button";
import AddWorkspaceDialog from "./dialog/AddWorkspaceDialog";
import Listbox from "./Listbox";
interface LayoutProps {
children: React.ReactNode;
@@ -43,8 +43,8 @@ interface LayoutProps {
const Layout = ({ children }: LayoutProps) => {
const router = useRouter();
const [workspaceMapping, setWorkspaceMapping] = useState<Map<string, string>[]>([]);
const [workspaceSelected, setWorkspaceSelected] = useState('∞');
const [newWorkspaceName, setNewWorkspaceName] = useState('');
const [workspaceSelected, setWorkspaceSelected] = useState("∞");
const [newWorkspaceName, setNewWorkspaceName] = useState("");
const [isOpen, setIsOpen] = useState(false);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(false);
@@ -77,12 +77,12 @@ const Layout = ({ children }: LayoutProps) => {
if (!currentWorkspaces.includes(workspaceName)) {
const newWorkspace = await createWorkspace({
workspaceName,
organizationId: tempLocalStorage('orgData.id')
organizationId: tempLocalStorage("orgData.id")
});
const newWorkspaceId = newWorkspace._id;
const randomBytes = crypto.randomBytes(16).toString('hex');
const PRIVATE_KEY = String(localStorage.getItem('PRIVATE_KEY'));
const randomBytes = crypto.randomBytes(16).toString("hex");
const PRIVATE_KEY = String(localStorage.getItem("PRIVATE_KEY"));
const myUser = await getUser();
@@ -95,15 +95,15 @@ const Layout = ({ children }: LayoutProps) => {
await uploadKeys(newWorkspaceId, myUser._id, ciphertext, nonce);
if (addAllUsers) {
console.log('adding other users');
console.log("adding other users");
const orgUsers = await getOrganizationUsers({
orgId: tempLocalStorage('orgData.id')
orgId: tempLocalStorage("orgData.id")
});
orgUsers.map(async (user: any) => {
if (user.status === 'accepted' && user.email !== myUser.email) {
if (user.status === "accepted" && user.email !== myUser.email) {
const result = await addUserToWorkspace(user.user.email, newWorkspaceId);
if (result?.invitee && result?.latestKey) {
const TEMP_PRIVATE_KEY = tempLocalStorage('PRIVATE_KEY');
const TEMP_PRIVATE_KEY = tempLocalStorage("PRIVATE_KEY");
// assymmetrically decrypt symmetric key with local private key
const key = decryptAssymmetric({
@@ -130,9 +130,9 @@ const Layout = ({ children }: LayoutProps) => {
}));
setWorkspaceSelected(workspaceName);
setIsOpen(false);
setNewWorkspaceName('');
setNewWorkspaceName("");
} else {
console.error('A project with this name already exists.');
console.error("A project with this name already exists.");
setError(true);
setLoading(false);
}
@@ -147,27 +147,27 @@ const Layout = ({ children }: LayoutProps) => {
() => [
{
href: `/dashboard/${workspaceMapping[workspaceSelected as any]}`,
title: t('nav.menu.secrets'),
title: t("nav.menu.secrets"),
emoji: <FontAwesomeIcon icon={faKey} />
},
{
href: `/users/${workspaceMapping[workspaceSelected as any]}`,
title: t('nav.menu.members'),
title: t("nav.menu.members"),
emoji: <FontAwesomeIcon icon={faUser} />
},
{
href: `/integrations/${workspaceMapping[workspaceSelected as any]}`,
title: t('nav.menu.integrations'),
title: t("nav.menu.integrations"),
emoji: <FontAwesomeIcon icon={faPlug} />
},
{
href: `/activity/${workspaceMapping[workspaceSelected as any]}`,
title: 'Audit Logs',
title: "Audit Logs",
emoji: <FontAwesomeIcon icon={faFileLines} />
},
{
href: `/settings/project/${workspaceMapping[workspaceSelected as any]}`,
title: t('nav.menu.project-settings'),
title: t("nav.menu.project-settings"),
emoji: <FontAwesomeIcon icon={faGear} />
}
],
@@ -178,35 +178,35 @@ const Layout = ({ children }: LayoutProps) => {
// Put a user in a workspace if they're not in one yet
const putUserInWorkSpace = async () => {
if (tempLocalStorage('orgData.id') === '') {
if (tempLocalStorage("orgData.id") === "") {
const userOrgs = await getOrganizations();
localStorage.setItem('orgData.id', userOrgs[0]._id);
localStorage.setItem("orgData.id", userOrgs[0]._id);
}
const orgUserProjects = await getOrganizationUserProjects({
orgId: tempLocalStorage('orgData.id')
orgId: tempLocalStorage("orgData.id")
});
const userWorkspaces = orgUserProjects;
if (
(userWorkspaces.length === 0 &&
router.asPath !== '/noprojects' &&
!router.asPath.includes('home') &&
!router.asPath.includes('settings')) ||
router.asPath === '/dashboard/undefined'
router.asPath !== "/noprojects" &&
!router.asPath.includes("home") &&
!router.asPath.includes("settings")) ||
router.asPath === "/dashboard/undefined"
) {
router.push('/noprojects');
} else if (router.asPath !== '/noprojects') {
router.push("/noprojects");
} else if (router.asPath !== "/noprojects") {
const intendedWorkspaceId = router.asPath
.split('/')
[router.asPath.split('/').length - 1].split('?')[0];
.split("/")
[router.asPath.split("/").length - 1].split("?")[0];
if (!['callback', 'create', 'authorize'].includes(intendedWorkspaceId)) {
localStorage.setItem('projectData.id', intendedWorkspaceId);
if (!["callback", "create", "authorize"].includes(intendedWorkspaceId)) {
localStorage.setItem("projectData.id", intendedWorkspaceId);
}
// If a user is not a member of a workspace they are trying to access, just push them to one of theirs
if (
!['callback', 'create', 'authorize'].includes(intendedWorkspaceId) &&
!["callback", "create", "authorize"].includes(intendedWorkspaceId) &&
!userWorkspaces
.map((workspace: { _id: string }) => workspace._id)
.includes(intendedWorkspaceId)
@@ -221,7 +221,7 @@ const Layout = ({ children }: LayoutProps) => {
setWorkspaceSelected(
Object.fromEntries(
userWorkspaces.map((workspace: any) => [workspace._id, workspace.name])
)[router.asPath.split('/')[router.asPath.split('/').length - 1].split('?')[0]]
)[router.asPath.split("/")[router.asPath.split("/").length - 1].split("?")[0]]
);
}
}
@@ -235,9 +235,9 @@ const Layout = ({ children }: LayoutProps) => {
if (
workspaceMapping[workspaceSelected as any] &&
`${workspaceMapping[workspaceSelected as any]}` !==
router.asPath.split('/')[router.asPath.split('/').length - 1].split('?')[0]
router.asPath.split("/")[router.asPath.split("/").length - 1].split("?")[0]
) {
localStorage.setItem('projectData.id', `${workspaceMapping[workspaceSelected as any]}`);
localStorage.setItem("projectData.id", `${workspaceMapping[workspaceSelected as any]}`);
router.push(`/dashboard/${workspaceMapping[workspaceSelected as any]}`);
}
} catch (err) {
@@ -256,7 +256,7 @@ const Layout = ({ children }: LayoutProps) => {
<div>
<div className="mt-6 mb-6 flex h-20 w-full flex-col items-center justify-center bg-bunker-600 px-4">
<div className="ml-1 mb-1 self-start text-xs font-semibold tracking-wide text-gray-400">
{t('nav.menu.project')}
{t("nav.menu.project")}
</div>
{Object.keys(workspaceMapping).length > 0 ? (
<Listbox
@@ -280,11 +280,11 @@ const Layout = ({ children }: LayoutProps) => {
{Object.keys(workspaceMapping).length > 0 &&
menuItems.map(({ href, title, emoji }) => (
<li className="mx-2 mt-0.5" key={title}>
{router.asPath.split('/')[1] === href.split('/')[1] &&
(['project', 'billing', 'org', 'personal'].includes(
router.asPath.split('/')[2]
{router.asPath.split("/")[1] === href.split("/")[1] &&
(["project", "billing", "org", "personal"].includes(
router.asPath.split("/")[2]
)
? router.asPath.split('/')[2] === href.split('/')[2]
? router.asPath.split("/")[2] === href.split("/")[2]
: true) ? (
<div className="relative flex cursor-pointer rounded bg-primary-50/10 px-0.5 py-2.5 text-sm text-white">
<div className="absolute inset-0 top-0 my-1 ml-1 mr-1 w-1 rounded-xl bg-primary" />
@@ -293,7 +293,7 @@ const Layout = ({ children }: LayoutProps) => {
</p>
{title}
</div>
) : router.asPath === '/noprojects' ? (
) : router.asPath === "/noprojects" ? (
<div className="flex rounded p-2.5 text-sm text-white">
<p className="flex w-10 items-center justify-center text-lg">{emoji}</p>
{title}
@@ -313,7 +313,7 @@ const Layout = ({ children }: LayoutProps) => {
</ul>
</div>
<div className="mt-40 mb-4 w-full px-2">
{router.asPath.split('/')[1] === 'home' ? (
{router.asPath.split("/")[1] === "home" ? (
<div className="relative flex cursor-pointer rounded bg-primary-50/10 px-0.5 py-2.5 text-sm text-white">
<div className="absolute inset-0 top-0 my-1 ml-1 mr-1 w-1 rounded-xl bg-primary" />
<p className="ml-4 mr-2 flex w-6 items-center justify-center text-lg">
@@ -321,12 +321,12 @@ const Layout = ({ children }: LayoutProps) => {
</p>
Infisical Guide
<img
src={`/images/progress-${totalOnboardingActionsDone === 0 ? '0' : ''}${
totalOnboardingActionsDone === 1 ? '14' : ''
}${totalOnboardingActionsDone === 2 ? '28' : ''}${
totalOnboardingActionsDone === 3 ? '43' : ''
}${totalOnboardingActionsDone === 4 ? '57' : ''}${
totalOnboardingActionsDone === 5 ? '71' : ''
src={`/images/progress-${totalOnboardingActionsDone === 0 ? "0" : ""}${
totalOnboardingActionsDone === 1 ? "14" : ""
}${totalOnboardingActionsDone === 2 ? "28" : ""}${
totalOnboardingActionsDone === 3 ? "43" : ""
}${totalOnboardingActionsDone === 4 ? "57" : ""}${
totalOnboardingActionsDone === 5 ? "71" : ""
}.svg`}
height={58}
width={58}
@@ -342,12 +342,12 @@ const Layout = ({ children }: LayoutProps) => {
</p>
Infisical Guide
<img
src={`/images/progress-${totalOnboardingActionsDone === 0 ? '0' : ''}${
totalOnboardingActionsDone === 1 ? '14' : ''
}${totalOnboardingActionsDone === 2 ? '28' : ''}${
totalOnboardingActionsDone === 3 ? '43' : ''
}${totalOnboardingActionsDone === 4 ? '57' : ''}${
totalOnboardingActionsDone === 5 ? '71' : ''
src={`/images/progress-${totalOnboardingActionsDone === 0 ? "0" : ""}${
totalOnboardingActionsDone === 1 ? "14" : ""
}${totalOnboardingActionsDone === 2 ? "28" : ""}${
totalOnboardingActionsDone === 3 ? "43" : ""
}${totalOnboardingActionsDone === 4 ? "57" : ""}${
totalOnboardingActionsDone === 5 ? "71" : ""
}.svg`}
height={58}
width={58}
@@ -375,7 +375,7 @@ const Layout = ({ children }: LayoutProps) => {
<div className="flex h-screen w-screen flex-col items-center justify-center bg-bunker-800 z-[200] md:hidden">
<FontAwesomeIcon icon={faMobile} className="mb-8 text-7xl text-gray-300" />
<p className="max-w-sm px-6 text-center text-lg text-gray-200">
{` ${t('common.no-mobile')} `}
{` ${t("common.no-mobile")} `}
</p>
</div>
</>

View File

@@ -1,7 +1,7 @@
import React, { Fragment } from 'react';
import { faAngleDown, faCheck, faPlus } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Listbox, Transition } from '@headlessui/react';
import React, { Fragment } from "react";
import { faAngleDown, faCheck, faPlus } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Listbox, Transition } from "@headlessui/react";
interface ListBoxProps {
isSelected: string;
@@ -35,13 +35,13 @@ const ListBox = ({
<div className="relative">
<Listbox.Button
className={`text-gray-400 relative ${
isFull ? 'w-full' : 'w-52'
isFull ? "w-full" : "w-52"
} cursor-default rounded-md bg-white/[0.07] hover:bg-white/[0.11] duration-200 py-2.5 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 sm:text-sm`}
>
<div className="flex flex-row">
{text}
<span className="ml-1 cursor-pointer block truncate font-semibold text-gray-300">
{' '}
{" "}
{isSelected}
</span>
</div>
@@ -64,11 +64,11 @@ const ListBox = ({
key={`${person}.${personIdx + 1}`}
className={({ active, selected }) =>
`my-0.5 relative cursor-default select-none py-2 pl-10 pr-4 rounded-md ${
selected ? 'bg-white/10 text-gray-400 font-bold' : ''
selected ? "bg-white/10 text-gray-400 font-bold" : ""
} ${
active && !selected
? 'bg-white/5 text-mineshaft-200 cursor-pointer'
: 'text-gray-400'
? "bg-white/5 text-mineshaft-200 cursor-pointer"
: "text-gray-400"
} `
}
value={person}
@@ -77,7 +77,7 @@ const ListBox = ({
<>
<span
className={`block truncate text-primary${
selected ? 'font-medium' : 'font-normal'
selected ? "font-medium" : "font-normal"
}`}
>
{person}

View File

@@ -1,4 +1,4 @@
import { Switch } from '@headlessui/react';
import { Switch } from "@headlessui/react";
interface ToggleProps {
enabled: boolean;
@@ -22,20 +22,20 @@ const Toggle = ({ enabled, setEnabled, addOverride, id }: ToggleProps): JSX.Elem
checked={enabled}
onChange={() => {
if (enabled === false) {
addOverride('', id);
addOverride("", id);
} else {
addOverride(undefined, id);
}
setEnabled(!enabled);
}}
className={`${
enabled ? 'bg-primary' : 'bg-bunker-400'
enabled ? "bg-primary" : "bg-bunker-400"
} relative inline-flex h-5 w-9 items-center rounded-full`}
>
<span className="sr-only">Enable notifications</span>
<span
className={`${
enabled ? 'translate-x-[1.26rem]' : 'translate-x-0.5'
enabled ? "translate-x-[1.26rem]" : "translate-x-0.5"
} inline-block h-3.5 w-3.5 transform rounded-full bg-bunker-800 transition`}
/>
</Switch>

View File

@@ -1,10 +1,10 @@
/* eslint-disable react/button-has-type */
import React, { ButtonHTMLAttributes } from 'react';
import Image from 'next/image';
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import React, { ButtonHTMLAttributes } from "react";
import Image from "next/image";
import { IconProp } from "@fortawesome/fontawesome-svg-core";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
const classNames = require('classnames');
const classNames = require("classnames");
type ButtonProps = {
text?: string;
@@ -47,49 +47,49 @@ const Button = ({
}: ButtonProps): JSX.Element => {
// Check if the button show always be 'active' - then true;
// or if it should switch between 'active' and 'disabled' - then give the status
const activityStatus = active || (text !== '' && textDisabled === undefined);
const activityStatus = active || (text !== "" && textDisabled === undefined);
const styleButton = classNames(
'group m-auto md:m-0 inline-block rounded-md duration-200',
"group m-auto md:m-0 inline-block rounded-md duration-200",
// Setting background colors and hover modes
color === 'mineshaft' && activityStatus && 'bg-mineshaft-800 border border-mineshaft-600 hover:bg-primary/[0.15] hover:border-primary/60',
color === 'mineshaft' && !activityStatus && 'bg-mineshaft',
(color === 'primary' || !color) && activityStatus && 'bg-primary border border-primary-400 opacity-80 hover:opacity-100',
(color === 'primary' || !color) && !activityStatus && 'bg-primary',
color === 'red' && 'bg-red-800 border border-red',
color === "mineshaft" && activityStatus && "bg-mineshaft-800 border border-mineshaft-600 hover:bg-primary/[0.15] hover:border-primary/60",
color === "mineshaft" && !activityStatus && "bg-mineshaft",
(color === "primary" || !color) && activityStatus && "bg-primary border border-primary-400 opacity-80 hover:opacity-100",
(color === "primary" || !color) && !activityStatus && "bg-primary",
color === "red" && "bg-red-800 border border-red",
// Changing the opacity when active vs when not
activityStatus ? 'opacity-100 cursor-pointer' : 'opacity-40',
activityStatus ? "opacity-100 cursor-pointer" : "opacity-40",
// Setting the button sizes
size === 'md' && 'h-10 w-full px-2 md:px-4',
size === 'lg' && 'h-12 w-full px-2 md:px-8',
!size && 'md:py-1 px-3 md:px-8',
size === 'icon-md' && 'h-10 w-10 flex items-center justify-center',
size === 'icon-sm' && 'h-9 w-9 flex items-center justify-center'
size === "md" && "h-10 w-full px-2 md:px-4",
size === "lg" && "h-12 w-full px-2 md:px-8",
!size && "md:py-1 px-3 md:px-8",
size === "icon-md" && "h-10 w-10 flex items-center justify-center",
size === "icon-sm" && "h-9 w-9 flex items-center justify-center"
);
const styleMainDiv = classNames(
'relative font-medium flex items-center',
"relative font-medium flex items-center",
// Setting the text color for the text and icon
color === 'mineshaft' && 'text-bunker-200',
color !== 'mineshaft' && color !== 'red' && color !== 'none' && 'text-black',
color === 'red' && 'text-gray-200',
color === 'none' && 'text-gray-200 text-xl',
activityStatus && color !== 'red' && color !== 'mineshaft' && color !== 'none' ? 'group-hover:text-black' : '',
color === "mineshaft" && "text-bunker-200",
color !== "mineshaft" && color !== "red" && color !== "none" && "text-black",
color === "red" && "text-gray-200",
color === "none" && "text-gray-200 text-xl",
activityStatus && color !== "red" && color !== "mineshaft" && color !== "none" ? "group-hover:text-black" : "",
size === 'icon' && 'flex items-center justify-center'
size === "icon" && "flex items-center justify-center"
);
const textStyle = classNames(
'relative duration-200 text-center w-full',
"relative duration-200 text-center w-full",
// Show the loading sign if the loading indicator is on
loading ? 'opacity-0' : 'opacity-100',
size === 'md' && 'text-sm',
size === 'lg' && 'text-lg'
loading ? "opacity-0" : "opacity-100",
size === "md" && "text-sm",
size === "lg" && "text-lg"
);
const button = (
@@ -102,7 +102,7 @@ const Button = ({
<div className={styleMainDiv}>
<div
className={`${
loading === true ? 'opacity-100' : 'opacity-0'
loading === true ? "opacity-100" : "opacity-0"
} absolute flex items-center px-3 bg-primary duration-200 w-full`}
>
<Image
@@ -116,16 +116,16 @@ const Button = ({
{icon && (
<FontAwesomeIcon
icon={icon}
className={`flex my-auto font-extrabold ${size === 'icon-sm' ? 'text-sm' : 'text-sm'} ${
(text || textDisabled) && 'mr-2'
className={`flex my-auto font-extrabold ${size === "icon-sm" ? "text-sm" : "text-sm"} ${
(text || textDisabled) && "mr-2"
}`}
/>
)}
{iconDisabled && (
<FontAwesomeIcon
icon={iconDisabled as IconProp}
className={`flex my-auto font-extrabold ${size === 'icon-sm' ? 'text-sm' : 'text-md'} ${
(text || textDisabled) && 'mr-2'
className={`flex my-auto font-extrabold ${size === "icon-sm" ? "text-sm" : "text-md"} ${
(text || textDisabled) && "mr-2"
}`}
/>
)}

View File

@@ -1,8 +1,8 @@
import { Fragment } from 'react';
import { useTranslation } from 'react-i18next';
import { Dialog, Transition } from '@headlessui/react';
import { Fragment } from "react";
import { useTranslation } from "react-i18next";
import { Dialog, Transition } from "@headlessui/react";
import Button from '../buttons/Button';
import Button from "../buttons/Button";
interface IntegrationOption {
clientId: string;
@@ -72,18 +72,18 @@ const ActivateBotDialog = ({
>
<Dialog.Panel className="w-full max-w-md transform overflow-hidden rounded-md border border-gray-700 bg-bunker-800 p-6 text-left align-middle shadow-xl transition-all">
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-gray-400">
{t('integrations.grant-access-to-secrets')}
{t("integrations.grant-access-to-secrets")}
</Dialog.Title>
<div className="mt-2 mb-2">
<p className="text-sm text-gray-500">
{t('integrations.why-infisical-needs-access')}
{t("integrations.why-infisical-needs-access")}
</p>
</div>
<div className="mt-6 max-w-max">
<Button
onButtonPressed={submit}
color="mineshaft"
text={t('integrations.grant-access-button') as string}
text={t("integrations.grant-access-button") as string}
size="md"
/>
</div>

View File

@@ -1,21 +1,21 @@
import { Fragment, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { faCheck, faCopy } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Dialog, Transition } from '@headlessui/react';
import { Fragment, useState } from "react";
import { useTranslation } from "react-i18next";
import { faCheck, faCopy } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Dialog, Transition } from "@headlessui/react";
import addAPIKey from '@app/pages/api/apiKey/addAPIKey';
import addAPIKey from "@app/pages/api/apiKey/addAPIKey";
import Button from '../buttons/Button';
import InputField from '../InputField';
import ListBox from '../Listbox';
import Button from "../buttons/Button";
import InputField from "../InputField";
import ListBox from "../Listbox";
const expiryMapping = {
'1 day': 86400,
'7 days': 604800,
'1 month': 2592000,
'6 months': 15552000,
'12 months': 31104000
"1 day": 86400,
"7 days": 604800,
"1 month": 2592000,
"6 months": 15552000,
"12 months": 31104000
};
type Props = {
@@ -28,9 +28,9 @@ type Props = {
// TODO: convert to TS
const AddApiKeyDialog = ({ isOpen, closeModal, apiKeys, setApiKeys }: Props) => {
const [apiKey, setApiKey] = useState('');
const [apiKeyName, setApiKeyName] = useState('');
const [apiKeyExpiresIn, setApiKeyExpiresIn] = useState('1 day');
const [apiKey, setApiKey] = useState("");
const [apiKeyName, setApiKeyName] = useState("");
const [apiKeyExpiresIn, setApiKeyExpiresIn] = useState("1 day");
const [apiKeyCopied, setApiKeyCopied] = useState(false);
const { t } = useTranslation();
@@ -46,7 +46,7 @@ const AddApiKeyDialog = ({ isOpen, closeModal, apiKeys, setApiKeys }: Props) =>
function copyToClipboard() {
// Get the text field
const copyText = document.getElementById('apiKey') as HTMLInputElement;
const copyText = document.getElementById("apiKey") as HTMLInputElement;
// Select the text field
copyText.select();
@@ -63,8 +63,8 @@ const AddApiKeyDialog = ({ isOpen, closeModal, apiKeys, setApiKeys }: Props) =>
const closeAddApiKeyModal = () => {
closeModal();
setApiKeyName('');
setApiKey('');
setApiKeyName("");
setApiKey("");
};
return (
@@ -94,24 +94,24 @@ const AddApiKeyDialog = ({ isOpen, closeModal, apiKeys, setApiKeys }: Props) =>
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
{apiKey === '' ? (
{apiKey === "" ? (
<Dialog.Panel className="w-full max-w-md transform rounded-md border border-gray-700 bg-bunker-800 p-6 text-left align-middle shadow-xl transition-all">
<Dialog.Title
as="h3"
className="z-50 text-lg font-medium leading-6 text-gray-400"
>
{t('section.api-key.add-dialog.title')}
{t("section.api-key.add-dialog.title")}
</Dialog.Title>
<div className="mt-2 mb-4">
<div className="flex flex-col">
<p className="text-sm text-gray-500">
{t('section.api-key.add-dialog.description')}
{t("section.api-key.add-dialog.description")}
</p>
</div>
</div>
<div className="mb-2 max-h-28">
<InputField
label={t('section.api-key.add-dialog.name')}
label={t("section.api-key.add-dialog.name")}
onChangeHandler={setApiKeyName}
type="varName"
value={apiKeyName}
@@ -123,9 +123,9 @@ const AddApiKeyDialog = ({ isOpen, closeModal, apiKeys, setApiKeys }: Props) =>
<ListBox
isSelected={apiKeyExpiresIn}
onChange={setApiKeyExpiresIn}
data={['1 day', '7 days', '1 month', '6 months', '12 months']}
data={["1 day", "7 days", "1 month", "6 months", "12 months"]}
isFull
text={`${t('common.expired-in')}: `}
text={`${t("common.expired-in")}: `}
/>
</div>
<div className="max-w-max">
@@ -133,10 +133,10 @@ const AddApiKeyDialog = ({ isOpen, closeModal, apiKeys, setApiKeys }: Props) =>
<Button
onButtonPressed={() => generateAPIKey()}
color="mineshaft"
text={t('section.api-key.add-dialog.add') as string}
textDisabled={t('section.api-key.add-dialog.add') as string}
text={t("section.api-key.add-dialog.add") as string}
textDisabled={t("section.api-key.add-dialog.add") as string}
size="md"
active={apiKeyName !== ''}
active={apiKeyName !== ""}
/>
</div>
</div>
@@ -147,12 +147,12 @@ const AddApiKeyDialog = ({ isOpen, closeModal, apiKeys, setApiKeys }: Props) =>
as="h3"
className="z-50 text-lg font-medium leading-6 text-gray-400"
>
{t('section.api-key.add-dialog.copy-service-token')}
{t("section.api-key.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">
{t('section.api-key.add-dialog.copy-service-token-description')}
{t("section.api-key.add-dialog.copy-service-token-description")}
</p>
</div>
</div>
@@ -181,7 +181,7 @@ const AddApiKeyDialog = ({ isOpen, closeModal, apiKeys, setApiKeys }: Props) =>
)}
</button>
<span className="absolute -left-8 -top-20 hidden w-28 translate-y-full rounded-md bg-chicago-900 px-3 py-2 text-center text-sm text-gray-400 duration-300 group-hover:flex group-hover:animate-popup">
{t('common.click-to-copy')}
{t("common.click-to-copy")}
</span>
</div>
</div>

View File

@@ -1,11 +1,11 @@
import { Fragment, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Dialog, Transition } from '@headlessui/react';
import { Fragment, useState } from "react";
import { useTranslation } from "react-i18next";
import { Dialog, Transition } from "@headlessui/react";
import addIncidentContact from '@app/pages/api/organization/addIncidentContact';
import addIncidentContact from "@app/pages/api/organization/addIncidentContact";
import Button from '../buttons/Button';
import InputField from '../InputField';
import Button from "../buttons/Button";
import InputField from "../InputField";
type Props = {
isOpen: boolean;
@@ -20,7 +20,7 @@ const AddIncidentContactDialog = ({
incidentContacts,
setIncidentContacts
}: Props) => {
const [incidentContactEmail, setIncidentContactEmail] = useState('');
const [incidentContactEmail, setIncidentContactEmail] = useState("");
const { t } = useTranslation();
const submit = () => {
@@ -29,7 +29,7 @@ const AddIncidentContactDialog = ({
? incidentContacts.concat([incidentContactEmail])
: [incidentContactEmail]
);
addIncidentContact(localStorage.getItem('orgData.id') as string, incidentContactEmail);
addIncidentContact(localStorage.getItem("orgData.id") as string, incidentContactEmail);
closeModal();
};
return (
@@ -61,16 +61,16 @@ const AddIncidentContactDialog = ({
>
<Dialog.Panel className="w-full max-w-md transform overflow-hidden rounded-md border border-gray-700 bg-bunker-800 p-6 text-left align-middle shadow-xl transition-all">
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-gray-400">
{t('section.incident.add-dialog.title')}
{t("section.incident.add-dialog.title")}
</Dialog.Title>
<div className="mt-2 mb-2">
<p className="text-sm text-gray-500">
{t('section.incident.add-dialog.description')}
{t("section.incident.add-dialog.description")}
</p>
</div>
<div className="max-h-28">
<InputField
label={t('common.email')}
label={t("common.email")}
onChangeHandler={setIncidentContactEmail}
type="varName"
value={incidentContactEmail}
@@ -82,7 +82,7 @@ const AddIncidentContactDialog = ({
<Button
onButtonPressed={submit}
color="mineshaft"
text={t('section.incident.add-dialog.add-incident') as string}
text={t("section.incident.add-dialog.add-incident") as string}
size="md"
/>
</div>

View File

@@ -1,10 +1,10 @@
import { Fragment } from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { useRouter } from 'next/router';
import { Dialog, Transition } from '@headlessui/react';
import { Fragment } from "react";
import { Trans, useTranslation } from "react-i18next";
import { useRouter } from "next/router";
import { Dialog, Transition } from "@headlessui/react";
import Button from '../buttons/Button';
import ListBox from '../Listbox';
import Button from "../buttons/Button";
import ListBox from "../Listbox";
type Props = {
isOpen: boolean;
@@ -59,21 +59,21 @@ const AddProjectMemberDialog = ({
as="h3"
className="z-50 text-lg font-medium leading-6 text-gray-400"
>
{t('section.members.add-dialog.add-member-to-project')}
{t("section.members.add-dialog.add-member-to-project")}
</Dialog.Title>
) : (
<Dialog.Title
as="h3"
className="z-50 text-lg font-medium text-mineshaft-300 mb-4"
>
{t('section.members.add-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('section.members.add-dialog.user-will-email')}
{t("section.members.add-dialog.user-will-email")}
</p>
<div className="">
<Trans
@@ -101,7 +101,7 @@ const AddProjectMemberDialog = ({
</div>
) : (
<p className="text-sm text-gray-500">
{t('section.members.add-dialog.add-user-org-first')}
{t("section.members.add-dialog.add-user-org-first")}
</p>
)}
</div>
@@ -121,7 +121,7 @@ const AddProjectMemberDialog = ({
<Button
onButtonPressed={submitModal}
color="mineshaft"
text={t('section.members.add-member') as string}
text={t("section.members.add-member") as string}
size="md"
/>
</div>
@@ -129,7 +129,7 @@ const AddProjectMemberDialog = ({
<Button
onButtonPressed={() => router.push(`/settings/org/${router.query.id}`)}
color="mineshaft"
text={t('section.members.add-dialog.add-user-to-org') as string}
text={t("section.members.add-dialog.add-user-to-org") as string}
size="md"
/>
)}

View File

@@ -1,25 +1,25 @@
import crypto from 'crypto';
import crypto from "crypto";
import { Fragment, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { faCheck, faCopy } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Dialog, Transition } from '@headlessui/react';
import { Fragment, useState } from "react";
import { useTranslation } from "react-i18next";
import { faCheck, faCopy } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Dialog, Transition } from "@headlessui/react";
import addServiceToken from '@app/pages/api/serviceToken/addServiceToken';
import getLatestFileKey from '@app/pages/api/workspace/getLatestFileKey';
import addServiceToken from "@app/pages/api/serviceToken/addServiceToken";
import getLatestFileKey from "@app/pages/api/workspace/getLatestFileKey";
import { decryptAssymmetric, encryptSymmetric } from '../../utilities/cryptography/crypto';
import Button from '../buttons/Button';
import InputField from '../InputField';
import ListBox from '../Listbox';
import { decryptAssymmetric, encryptSymmetric } from "../../utilities/cryptography/crypto";
import Button from "../buttons/Button";
import InputField from "../InputField";
import ListBox from "../Listbox";
const expiryMapping = {
'1 day': 86400,
'7 days': 604800,
'1 month': 2592000,
'6 months': 15552000,
'12 months': 31104000
"1 day": 86400,
"7 days": 604800,
"1 month": 2592000,
"6 months": 15552000,
"12 months": 31104000
};
type Props = {
@@ -41,10 +41,10 @@ const AddServiceTokenDialog = ({
environments,
setServiceTokens
}: Props) => {
const [serviceToken, setServiceToken] = useState('');
const [serviceTokenName, setServiceTokenName] = useState('');
const [serviceToken, setServiceToken] = useState("");
const [serviceTokenName, setServiceTokenName] = useState("");
const [selectedServiceTokenEnv, setSelectedServiceTokenEnv] = useState(environments?.[0]);
const [serviceTokenExpiresIn, setServiceTokenExpiresIn] = useState('1 day');
const [serviceTokenExpiresIn, setServiceTokenExpiresIn] = useState("1 day");
const [serviceTokenCopied, setServiceTokenCopied] = useState(false);
const { t } = useTranslation();
@@ -55,10 +55,10 @@ const AddServiceTokenDialog = ({
ciphertext: latestFileKey.latestKey.encryptedKey,
nonce: latestFileKey.latestKey.nonce,
publicKey: latestFileKey.latestKey.sender.publicKey,
privateKey: localStorage.getItem('PRIVATE_KEY') as string
privateKey: localStorage.getItem("PRIVATE_KEY") as string
});
const randomBytes = crypto.randomBytes(16).toString('hex');
const randomBytes = crypto.randomBytes(16).toString("hex");
const { ciphertext, iv, tag } = encryptSymmetric({
plaintext: key,
key: randomBytes
@@ -88,7 +88,7 @@ const AddServiceTokenDialog = ({
function copyToClipboard() {
// Get the text field
const copyText = document.getElementById('serviceToken') as HTMLInputElement;
const copyText = document.getElementById("serviceToken") as HTMLInputElement;
// Select the text field
copyText.select();
@@ -105,8 +105,8 @@ const AddServiceTokenDialog = ({
const closeAddServiceTokenModal = () => {
closeModal();
setServiceTokenName('');
setServiceToken('');
setServiceTokenName("");
setServiceToken("");
};
return (
@@ -136,26 +136,26 @@ const AddServiceTokenDialog = ({
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
{serviceToken === '' ? (
{serviceToken === "" ? (
<Dialog.Panel className="w-full max-w-md transform rounded-md border border-gray-700 bg-bunker-800 p-6 text-left align-middle shadow-xl transition-all">
<Dialog.Title
as="h3"
className="z-50 text-lg font-medium leading-6 text-gray-400"
>
{t('section.token.add-dialog.title', {
{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">
{t('section.token.add-dialog.description')}
{t("section.token.add-dialog.description")}
</p>
</div>
</div>
<div className="mb-2 max-h-28">
<InputField
label={t('section.token.add-dialog.name')}
label={t("section.token.add-dialog.name")}
onChangeHandler={setServiceTokenName}
type="varName"
value={serviceTokenName}
@@ -174,22 +174,22 @@ const AddServiceTokenDialog = ({
onChange={(envName) =>
setSelectedServiceTokenEnv(
environments.find(({ name }) => envName === name) || {
name: 'unknown',
slug: 'unknown'
name: "unknown",
slug: "unknown"
}
)
}
isFull
text={`${t('common.environment')}: `}
text={`${t("common.environment")}: `}
/>
</div>
<div className="max-h-28">
<ListBox
isSelected={serviceTokenExpiresIn}
onChange={setServiceTokenExpiresIn}
data={['1 day', '7 days', '1 month', '6 months', '12 months']}
data={["1 day", "7 days", "1 month", "6 months", "12 months"]}
isFull
text={`${t('common.expired-in')}: `}
text={`${t("common.expired-in")}: `}
/>
</div>
<div className="max-w-max">
@@ -197,10 +197,10 @@ const AddServiceTokenDialog = ({
<Button
onButtonPressed={() => generateServiceToken()}
color="mineshaft"
text={t('section.token.add-dialog.add') as string}
textDisabled={t('section.token.add-dialog.add') as string}
text={t("section.token.add-dialog.add") as string}
textDisabled={t("section.token.add-dialog.add") as string}
size="md"
active={serviceTokenName !== ''}
active={serviceTokenName !== ""}
/>
</div>
</div>
@@ -211,12 +211,12 @@ const AddServiceTokenDialog = ({
as="h3"
className="z-50 text-lg font-medium leading-6 text-gray-400"
>
{t('section.token.add-dialog.copy-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">
{t('section.token.add-dialog.copy-service-token-description')}
{t("section.token.add-dialog.copy-service-token-description")}
</p>
</div>
</div>
@@ -244,7 +244,7 @@ const AddServiceTokenDialog = ({
)}
</button>
<span className="absolute -left-8 -top-20 hidden w-28 translate-y-full rounded-md bg-chicago-900 px-3 py-2 text-center text-sm text-gray-400 duration-300 group-hover:flex group-hover:animate-popup">
{t('common.click-to-copy')}
{t("common.click-to-copy")}
</span>
</div>
</div>

View File

@@ -1,8 +1,8 @@
import { FormEventHandler, Fragment, useEffect, useState } from 'react';
import { Dialog, Transition } from '@headlessui/react';
import { FormEventHandler, Fragment, useEffect, useState } from "react";
import { Dialog, Transition } from "@headlessui/react";
import Button from '../buttons/Button';
import InputField from '../InputField';
import Button from "../buttons/Button";
import InputField from "../InputField";
type FormFields = { name: string; slug: string };
@@ -31,14 +31,14 @@ export const AddUpdateEnvironmentDialog = ({
isEditMode,
}: Props) => {
const [formInput, setFormInput] = useState<FormFields>({
name: '',
slug: '',
name: "",
slug: "",
});
// This use effect can be removed when the unmount is happening from outside the component
// When unmount happens outside state gets unmounted also
useEffect(() => {
setFormInput(initialValues || { name: '', slug: '' });
setFormInput(initialValues || { name: "", slug: "" });
}, [isOpen]);
// REFACTOR: Move to react-hook-form with yup for better form management
@@ -92,14 +92,14 @@ export const AddUpdateEnvironmentDialog = ({
className='text-lg font-medium leading-6 text-gray-400'
>
{isEditMode
? 'Update environment'
: 'Create a new environment'}
? "Update environment"
: "Create a new environment"}
</Dialog.Title>
<form onSubmit={onFormSubmit}>
<div className='max-h-28 mt-4'>
<InputField
label='Environment Name'
onChangeHandler={(val) => onInputChange('name', val)}
onChangeHandler={(val) => onInputChange("name", val)}
type='varName'
value={formInput.name}
placeholder=''
@@ -111,7 +111,7 @@ export const AddUpdateEnvironmentDialog = ({
<div className='max-h-28 mt-4'>
<InputField
label='Environment Slug'
onChangeHandler={(val) => onInputChange('slug', val)}
onChangeHandler={(val) => onInputChange("slug", val)}
type='varName'
value={formInput.slug}
placeholder=''
@@ -128,8 +128,8 @@ export const AddUpdateEnvironmentDialog = ({
onButtonPressed={() => null}
type='submit'
color='mineshaft'
text={isEditMode ? 'Update' : 'Create'}
active={formInput.name !== '' && formInput.slug !== ''}
text={isEditMode ? "Update" : "Create"}
active={formInput.name !== "" && formInput.slug !== ""}
size='md'
/>
</div>

View File

@@ -1,8 +1,8 @@
import { Fragment } from 'react';
import { Dialog, Transition } from '@headlessui/react';
import { Fragment } from "react";
import { Dialog, Transition } from "@headlessui/react";
import Button from '../buttons/Button';
import InputField from '../InputField';
import Button from "../buttons/Button";
import InputField from "../InputField";
type Props = {
isOpen: boolean;

View File

@@ -1,7 +1,7 @@
import { Fragment, useEffect, useState } from 'react';
import { Dialog, Transition } from '@headlessui/react';
import { Fragment, useEffect, useState } from "react";
import { Dialog, Transition } from "@headlessui/react";
import InputField from '../InputField';
import InputField from "../InputField";
// REFACTOR: Move all these modals into one reusable one
type Props = {

View File

@@ -47,11 +47,11 @@ export const DeleteEnvVar = ({ isOpen, onClose, onSubmit }: Props) => {
>
<Dialog.Panel className="w-full max-w-md transform overflow-hidden rounded-md bg-bunker border border-mineshaft-600 p-6 text-left align-middle shadow-xl transition-all">
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-bunker-200">
{t('dashboard:sidebar.delete-key-dialog.title')}
{t("dashboard:sidebar.delete-key-dialog.title")}
</Dialog.Title>
<div className="mt-2">
<p className="text-sm text-bunker-300">
{t('dashboard:sidebar.delete-key-dialog.confirm-delete-message')}
{t("dashboard:sidebar.delete-key-dialog.confirm-delete-message")}
</p>
</div>
<div className="mt-6 flex justify-start">

View File

@@ -1,5 +1,5 @@
import { Fragment } from 'react';
import { Dialog, Transition } from '@headlessui/react';
import { Fragment } from "react";
import { Dialog, Transition } from "@headlessui/react";
// #TODO: USE THIS. Currently it's not. Kinda complicated to set up because of state.

View File

@@ -1,6 +1,6 @@
import { Fragment } from 'react';
import { useRouter } from 'next/router';
import { Dialog, Transition } from '@headlessui/react';
import { Fragment } from "react";
import { useRouter } from "next/router";
import { Dialog, Transition } from "@headlessui/react";
// REFACTOR: Move all these modals into one reusable one
type Props = {

View File

@@ -1,5 +1,5 @@
import { faXmark } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faXmark } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
interface PopupProps {
buttonText: string;

View File

@@ -1,10 +1,10 @@
import { faX } from '@fortawesome/free-solid-svg-icons';
import { faX } from "@fortawesome/free-solid-svg-icons";
import { useNotificationContext } from '@app/components/context/Notifications/NotificationProvider';
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
import deleteAPIKey from '../../../pages/api/apiKey/deleteAPIKey';
import guidGenerator from '../../utilities/randomId';
import Button from '../buttons/Button';
import deleteAPIKey from "../../../pages/api/apiKey/deleteAPIKey";
import guidGenerator from "../../utilities/randomId";
import Button from "../buttons/Button";
interface TokenProps {
_id: string;
@@ -58,7 +58,7 @@ const ApiKeyTable = ({ data, setApiKeys }: ServiceTokensProps) => {
setApiKeys(data.filter((token) => token._id !== row._id));
createNotification({
text: `'${row.name}' API key has been revoked.`,
type: 'error'
type: "error"
});
}}
color="red"

View File

@@ -1,13 +1,13 @@
import { useEffect, useState } from 'react';
import { faPencil, faPlus, faX } from '@fortawesome/free-solid-svg-icons';
import { plans } from 'public/data/frequentConstants';
import { useEffect, useState } from "react";
import { faPencil, faPlus, faX } from "@fortawesome/free-solid-svg-icons";
import { plans } from "public/data/frequentConstants";
import { usePopUp } from '../../../hooks/usePopUp';
import getOrganizationSubscriptions from '../../../pages/api/organization/GetOrgSubscription';
import Button from '../buttons/Button';
import { AddUpdateEnvironmentDialog } from '../dialog/AddUpdateEnvironmentDialog';
import DeleteActionModal from '../dialog/DeleteActionModal';
import UpgradePlanModal from '../dialog/UpgradePlan';
import { usePopUp } from "../../../hooks/usePopUp";
import getOrganizationSubscriptions from "../../../pages/api/organization/GetOrgSubscription";
import Button from "../buttons/Button";
import { AddUpdateEnvironmentDialog } from "../dialog/AddUpdateEnvironmentDialog";
import DeleteActionModal from "../dialog/DeleteActionModal";
import UpgradePlanModal from "../dialog/UpgradePlan";
type Env = { name: string; slug: string };
@@ -20,17 +20,17 @@ type Props = {
const EnvironmentTable = ({ data = [], onCreateEnv, onDeleteEnv, onUpdateEnv }: Props) => {
const { popUp, handlePopUpOpen, handlePopUpClose } = usePopUp([
'createUpdateEnv',
'deleteEnv',
'upgradePlan'
"createUpdateEnv",
"deleteEnv",
"upgradePlan"
] as const);
const [plan, setPlan] = useState('');
const [plan, setPlan] = useState("");
const host = window.location.origin;
useEffect(() => {
// on initial load - run auth check
(async () => {
const orgId = localStorage.getItem('orgData.id') as string;
const orgId = localStorage.getItem("orgData.id") as string;
const subscriptions = await getOrganizationSubscriptions({
orgId
});
@@ -44,7 +44,7 @@ const EnvironmentTable = ({ data = [], onCreateEnv, onDeleteEnv, onUpdateEnv }:
const onEnvCreateCB = async (env: Env) => {
try {
await onCreateEnv(env);
handlePopUpClose('createUpdateEnv');
handlePopUpClose("createUpdateEnv");
} catch (error) {
console.error(error);
}
@@ -52,8 +52,8 @@ const EnvironmentTable = ({ data = [], onCreateEnv, onDeleteEnv, onUpdateEnv }:
const onEnvUpdateCB = async (env: Env) => {
try {
await onUpdateEnv((popUp.createUpdateEnv?.data as Pick<Env, 'slug'>)?.slug, env);
handlePopUpClose('createUpdateEnv');
await onUpdateEnv((popUp.createUpdateEnv?.data as Pick<Env, "slug">)?.slug, env);
handlePopUpClose("createUpdateEnv");
} catch (error) {
console.error(error);
}
@@ -61,8 +61,8 @@ const EnvironmentTable = ({ data = [], onCreateEnv, onDeleteEnv, onUpdateEnv }:
const onEnvDeleteCB = async () => {
try {
await onDeleteEnv((popUp.deleteEnv?.data as Pick<Env, 'slug'>)?.slug);
handlePopUpClose('deleteEnv');
await onDeleteEnv((popUp.deleteEnv?.data as Pick<Env, "slug">)?.slug);
handlePopUpClose("deleteEnv");
} catch (error) {
console.error(error);
}
@@ -85,10 +85,10 @@ const EnvironmentTable = ({ data = [], onCreateEnv, onDeleteEnv, onUpdateEnv }:
<Button
text="Add New Environment"
onButtonPressed={() => {
if (plan !== plans.starter || host !== 'https://app.infisical.com' || localStorage.getItem('projectData.id') === '63ea8121b6e2b0543ba79616') {
handlePopUpOpen('createUpdateEnv');
if (plan !== plans.starter || host !== "https://app.infisical.com" || localStorage.getItem("projectData.id") === "63ea8121b6e2b0543ba79616") {
handlePopUpOpen("createUpdateEnv");
} else {
handlePopUpOpen('upgradePlan');
handlePopUpOpen("upgradePlan");
}
}}
color="mineshaft"
@@ -117,10 +117,10 @@ const EnvironmentTable = ({ data = [], onCreateEnv, onDeleteEnv, onUpdateEnv }:
<div className="mr-2 flex items-center duration-200 hover:opacity-100">
<Button
onButtonPressed={() => {
if (plan !== plans.starter || host !== 'https://app.infisical.com') {
handlePopUpOpen('createUpdateEnv', { name, slug });
if (plan !== plans.starter || host !== "https://app.infisical.com") {
handlePopUpOpen("createUpdateEnv", { name, slug });
} else {
handlePopUpOpen('upgradePlan');
handlePopUpOpen("upgradePlan");
}
}}
color="mineshaft"
@@ -131,10 +131,10 @@ const EnvironmentTable = ({ data = [], onCreateEnv, onDeleteEnv, onUpdateEnv }:
<div className="mr-6 flex items-center opacity-50 duration-200 hover:opacity-100">
<Button
onButtonPressed={() => {
if (plan !== plans.starter || host !== 'https://app.infisical.com') {
handlePopUpOpen('deleteEnv', { name, slug });
if (plan !== plans.starter || host !== "https://app.infisical.com") {
handlePopUpOpen("deleteEnv", { name, slug });
} else {
handlePopUpOpen('upgradePlan');
handlePopUpOpen("upgradePlan");
}
}}
color="red"
@@ -157,23 +157,23 @@ const EnvironmentTable = ({ data = [], onCreateEnv, onDeleteEnv, onUpdateEnv }:
<DeleteActionModal
isOpen={popUp.deleteEnv.isOpen}
title={`Are you sure want to delete ${
(popUp?.deleteEnv?.data as { name: string })?.name || ' '
(popUp?.deleteEnv?.data as { name: string })?.name || " "
}?`}
deleteKey={(popUp?.deleteEnv?.data as { slug: string })?.slug || ''}
onClose={() => handlePopUpClose('deleteEnv')}
deleteKey={(popUp?.deleteEnv?.data as { slug: string })?.slug || ""}
onClose={() => handlePopUpClose("deleteEnv")}
onSubmit={onEnvDeleteCB}
/>
<AddUpdateEnvironmentDialog
isOpen={popUp.createUpdateEnv.isOpen}
isEditMode={Boolean(popUp.createUpdateEnv?.data)}
initialValues={popUp?.createUpdateEnv?.data as any}
onClose={() => handlePopUpClose('createUpdateEnv')}
onClose={() => handlePopUpClose("createUpdateEnv")}
onCreateSubmit={onEnvCreateCB}
onEditSubmit={onEnvUpdateCB}
/>
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onClose={() => handlePopUpClose('upgradePlan')}
onClose={() => handlePopUpClose("upgradePlan")}
text="You can add custom environments if you switch to Infisical's Team plan."
/>
</div>

View File

@@ -1,22 +1,22 @@
import { useEffect, useState } from 'react';
import { useRouter } from 'next/router';
import { faEye, faEyeSlash, faPenToSquare, faPlus, faX } from '@fortawesome/free-solid-svg-icons';
import { plans } from 'public/data/frequentConstants';
import { useEffect, useState } from "react";
import { useRouter } from "next/router";
import { faEye, faEyeSlash, faPenToSquare, faPlus, faX } from "@fortawesome/free-solid-svg-icons";
import { plans } from "public/data/frequentConstants";
import { useNotificationContext } from '@app/components/context/Notifications/NotificationProvider';
import { Select, SelectItem } from '@app/components/v2';
import updateUserProjectPermission from '@app/ee/api/memberships/UpdateUserProjectPermission';
import getOrganizationSubscriptions from '@app/pages/api/organization/GetOrgSubscription';
import changeUserRoleInWorkspace from '@app/pages/api/workspace/changeUserRoleInWorkspace';
import deleteUserFromWorkspace from '@app/pages/api/workspace/deleteUserFromWorkspace';
import getLatestFileKey from '@app/pages/api/workspace/getLatestFileKey';
import getProjectInfo from '@app/pages/api/workspace/getProjectInfo';
import uploadKeys from '@app/pages/api/workspace/uploadKeys';
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
import { Select, SelectItem } from "@app/components/v2";
import updateUserProjectPermission from "@app/ee/api/memberships/UpdateUserProjectPermission";
import getOrganizationSubscriptions from "@app/pages/api/organization/GetOrgSubscription";
import changeUserRoleInWorkspace from "@app/pages/api/workspace/changeUserRoleInWorkspace";
import deleteUserFromWorkspace from "@app/pages/api/workspace/deleteUserFromWorkspace";
import getLatestFileKey from "@app/pages/api/workspace/getLatestFileKey";
import getProjectInfo from "@app/pages/api/workspace/getProjectInfo";
import uploadKeys from "@app/pages/api/workspace/uploadKeys";
import { decryptAssymmetric, encryptAssymmetric } from '../../utilities/cryptography/crypto';
import guidGenerator from '../../utilities/randomId';
import Button from '../buttons/Button';
import UpgradePlanModal from '../dialog/UpgradePlan';
import { decryptAssymmetric, encryptAssymmetric } from "../../utilities/cryptography/crypto";
import guidGenerator from "../../utilities/randomId";
import Button from "../buttons/Button";
import UpgradePlanModal from "../dialog/UpgradePlan";
// const roles = ['admin', 'user'];
// TODO: Set type for this
@@ -45,8 +45,8 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter, isUserListLoa
);
const host = window.location.origin;
const router = useRouter();
const [myRole, setMyRole] = useState('member');
const [currentPlan, setCurrentPlan] = useState('');
const [myRole, setMyRole] = useState("member");
const [currentPlan, setCurrentPlan] = useState("");
const [workspaceEnvs, setWorkspaceEnvs] = useState<EnvironmentProps[]>([]);
const [isUpgradeModalOpen, setIsUpgradeModalOpen] = useState(false);
const { createNotification } = useNotificationContext();
@@ -87,8 +87,8 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter, isUserListLoa
...userData.slice(index + 1, userData?.length)
]);
createNotification({
text: `Successfully changed user role.`,
type: 'success'
text: "Successfully changed user role.",
type: "success"
});
};
@@ -99,28 +99,28 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter, isUserListLoa
slug: string
) => {
let denials: { ability: string; environmentSlug: string }[];
if (val === 'Read Only') {
if (val === "Read Only") {
denials = [
{
ability: 'write',
ability: "write",
environmentSlug: slug
}
];
} else if (val === 'No Access') {
} else if (val === "No Access") {
denials = [
{
ability: 'write',
ability: "write",
environmentSlug: slug
},
{
ability: 'read',
ability: "read",
environmentSlug: slug
}
];
} else if (val === 'Add Only') {
} else if (val === "Add Only") {
denials = [
{
ability: 'read',
ability: "read",
environmentSlug: slug
}
];
@@ -128,7 +128,7 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter, isUserListLoa
denials = [];
}
if (currentPlan !== plans.professional && host === 'https://app.infisical.com' && workspaceId !== '63ea8121b6e2b0543ba79616') {
if (currentPlan !== plans.professional && host === "https://app.infisical.com" && workspaceId !== "63ea8121b6e2b0543ba79616") {
setIsUpgradeModalOpen(true);
} else {
const allDenials = userData[index].deniedPermissions
@@ -156,8 +156,8 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter, isUserListLoa
...userData.slice(index + 1, userData?.length)
]);
createNotification({
text: `Successfully changed user permissions.`,
type: 'success'
text: "Successfully changed user permissions.",
type: "success"
});
}
};
@@ -168,7 +168,7 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter, isUserListLoa
const result = await getProjectInfo({ projectId: workspaceId });
setWorkspaceEnvs(result.environments);
const orgId = localStorage.getItem('orgData.id') as string;
const orgId = localStorage.getItem("orgData.id") as string;
const subscriptions = await getOrganizationSubscriptions({
orgId
});
@@ -181,7 +181,7 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter, isUserListLoa
const grantAccess = async (id: string, publicKey: string) => {
const result = await getLatestFileKey({ workspaceId });
const PRIVATE_KEY = localStorage.getItem('PRIVATE_KEY') as string;
const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY") as string;
// assymmetrically decrypt symmetric key with local private key
const key = decryptAssymmetric({
@@ -261,13 +261,13 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter, isUserListLoa
// open={isOpen}
onValueChange={(e) => handleRoleUpdate(index, e)}
value={row.role}
isDisabled={myRole !== 'admin' || myUser === row.email}
isDisabled={myRole !== "admin" || myUser === row.email}
// onOpenChange={(open) => setIsOpen(open)}
>
<SelectItem value="admin">Admin</SelectItem>
<SelectItem value="member">Member</SelectItem>
</Select>
{row.status === 'completed' && myUser !== row.email && (
{row.status === "completed" && myUser !== row.email && (
<div className="rounded-md border border-mineshaft-700 bg-white/5 text-white duration-200 hover:bg-primary hover:text-black">
<Button
onButtonPressed={() => grantAccess(row.userId, row.publicKey)}
@@ -297,66 +297,66 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter, isUserListLoa
row.deniedPermissions
.filter((perm: any) => perm.environmentSlug === env.slug)
.map((perm: { ability: string }) => perm.ability)
.includes('write') &&
.includes("write") &&
row.deniedPermissions
.filter((perm: any) => perm.environmentSlug === env.slug)
.map((perm: { ability: string }) => perm.ability)
.includes('read')
? 'No Access'
.includes("read")
? "No Access"
: // eslint-disable-next-line no-nested-ternary
row.deniedPermissions
.filter((perm: any) => perm.environmentSlug === env.slug)
.map((perm: { ability: string }) => perm.ability)
.includes('write') &&
.includes("write") &&
!row.deniedPermissions
.filter((perm: any) => perm.environmentSlug === env.slug)
.map((perm: { ability: string }) => perm.ability)
.includes('read')
? 'Read Only'
.includes("read")
? "Read Only"
: !row.deniedPermissions
.filter((perm: any) => perm.environmentSlug === env.slug)
.map((perm: { ability: string }) => perm.ability)
.includes('write') &&
.includes("write") &&
row.deniedPermissions
.filter((perm: any) => perm.environmentSlug === env.slug)
.map((perm: { ability: string }) => perm.ability)
.includes('read')
? 'Add Only'
: 'Read & Write'
.includes("read")
? "Add Only"
: "Read & Write"
}
icon={
// eslint-disable-next-line no-nested-ternary
row.deniedPermissions
.filter((perm: any) => perm.environmentSlug === env.slug)
.map((perm: { ability: string }) => perm.ability)
.includes('write') &&
.includes("write") &&
row.deniedPermissions
.filter((perm: any) => perm.environmentSlug === env.slug)
.map((perm: { ability: string }) => perm.ability)
.includes('read')
.includes("read")
? faEyeSlash
: // eslint-disable-next-line no-nested-ternary
row.deniedPermissions
.filter((perm: any) => perm.environmentSlug === env.slug)
.map((perm: { ability: string }) => perm.ability)
.includes('write') &&
.includes("write") &&
!row.deniedPermissions
.filter((perm: any) => perm.environmentSlug === env.slug)
.map((perm: { ability: string }) => perm.ability)
.includes('read')
.includes("read")
? faEye
: !row.deniedPermissions
.filter((perm: any) => perm.environmentSlug === env.slug)
.map((perm: { ability: string }) => perm.ability)
.includes('write') &&
.includes("write") &&
row.deniedPermissions
.filter((perm: any) => perm.environmentSlug === env.slug)
.map((perm: { ability: string }) => perm.ability)
.includes('read')
.includes("read")
? faPlus
: faPenToSquare
}
isDisabled={myRole !== 'admin'}
isDisabled={myRole !== "admin"}
// onOpenChange={(open) => setIsOpen(open)}
>
<SelectItem value="No Access" customIcon={faEyeSlash}>
@@ -377,7 +377,7 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter, isUserListLoa
<td className="border-0.5 flex flex-row justify-end border-t border-mineshaft-700 py-2 pl-8 pr-8">
{myUser !== row.email &&
// row.role !== "admin" &&
myRole !== 'member' ? (
myRole !== "member" ? (
<div className="mt-0.5 flex items-center opacity-50 hover:opacity-100">
<Button
onButtonPressed={() => handleDelete(row.membershipId, index)}

View File

@@ -1,10 +1,10 @@
import { faX } from '@fortawesome/free-solid-svg-icons';
import { faX } from "@fortawesome/free-solid-svg-icons";
import { useNotificationContext } from '@app/components/context/Notifications/NotificationProvider';
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
import deleteServiceToken from '../../../pages/api/serviceToken/deleteServiceToken';
import guidGenerator from '../../utilities/randomId';
import Button from '../buttons/Button';
import deleteServiceToken from "../../../pages/api/serviceToken/deleteServiceToken";
import guidGenerator from "../../utilities/randomId";
import Button from "../buttons/Button";
interface TokenProps {
_id: string;
@@ -71,7 +71,7 @@ const ServiceTokenTable = ({ data, workspaceName, setServiceTokens }: ServiceTok
setServiceTokens(data.filter((token) => token._id !== row._id));
createNotification({
text: `'${row.name}' token has been revoked.`,
type: 'error'
type: "error"
});
}}
color="red"

View File

@@ -1,18 +1,18 @@
import { useEffect, useState } from 'react';
import { useRouter } from 'next/router';
import { faX } from '@fortawesome/free-solid-svg-icons';
import { useEffect, useState } from "react";
import { useRouter } from "next/router";
import { faX } from "@fortawesome/free-solid-svg-icons";
import changeUserRoleInOrganization from '@app/pages/api/organization/changeUserRoleInOrganization';
import deleteUserFromOrganization from '@app/pages/api/organization/deleteUserFromOrganization';
import getOrganizationProjectMemberships from '@app/pages/api/organization/GetOrgProjectMemberships';
import deleteUserFromWorkspace from '@app/pages/api/workspace/deleteUserFromWorkspace';
import getLatestFileKey from '@app/pages/api/workspace/getLatestFileKey';
import uploadKeys from '@app/pages/api/workspace/uploadKeys';
import changeUserRoleInOrganization from "@app/pages/api/organization/changeUserRoleInOrganization";
import deleteUserFromOrganization from "@app/pages/api/organization/deleteUserFromOrganization";
import getOrganizationProjectMemberships from "@app/pages/api/organization/GetOrgProjectMemberships";
import deleteUserFromWorkspace from "@app/pages/api/workspace/deleteUserFromWorkspace";
import getLatestFileKey from "@app/pages/api/workspace/getLatestFileKey";
import uploadKeys from "@app/pages/api/workspace/uploadKeys";
import { decryptAssymmetric, encryptAssymmetric } from '../../utilities/cryptography/crypto';
import guidGenerator from '../../utilities/randomId';
import Button from '../buttons/Button';
import Listbox from '../Listbox';
import { decryptAssymmetric, encryptAssymmetric } from "../../utilities/cryptography/crypto";
import guidGenerator from "../../utilities/randomId";
import Button from "../buttons/Button";
import Listbox from "../Listbox";
// const roles = ['admin', 'user'];
// TODO: Set type for this
@@ -36,7 +36,7 @@ const UserTable = ({ userData, changeData, myUser, filter, resendInvite, isOrg }
Array(userData?.length).fill(userData.map((user) => user.role))
);
const router = useRouter();
const [myRole, setMyRole] = useState('member');
const [myRole, setMyRole] = useState("member");
const [userProjectMemberships, setUserProjectMemberships] = useState<any[]>([]);
const workspaceId = router.query.id as string;
@@ -90,7 +90,7 @@ const UserTable = ({ userData, changeData, myUser, filter, resendInvite, isOrg }
const grantAccess = async (id: string, publicKey: string) => {
const result = await getLatestFileKey({ workspaceId });
const PRIVATE_KEY = localStorage.getItem('PRIVATE_KEY') as string;
const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY") as string;
// assymmetrically decrypt symmetric key with local private key
const key = decryptAssymmetric({
@@ -152,29 +152,29 @@ const UserTable = ({ userData, changeData, myUser, filter, resendInvite, isOrg }
</td>
<td className="pl-6 pr-10 py-2 border-mineshaft-700 border-t text-gray-300">
<div className="justify-start h-full flex flex-row items-center">
{row.status === 'accepted' &&
((myRole === 'admin' && row.role !== 'owner') || myRole === 'owner') &&
{row.status === "accepted" &&
((myRole === "admin" && row.role !== "owner") || myRole === "owner") &&
(myUser !== row.email) ? (
<Listbox
isSelected={row.role}
onChange={(e) => handleRoleUpdate(index, e)}
data={
myRole === 'owner' ? ['owner', 'admin', 'member'] : ['admin', 'member']
myRole === "owner" ? ["owner", "admin", "member"] : ["admin", "member"]
}
/>
) : (
row.status !== 'invited' &&
row.status !== 'verified' && (
row.status !== "invited" &&
row.status !== "verified" && (
<Listbox
isSelected={row.role}
onChange={() => {
throw new Error('Function not implemented.');
throw new Error("Function not implemented.");
}}
data={null}
/>
)
)}
{(row.status === 'invited' || row.status === 'verified') && (
{(row.status === "invited" || row.status === "verified") && (
<div className="w-full pr-20">
<Button
onButtonPressed={() => deleteMembershipAndResendInvite(row.email)}
@@ -184,7 +184,7 @@ const UserTable = ({ userData, changeData, myUser, filter, resendInvite, isOrg }
/>
</div>
)}
{row.status === 'completed' && myUser !== row.email && (
{row.status === "completed" && myUser !== row.email && (
<div className="border border-mineshaft-700 rounded-md bg-white/5 hover:bg-primary text-white hover:text-black duration-200">
<Button
onButtonPressed={() => grantAccess(row.userId, row.publicKey)}
@@ -210,7 +210,7 @@ const UserTable = ({ userData, changeData, myUser, filter, resendInvite, isOrg }
<td className="flex flex-row justify-end pl-8 pr-8 py-2 border-t border-0.5 border-mineshaft-700">
{myUser !== row.email &&
// row.role !== "admin" &&
myRole !== 'member' ? (
myRole !== "member" ? (
<div className="opacity-50 hover:opacity-100 flex items-center mt-0.5">
<Button
onButtonPressed={() => handleDelete(row.membershipId, index)}

View File

@@ -1,8 +1,8 @@
import React from 'react';
import React from "react";
import StripeRedirect from '@app/pages/api/organization/StripeRedirect';
import StripeRedirect from "@app/pages/api/organization/StripeRedirect";
import { tempLocalStorage } from '../utilities/checks/tempLocalStorage';
import { tempLocalStorage } from "../utilities/checks/tempLocalStorage";
interface Props {
plan: {
@@ -21,7 +21,7 @@ export default function Plan({ plan }: Props) {
return (
<div
className={`relative flex flex-col justify-between border min-w-fit w-96 rounded-lg h-68 mr-4 bg-mineshaft-800 ${
plan.name !== 'Starter' && plan.current === true ? 'border-2 border-primary' : 'border-mineshaft-600'
plan.name !== "Starter" && plan.current === true ? "border-2 border-primary" : "border-mineshaft-600"
}
`}
>
@@ -39,7 +39,7 @@ export default function Plan({ plan }: Props) {
<div className="flex flex-row items-center">
{plan.current === false ? (
<>
{plan.buttonTextMain === 'Schedule a Demo' ? (
{plan.buttonTextMain === "Schedule a Demo" ? (
<a href="/scheduledemo" target='_blank rel="noopener"'>
<div className="relative z-10 mx-5 mt-3 mb-4 py-2 px-4 border border-1 border-mineshaft-600 hover:text-black hover:border-primary text-gray-400 font-semibold hover:bg-primary bg-bunker duration-200 cursor-pointer rounded-md flex w-max">
{plan.buttonTextMain}
@@ -48,16 +48,16 @@ export default function Plan({ plan }: Props) {
) : (
<div
className={`relative z-10 mx-5 mt-3 mb-4 py-2 px-4 border border-1 border-mineshaft-600 text-gray-400 font-semibold ${
plan.buttonTextMain === 'Downgrade'
? 'hover:bg-red hover:text-white hover:border-red'
: 'hover:bg-primary hover:text-black hover:border-primary'
plan.buttonTextMain === "Downgrade"
? "hover:bg-red hover:text-white hover:border-red"
: "hover:bg-primary hover:text-black hover:border-primary"
} bg-bunker duration-200 cursor-pointer rounded-md flex w-max`}
>
<button
type="button"
onClick={() =>
StripeRedirect({
orgId: tempLocalStorage('orgData.id')
orgId: tempLocalStorage("orgData.id")
})
}
>
@@ -74,7 +74,7 @@ export default function Plan({ plan }: Props) {
) : (
<div
className={`h-8 w-full rounded-b-md flex justify-center items-center z-10 ${
plan.name !== 'Starter' && plan.current === true ? 'bg-primary' : 'bg-mineshaft-400'
plan.name !== "Starter" && plan.current === true ? "bg-primary" : "bg-mineshaft-400"
}`}
>
<p className="text-xs text-black font-semibold">CURRENT PLAN</p>

View File

@@ -1,8 +1,8 @@
import { useEffect, useRef } from 'react';
import { faXmark } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useEffect, useRef } from "react";
import { faXmark } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
type NotificationType = 'success' | 'error' | 'info';
type NotificationType = "success" | "error" | "info";
export type TNotification = {
text: string;
@@ -39,13 +39,13 @@ const Notification = ({ notification, clearNotification }: NotificationProps) =>
className="relative w-full flex items-center justify-between px-6 py-4 rounded-md border border-bunker-500 pointer-events-auto bg-mineshaft-700 mb-3 right-3"
role="alert"
>
{notification.type === 'error' && (
{notification.type === "error" && (
<div className="absolute w-full h-1 bg-red top-0 left-0 rounded-t-md" />
)}
{notification.type === 'success' && (
{notification.type === "success" && (
<div className="absolute w-full h-1 bg-green top-0 left-0 rounded-t-md" />
)}
{notification.type === 'info' && (
{notification.type === "info" && (
<div className="absolute w-full h-1 bg-yellow top-0 left-0 rounded-t-md" />
)}
<p className="text-bunker-200 text-md font-base mt-0.5">{notification.text}</p>

View File

@@ -1,14 +1,14 @@
import { createContext, ReactNode, useCallback, useContext, useMemo, useState } from 'react';
import { createContext, ReactNode, useCallback, useContext, useMemo, useState } from "react";
import { TNotification } from './Notification';
import Notifications from './Notifications';
import { TNotification } from "./Notification";
import Notifications from "./Notifications";
type NotificationContextState = {
createNotification: (newNotification: TNotification) => void;
};
const NotificationContext = createContext<NotificationContextState>({
createNotification: () => console.log('createNotification not set!')
createNotification: () => console.log("createNotification not set!")
});
export const useNotificationContext = () => useContext(NotificationContext);
@@ -25,7 +25,7 @@ const NotificationProvider = ({ children }: NotificationProviderProps) => {
setNotifications((state) => state.filter((notif) => notif.text !== text));
const createNotification = useCallback(
({ text, type = 'success', timeoutMs = 4000 }: TNotification) => {
({ text, type = "success", timeoutMs = 4000 }: TNotification) => {
const doesNotifExist = notifications.some((notif) => notif.text === text);
if (doesNotifExist) {

View File

@@ -1,4 +1,4 @@
import Notification, { TNotification } from './Notification';
import Notification, { TNotification } from "./Notification";
interface NoticationsProps {
notifications: Required<TNotification>[];

View File

@@ -1,9 +1,9 @@
import { Fragment } from 'react';
import { useRouter } from 'next/router';
import { faCheckSquare, faPlus, faSquare } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Menu, Transition } from '@headlessui/react';
import { Tag } from 'public/data/frequentInterfaces';
import { Fragment } from "react";
import { useRouter } from "next/router";
import { faCheckSquare, faPlus, faSquare } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Menu, Transition } from "@headlessui/react";
import { Tag } from "public/data/frequentInterfaces";
/**
* This is the menu that is used to add more tags to a secret

View File

@@ -1,4 +1,4 @@
import { useTranslation } from 'react-i18next';
import { useTranslation } from "react-i18next";
/**
* This is the text field where people can add comments to particular secrets.
@@ -16,7 +16,7 @@ const CommentField = ({
return (
<div className="relative mt-4 px-4 pt-6">
<p className="pl-0.5 text-sm text-bunker-300">{t('dashboard.sidebar.comments')}</p>
<p className="pl-0.5 text-sm text-bunker-300">{t("dashboard.sidebar.comments")}</p>
<textarea
className="h-32 w-full rounded-md border border-mineshaft-500 bg-bunker-800 px-2 py-1.5 text-sm text-bunker-300 outline-none ring-primary-800 ring-opacity-70 placeholder:text-bunker-400 focus:ring-2 dark:[color-scheme:dark]"
value={comment}

View File

@@ -1,10 +1,10 @@
import { SetStateAction, useEffect, useState } from 'react';
import Image from 'next/image';
import { SetStateAction, useEffect, useState } from "react";
import Image from "next/image";
import { WorkspaceEnv } from '@app/hooks/api/types';
import { WorkspaceEnv } from "@app/hooks/api/types";
import getSecretsForProject from '../utilities/secrets/getSecretsForProject';
import { Modal, ModalContent } from '../v2';
import getSecretsForProject from "../utilities/secrets/getSecretsForProject";
import { Modal, ModalContent } from "../v2";
interface Secrets {
label: string;
@@ -40,7 +40,7 @@ const CompareSecretsModal = ({
// #TODO: optimize this query somehow...
const allSecrets = await getSecretsForProject({ env: env.slug, workspaceId });
const secret =
allSecrets.find((item) => item.key === currentSecret.key)?.value ?? 'Not found';
allSecrets.find((item) => item.key === currentSecret.key)?.value ?? "Not found";
return { label: env.name, secret };
})
);

View File

@@ -1,9 +1,9 @@
import { Button, Modal, ModalContent } from '../v2';
import { Button, Modal, ModalContent } from "../v2";
type Props = {
isOpen: boolean;
onClose: () => void;
onOverwriteConfirm: (preserve: 'old' | 'new') => void;
onOverwriteConfirm: (preserve: "old" | "new") => void;
duplicateKeys: string[];
};
@@ -19,10 +19,10 @@ const ConfirmEnvOverwriteModal = ({
title="Duplicate Secrets"
footerContent={
<div className="flex items-center gap-4">
<Button colorSchema="primary" onClick={() => onOverwriteConfirm('old')}>
<Button colorSchema="primary" onClick={() => onOverwriteConfirm("old")}>
Keep Old
</Button>
<Button colorSchema="danger" onClick={() => onOverwriteConfirm('new')}>
<Button colorSchema="danger" onClick={() => onOverwriteConfirm("new")}>
Overwrite
</Button>
</div>
@@ -31,7 +31,7 @@ const ConfirmEnvOverwriteModal = ({
>
<div className="flex flex-col gap-2">
<p className='text-gray-400'>Your file contains the following duplicate secrets:</p>
<p className="text-sm text-gray-500">{duplicateKeys.join(', ')}</p>
<p className="text-sm text-gray-500">{duplicateKeys.join(", ")}</p>
<p className='text-md text-gray-400'>Are you sure you want to overwrite these secrets?</p>
</div>
</ModalContent>

View File

@@ -1,10 +1,10 @@
import { memo, SyntheticEvent, useRef } from 'react';
import { faCircle, faCodeBranch, faExclamationCircle, faEye } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { memo, SyntheticEvent, useRef } from "react";
import { faCircle, faCodeBranch, faExclamationCircle, faEye } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import guidGenerator from '../utilities/randomId';
import { HoverObject } from '../v2/HoverCard';
import { PopoverObject } from '../v2/Popover/Popover';
import guidGenerator from "../utilities/randomId";
import { HoverObject } from "../v2/HoverCard";
import { PopoverObject } from "../v2/Popover/Popover";
const REGEX = /([$]{.*?})/g;
@@ -12,7 +12,7 @@ interface DashboardInputFieldProps {
id: string;
onChangeHandler: (value: string, id: string) => void;
value: string | undefined;
type: 'varName' | 'value' | 'comment';
type: "varName" | "value" | "comment";
blurred?: boolean;
isDuplicate?: boolean;
isCapitalized?: boolean;
@@ -56,19 +56,19 @@ const DashboardInputField = ({
ref.current.scrollLeft = e.currentTarget.scrollLeft;
};
if (type === 'varName') {
const startsWithNumber = !Number.isNaN(Number(value?.charAt(0))) && value !== '';
if (type === "varName") {
const startsWithNumber = !Number.isNaN(Number(value?.charAt(0))) && value !== "";
const error = startsWithNumber || isDuplicate;
return (
<div className={`relative flex-col w-full h-10 ${
error && value !== '' ? 'bg-red/[0.15]' : ''
error && value !== "" ? "bg-red/[0.15]" : ""
} ${
isSideBarOpen && 'bg-mineshaft-700 duration-200'
isSideBarOpen && "bg-mineshaft-700 duration-200"
}`}>
<div
className={`group relative flex flex-col justify-center items-center h-full ${
error ? 'w-max' : 'w-full'
error ? "w-max" : "w-full"
}`}
>
<input
@@ -76,7 +76,7 @@ const DashboardInputField = ({
type={type}
value={value}
className={`z-10 peer font-mono ph-no-capture bg-transparent h-full caret-bunker-200 text-sm px-2 w-full min-w-16 outline-none ${
error ? 'text-red-600 focus:text-red-500' : 'text-bunker-300 focus:text-bunker-100'
error ? "text-red-600 focus:text-red-500" : "text-bunker-300 focus:text-bunker-100"
} duration-200`}
spellCheck="false"
/>
@@ -90,7 +90,7 @@ const DashboardInputField = ({
/>
</div>
)}
{isDuplicate && value !== '' && !startsWithNumber && (
{isDuplicate && value !== "" && !startsWithNumber && (
<div className='absolute right-2 top-2 text-red z-50'>
<HoverObject
text="Secret names should be unique"
@@ -100,39 +100,39 @@ const DashboardInputField = ({
</div>
)}
{!error && <div className={`absolute right-0 top-0 text-red z-50 bg-mineshaft-800 group-hover:bg-mineshaft-700 ${
overrideEnabled ? 'visible' : 'invisible group-hover:visible'
overrideEnabled ? "visible" : "invisible group-hover:visible"
} cursor-pointer duration-0 h-10 flex items-center px-2`}>
<button type="button" onClick={() => {
if (modifyValueOverride) {
if (overrideEnabled === false) {
modifyValueOverride('', id);
modifyValueOverride("", id);
} else {
modifyValueOverride(undefined, id);
}
}
}}>
<HoverObject
text={overrideEnabled ? 'This secret is overriden with your personal value' : 'You can override this secret with a personal value'}
text={overrideEnabled ? "This secret is overriden with your personal value" : "You can override this secret with a personal value"}
icon={faCodeBranch}
color={overrideEnabled ? 'primary' : 'bunker-400'}
color={overrideEnabled ? "primary" : "bunker-400"}
/>
</button>
</div>}
</div>
);
}
if (type === 'comment') {
const startsWithNumber = !Number.isNaN(Number(value?.charAt(0))) && value !== '';
if (type === "comment") {
const startsWithNumber = !Number.isNaN(Number(value?.charAt(0))) && value !== "";
const error = startsWithNumber || isDuplicate;
return (
<PopoverObject text={value || ''} onChangeHandler={onChangeHandler} id={id}>
<PopoverObject text={value || ""} onChangeHandler={onChangeHandler} id={id}>
<div title={value} className={`relative flex-col w-full h-10 overflow-hidden ${
isSideBarOpen && 'bg-mineshaft-700 duration-200'
isSideBarOpen && "bg-mineshaft-700 duration-200"
}`}>
<div
className={`group relative flex flex-col justify-center items-center h-full ${
error ? 'w-max' : 'w-full'
error ? "w-max" : "w-full"
}`}
>
{value?.split("\n")[0] ? <span className='ph-no-capture truncate break-all bg-transparent leading-tight text-xs px-2 w-full min-w-16 outline-none text-bunker-300 focus:text-bunker-100 placeholder:text-bunker-400 placeholder:focus:text-transparent placeholder duration-200'>
@@ -146,7 +146,7 @@ const DashboardInputField = ({
</PopoverObject>
);
}
if (type === 'value') {
if (type === "value") {
return (
<div className="flex-col w-full">
<div className="group relative whitespace-pre flex flex-col justify-center w-full">
@@ -161,8 +161,8 @@ const DashboardInputField = ({
onScroll={syncScroll}
className={`${
blurred
? 'text-transparent focus:text-transparent active:text-transparent'
: ''
? "text-transparent focus:text-transparent active:text-transparent"
: ""
} z-10 peer font-mono ph-no-capture bg-transparent caret-white text-transparent text-sm px-2 py-2 w-full min-w-16 outline-none duration-200 no-scrollbar no-scrollbar::-webkit-scrollbar`}
spellCheck="false"
/>
@@ -170,10 +170,10 @@ const DashboardInputField = ({
ref={ref}
className={`${
blurred && !overrideEnabled
? 'text-bunker-800 group-hover:text-gray-400 peer-focus:text-gray-100 peer-active:text-gray-400 duration-200'
: ''
} ${overrideEnabled ? 'text-primary-300' : 'text-gray-400'}
absolute flex flex-row whitespace-pre font-mono z-0 ${blurred ? 'invisible' : 'visible'} peer-focus:visible mt-0.5 ph-no-capture overflow-x-scroll bg-transparent h-10 text-sm px-2 py-2 w-full min-w-16 outline-none duration-100 no-scrollbar no-scrollbar::-webkit-scrollbar`}
? "text-bunker-800 group-hover:text-gray-400 peer-focus:text-gray-100 peer-active:text-gray-400 duration-200"
: ""
} ${overrideEnabled ? "text-primary-300" : "text-gray-400"}
absolute flex flex-row whitespace-pre font-mono z-0 ${blurred ? "invisible" : "visible"} peer-focus:visible mt-0.5 ph-no-capture overflow-x-scroll bg-transparent h-10 text-sm px-2 py-2 w-full min-w-16 outline-none duration-100 no-scrollbar no-scrollbar::-webkit-scrollbar`}
>
{value?.split(REGEX).map((word) => {
if (word.match(REGEX) !== null) {
@@ -183,7 +183,7 @@ const DashboardInputField = ({
<span className="ph-no-capture text-yellow-200/80">
{word.slice(2, word.length - 1)}
</span>
{word.slice(word.length - 1, word.length) === '}' ? (
{word.slice(word.length - 1, word.length) === "}" ? (
<span className="ph-no-capture text-yellow">
{word.slice(word.length - 1, word.length)}
</span>
@@ -204,17 +204,17 @@ const DashboardInputField = ({
</div>
{blurred && (
<div className={`absolute flex flex-row justify-between items-center z-0 peer pr-2 ${
isSideBarOpen ? 'bg-mineshaft-700 duration-200' : 'bg-mineshaft-800'
isSideBarOpen ? "bg-mineshaft-700 duration-200" : "bg-mineshaft-800"
} peer-active:hidden peer-focus:hidden group-hover:bg-white/[0.00] duration-100 h-10 w-full text-bunker-400 text-clip`}>
<div className="px-2 flex flex-row items-center overflow-x-scroll no-scrollbar no-scrollbar::-webkit-scrollbar">
{value?.split('').map(() => (
{value?.split("").map(() => (
<FontAwesomeIcon
key={guidGenerator()}
className="text-xxs mr-0.5"
icon={faCircle}
/>
))}
{value?.split('').length === 0 && <span className='text-bunker-400/80'>EMPTY</span>}
{value?.split("").length === 0 && <span className='text-bunker-400/80'>EMPTY</span>}
</div>
<div className='invisible group-hover:visible cursor-default z-[100]'><FontAwesomeIcon icon={faEye} /></div>
</div>

View File

@@ -1,9 +1,9 @@
import React from 'react'
import { useTranslation } from 'react-i18next';
import { faXmark } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import React from "react"
import { useTranslation } from "react-i18next";
import { faXmark } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import Button from '../basic/buttons/Button';
import Button from "../basic/buttons/Button";
type Props = {
onSubmit: () => void;
@@ -16,8 +16,8 @@ export const DeleteActionButton = ({ onSubmit, isPlain }: Props) => {
return (
<div className={`${
!isPlain
? 'bg-[#9B3535] opacity-70 hover:opacity-100 w-[4.5rem] h-[2.5rem] rounded-md duration-200 ml-2'
: 'cursor-pointer w-[1.5rem] h-[2.35rem] mr-2 flex items-center justfy-center'}`}>
? "bg-[#9B3535] opacity-70 hover:opacity-100 w-[4.5rem] h-[2.5rem] rounded-md duration-200 ml-2"
: "cursor-pointer w-[1.5rem] h-[2.35rem] mr-2 flex items-center justfy-center"}`}>
{isPlain
? <div
onKeyDown={() => null}

View File

@@ -1,11 +1,11 @@
import { Fragment } from 'react';
import { faDownload } from '@fortawesome/free-solid-svg-icons';
import { Menu, Transition } from '@headlessui/react';
import { SecretDataProps } from 'public/data/frequentInterfaces';
import { Fragment } from "react";
import { faDownload } from "@fortawesome/free-solid-svg-icons";
import { Menu, Transition } from "@headlessui/react";
import { SecretDataProps } from "public/data/frequentInterfaces";
import Button from '../basic/buttons/Button';
import downloadDotEnv from '../utilities/secrets/downloadDotEnv';
import downloadYaml from '../utilities/secrets/downloadYaml';
import Button from "../basic/buttons/Button";
import downloadDotEnv from "../utilities/secrets/downloadDotEnv";
import downloadYaml from "../utilities/secrets/downloadYaml";
/**
* This is the menu that is used to download secrets as .env ad .yml files (in future we may have more options)

View File

@@ -1,16 +1,16 @@
/* eslint-disable no-nested-ternary */
import { type ChangeEvent, type DragEvent, useState } from 'react';
import { useTranslation } from 'react-i18next';
import Image from 'next/image';
import { faUpload } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { parseDocument, Scalar, YAMLMap } from 'yaml';
import { type ChangeEvent, type DragEvent, useState } from "react";
import { useTranslation } from "react-i18next";
import Image from "next/image";
import { faUpload } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { parseDocument, Scalar, YAMLMap } from "yaml";
import Button from '../basic/buttons/Button';
import Error from '../basic/Error';
import { useNotificationContext } from '../context/Notifications/NotificationProvider';
import { parseDotEnv } from '../utilities/parseDotEnv';
import guidGenerator from '../utilities/randomId';
import Button from "../basic/buttons/Button";
import Error from "../basic/Error";
import { useNotificationContext } from "../context/Notifications/NotificationProvider";
import { parseDotEnv } from "../utilities/parseDotEnv";
import guidGenerator from "../utilities/randomId";
interface DropZoneProps {
// TODO: change Data type from any
@@ -50,7 +50,7 @@ const DropZone = ({
e.stopPropagation();
// set dropEffect to copy i.e copy of the source item
e.dataTransfer.dropEffect = 'copy';
e.dataTransfer.dropEffect = "copy";
};
const [loading, setLoading] = useState(false);
@@ -58,33 +58,33 @@ const DropZone = ({
const getSecrets = (file: ArrayBuffer, fileType: string) => {
let secrets;
switch (fileType) {
case 'env': {
case "env": {
const keyPairs = parseDotEnv(file);
secrets = Object.keys(keyPairs).map((key, index) => ({
id: guidGenerator(),
pos: numCurrentRows + index,
key,
value: keyPairs[key as keyof typeof keyPairs].value,
comment: keyPairs[key as keyof typeof keyPairs].comments.join('\n'),
type: 'shared',
comment: keyPairs[key as keyof typeof keyPairs].comments.join("\n"),
type: "shared",
tags: []
}));
break;
}
case 'json': {
case "json": {
const keyPairs = JSON.parse(String(file));
secrets = Object.keys(keyPairs).map((key, index) => ({
id: guidGenerator(),
pos: numCurrentRows + index,
key,
value: keyPairs[key as keyof typeof keyPairs],
comment: '',
type: 'shared',
comment: "",
type: "shared",
tags: []
}));
break;
}
case 'yml': {
case "yml": {
const parsedFile = parseDocument(file.toString());
const keyPairs = parsedFile.contents!.toJSON();
@@ -93,26 +93,26 @@ const DropZone = ({
const comment =
fileContent!.items
.find((item) => item.key.value === key)
?.key?.commentBefore?.split('\n')
?.key?.commentBefore?.split("\n")
.map((cmnt) => cmnt.trim())
.join('\n') ?? '';
.join("\n") ?? "";
return {
id: guidGenerator(),
pos: numCurrentRows + index,
key,
value: keyPairs[key as keyof typeof keyPairs]?.toString() ?? '',
value: keyPairs[key as keyof typeof keyPairs]?.toString() ?? "",
comment,
type: 'shared',
type: "shared",
tags: []
};
});
break;
}
default:
secrets = '';
secrets = "";
createNotification({
text: `The file you are dropping should have one of the following extensions: .env, .yml, .json.`,
type: 'error'
text: "The file you are dropping should have one of the following extensions: .env, .yml, .json.",
type: "error"
});
break;
}
@@ -125,20 +125,20 @@ const DropZone = ({
setTimeout(() => setLoading(false), 5000);
e.preventDefault();
e.stopPropagation();
e.dataTransfer.dropEffect = 'copy';
e.dataTransfer.dropEffect = "copy";
const file = e.dataTransfer.files[0];
const reader = new FileReader();
if (file === undefined) {
createNotification({
text: `You can't inject files from VS Code. Click 'Reveal in finder', and drag your file directly from the directory where it's located.`,
type: 'error',
text: "You can't inject files from VS Code. Click 'Reveal in finder', and drag your file directly from the directory where it's located.",
type: "error",
timeoutMs: 10000
});
setLoading(false);
return;
}
const fileType = file.name.split('.')[1];
const fileType = file.name.split(".")[1];
reader.onload = (event) => {
if (event.target === null || event.target.result === null) return;
@@ -148,7 +148,7 @@ const DropZone = ({
setData(newData);
setButtonReady(true);
} catch (error) {
console.log('Error while dropping the file: ', error);
console.log("Error while dropping the file: ", error);
}
};
@@ -168,7 +168,7 @@ const DropZone = ({
setTimeout(() => setLoading(false), 5000);
if (e.currentTarget.files === null) return;
const file = e.currentTarget.files[0];
const fileType = file.name.split('.')[1];
const fileType = file.name.split(".")[1];
const reader = new FileReader();
reader.onload = (event) => {
if (event.target === null || event.target.result === null) return;
@@ -202,7 +202,7 @@ const DropZone = ({
{errorDragAndDrop ? <div className="my-3 max-w-xl opacity-80" /> : <div className="" />}
<div className="flex flex-row">
<FontAwesomeIcon icon={faUpload} className="mr-6 text-3xl text-bunker-300" />
<p className="mt-1 text-bunker-300">{t('common.drop-zone-keys')}</p>
<p className="mt-1 text-bunker-300">{t("common.drop-zone-keys")}</p>
</div>
{errorDragAndDrop && (
<div className="mt-8 max-w-xl opacity-80">
@@ -219,7 +219,7 @@ const DropZone = ({
onDrop={handleDrop}
>
<FontAwesomeIcon icon={faUpload} className="mb-8 text-7xl" />
<p className="">{t('common.drop-zone')}</p>
<p className="">{t("common.drop-zone")}</p>
<input
id="fileSelect"
type="file"
@@ -235,7 +235,7 @@ const DropZone = ({
<div className="z-10 mb-6">
<Button
color="mineshaft"
text={String(t('dashboard.add-secret'))}
text={String(t("dashboard.add-secret"))}
onButtonPressed={createNewFile}
size="md"
/>

View File

@@ -1,8 +1,8 @@
import { Fragment, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { faShuffle } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Menu, Transition } from '@headlessui/react';
import { Fragment, useState } from "react";
import { useTranslation } from "react-i18next";
import { faShuffle } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Menu, Transition } from "@headlessui/react";
/**
* This is the menu that is used to (re)generate secrets (currently we only have ranom hex, in future we will have more options)
@@ -50,7 +50,7 @@ const GenerateSecretMenu = ({
modifyValue(
[...Array(randomStringLength)]
.map(() => Math.floor(Math.random() * 16).toString(16))
.join(''),
.join(""),
id
);
}
@@ -59,8 +59,8 @@ const GenerateSecretMenu = ({
>
<FontAwesomeIcon className="pl-1.5 pr-3 text-lg" icon={faShuffle} />
<div className="flex w-full flex-row justify-between text-sm">
<p>{t('dashboard.sidebar.generate-random-hex')}</p>
<p>{t('dashboard.sidebar.digits')}</p>
<p>{t("dashboard.sidebar.generate-random-hex")}</p>
<p>{t("dashboard.sidebar.digits")}</p>
</div>
</div>
<div className="absolute bottom-[0.4rem] right-[3.3rem] flex w-16 flex-row rounded-md border border-chicago-700 bg-bunker-800 text-bunker-200 ">

View File

@@ -1,10 +1,10 @@
import { faEllipsis, faXmark } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { SecretDataProps, Tag } from 'public/data/frequentInterfaces';
import { faEllipsis, faXmark } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { SecretDataProps, Tag } from "public/data/frequentInterfaces";
import AddTagsMenu from './AddTagsMenu';
import DashboardInputField from './DashboardInputField';
import { DeleteActionButton } from './DeleteActionButton';
import AddTagsMenu from "./AddTagsMenu";
import DashboardInputField from "./DashboardInputField";
import { DeleteActionButton } from "./DeleteActionButton";
interface KeyPairProps {
keyPair: SecretDataProps;
@@ -30,26 +30,26 @@ export interface DeleteRowFunctionProps {
}
const colors = [
'bg-[#f1c40f]/40',
'bg-[#cb1c8d]/40',
'bg-[#badc58]/40',
'bg-[#ff5400]/40',
'bg-[#3AB0FF]/40',
'bg-[#6F1AB6]/40',
'bg-[#C40B13]/40',
'bg-[#332FD0]/40'
"bg-[#f1c40f]/40",
"bg-[#cb1c8d]/40",
"bg-[#badc58]/40",
"bg-[#ff5400]/40",
"bg-[#3AB0FF]/40",
"bg-[#6F1AB6]/40",
"bg-[#C40B13]/40",
"bg-[#332FD0]/40"
]
const colorsText = [
'text-[#fcf0c3]/70',
'text-[#f2c6e3]/70',
'text-[#eef6d5]/70',
'text-[#ffddcc]/70',
'text-[#f0fffd]/70',
'text-[#FFE5F1]/70',
'text-[#FFDEDE]/70',
'text-[#DFF6FF]/70'
"text-[#fcf0c3]/70",
"text-[#f2c6e3]/70",
"text-[#eef6d5]/70",
"text-[#ffddcc]/70",
"text-[#f0fffd]/70",
"text-[#FFE5F1]/70",
"text-[#FFDEDE]/70",
"text-[#DFF6FF]/70"
]
/**
@@ -96,8 +96,8 @@ const KeyPair = ({
return (
<div
className={`group flex flex-col items-center border-b border-mineshaft-500 hover:bg-white/[0.03] duration-100 ${isSnapshot && 'pointer-events-none'} ${
keyPair.id === sidebarSecretId && 'bg-mineshaft-700 duration-200'
className={`group flex flex-col items-center border-b border-mineshaft-500 hover:bg-white/[0.03] duration-100 ${isSnapshot && "pointer-events-none"} ${
keyPair.id === sidebarSecretId && "bg-mineshaft-700 duration-200"
}`}
>
<div className="relative flex flex-row justify-between w-full mr-auto max-h-14 items-center">
@@ -108,7 +108,7 @@ const KeyPair = ({
isCapitalized = {isCapitalized}
onChangeHandler={modifyKey}
type="varName"
id={keyPair.id ? keyPair.id : (keyPair.idOverride || '')}
id={keyPair.id ? keyPair.id : (keyPair.idOverride || "")}
value={keyPair.key}
isDuplicate={isDuplicate}
overrideEnabled={keyPair.valueOverride !== undefined}
@@ -124,7 +124,7 @@ const KeyPair = ({
<DashboardInputField
onChangeHandler={keyPair.valueOverride !== undefined ? modifyValueOverride : modifyValue}
type="value"
id={keyPair.id ? keyPair.id : (keyPair.idOverride || '')}
id={keyPair.id ? keyPair.id : (keyPair.idOverride || "")}
value={keyPair.valueOverride !== undefined ? keyPair.valueOverride : keyPair.value}
blurred={isBlurred}
overrideEnabled={keyPair.valueOverride !== undefined}
@@ -137,7 +137,7 @@ const KeyPair = ({
<DashboardInputField
onChangeHandler={modifyComment}
type="comment"
id={keyPair.id ? keyPair.id : (keyPair.idOverride || '')}
id={keyPair.id ? keyPair.id : (keyPair.idOverride || "")}
value={keyPair.comment}
isDuplicate={isDuplicate}
isSideBarOpen={keyPair.id === sidebarSecretId}
@@ -153,7 +153,7 @@ const KeyPair = ({
</div>
))}
<AddTagsMenu allTags={tags} currentTags={keyPair.tags} modifyTags={modifyTags} id={keyPair.id ? keyPair.id : (keyPair.idOverride || '')} />
<AddTagsMenu allTags={tags} currentTags={keyPair.tags} modifyTags={modifyTags} id={keyPair.id ? keyPair.id : (keyPair.idOverride || "")} />
</div>
</div>
<div
@@ -166,11 +166,11 @@ const KeyPair = ({
}
toggleSidebar(keyPair.id)
}}
className={`cursor-pointer w-[1.5rem] h-[2.35rem] ml-auto group-hover:bg-mineshaft-700 z-50 rounded-md invisible group-hover:visible flex flex-row justify-center items-center ${isSnapshot ?? 'invisible'}`}
className={`cursor-pointer w-[1.5rem] h-[2.35rem] ml-auto group-hover:bg-mineshaft-700 z-50 rounded-md invisible group-hover:visible flex flex-row justify-center items-center ${isSnapshot ?? "invisible"}`}
>
<FontAwesomeIcon className="text-bunker-300 hover:text-primary text-lg" icon={faEllipsis} />
</div>
<div className={`group-hover:bg-mineshaft-700 z-50 ${isSnapshot ?? 'invisible'}`}>
<div className={`group-hover:bg-mineshaft-700 z-50 ${isSnapshot ?? "invisible"}`}>
{keyPair.key || keyPair.value
? <DeleteActionButton
onSubmit={() => { if (deleteRow) {

View File

@@ -1,20 +1,20 @@
/* eslint-disable react/no-unused-prop-types */
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import Image from 'next/image';
import { faXmark } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useState } from "react";
import { useTranslation } from "react-i18next";
import Image from "next/image";
import { faXmark } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import SecretVersionList from '@app/ee/components/SecretVersionList';
import { WorkspaceEnv } from '@app/hooks/api/types';
import SecretVersionList from "@app/ee/components/SecretVersionList";
import { WorkspaceEnv } from "@app/hooks/api/types";
import Button from '../basic/buttons/Button';
import Toggle from '../basic/Toggle';
import CommentField from './CommentField';
import CompareSecretsModal from './CompareSecretsModal';
import DashboardInputField from './DashboardInputField';
import { DeleteActionButton } from './DeleteActionButton';
import GenerateSecretMenu from './GenerateSecretMenu';
import Button from "../basic/buttons/Button";
import Toggle from "../basic/Toggle";
import CommentField from "./CommentField";
import CompareSecretsModal from "./CompareSecretsModal";
import DashboardInputField from "./DashboardInputField";
import { DeleteActionButton } from "./DeleteActionButton";
import GenerateSecretMenu from "./GenerateSecretMenu";
interface SecretProps {
key: string;
@@ -93,19 +93,19 @@ const SideBar = ({
) : (
<div className="h-min w-full overflow-y-auto">
<div className="flex flex-row items-center justify-between border-b border-mineshaft-500 px-4 py-3">
<p className="text-lg font-semibold text-bunker-200">{t('dashboard.sidebar.secret')}</p>
<p className="text-lg font-semibold text-bunker-200">{t("dashboard.sidebar.secret")}</p>
<div
onKeyDown={() => null}
role="button"
tabIndex={0}
className="p-1"
onClick={() => toggleSidebar('None')}
onClick={() => toggleSidebar("None")}
>
<FontAwesomeIcon icon={faXmark} className="h-4 w-4 cursor-pointer text-bunker-300" />
</div>
</div>
<div className="pointer-events-none mt-4 px-4">
<p className="text-sm text-bunker-300">{t('dashboard.sidebar.key')}</p>
<p className="text-sm text-bunker-300">{t("dashboard.sidebar.key")}</p>
<div className="overflow-hidden rounded-md border border-mineshaft-600 bg-white/5">
<DashboardInputField
onChangeHandler={modifyKey}
@@ -117,13 +117,13 @@ const SideBar = ({
/>
</div>
</div>
{data[0]?.value || data[0]?.value === '' ? (
{data[0]?.value || data[0]?.value === "" ? (
<div
className={`relative mt-2 px-4 ${
overrideEnabled && 'pointer-events-none opacity-40'
overrideEnabled && "pointer-events-none opacity-40"
} duration-200`}
>
<p className="text-sm text-bunker-300">{t('dashboard.sidebar.value')}</p>
<p className="text-sm text-bunker-300">{t("dashboard.sidebar.value")}</p>
<div className="overflow-hidden rounded-md border border-mineshaft-600 bg-white/5">
<DashboardInputField
onChangeHandler={modifyValue}
@@ -141,15 +141,15 @@ const SideBar = ({
) : (
<div className="px-4 pt-4 text-sm text-bunker-300">
<span className="mr-1 rounded-md bg-primary-200/10 py-0.5 px-1">
{t('common.note')}:
{t("common.note")}:
</span>
{t('dashboard.sidebar.personal-explanation')}
{t("dashboard.sidebar.personal-explanation")}
</div>
)}
<div className="mt-4 px-4">
{(data[0]?.value || data[0]?.value === '') && (
{(data[0]?.value || data[0]?.value === "") && (
<div className="my-2 flex flex-row items-center justify-between pl-1 pr-2">
<p className="text-sm text-bunker-300">{t('dashboard.sidebar.override')}</p>
<p className="text-sm text-bunker-300">{t("dashboard.sidebar.override")}</p>
<Toggle
enabled={overrideEnabled}
setEnabled={setOverrideEnabled}
@@ -160,7 +160,7 @@ const SideBar = ({
)}
<div
className={`relative ${
!overrideEnabled && 'pointer-events-none opacity-40'
!overrideEnabled && "pointer-events-none opacity-40"
} duration-200`}
>
<div className="overflow-hidden rounded-md border border-mineshaft-600 bg-white/5">
@@ -193,7 +193,7 @@ const SideBar = ({
<CompareSecretsModal
compareModal={compareModal}
setCompareModal={setCompareModal}
currentSecret={{ key: data[0]?.key, value: data[0]?.value ?? '' }}
currentSecret={{ key: data[0]?.key, value: data[0]?.value ?? "" }}
workspaceEnvs={workspaceEnvs}
selectedEnv={selectedEnv}
workspaceId={workspaceId}
@@ -201,7 +201,7 @@ const SideBar = ({
</div>
<div className="flex">
<Button
text={String(t('common.save-changes'))}
text={String(t("common.save-changes"))}
onButtonPressed={savePush}
color="primary"
size="md"

View File

@@ -1,8 +1,8 @@
import Image from 'next/image';
import { faCheck, faXmark } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import Image from "next/image";
import { faCheck, faXmark } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import deleteIntegrationAuth from '../../pages/api/integrations/DeleteIntegrationAuth';
import deleteIntegrationAuth from "../../pages/api/integrations/DeleteIntegrationAuth";
interface IntegrationOption {
clientId: string;
@@ -44,8 +44,8 @@ const CloudIntegration = ({
tabIndex={0}
className={`relative ${
cloudIntegrationOption.isAvailable
? 'cursor-pointer duration-200 hover:bg-mineshaft-700'
: 'opacity-50'
? "cursor-pointer duration-200 hover:bg-mineshaft-700"
: "opacity-50"
} flex h-32 flex-row items-center rounded-md bg-mineshaft-800 border border-mineshaft-600 p-4`}
onClick={() => {
if (!cloudIntegrationOption.isAvailable) return;
@@ -60,11 +60,11 @@ const CloudIntegration = ({
width={70}
alt="integration logo"
/>
{cloudIntegrationOption.name.split(' ').length > 2 ? (
{cloudIntegrationOption.name.split(" ").length > 2 ? (
<div className="ml-4 max-w-xs text-3xl font-semibold text-gray-300 duration-200 group-hover:text-gray-200">
<div>{cloudIntegrationOption.name.split(' ')[0]}</div>
<div>{cloudIntegrationOption.name.split(" ")[0]}</div>
<div className="text-base">
{cloudIntegrationOption.name.split(' ')[1]} {cloudIntegrationOption.name.split(' ')[2]}
{cloudIntegrationOption.name.split(" ")[1]} {cloudIntegrationOption.name.split(" ")[2]}
</div>
</div>
) : (

View File

@@ -1,6 +1,6 @@
import { useTranslation } from 'react-i18next';
import { useTranslation } from "react-i18next";
import CloudIntegration from './CloudIntegration';
import CloudIntegration from "./CloudIntegration";
interface IntegrationOption {
clientId: string;
@@ -41,8 +41,8 @@ const CloudIntegrationSection = ({
return (
<>
<div className="m-4 mt-7 flex max-w-5xl flex-col items-start justify-between px-2 text-xl">
<h1 className="text-3xl font-semibold">{t('integrations.cloud-integrations')}</h1>
<p className="text-base text-gray-400">{t('integrations.click-to-start')}</p>
<h1 className="text-3xl font-semibold">{t("integrations.cloud-integrations")}</h1>
<p className="text-base text-gray-400">{t("integrations.click-to-start")}</p>
</div>
<div className="mx-6 grid max-w-5xl grid-cols-4 grid-rows-2 gap-4">
{cloudIntegrationOptions.map((cloudIntegrationOption) => (

View File

@@ -1,4 +1,4 @@
import Image from 'next/image';
import Image from "next/image";
interface Framework {
name: string;
@@ -16,7 +16,7 @@ const FrameworkIntegration = ({ framework }: { framework: Framework }) => (
>
<div
className={`hover:bg-mineshaft-700 cursor-pointer font-semibold bg-mineshaft-800 border border-mineshaft-600 flex flex-col items-center justify-center h-full w-full rounded-md text-gray-300 group-hover:text-gray-200 duration-200 ${
framework?.name?.split(' ').length > 1 ? 'text-sm px-1' : 'text-xl px-2'
framework?.name?.split(" ").length > 1 ? "text-sm px-1" : "text-xl px-2"
} text-center w-full max-w-xs`}
>
{framework?.image && (

View File

@@ -1,6 +1,6 @@
import { useTranslation } from 'react-i18next';
import { useTranslation } from "react-i18next";
import FrameworkIntegration from './FrameworkIntegration';
import FrameworkIntegration from "./FrameworkIntegration";
interface Framework {
name: string;
@@ -20,8 +20,8 @@ const FrameworkIntegrationSection = ({ frameworks }: Props) => {
return (
<>
<div className="mx-4 mt-12 mb-4 flex max-w-5xl flex-col items-start justify-between px-2 text-xl">
<h1 className="text-3xl font-semibold">{t('integrations.framework-integrations')}</h1>
<p className="text-base text-gray-400">{t('integrations.click-to-setup')}</p>
<h1 className="text-3xl font-semibold">{t("integrations.framework-integrations")}</h1>
<p className="text-base text-gray-400">{t("integrations.click-to-setup")}</p>
</div>
<div className="mx-6 mt-4 grid max-w-5xl grid-cols-7 grid-rows-2 gap-4">
{frameworks.map((framework) => (

View File

@@ -1,21 +1,21 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { useEffect, useState } from 'react';
import { useRouter } from 'next/router';
import { faArrowRight, faCheck, faXmark } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useEffect, useState } from "react";
import { useRouter } from "next/router";
import { faArrowRight, faCheck, faXmark } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
// TODO: This needs to be moved from public folder
import {
contextNetlifyMapping,
integrationSlugNameMapping,
reverseContextNetlifyMapping
} from 'public/data/frequentConstants';
} from "public/data/frequentConstants";
import Button from '@app/components/basic/buttons/Button';
import ListBox from '@app/components/basic/Listbox';
import Button from "@app/components/basic/buttons/Button";
import ListBox from "@app/components/basic/Listbox";
import deleteIntegration from '../../pages/api/integrations/DeleteIntegration';
import getIntegrationApps from '../../pages/api/integrations/GetIntegrationApps';
import updateIntegration from '../../pages/api/integrations/updateIntegration';
import deleteIntegration from "../../pages/api/integrations/DeleteIntegration";
import getIntegrationApps from "../../pages/api/integrations/GetIntegrationApps";
import updateIntegration from "../../pages/api/integrations/updateIntegration";
interface Integration {
_id: string;
@@ -60,16 +60,16 @@ const IntegrationTile = ({
environments = [],
handleDeleteIntegration
}: Props) => {
const [integrationEnvironment, setIntegrationEnvironment] = useState<Props['environments'][0]>(
const [integrationEnvironment, setIntegrationEnvironment] = useState<Props["environments"][0]>(
environments.find(({ slug }) => slug === integration?.environment) || {
name: '',
slug: ''
name: "",
slug: ""
}
);
const router = useRouter();
const [apps, setApps] = useState<IntegrationApp[]>([]); // integration app objects
const [integrationApp, setIntegrationApp] = useState(''); // integration app name
const [integrationTargetEnvironment, setIntegrationTargetEnvironment] = useState('');
const [integrationApp, setIntegrationApp] = useState(""); // integration app name
const [integrationTargetEnvironment, setIntegrationTargetEnvironment] = useState("");
useEffect(() => {
const loadIntegration = async () => {
@@ -86,23 +86,23 @@ const IntegrationTile = ({
} else if (tempApps.length > 0) {
setIntegrationApp(tempApps[0].name);
} else {
setIntegrationApp('');
setIntegrationApp("");
}
switch (integration.integration) {
case 'vercel':
case "vercel":
setIntegrationTargetEnvironment(
integration?.targetEnvironment
? integration.targetEnvironment.charAt(0).toUpperCase() +
integration.targetEnvironment.substring(1)
: 'Development'
: "Development"
);
break;
case 'netlify':
case "netlify":
setIntegrationTargetEnvironment(
integration?.targetEnvironment
? contextNetlifyMapping[integration.targetEnvironment]
: 'Local development'
: "Local development"
);
break;
default:
@@ -116,9 +116,9 @@ const IntegrationTile = ({
const handleStartIntegration = async () => {
const reformatTargetEnvironment = (targetEnvironment: string) => {
switch (integration.integration) {
case 'vercel':
case "vercel":
return targetEnvironment.toLowerCase();
case 'netlify':
case "netlify":
return reverseContextNetlifyMapping[targetEnvironment];
default:
return null;
@@ -153,26 +153,26 @@ const IntegrationTile = ({
const renderIntegrationSpecificParams = (integration: Integration) => {
try {
switch (integration.integration) {
case 'vercel':
case "vercel":
return (
<div>
<div className="mb-2 w-60 text-xs font-semibold text-gray-400">ENVIRONMENT</div>
<ListBox
data={!integration.isActive ? ['Development', 'Preview', 'Production'] : null}
data={!integration.isActive ? ["Development", "Preview", "Production"] : null}
isSelected={integrationTargetEnvironment}
onChange={setIntegrationTargetEnvironment}
isFull
/>
</div>
);
case 'netlify':
case "netlify":
return (
<div>
<div className="mb-2 text-xs font-semibold text-gray-400">CONTEXT</div>
<ListBox
data={
!integration.isActive
? ['Production', 'Deploy previews', 'Branch deploys', 'Local development']
? ["Production", "Deploy previews", "Branch deploys", "Local development"]
: null
}
isSelected={integrationTargetEnvironment}
@@ -180,14 +180,14 @@ const IntegrationTile = ({
/>
</div>
);
case 'railway':
case "railway":
return (
<div>
<div className="mb-2 text-xs font-semibold text-gray-400">ENVIRONMENT</div>
<ListBox
data={
!integration.isActive
? ['Production', 'Deploy previews', 'Branch deploys', 'Local development']
? ["Production", "Deploy previews", "Branch deploys", "Local development"]
: null
}
isSelected={integration.targetEnvironment}
@@ -195,7 +195,7 @@ const IntegrationTile = ({
/>
</div>
);
case 'gitlab':
case "gitlab":
return (
<div>
<div className="mb-2 text-xs font-semibold text-gray-400">ENVIRONMENT</div>
@@ -216,10 +216,10 @@ const IntegrationTile = ({
return <div />;
};
if (!integrationApp && integration.integration !== 'checkly') return <div />;
if (!integrationApp && integration.integration !== "checkly") return <div />;
const isSelected =
integration.integration === 'hashicorp-vault'
integration.integration === "hashicorp-vault"
? `${integration.app} - path: ${integration.path}`
: integrationApp;
@@ -234,8 +234,8 @@ const IntegrationTile = ({
onChange={(envName) =>
setIntegrationEnvironment(
environments.find(({ name }) => envName === name) || {
name: 'unknown',
slug: 'unknown'
name: "unknown",
slug: "unknown"
}
)
}

View File

@@ -1,4 +1,4 @@
import IntegrationTile from './Integration';
import IntegrationTile from "./Integration";
interface Props {
integrations: any;

View File

@@ -1,14 +1,14 @@
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import Link from 'next/link';
import { useRouter } from 'next/router';
import { useState } from "react";
import { useTranslation } from "react-i18next";
import Link from "next/link";
import { useRouter } from "next/router";
import attemptLogin from '@app/components/utilities/attemptLogin';
import attemptLogin from "@app/components/utilities/attemptLogin";
import Error from '../basic/Error';
import Error from "../basic/Error";
// import { faGoogle } from '@fortawesome/free-brands-svg-icons';
// import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Button, Input } from '../v2';
import { Button, Input } from "../v2";
export default function InitialLoginStep({
setStep,
@@ -51,7 +51,7 @@ export default function InitialLoginStep({
}
// case: login does not require MFA step
router.push(`/dashboard/${localStorage.getItem('projectData.id')}`);
router.push(`/dashboard/${localStorage.getItem("projectData.id")}`);
}
} catch (err) {
@@ -103,7 +103,7 @@ export default function InitialLoginStep({
/>
</div>
</div>
{!isLoading && loginError && <Error text={t('login.error-login') ?? ''} />}
{!isLoading && loginError && <Error text={t("login.error-login") ?? ""} />}
<div className='lg:w-1/6 w-1/4 min-w-[21.2rem] md:min-w-[20.1rem] text-center rounded-md mt-4'>
<Button
onClick={async () => handleLogin()}
@@ -134,7 +134,7 @@ export default function InitialLoginStep({
<div className="mt-6 text-bunker-400 text-sm flex flex-row">
<span className="mr-1">Don&apos;t have an acount yet?</span>
<Link href="/signup">
<span className='hover:underline hover:underline-offset-4 hover:decoration-primary-700 hover:text-bunker-200 duration-200 cursor-pointer'>{t('login.create-account')}</span>
<span className='hover:underline hover:underline-offset-4 hover:decoration-primary-700 hover:text-bunker-200 duration-200 cursor-pointer'>{t("login.create-account")}</span>
</Link>
</div>
<div className="text-bunker-400 text-sm flex flex-row">

View File

@@ -1,14 +1,14 @@
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import Link from 'next/link';
import { useRouter } from 'next/router';
import { faWarning } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import Link from "next/link";
import { useRouter } from "next/router";
import { faWarning } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import Error from '@app/components/basic/Error';
import attemptLogin from '@app/components/utilities/attemptLogin';
import Error from "@app/components/basic/Error";
import attemptLogin from "@app/components/utilities/attemptLogin";
import { Button, Input } from '../v2';
import { Button, Input } from "../v2";
/**
* 1st step of login - user enters their username and password
@@ -61,7 +61,7 @@ export default function LoginStep({
}
// case: login does not require MFA step
router.push(`/dashboard/${localStorage.getItem('projectData.id')}`);
router.push(`/dashboard/${localStorage.getItem("projectData.id")}`);
}
} catch (err) {
@@ -75,7 +75,7 @@ export default function LoginStep({
<form onSubmit={(e) => e.preventDefault()}>
<div className="w-full mx-auto h-full px-6">
<p className="text-xl w-max mx-auto flex justify-center text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200 mb-6">
{t('login.login')}
{t("login.login")}
</p>
<div className="flex items-center justify-center lg:w-1/6 w-1/4 min-w-[22rem] mx-auto w-full md:p-2 rounded-lg mt-4 md:mt-0 max-h-24 md:max-h-28">
<Input
@@ -102,7 +102,7 @@ export default function LoginStep({
/>
</div>
</div>
{!isLoading && loginError && <Error text={t('login.error-login') ?? ''} />}
{!isLoading && loginError && <Error text={t("login.error-login") ?? ""} />}
<div className="flex flex-col items-center justify-center lg:w-1/6 w-1/4 min-w-[22rem] px-2 mt-4 max-w-xs md:max-w-md mx-auto text-sm text-center md:text-left">
<div className="text-l py-1 text-lg w-full">
<Button
@@ -113,19 +113,19 @@ export default function LoginStep({
colorSchema="primary"
variant="outline_bg"
isLoading={isLoading}
> {String(t('login.login'))} </Button>
> {String(t("login.login"))} </Button>
</div>
</div>
</div>
<div className="text-bunker-400 text-sm flex flex-row w-max mx-auto">
<Link href="/verify-email">
<span className='hover:underline hover:underline-offset-4 hover:decoration-primary-700 hover:text-bunker-200 duration-200 cursor-pointer'>{t('login.forgot-password')}</span>
<span className='hover:underline hover:underline-offset-4 hover:decoration-primary-700 hover:text-bunker-200 duration-200 cursor-pointer'>{t("login.forgot-password")}</span>
</Link>
</div>
{false && (
<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('common.maintenance-alert')}
{t("common.maintenance-alert")}
</div>
)}
</form>

View File

@@ -1,32 +1,32 @@
/* eslint-disable react/jsx-props-no-spreading */
import React, { useState } from 'react';
import ReactCodeInput from 'react-code-input';
import { useTranslation } from 'react-i18next';
import { useRouter } from 'next/router';
import React, { useState } from "react";
import ReactCodeInput from "react-code-input";
import { useTranslation } from "react-i18next";
import { useRouter } from "next/router";
import attemptLoginMfa from '@app/components/utilities/attemptLoginMfa';
import { useSendMfaToken } from '@app/hooks/api/auth';
import attemptLoginMfa from "@app/components/utilities/attemptLoginMfa";
import { useSendMfaToken } from "@app/hooks/api/auth";
import Error from '../basic/Error';
import { Button } from '../v2';
import Error from "../basic/Error";
import { Button } from "../v2";
// The style for the verification code input
const props = {
inputStyle: {
fontFamily: 'monospace',
margin: '4px',
MozAppearance: 'textfield',
width: '48px',
borderRadius: '5px',
fontSize: '24px',
height: '48px',
paddingLeft: '7',
backgroundColor: '#0d1117',
color: 'white',
border: '1px solid #2d2f33',
textAlign: 'center',
outlineColor: '#8ca542',
borderColor: '#2d2f33'
fontFamily: "monospace",
margin: "4px",
MozAppearance: "textfield",
width: "48px",
borderRadius: "5px",
fontSize: "24px",
height: "48px",
paddingLeft: "7",
backgroundColor: "#0d1117",
color: "white",
border: "1px solid #2d2f33",
textAlign: "center",
outlineColor: "#8ca542",
borderColor: "#2d2f33"
}
} as const;
@@ -62,7 +62,7 @@ export default function MFAStep({
const router = useRouter();
const [isLoading, setIsLoading] = useState(false);
const [isLoadingResend, setIsLoadingResend] = useState(false);
const [mfaCode, setMfaCode] = useState('');
const [mfaCode, setMfaCode] = useState("");
const [triesLeft, setTriesLeft] = useState<number | undefined>(undefined);
const { t } = useTranslation();
@@ -85,7 +85,7 @@ export default function MFAStep({
if (isLoginSuccessful) {
setIsLoading(false);
router.push(`/dashboard/${localStorage.getItem('projectData.id')}`);
router.push(`/dashboard/${localStorage.getItem("projectData.id")}`);
}
} catch (err) {
const error = err as VerifyMfaTokenError;
@@ -116,7 +116,7 @@ export default function MFAStep({
return (
<form className="mx-auto w-max md:px-8 pb-4 pt-4 md:mb-16">
<p className="text-l flex justify-center text-bunker-300">{t('mfa.step2-message')}</p>
<p className="text-l flex justify-center text-bunker-300">{t("mfa.step2-message")}</p>
<p className="text-l my-1 flex justify-center font-semibold text-bunker-300">{email} </p>
<div className="hidden md:block w-max min-w-[20rem] mx-auto">
<ReactCodeInput
@@ -140,8 +140,8 @@ export default function MFAStep({
className="mt-2 mb-2"
/>
</div>
{typeof triesLeft === 'number' && (
<Error text={`${t('mfa.step2-code-error')} ${triesLeft}`} />
{typeof triesLeft === "number" && (
<Error text={`${t("mfa.step2-code-error")} ${triesLeft}`} />
)}
<div className="flex flex-col mt-6 items-center justify-center lg:w-[19%] w-1/4 min-w-[20rem] mt-2 max-w-xs md:max-w-md mx-auto text-sm text-center md:text-left">
<div className="text-l py-1 text-lg w-full">
@@ -152,23 +152,23 @@ export default function MFAStep({
className='h-14'
colorSchema="primary"
variant="outline_bg"
> {String(t('mfa.verify'))} </Button>
> {String(t("mfa.verify"))} </Button>
</div>
</div>
<div className="flex flex-col items-center justify-center w-full max-h-24 max-w-md mx-auto pt-2">
<div className="flex flex-row items-baseline gap-1 text-sm">
<span className="text-bunker-400">{t('signup.step2-resend-alert')}</span>
<span className="text-bunker-400">{t("signup.step2-resend-alert")}</span>
<div className="mt-2 text-bunker-400 text-md flex flex-row">
<button disabled={isLoading} onClick={handleResendMfaCode} type="button">
<span className='hover:underline hover:underline-offset-4 hover:decoration-primary-700 hover:text-bunker-200 duration-200 cursor-pointer'>
{isLoadingResend
? t('signup.step2-resend-progress')
: t('signup.step2-resend-submit')}
? t("signup.step2-resend-progress")
: t("signup.step2-resend-submit")}
</span>
</button>
</div>
</div>
<p className="text-sm text-bunker-400 pb-2">{t('signup.step2-spam-alert')}</p>
<p className="text-sm text-bunker-400 pb-2">{t("signup.step2-spam-alert")}</p>
</div>
</form>
);

View File

@@ -1,13 +1,13 @@
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import Link from 'next/link';
import { useRouter } from 'next/router';
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import Link from "next/link";
import { useRouter } from "next/router";
import Error from '@app/components/basic/Error';
import attemptLogin from '@app/components/utilities/attemptLogin';
import Error from "@app/components/basic/Error";
import attemptLogin from "@app/components/utilities/attemptLogin";
import SecurityClient from '../utilities/SecurityClient';
import { Button, Input } from '../v2';
import SecurityClient from "../utilities/SecurityClient";
import { Button, Input } from "../v2";
export default function PasswordInputStep({
email,
@@ -50,7 +50,7 @@ export default function PasswordInputStep({
}
// case: login does not require MFA step
router.push(`/dashboard/${localStorage.getItem('projectData.id')}`);
router.push(`/dashboard/${localStorage.getItem("projectData.id")}`);
}
} catch (err) {
setLoginError(true);
@@ -79,7 +79,7 @@ export default function PasswordInputStep({
/>
</div>
</div>
{!isLoading && loginError && <Error text={t('login.error-login') ?? ''} />}
{!isLoading && loginError && <Error text={t("login.error-login") ?? ""} />}
<div className='lg:w-1/6 w-1/4 w-full mx-auto flex items-center justify-center min-w-[22rem] text-center rounded-md mt-4'>
<Button
colorSchema="primary"
@@ -89,7 +89,7 @@ export default function PasswordInputStep({
isLoading={isLoading}
className="h-14"
>
{t('login.login')}
{t("login.login")}
</Button>
</div>
<div className="text-bunker-400 text-xs flex flex-col items-center w-max mx-auto mt-4">
@@ -97,20 +97,20 @@ export default function PasswordInputStep({
Infisical Master Password serves as a decryption mechanism so that even Google is not able to access your secrets.
</span>
<Link href="/verify-email">
<span className='hover:underline mt-2 hover:underline-offset-4 hover:decoration-primary-700 hover:text-bunker-200 duration-200 cursor-pointer'>{t('login.forgot-password')}</span>
<span className='hover:underline mt-2 hover:underline-offset-4 hover:decoration-primary-700 hover:text-bunker-200 duration-200 cursor-pointer'>{t("login.forgot-password")}</span>
</Link>
</div>
<div className="flex flex-row items-center justify-center">
<button
onClick={(e) => {
e.preventDefault();
SecurityClient.setProviderAuthToken('');
setProviderAuthToken('');
SecurityClient.setProviderAuthToken("");
setProviderAuthToken("");
}}
type="button"
className="text-bunker-400 text-xs hover:underline mt-2 hover:underline-offset-4 hover:decoration-primary-700 hover:text-bunker-200 duration-200 cursor-pointer"
>
{t('login.other-option')}
{t("login.other-option")}
</button>
</div>
</div>

View File

@@ -1,11 +1,11 @@
/* eslint-disable jsx-a11y/anchor-is-valid */
/* eslint-disable react/jsx-key */
import { Fragment, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import Image from 'next/image';
import { useRouter } from 'next/router';
import { faGithub, faSlack } from '@fortawesome/free-brands-svg-icons';
import { faCircleQuestion } from '@fortawesome/free-regular-svg-icons';
import { Fragment, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import Image from "next/image";
import { useRouter } from "next/router";
import { faGithub, faSlack } from "@fortawesome/free-brands-svg-icons";
import { faCircleQuestion } from "@fortawesome/free-regular-svg-icons";
import {
faAngleDown,
faBook,
@@ -14,38 +14,38 @@ import {
faGear,
faPlus,
faRightFromBracket
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Menu, Transition } from '@headlessui/react';
import {TFunction} from 'i18next'
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Menu, Transition } from "@headlessui/react";
import {TFunction} from "i18next"
import logout from '@app/pages/api/auth/Logout';
import logout from "@app/pages/api/auth/Logout";
import getOrganization from '../../pages/api/organization/GetOrg';
import getOrganizations from '../../pages/api/organization/getOrgs';
import getUser from '../../pages/api/user/getUser';
import guidGenerator from '../utilities/randomId';
import getOrganization from "../../pages/api/organization/GetOrg";
import getOrganizations from "../../pages/api/organization/getOrgs";
import getUser from "../../pages/api/user/getUser";
import guidGenerator from "../utilities/randomId";
const supportOptions = (t: TFunction) => [
[
<FontAwesomeIcon className="text-lg pl-1.5 pr-3" icon={faSlack} />,
t('nav.support.slack'),
'https://join.slack.com/t/infisical-users/shared_invite/zt-1wehzfnzn-1aMo5JcGENJiNAC2SD8Jlg'
t("nav.support.slack"),
"https://join.slack.com/t/infisical-users/shared_invite/zt-1wehzfnzn-1aMo5JcGENJiNAC2SD8Jlg"
],
[
<FontAwesomeIcon className="text-lg pl-1.5 pr-3" icon={faBook} />,
t('nav.support.docs'),
'https://infisical.com/docs/documentation/getting-started/introduction'
t("nav.support.docs"),
"https://infisical.com/docs/documentation/getting-started/introduction"
],
[
<FontAwesomeIcon className="text-lg pl-1.5 pr-3" icon={faGithub} />,
t('nav.support.issue'),
'https://github.com/Infisical/infisical-cli/issues'
t("nav.support.issue"),
"https://github.com/Infisical/infisical-cli/issues"
],
[
<FontAwesomeIcon className="text-lg pl-1.5 pr-3" icon={faEnvelope} />,
t('nav.support.email'),
'mailto:support@infisical.com'
t("nav.support.email"),
"mailto:support@infisical.com"
]
];
@@ -81,7 +81,7 @@ export default function Navbar() {
const orgsData = await getOrganizations();
setOrgs(orgsData);
const currentUserOrg = await getOrganization({
orgId: String(localStorage.getItem('orgData.id'))
orgId: String(localStorage.getItem("orgData.id"))
});
setCurrentOrg(currentUserOrg);
})();
@@ -89,7 +89,7 @@ export default function Navbar() {
const closeApp = async () => {
await logout();
router.push('/login');
router.push("/login");
};
return (
@@ -169,7 +169,7 @@ export default function Navbar() {
<Menu.Items className="absolute right-0 mt-0.5 w-64 origin-top-right divide-y divide-gray-700 rounded-md bg-bunker border border-mineshaft-700 shadow-lg ring-1 ring-black z-[999] ring-opacity-5 focus:outline-none">
<div className="px-1 py-1 z-[100]">
<div className="text-gray-400 self-start ml-2 mt-2 text-xs font-semibold tracking-wide">
{t('nav.user.signed-in-as')}
{t("nav.user.signed-in-as")}
</div>
<div
onKeyDown={() => null}
@@ -184,7 +184,7 @@ export default function Navbar() {
<div className="flex items-center justify-between w-full">
<div>
<p className="text-gray-300 px-2 pt-1 text-sm">
{' '}
{" "}
{user?.firstName} {user?.lastName}
</p>
<p className="text-gray-400 px-2 pb-1 text-xs"> {user?.email}</p>
@@ -198,7 +198,7 @@ export default function Navbar() {
</div>
<div className="px-2 pt-2">
<div className="text-gray-400 self-start ml-2 mt-2 text-xs font-semibold tracking-wide">
{t('nav.user.current-organization')}
{t("nav.user.current-organization")}
</div>
<div
onKeyDown={() => null}
@@ -231,7 +231,7 @@ export default function Navbar() {
className="mt-1 relative flex justify-start cursor-pointer select-none py-2 px-2 rounded-md text-gray-400 hover:bg-white/5 duration-200 hover:text-gray-200"
>
<FontAwesomeIcon className="text-lg pl-1.5 pr-3" icon={faCoins} />
<div className="text-sm">{t('nav.user.usage-billing')}</div>
<div className="text-sm">{t("nav.user.usage-billing")}</div>
</div>
</button>
<button
@@ -249,19 +249,19 @@ export default function Navbar() {
<span className="rounded-lg absolute inset-y-0 left-0 flex items-center pl-3 pr-4">
<FontAwesomeIcon icon={faPlus} className="ml-1" />
</span>
<div className="text-sm ml-1">{t('nav.user.invite')}</div>
<div className="text-sm ml-1">{t("nav.user.invite")}</div>
</div>
</button>
</div>
{orgs?.length > 1 && (
<div className="px-1 pt-1">
<div className="text-gray-400 self-start ml-2 mt-2 text-xs font-semibold tracking-wide">
{t('nav.user.other-organizations')}
{t("nav.user.other-organizations")}
</div>
<div className="flex flex-col items-start px-1 mt-3 mb-2">
{orgs
.filter(
(org: { _id: string }) => org._id !== localStorage.getItem('orgData.id')
(org: { _id: string }) => org._id !== localStorage.getItem("orgData.id")
)
.map((org: { _id: string; name: string }) => (
<div
@@ -270,7 +270,7 @@ export default function Navbar() {
tabIndex={0}
key={guidGenerator()}
onClick={() => {
localStorage.setItem('orgData.id', org._id);
localStorage.setItem("orgData.id", org._id);
router.reload();
}}
className="flex flex-row justify-start items-center hover:bg-white/5 w-full p-1.5 cursor-pointer rounded-md"
@@ -293,7 +293,7 @@ export default function Navbar() {
type="button"
onClick={closeApp}
className={`${
active ? 'bg-red font-semibold text-white' : 'text-gray-400'
active ? "bg-red font-semibold text-white" : "text-gray-400"
} group flex w-full items-center rounded-md px-2 py-2 text-sm`}
>
<div className="relative flex justify-start items-center cursor-pointer select-none">
@@ -301,7 +301,7 @@ export default function Navbar() {
className="text-lg ml-1.5 mr-3"
icon={faRightFromBracket}
/>
{t('common.logout')}
{t("common.logout")}
</div>
</button>
)}

View File

@@ -1,12 +1,12 @@
import { useMemo } from 'react';
import Link from 'next/link';
import { useRouter } from 'next/router';
import { faAngleRight } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useMemo } from "react";
import Link from "next/link";
import { useRouter } from "next/router";
import { faAngleRight } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useOrganization, useWorkspace } from '@app/context';
import { useOrganization, useWorkspace } from "@app/context";
import { Select, SelectItem, Tooltip } from '../v2';
import { Select, SelectItem, Tooltip } from "../v2";
type Props = {
pageName: string;
@@ -75,11 +75,11 @@ export default function NavHeader({
</>
)}
<FontAwesomeIcon icon={faAngleRight} className="ml-3 mr-3 text-sm text-gray-400" />
{pageName === 'Secrets' ? (
{pageName === "Secrets" ? (
<Link
passHref
legacyBehavior
href={{ pathname: '/dashboard/[id]', query: { id: router.query.id } }}
href={{ pathname: "/dashboard/[id]", query: { id: router.query.id } }}
>
<a className="text-sm font-semibold text-primary/80 hover:text-primary">{pageName}</a>
</Link>
@@ -112,7 +112,7 @@ export default function NavHeader({
{isFolderMode &&
folders?.map(({ id, name }, index) => {
const query = { ...router.query };
if (name !== 'root') query.folderId = id;
if (name !== "root") query.folderId = id;
else delete query.folderId;
return (
<div className="flex items-center space-x-3" key={`breadcrumb-folder-${id}`}>
@@ -120,9 +120,9 @@ export default function NavHeader({
{index + 1 === folders?.length ? (
<span className="text-sm font-semibold text-bunker-300">{name}</span>
) : (
<Link passHref legacyBehavior href={{ pathname: '/dashboard/[id]', query }}>
<Link passHref legacyBehavior href={{ pathname: "/dashboard/[id]", query }}>
<a className="text-sm font-semibold text-primary/80 hover:text-primary">
{name === 'root' ? selectedEnv?.name : name}
{name === "root" ? selectedEnv?.name : name}
</a>
</Link>
)}

View File

@@ -1,10 +1,10 @@
import { useRouter } from 'next/router';
import { faAngleRight } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useRouter } from "next/router";
import { faAngleRight } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useOrganization, useWorkspace } from '@app/context';
import { useOrganization, useWorkspace } from "@app/context";
import { Select, SelectItem, Tooltip } from '../v2';
import { Select, SelectItem, Tooltip } from "../v2";
/**
@@ -60,7 +60,7 @@ export default function NavHeaderSecrets({
</>
)}
<FontAwesomeIcon icon={faAngleRight} className="ml-3 mr-3 text-sm text-gray-400" />
{pageName === 'Secrets'
{pageName === "Secrets"
? <a className="text-md font-medium text-primary/80 hover:text-primary" href={`${router.asPath.split("?")[0]}`}>{pageName}</a>
: <div className="text-md text-gray-400">{pageName}</div>}
{currentEnv &&

View File

@@ -1,48 +1,48 @@
/* eslint-disable react/jsx-props-no-spreading */
import React, { useState } from 'react';
import ReactCodeInput from 'react-code-input';
import { useTranslation } from 'react-i18next';
import React, { useState } from "react";
import ReactCodeInput from "react-code-input";
import { useTranslation } from "react-i18next";
import sendVerificationEmail from '@app/pages/api/auth/SendVerificationEmail';
import sendVerificationEmail from "@app/pages/api/auth/SendVerificationEmail";
import Error from '../basic/Error';
import { Button } from '../v2';
import Error from "../basic/Error";
import { Button } from "../v2";
// The style for the verification code input
const props = {
inputStyle: {
fontFamily: 'monospace',
margin: '4px',
MozAppearance: 'textfield',
width: '55px',
borderRadius: '5px',
fontSize: '24px',
height: '55px',
paddingLeft: '7',
backgroundColor: '#0d1117',
color: 'white',
border: '1px solid #2d2f33',
textAlign: 'center',
outlineColor: '#8ca542',
borderColor: '#2d2f33'
fontFamily: "monospace",
margin: "4px",
MozAppearance: "textfield",
width: "55px",
borderRadius: "5px",
fontSize: "24px",
height: "55px",
paddingLeft: "7",
backgroundColor: "#0d1117",
color: "white",
border: "1px solid #2d2f33",
textAlign: "center",
outlineColor: "#8ca542",
borderColor: "#2d2f33"
}
} as const;
const propsPhone = {
inputStyle: {
fontFamily: 'monospace',
margin: '4px',
MozAppearance: 'textfield',
width: '40px',
borderRadius: '5px',
fontSize: '24px',
height: '40px',
paddingLeft: '7',
backgroundColor: '#0d1117',
color: 'white',
border: '1px solid #2d2f33',
textAlign: 'center',
outlineColor: '#8ca542',
borderColor: '#2d2f33'
fontFamily: "monospace",
margin: "4px",
MozAppearance: "textfield",
width: "40px",
borderRadius: "5px",
fontSize: "24px",
height: "40px",
paddingLeft: "7",
backgroundColor: "#0d1117",
color: "white",
border: "1px solid #2d2f33",
textAlign: "center",
outlineColor: "#8ca542",
borderColor: "#2d2f33"
}
} as const;
@@ -86,7 +86,7 @@ export default function CodeInputStep({
return (
<div className="mx-auto h-full w-full pb-4 md:px-8">
<p className="text-md flex justify-center text-bunker-200">{t('signup.step2-message')}</p>
<p className="text-md flex justify-center text-bunker-200">{t("signup.step2-message")}</p>
<p className="text-md flex justify-center font-semibold my-1 text-bunker-200">{email} </p>
<div className="hidden md:block w-max min-w-[20rem] mx-auto">
<ReactCodeInput
@@ -110,7 +110,7 @@ export default function CodeInputStep({
className="mt-2 mb-2"
/>
</div>
{codeError && <Error text={t('signup.step2-code-error')} />}
{codeError && <Error text={t("signup.step2-code-error")} />}
<div className="flex flex-col items-center justify-center lg:w-[19%] w-1/4 min-w-[20rem] mt-2 max-w-xs md:max-w-md mx-auto text-sm text-center md:text-left">
<div className="text-l py-1 text-lg w-full">
<Button
@@ -121,23 +121,23 @@ export default function CodeInputStep({
colorSchema="primary"
variant="outline_bg"
isLoading={isCodeInputCheckLoading}
> {String(t('signup.verify'))} </Button>
> {String(t("signup.verify"))} </Button>
</div>
</div>
<div className="flex flex-col items-center justify-center w-full max-h-24 max-w-md mx-auto pt-2">
<div className="flex flex-row items-baseline gap-1 text-sm">
<span className="text-bunker-400">{t('signup.step2-resend-alert')}</span>
<span className="text-bunker-400">{t("signup.step2-resend-alert")}</span>
<div className="mt-2 text-bunker-400 text-md flex flex-row">
<button disabled={isLoading} onClick={resendVerificationEmail} type="button">
<span className='hover:underline hover:underline-offset-4 hover:decoration-primary-700 hover:text-bunker-200 duration-200 cursor-pointer'>
{isResendingVerificationEmail
? t('signup.step2-resend-progress')
: t('signup.step2-resend-submit')}
? t("signup.step2-resend-progress")
: t("signup.step2-resend-submit")}
</span>
</button>
</div>
</div>
<p className="text-sm text-bunker-400 pb-2">{t('signup.step2-spam-alert')}</p>
<p className="text-sm text-bunker-400 pb-2">{t("signup.step2-spam-alert")}</p>
</div>
</div>
);

View File

@@ -1,9 +1,9 @@
import { useTranslation } from 'react-i18next';
import { faWarning } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useTranslation } from "react-i18next";
import { faWarning } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import issueBackupKey from '../utilities/cryptography/issueBackupKey';
import { Button } from '../v2';
import issueBackupKey from "../utilities/cryptography/issueBackupKey";
import { Button } from "../v2";
interface DownloadBackupPDFStepProps {
incrementStep: () => void;
@@ -32,11 +32,11 @@ export default function DonwloadBackupPDFStep({
return (
<div className="flex flex-col items-center w-full h-full md:px-6 mx-auto mb-36 md:mb-16">
<p className="text-xl text-center font-medium flex justify-center text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200">
<FontAwesomeIcon icon={faWarning} className="ml-2 mr-3 pt-1 text-2xl text-bunker-200" />{t('signup.step4-message')}
<FontAwesomeIcon icon={faWarning} className="ml-2 mr-3 pt-1 text-2xl text-bunker-200" />{t("signup.step4-message")}
</p>
<div className="flex flex-col pb-2 bg-mineshaft-800 border border-mineshaft-600 items-center justify-center text-center lg:w-1/6 w-full md:min-w-[24rem] mt-8 max-w-md text-bunker-300 text-md rounded-md">
<div className="w-full mt-4 md:mt-8 flex flex-row text-center items-center m-2 text-bunker-300 rounded-md lg:w-1/6 lg:w-1/6 w-full md:min-w-[23rem] px-3 mx-auto">
<span className='mb-2'>{t('signup.step4-description1')} {t('signup.step4-description3')}</span>
<span className='mb-2'>{t("signup.step4-description1")} {t("signup.step4-description3")}</span>
</div>
<div className="flex flex-col items-center px-3 justify-center mt-0 md:mt-4 mb-2 md:mb-4 lg:w-1/6 w-full md:min-w-[20rem] mt-2 md:max-w-md mx-auto text-sm text-center md:text-left">
<div className="text-l py-1 text-lg w-full">

View File

@@ -1,10 +1,10 @@
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import Link from 'next/link';
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import Link from "next/link";
import sendVerificationEmail from '@app/pages/api/auth/SendVerificationEmail';
import sendVerificationEmail from "@app/pages/api/auth/SendVerificationEmail";
import { Button, Input } from '../v2';
import { Button, Input } from "../v2";
interface DownloadBackupPDFStepProps {
incrementStep: () => void;
@@ -36,7 +36,7 @@ export default function EnterEmailStep({
if (!email) {
setEmailError(true);
emailCheckBool = true;
} else if (!email.includes('@') || !email.includes('.') || !/[a-z]/.test(email)) {
} else if (!email.includes("@") || !email.includes(".") || !/[a-z]/.test(email)) {
setEmailError(true);
emailCheckBool = true;
} else {
@@ -54,7 +54,7 @@ export default function EnterEmailStep({
<div>
<div className="w-full md:px-6 mx-auto">
<p className="text-xl font-medium flex justify-center text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200">
{t('signup.step1-start')}
{t("signup.step1-start")}
</p>
<div className="flex flex-col items-center justify-center lg:w-1/6 w-1/4 min-w-[20rem] m-auto rounded-lg mt-8">
<Input
@@ -76,7 +76,7 @@ export default function EnterEmailStep({
className='h-14'
colorSchema="primary"
variant="outline_bg"
> {String(t('signup.step1-submit'))} </Button>
> {String(t("signup.step1-submit"))} </Button>
</div>
</div>
</div>
@@ -84,7 +84,7 @@ export default function EnterEmailStep({
<Link href="/login">
<button type="button" className="w-max pb-3 duration-200 hover:opacity-90">
<span className="text-sm text-mineshaft-400 hover:underline hover:underline-offset-4 hover:decoration-primary-700 hover:text-bunker-200 duration-200 cursor-pointer">
{t('signup.already-have-account')}
{t("signup.already-have-account")}
</span>
</button>
</Link>

View File

@@ -1,10 +1,10 @@
import { useTranslation } from 'react-i18next';
import Link from 'next/link';
import { useRouter } from 'next/router';
import { useTranslation } from "react-i18next";
import Link from "next/link";
import { useRouter } from "next/router";
// import { faGoogle } from '@fortawesome/free-brands-svg-icons';
// import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Button } from '../v2';
import { Button } from "../v2";
export default function InitialSignupStep({
setIsSignupWithEmail,
@@ -15,7 +15,7 @@ export default function InitialSignupStep({
const router = useRouter();
return <div className='flex flex-col mx-auto w-full justify-center items-center'>
<h1 className='text-xl font-medium text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200 text-center mb-8' >{t('signup.initial-title')}</h1>
<h1 className='text-xl font-medium text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200 text-center mb-8' >{t("signup.initial-title")}</h1>
{/* <div className='lg:w-1/6 w-1/4 min-w-[20rem] rounded-md'>
<Button
colorSchema="primary"
@@ -54,11 +54,11 @@ export default function InitialSignupStep({
</Button>
</div>
<div className='lg:w-1/6 w-1/4 min-w-[20rem] px-8 text-center mt-6 text-xs text-bunker-400'>
{t('signup.create-policy')}
{t("signup.create-policy")}
</div>
<div className="mt-2 text-bunker-400 text-xs flex flex-row">
<Link href="/login">
<span className='hover:underline hover:underline-offset-4 hover:decoration-primary-700 hover:text-bunker-200 duration-200 cursor-pointer'>{t('signup.already-have-account')}</span>
<span className='hover:underline hover:underline-offset-4 hover:decoration-primary-700 hover:text-bunker-200 duration-200 cursor-pointer'>{t("signup.already-have-account")}</span>
</Link>
</div>
</div>

View File

@@ -1,23 +1,23 @@
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useRouter } from 'next/router';
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { useRouter } from "next/router";
import { useFetchServerStatus } from '@app/hooks/api/serverDetails';
import { usePopUp } from '@app/hooks/usePopUp';
import addUserToOrg from '@app/pages/api/organization/addUserToOrg';
import getWorkspaces from '@app/pages/api/workspace/getWorkspaces';
import { useFetchServerStatus } from "@app/hooks/api/serverDetails";
import { usePopUp } from "@app/hooks/usePopUp";
import addUserToOrg from "@app/pages/api/organization/addUserToOrg";
import getWorkspaces from "@app/pages/api/workspace/getWorkspaces";
import { Button, EmailServiceSetupModal } from '../v2';
import { Button, EmailServiceSetupModal } from "../v2";
/**
* This is the last step of the signup flow. People can optionally invite their teammates here.
*/
export default function TeamInviteStep(): JSX.Element {
const [emails, setEmails] = useState('');
const [emails, setEmails] = useState("");
const { t } = useTranslation();
const router = useRouter();
const { data: serverDetails } = useFetchServerStatus();
const { handlePopUpToggle, popUp, handlePopUpOpen } = usePopUp(['setUpEmail'] as const);
const { handlePopUpToggle, popUp, handlePopUpOpen } = usePopUp(["setUpEmail"] as const);
// Redirect user to the getting started page
const redirectToHome = async () => {
@@ -28,9 +28,9 @@ export default function TeamInviteStep(): JSX.Element {
const inviteUsers = async ({ emails: inviteEmails }: { emails: string }) => {
inviteEmails
.split(',')
.split(",")
.map((email) => email.trim())
.map(async (email) => addUserToOrg(email, String(localStorage.getItem('orgData.id'))));
.map(async (email) => addUserToOrg(email, String(localStorage.getItem("orgData.id"))));
await redirectToHome();
};
@@ -38,10 +38,10 @@ export default function TeamInviteStep(): JSX.Element {
return (
<div className="w-max mx-auto min-w-lg h-full pb-4 px-8 mb-64 md:mb-32">
<p className="text-2xl font-semibold flex justify-center text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200">
{t('signup.step5-invite-team')}
{t("signup.step5-invite-team")}
</p>
<p className="text-center flex justify-center text-bunker-400 md:mx-8 mb-6 mt-4">
{t('signup.step5-subtitle')}
{t("signup.step5-subtitle")}
</p>
<div className="bg-mineshaft-800 border border-mineshaft-500 w-max mx-auto pt-6 pb-4 px-8 rounded-xl drop-shadow-xl mb-6">
<div>
@@ -61,7 +61,7 @@ export default function TeamInviteStep(): JSX.Element {
if (serverDetails?.emailConfigured) {
inviteUsers({ emails })
} else {
handlePopUpOpen('setUpEmail');
handlePopUpOpen("setUpEmail");
}
}}
size="sm"
@@ -69,11 +69,11 @@ export default function TeamInviteStep(): JSX.Element {
className='h-10'
colorSchema="primary"
variant="solid"
> {t('signup.step5-send-invites') ?? ''} </Button>
> {t("signup.step5-send-invites") ?? ""} </Button>
</div>
<EmailServiceSetupModal
isOpen={popUp.setUpEmail?.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle('setUpEmail', isOpen)}
onOpenChange={(isOpen) => handlePopUpToggle("setUpEmail", isOpen)}
/>
</div>
<div className="flex flex-row max-w-max min-w-28 items-center justify-center md:p-2 min-w-[20rem] max-h-24 mx-auto text-lg px-4 mt-4 mb-2">
@@ -84,7 +84,7 @@ export default function TeamInviteStep(): JSX.Element {
className='h-12'
colorSchema="secondary"
variant="outline"
> {t('signup.step5-skip') ?? 'Skip'} </Button>
> {t("signup.step5-skip") ?? "Skip"} </Button>
</div>
</div>
);

View File

@@ -1,25 +1,25 @@
import crypto from 'crypto';
import crypto from "crypto";
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { faXmark } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import jsrp from 'jsrp';
import nacl from 'tweetnacl';
import { encodeBase64 } from 'tweetnacl-util';
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { faXmark } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import jsrp from "jsrp";
import nacl from "tweetnacl";
import { encodeBase64 } from "tweetnacl-util";
import { useGetCommonPasswords } from '@app/hooks/api';
import completeAccountInformationSignup from '@app/pages/api/auth/CompleteAccountInformationSignup';
import getOrganizations from '@app/pages/api/organization/getOrgs';
import ProjectService from '@app/services/ProjectService';
import { useGetCommonPasswords } from "@app/hooks/api";
import completeAccountInformationSignup from "@app/pages/api/auth/CompleteAccountInformationSignup";
import getOrganizations from "@app/pages/api/organization/getOrgs";
import ProjectService from "@app/services/ProjectService";
import InputField from '../basic/InputField';
import checkPassword from '../utilities/checks/checkPassword';
import Aes256Gcm from '../utilities/cryptography/aes-256-gcm';
import { deriveArgonKey } from '../utilities/cryptography/crypto';
import { saveTokenToLocalStorage } from '../utilities/saveTokenToLocalStorage';
import SecurityClient from '../utilities/SecurityClient';
import { Button, Input } from '../v2';
import InputField from "../basic/InputField";
import checkPassword from "../utilities/checks/checkPassword";
import Aes256Gcm from "../utilities/cryptography/aes-256-gcm";
import { deriveArgonKey } from "../utilities/cryptography/crypto";
import { saveTokenToLocalStorage } from "../utilities/saveTokenToLocalStorage";
import SecurityClient from "../utilities/SecurityClient";
import { Button, Input } from "../v2";
// eslint-disable-next-line new-cap
const client = new jsrp.client();
@@ -113,7 +113,7 @@ export default function UserInfoStep({
const publicKeyUint8Array = pair.publicKey;
const privateKey = encodeBase64(secretKeyUint8Array);
const publicKey = encodeBase64(publicKeyUint8Array);
localStorage.setItem('PRIVATE_KEY', privateKey);
localStorage.setItem("PRIVATE_KEY", privateKey);
client.init(
{
@@ -133,7 +133,7 @@ export default function UserInfoStep({
hashLen: 32
});
if (!derivedKey) throw new Error('Failed to derive key from password');
if (!derivedKey) throw new Error("Failed to derive key from password");
const key = crypto.randomBytes(32);
@@ -155,14 +155,14 @@ export default function UserInfoStep({
iv: protectedKeyIV,
tag: protectedKeyTag
} = Aes256Gcm.encrypt({
text: key.toString('hex'),
text: key.toString("hex"),
secret: Buffer.from(derivedKey.hash)
});
const response = await completeAccountInformationSignup({
email,
firstName: name.split(" ")[0],
lastName: name.split(" ").slice(1).join(' '),
lastName: name.split(" ").slice(1).join(" "),
protectedKey,
protectedKeyIV,
protectedKeyTag,
@@ -178,9 +178,9 @@ export default function UserInfoStep({
});
// unset signup JWT token and set JWT token
SecurityClient.setSignupToken('');
SecurityClient.setSignupToken("");
SecurityClient.setToken(response.token);
SecurityClient.setProviderAuthToken('');
SecurityClient.setProviderAuthToken("");
saveTokenToLocalStorage({
publicKey,
@@ -194,11 +194,11 @@ export default function UserInfoStep({
const orgId = userOrgs[0]?._id;
const project = await ProjectService.initProject({
organizationId: orgId,
projectName: 'Example Project'
projectName: "Example Project"
});
localStorage.setItem('orgData.id', orgId);
localStorage.setItem('projectData.id', project._id);
localStorage.setItem("orgData.id", orgId);
localStorage.setItem("projectData.id", project._id);
incrementStep();
} catch (error) {
@@ -216,7 +216,7 @@ export default function UserInfoStep({
return (
<div className="h-full mx-auto mb-36 w-max rounded-xl md:px-8 md:mb-16">
<p className="mx-8 mb-6 flex justify-center text-xl font-bold text-medium md:mx-16 text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200">
{t('signup.step3-message')}
{t("signup.step3-message")}
</p>
<div className="h-full mx-auto mb-36 w-max rounded-xl py-6 md:px-8 md:mb-16 md:border md:border-mineshaft-600 md:bg-mineshaft-800">
<div className="relative z-0 lg:w-1/6 w-1/4 min-w-[20rem] flex flex-col items-center justify-end w-full py-2 rounded-lg">
@@ -254,7 +254,7 @@ export default function UserInfoStep({
</div>
<div className="mt-2 flex lg:w-1/6 w-1/4 min-w-[20rem] max-h-60 w-full flex-col items-center justify-center rounded-lg py-2">
<InputField
label={t('section.password.password')}
label={t("section.password.password")}
onChangeHandler={(pass: string) => {
setPassword(pass);
checkPassword({
@@ -272,7 +272,7 @@ export default function UserInfoStep({
/>
{Object.keys(errors).length > 0 && (
<div className="mt-4 flex w-full flex-col items-start rounded-md bg-white/5 px-2 py-2">
<div className="mb-2 text-sm text-gray-400">{t('section.password.validate-base')}</div>
<div className="mb-2 text-sm text-gray-400">{t("section.password.validate-base")}</div>
{Object.keys(errors).map((key) => {
if (errors[key as keyof Errors]) {
return (
@@ -308,7 +308,7 @@ export default function UserInfoStep({
colorSchema="primary"
variant="outline_bg"
isLoading={isLoading}
> {String(t('signup.signup'))} </Button>
> {String(t("signup.signup"))} </Button>
</div>
</div>
</div>

View File

@@ -2,16 +2,16 @@ import {
getAuthToken,
setAuthToken,
setMfaTempToken,
setSignupTempToken} from '@app/reactQuery';
setSignupTempToken} from "@app/reactQuery";
export const PROVIDER_AUTH_TOKEN_KEY = 'infisical__provider-auth-token';
export const PROVIDER_AUTH_TOKEN_KEY = "infisical__provider-auth-token";
// depreciated: go for apiRequest module in config/api
export default class SecurityClient {
static setProviderAuthToken(tokenStr: string) {
localStorage.setItem(PROVIDER_AUTH_TOKEN_KEY, tokenStr || '')
localStorage.setItem(PROVIDER_AUTH_TOKEN_KEY, tokenStr || "")
}
static getProviderAuthToken() {
@@ -36,7 +36,7 @@ export default class SecurityClient {
const token = getAuthToken();
if (token) {
req.headers.set('Authorization', `Bearer ${token}`);
req.headers.set("Authorization", `Bearer ${token}`);
}
return fetch(req);

View File

@@ -1,15 +1,15 @@
/* eslint-disable prefer-destructuring */
import jsrp from 'jsrp';
import jsrp from "jsrp";
import login1 from '@app/pages/api/auth/Login1';
import login2 from '@app/pages/api/auth/Login2';
import getOrganizations from '@app/pages/api/organization/getOrgs';
import getOrganizationUserProjects from '@app/pages/api/organization/GetOrgUserProjects';
import KeyService from '@app/services/KeyService';
import login1 from "@app/pages/api/auth/Login1";
import login2 from "@app/pages/api/auth/Login2";
import getOrganizations from "@app/pages/api/organization/getOrgs";
import getOrganizationUserProjects from "@app/pages/api/organization/GetOrgUserProjects";
import KeyService from "@app/services/KeyService";
import Telemetry from './telemetry/Telemetry';
import { saveTokenToLocalStorage } from './saveTokenToLocalStorage';
import SecurityClient from './SecurityClient';
import Telemetry from "./telemetry/Telemetry";
import { saveTokenToLocalStorage } from "./saveTokenToLocalStorage";
import SecurityClient from "./SecurityClient";
// eslint-disable-next-line new-cap
const client = new jsrp.client();
@@ -97,7 +97,7 @@ const attemptLogin = async (
// case: MFA is not enabled
// unset provider auth token in case it was used
SecurityClient.setProviderAuthToken('');
SecurityClient.setProviderAuthToken("");
// set JWT token
SecurityClient.setToken(token);
@@ -126,19 +126,19 @@ const attemptLogin = async (
// and not initializing the login details
const userOrgs = await getOrganizations();
const orgId = userOrgs[0]._id;
localStorage.setItem('orgData.id', orgId);
localStorage.setItem("orgData.id", orgId);
const orgUserProjects = await getOrganizationUserProjects({
orgId
});
if (orgUserProjects.length > 0) {
localStorage.setItem('projectData.id', orgUserProjects[0]._id);
localStorage.setItem("projectData.id", orgUserProjects[0]._id);
}
if (email) {
telemetry.identify(email, email);
telemetry.capture('User Logged In');
telemetry.capture("User Logged In");
}
resolve({

View File

@@ -1,14 +1,14 @@
/* eslint-disable prefer-destructuring */
import jsrp from 'jsrp';
import jsrp from "jsrp";
import login1 from '@app/pages/api/auth/Login1';
import verifyMfaToken from '@app/pages/api/auth/verifyMfaToken';
import getOrganizations from '@app/pages/api/organization/getOrgs';
import getOrganizationUserProjects from '@app/pages/api/organization/GetOrgUserProjects';
import KeyService from '@app/services/KeyService';
import login1 from "@app/pages/api/auth/Login1";
import verifyMfaToken from "@app/pages/api/auth/verifyMfaToken";
import getOrganizations from "@app/pages/api/organization/getOrgs";
import getOrganizationUserProjects from "@app/pages/api/organization/GetOrgUserProjects";
import KeyService from "@app/services/KeyService";
import { saveTokenToLocalStorage } from './saveTokenToLocalStorage';
import SecurityClient from './SecurityClient';
import { saveTokenToLocalStorage } from "./saveTokenToLocalStorage";
import SecurityClient from "./SecurityClient";
// eslint-disable-next-line new-cap
const client = new jsrp.client();
@@ -60,9 +60,9 @@ const attemptLoginMfa = async ({
});
// unset temporary (MFA) JWT token and set JWT token
SecurityClient.setMfaToken('');
SecurityClient.setMfaToken("");
SecurityClient.setToken(token);
SecurityClient.setProviderAuthToken('');
SecurityClient.setProviderAuthToken("");
const privateKey = await KeyService.decryptPrivateKey({
encryptionVersion,
@@ -89,12 +89,12 @@ const attemptLoginMfa = async ({
// and not initializing the login details
const userOrgs = await getOrganizations();
const orgId = userOrgs[0]._id;
localStorage.setItem('orgData.id', orgId);
localStorage.setItem("orgData.id", orgId);
const orgUserProjects = await getOrganizationUserProjects({
orgId
});
localStorage.setItem('projectData.id', orgUserProjects[0]._id);
localStorage.setItem("projectData.id", orgUserProjects[0]._id);
resolve(true);
} catch (err) {

View File

@@ -1,5 +1,5 @@
import getOrganizationUsers from '@app/pages/api/organization/GetOrgUsers';
import checkUserAction from '@app/pages/api/userActions/checkUserAction';
import getOrganizationUsers from "@app/pages/api/organization/GetOrgUsers";
import checkUserAction from "@app/pages/api/userActions/checkUserAction";
interface OnboardingCheckProps {
setTotalOnboardingActionsDone?: (value: number) => void;
@@ -23,7 +23,7 @@ const onboardingCheck = async ({
}: OnboardingCheckProps) => {
let countActions = 0;
const userActionSlack = await checkUserAction({
action: 'slack_cta_clicked'
action: "slack_cta_clicked"
});
if (userActionSlack) {
countActions += 1;
@@ -31,7 +31,7 @@ const onboardingCheck = async ({
if (setHasUserClickedSlack) setHasUserClickedSlack(!!userActionSlack);
const userActionSecrets = await checkUserAction({
action: 'first_time_secrets_pushed'
action: "first_time_secrets_pushed"
});
if (userActionSecrets) {
countActions += 1;
@@ -39,7 +39,7 @@ const onboardingCheck = async ({
if (setHasUserPushedSecrets) setHasUserPushedSecrets(!!userActionSecrets);
const userActionIntro = await checkUserAction({
action: 'intro_cta_clicked'
action: "intro_cta_clicked"
});
if (userActionIntro) {
countActions += 1;
@@ -47,16 +47,16 @@ const onboardingCheck = async ({
if (setHasUserClickedIntro) setHasUserClickedIntro(!!userActionIntro);
const userActionStar = await checkUserAction({
action: 'star_cta_clicked'
action: "star_cta_clicked"
});
if (userActionStar) {
countActions += 1;
}
if (setHasUserStarred) setHasUserStarred(!!userActionStar);
const orgId = localStorage.getItem('orgData.id');
const orgId = localStorage.getItem("orgData.id");
const orgUsers = await getOrganizationUsers({
orgId: orgId || ''
orgId: orgId || ""
});
if (orgUsers.length > 1) {
countActions += 1;

View File

@@ -2,9 +2,9 @@
* @fileoverview Provides easy encryption/decryption methods using AES 256 GCM.
*/
import crypto from 'crypto';
import crypto from "crypto";
const ALGORITHM = 'aes-256-gcm';
const ALGORITHM = "aes-256-gcm";
const BLOCK_SIZE_BYTES = 16; // 128 bit
interface EncryptProps {
@@ -45,12 +45,12 @@ class Aes256Gcm {
const iv = crypto.randomBytes(BLOCK_SIZE_BYTES);
const cipher = crypto.createCipheriv(ALGORITHM, secret, iv);
let ciphertext = cipher.update(text, 'utf8', 'base64');
ciphertext += cipher.final('base64');
let ciphertext = cipher.update(text, "utf8", "base64");
ciphertext += cipher.final("base64");
return {
ciphertext,
iv: iv.toString('base64'),
tag: cipher.getAuthTag().toString('base64')
iv: iv.toString("base64"),
tag: cipher.getAuthTag().toString("base64")
};
}
@@ -64,11 +64,11 @@ class Aes256Gcm {
* @returns {string}
*/
static decrypt({ ciphertext, iv, tag, secret }: DecryptProps): string {
const decipher = crypto.createDecipheriv(ALGORITHM, secret, Buffer.from(iv, 'base64'));
decipher.setAuthTag(Buffer.from(tag, 'base64'));
const decipher = crypto.createDecipheriv(ALGORITHM, secret, Buffer.from(iv, "base64"));
decipher.setAuthTag(Buffer.from(tag, "base64"));
let cleartext = decipher.update(ciphertext, 'base64', 'utf8');
cleartext += decipher.final('utf8');
let cleartext = decipher.update(ciphertext, "base64", "utf8");
cleartext += decipher.final("utf8");
return cleartext;
}

View File

@@ -1,14 +1,14 @@
/* eslint-disable new-cap */
import crypto from 'crypto';
import crypto from "crypto";
import jsrp from 'jsrp';
import jsrp from "jsrp";
import changePassword2 from '@app/pages/api/auth/ChangePassword2';
import SRP1 from '@app/pages/api/auth/SRP1';
import changePassword2 from "@app/pages/api/auth/ChangePassword2";
import SRP1 from "@app/pages/api/auth/SRP1";
import { saveTokenToLocalStorage } from '../saveTokenToLocalStorage';
import Aes256Gcm from './aes-256-gcm';
import { deriveArgonKey } from './crypto';
import { saveTokenToLocalStorage } from "../saveTokenToLocalStorage";
import Aes256Gcm from "./aes-256-gcm";
import { deriveArgonKey } from "./crypto";
const clientOldPassword = new jsrp.client();
const clientNewPassword = new jsrp.client();
@@ -53,7 +53,7 @@ const changePassword = async (
salt = res.salt;
} catch (err) {
setCurrentPasswordError(true);
console.log('Wrong current password', err, 1);
console.log("Wrong current password", err, 1);
}
clientOldPassword.setSalt(salt);
@@ -77,7 +77,7 @@ const changePassword = async (
hashLen: 32
});
if (!derivedKey) throw new Error('Failed to derive key from password');
if (!derivedKey) throw new Error("Failed to derive key from password");
const key = crypto.randomBytes(32);
@@ -88,7 +88,7 @@ const changePassword = async (
iv: encryptedPrivateKeyIV,
tag: encryptedPrivateKeyTag
} = Aes256Gcm.encrypt({
text: localStorage.getItem('PRIVATE_KEY') as string,
text: localStorage.getItem("PRIVATE_KEY") as string,
secret: key
});
@@ -99,7 +99,7 @@ const changePassword = async (
iv: protectedKeyIV,
tag: protectedKeyTag
} = Aes256Gcm.encrypt({
text: key.toString('hex'),
text: key.toString("hex"),
secret: Buffer.from(derivedKey.hash)
});
@@ -123,10 +123,10 @@ const changePassword = async (
});
setPasswordChanged(true);
setCurrentPassword('');
setNewPassword('');
setCurrentPassword("");
setNewPassword("");
window.location.href = '/login';
window.location.href = "/login";
// move to login page
} catch (error) {
@@ -139,7 +139,7 @@ const changePassword = async (
}
);
} catch (error) {
console.log('Something went wrong during changing the password');
console.log("Something went wrong during changing the password");
}
return true;
};

View File

@@ -1,9 +1,9 @@
import argon2 from 'argon2-browser';
import argon2 from "argon2-browser";
import aes from './aes-256-gcm';
import aes from "./aes-256-gcm";
const nacl = require('tweetnacl');
nacl.util = require('tweetnacl-util');
const nacl = require("tweetnacl");
nacl.util = require("tweetnacl-util");
/**
* Return new base64, NaCl, public-private key pair.
@@ -47,7 +47,7 @@ const verifyPrivateKey = ({
);
if (derivedPublicKey !== publicKey) {
throw new Error('Failed to verify private key');
throw new Error("Failed to verify private key");
}
}
@@ -183,7 +183,7 @@ const encryptSymmetric = ({ plaintext, key }: EncryptSymmetricProps): EncryptSym
iv = obj.iv;
tag = obj.tag;
} catch (err) {
console.log('Failed to perform encryption');
console.log("Failed to perform encryption");
console.log(err);
process.exit(1);
}
@@ -213,12 +213,12 @@ type DecryptSymmetricProps = {
*
*/
const decryptSymmetric = ({ ciphertext, iv, tag, key }: DecryptSymmetricProps): string => {
if (!ciphertext) return '';
if (!ciphertext) return "";
let plaintext;
try {
plaintext = aes.decrypt({ ciphertext, iv, tag, secret: key });
} catch (err) {
console.log('Failed to perform decryption');
console.log("Failed to perform decryption");
process.exit(1);
}

View File

@@ -1,13 +1,13 @@
/* eslint-disable new-cap */
import crypto from 'crypto';
import crypto from "crypto";
import jsrp from 'jsrp';
import jsrp from "jsrp";
import issueBackupPrivateKey from '@app/pages/api/auth/IssueBackupPrivateKey';
import SRP1 from '@app/pages/api/auth/SRP1';
import issueBackupPrivateKey from "@app/pages/api/auth/IssueBackupPrivateKey";
import SRP1 from "@app/pages/api/auth/SRP1";
import generateBackupPDF from '../generateBackupPDF';
import Aes256Gcm from './aes-256-gcm';
import generateBackupPDF from "../generateBackupPDF";
import Aes256Gcm from "./aes-256-gcm";
const clientPassword = new jsrp.client();
const clientKey = new jsrp.client();
@@ -58,14 +58,14 @@ const issueBackupKey = async ({
salt = res.salt;
} catch (err) {
setBackupKeyError(true);
console.log('Wrong current password', err, 1);
console.log("Wrong current password", err, 1);
}
clientPassword.setSalt(salt);
clientPassword.setServerPublicKey(serverPublicKey);
const clientProof = clientPassword.getProof(); // called M1
const generatedKey = crypto.randomBytes(16).toString('hex');
const generatedKey = crypto.randomBytes(16).toString("hex");
clientKey.init(
{
@@ -76,7 +76,7 @@ const issueBackupKey = async ({
clientKey.createVerifier(
async (err: any, result: { salt: string; verifier: string }) => {
const { ciphertext, iv, tag } = Aes256Gcm.encrypt({
text: String(localStorage.getItem('PRIVATE_KEY')),
text: String(localStorage.getItem("PRIVATE_KEY")),
secret: generatedKey
});
@@ -107,7 +107,7 @@ const issueBackupKey = async ({
);
} catch (error) {
setBackupKeyError(true);
console.log('Failed to issue a backup key');
console.log("Failed to issue a backup key");
}
return true;
};

File diff suppressed because one or more lines are too long

View File

@@ -9,7 +9,7 @@
/* eslint-disable func-names */
// @ts-nocheck
import { INTERCOM_ID as APP_ID } from '@app/components/utilities/config';
import { INTERCOM_ID as APP_ID } from "@app/components/utilities/config";
// Loads Intercom with the snippet
// This must be run before boot, it initializes window.Intercom
@@ -21,8 +21,8 @@ export const load = () => {
var ic=w.Intercom;
if(typeof ic==="function"){
ic('reattach_activator');
ic('update',w.intercomSettings);
ic("reattach_activator");
ic("update",w.intercomSettings);
} else {
var d=document;
var i=function() {
@@ -34,19 +34,19 @@ export const load = () => {
};
w.Intercom=i;
var l=function() {
var s=d.createElement('script');
s.type='text/javascript';
var s=d.createElement("script");
s.type="text/javascript";
s.async=true;
s.src='https://widget.intercom.io/widget/' + APP_ID;
var x=d.getElementsByTagName('script')[0];
s.src="https://widget.intercom.io/widget/" + APP_ID;
var x=d.getElementsByTagName("script")[0];
x.parentNode.insertBefore(s, x);
};
if (document.readyState==='complete') {
if (document.readyState==="complete") {
l();
} else if (w.attachEvent) {
w.attachEvent('onload',l);
w.attachEvent("onload",l);
} else {
w.addEventListener('load',l,false);
w.addEventListener("load",l,false);
}
}
})();

View File

@@ -15,16 +15,16 @@ export function parseDotEnv(src: ArrayBuffer) {
let lines = src.toString();
// Convert line breaks to same format
lines = lines.replace(/\r\n?/gm, '\n');
lines = lines.replace(/\r\n?/gm, "\n");
let comments: string[] = [];
lines
.split('\n')
.split("\n")
.map((line) => {
// collect comments of each env variable
if (line.startsWith('#')) {
comments.push(line.replace('#', '').trim());
if (line.startsWith("#")) {
comments.push(line.replace("#", "").trim());
} else if (line) {
let match;
let item: [string, string, string[]] | [] = [];
@@ -34,7 +34,7 @@ export function parseDotEnv(src: ArrayBuffer) {
const key = match[1];
// Default undefined or null to empty string
let value = match[2] || '';
let value = match[2] || "";
// Remove whitespace
value = value.trim();
@@ -43,12 +43,12 @@ export function parseDotEnv(src: ArrayBuffer) {
const maybeQuote = value[0];
// Remove surrounding quotes
value = value.replace(/^(['"`])([\s\S]*)\1$/gm, '$2');
value = value.replace(/^(['"`])([\s\S]*)\1$/gm, "$2");
// Expand newlines if double quoted
if (maybeQuote === '"') {
value = value.replace(/\\n/g, '\n');
value = value.replace(/\\r/g, '\r');
value = value.replace(/\\n/g, "\n");
value = value.replace(/\\r/g, "\r");
}
item = [key, value, comments];
}

View File

@@ -1,4 +1,4 @@
import { SecretDataProps } from 'public/data/frequentInterfaces';
import { SecretDataProps } from "public/data/frequentInterfaces";
/**
* This function downloads the secrets as a .env file
@@ -10,8 +10,8 @@ const checkOverrides = async ({ data }: { data: SecretDataProps[] }) => {
let secrets: SecretDataProps[] = data!.map((secret) => Object.create(secret));
const overridenSecrets = data!.filter((secret) =>
secret.valueOverride === undefined || secret?.value !== secret?.valueOverride
? 'shared'
: 'personal'
? "shared"
: "personal"
);
if (overridenSecrets.length) {
overridenSecrets.forEach((secret) => {

View File

@@ -1,6 +1,6 @@
import { SecretDataProps } from 'public/data/frequentInterfaces';
import { SecretDataProps } from "public/data/frequentInterfaces";
import checkOverrides from './checkOverrides';
import checkOverrides from "./checkOverrides";
/**
* This function downloads the secrets as a .env file
@@ -18,17 +18,17 @@ const downloadDotEnv = async ({ data, env }: { data: SecretDataProps[]; env: str
`${
item.comment
? `${item.comment
.split('\n')
.map((comment) => '# '.concat(comment))
.join('\n')}\n`
: ''
}${[item.key, item.value].join('=')}`
.split("\n")
.map((comment) => "# ".concat(comment))
.join("\n")}\n`
: ""
}${[item.key, item.value].join("=")}`
)
.join('\n');
.join("\n");
const blob = new Blob([file]);
const fileDownloadUrl = URL.createObjectURL(blob);
const alink = document.createElement('a');
const alink = document.createElement("a");
alink.href = fileDownloadUrl;
alink.download = `${env}.env`;
alink.click();

View File

@@ -1,7 +1,7 @@
// import YAML from 'yaml';
// import { YAMLSeq } from 'yaml/types';
import { SecretDataProps } from 'public/data/frequentInterfaces';
import { SecretDataProps } from "public/data/frequentInterfaces";
// import { envMapping } from "../../../public/data/frequentConstants";
// import checkOverrides from './checkOverrides';

View File

@@ -1,10 +1,10 @@
import crypto from 'crypto';
import crypto from "crypto";
import { SecretDataProps, Tag } from 'public/data/frequentInterfaces';
import { SecretDataProps, Tag } from "public/data/frequentInterfaces";
import getLatestFileKey from '@app/pages/api/workspace/getLatestFileKey';
import getLatestFileKey from "@app/pages/api/workspace/getLatestFileKey";
import { decryptAssymmetric, encryptSymmetric } from '../cryptography/crypto';
import { decryptAssymmetric, encryptSymmetric } from "../cryptography/crypto";
interface EncryptedSecretProps {
id: string;
@@ -20,7 +20,7 @@ interface EncryptedSecretProps {
secretValueCiphertext: string;
secretValueIV: string;
secretValueTag: string;
type: 'personal' | 'shared';
type: "personal" | "shared";
tags: Tag[];
}
@@ -44,7 +44,7 @@ const encryptSecrets = async ({
try {
const sharedKey = await getLatestFileKey({ workspaceId });
const PRIVATE_KEY = localStorage.getItem('PRIVATE_KEY') as string;
const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY") as string;
let randomBytes: string;
if (Object.keys(sharedKey).length > 0) {
@@ -57,7 +57,7 @@ const encryptSecrets = async ({
});
} else {
// case: a (shared) key does not exist for the workspace
randomBytes = crypto.randomBytes(16).toString('hex');
randomBytes = crypto.randomBytes(16).toString("hex");
}
secrets = secretsToEncrypt.map((secret) => {
@@ -77,7 +77,7 @@ const encryptSecrets = async ({
iv: secretValueIV,
tag: secretValueTag
} = encryptSymmetric({
plaintext: secret.value ?? '',
plaintext: secret.value ?? "",
key: randomBytes
});
@@ -87,13 +87,13 @@ const encryptSecrets = async ({
iv: secretCommentIV,
tag: secretCommentTag
} = encryptSymmetric({
plaintext: secret.comment ?? '',
plaintext: secret.comment ?? "",
key: randomBytes
});
const result: EncryptedSecretProps = {
id: secret.id,
createdAt: '',
createdAt: "",
environment: env,
secretName: secret.key,
secretKeyCiphertext,
@@ -107,15 +107,15 @@ const encryptSecrets = async ({
secretCommentTag,
type:
secret.valueOverride === undefined || secret?.value !== secret?.valueOverride
? 'shared'
: 'personal',
? "shared"
: "personal",
tags: secret.tags
};
return result;
});
} catch (error) {
console.log('Error while encrypting secrets');
console.log("Error while encrypting secrets");
}
return secrets;

View File

@@ -1,9 +1,9 @@
import { Tag } from 'public/data/frequentInterfaces';
import { Tag } from "public/data/frequentInterfaces";
import getSecrets from '@app/pages/api/files/GetSecrets';
import getLatestFileKey from '@app/pages/api/workspace/getLatestFileKey';
import getSecrets from "@app/pages/api/files/GetSecrets";
import getLatestFileKey from "@app/pages/api/workspace/getLatestFileKey";
import { decryptAssymmetric, decryptSymmetric } from '../cryptography/crypto';
import { decryptAssymmetric, decryptSymmetric } from "../cryptography/crypto";
interface EncryptedSecretProps {
_id: string;
@@ -18,14 +18,14 @@ interface EncryptedSecretProps {
secretValueCiphertext: string;
secretValueIV: string;
secretValueTag: string;
type: 'personal' | 'shared';
type: "personal" | "shared";
tags: Tag[];
}
interface SecretProps {
key: string;
value: string | undefined;
type: 'personal' | 'shared';
type: "personal" | "shared";
comment: string;
id: string;
tags: Tag[];
@@ -57,16 +57,16 @@ const getSecretsForProject = async ({
try {
encryptedSecrets = await getSecrets(workspaceId, env);
} catch (error) {
console.log('ERROR: Not able to access the latest version of secrets');
console.log("ERROR: Not able to access the latest version of secrets");
}
const latestKey = await getLatestFileKey({ workspaceId });
// This is called isKeyAvailable but what it really means is if a person is able to create new key pairs
if (typeof setIsKeyAvailable === 'function') {
if (typeof setIsKeyAvailable === "function") {
setIsKeyAvailable(!latestKey ? encryptedSecrets.length === 0 : true);
}
const PRIVATE_KEY = localStorage.getItem('PRIVATE_KEY') as string;
const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY") as string;
const tempDecryptedSecrets: SecretProps[] = [];
if (latestKey) {
@@ -108,7 +108,7 @@ const getSecretsForProject = async ({
key
});
} else {
plainTextComment = '';
plainTextComment = "";
}
tempDecryptedSecrets.push({
@@ -125,34 +125,34 @@ const getSecretsForProject = async ({
const secretKeys = [...new Set(tempDecryptedSecrets.map((secret) => secret.key))];
const result = secretKeys.map((key, index) => ({
id: tempDecryptedSecrets.filter((secret) => secret.key === key && secret.type === 'shared')[0]
id: tempDecryptedSecrets.filter((secret) => secret.key === key && secret.type === "shared")[0]
?.id,
idOverride: tempDecryptedSecrets.filter(
(secret) => secret.key === key && secret.type === 'personal'
(secret) => secret.key === key && secret.type === "personal"
)[0]?.id,
pos: index,
key,
value: tempDecryptedSecrets.filter(
(secret) => secret.key === key && secret.type === 'shared'
(secret) => secret.key === key && secret.type === "shared"
)[0]?.value,
valueOverride: tempDecryptedSecrets.filter(
(secret) => secret.key === key && secret.type === 'personal'
(secret) => secret.key === key && secret.type === "personal"
)[0]?.value,
comment: tempDecryptedSecrets.filter(
(secret) => secret.key === key && secret.type === 'shared'
(secret) => secret.key === key && secret.type === "shared"
)[0]?.comment,
tags: tempDecryptedSecrets.filter(
(secret) => secret.key === key && secret.type === 'shared'
(secret) => secret.key === key && secret.type === "shared"
)[0]?.tags
}));
if (typeof setData === 'function') {
if (typeof setData === "function") {
setData(result);
}
return result;
} catch (error) {
console.log('Something went wrong during accessing or decripting secrets.');
console.log("Something went wrong during accessing or decripting secrets.");
}
return [];
};

View File

@@ -1,21 +1,21 @@
import { faPlus } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import type { Meta, StoryObj } from '@storybook/react';
import { faPlus } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import type { Meta, StoryObj } from "@storybook/react";
import { Button } from './Button';
import { Button } from "./Button";
const meta: Meta<typeof Button> = {
title: 'Components/Button',
title: "Components/Button",
component: Button,
tags: ['v2'],
tags: ["v2"],
argTypes: {
isRounded: {
defaultValue: true,
type: 'boolean'
type: "boolean"
},
isFullWidth: {
defaultValue: false,
type: 'boolean'
type: "boolean"
}
}
};
@@ -26,71 +26,71 @@ type Story = StoryObj<typeof Button>;
// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args
export const Primary: Story = {
args: {
children: 'Hello Infisical'
children: "Hello Infisical"
}
};
export const Secondary: Story = {
args: {
children: 'Hello Infisical',
colorSchema: 'secondary',
variant: 'outline'
children: "Hello Infisical",
colorSchema: "secondary",
variant: "outline"
}
};
export const Star: Story = {
args: {
children: 'Hello Infisical',
variant: 'star'
children: "Hello Infisical",
variant: "star"
}
};
export const Danger: Story = {
args: {
children: 'Hello Infisical',
colorSchema: 'danger',
variant: 'solid'
children: "Hello Infisical",
colorSchema: "danger",
variant: "solid"
}
};
export const Plain: Story = {
args: {
children: 'Hello Infisical',
variant: 'plain'
children: "Hello Infisical",
variant: "plain"
}
};
export const Disabled: Story = {
args: {
children: 'Hello Infisical',
children: "Hello Infisical",
disabled: true
}
};
export const FullWidth: Story = {
args: {
children: 'Hello Infisical',
children: "Hello Infisical",
isFullWidth: true
}
};
export const Loading: Story = {
args: {
children: 'Hello Infisical',
children: "Hello Infisical",
isLoading: true
}
};
export const LeftIcon: Story = {
args: {
children: 'Hello Infisical',
children: "Hello Infisical",
leftIcon: <FontAwesomeIcon icon={faPlus} className="pr-0.5" />
}
};
export const RightIcon: Story = {
args: {
children: 'Hello Infisical',
children: "Hello Infisical",
rightIcon: <FontAwesomeIcon icon={faPlus} className="pr-0.5" />
}
};

View File

@@ -1,6 +1,6 @@
import { ButtonHTMLAttributes, forwardRef, ReactNode } from 'react';
import { cva, VariantProps } from 'cva';
import { twMerge } from 'tailwind-merge';
import { ButtonHTMLAttributes, forwardRef, ReactNode } from "react";
import { cva, VariantProps } from "cva";
import { twMerge } from "tailwind-merge";
type Props = {
children: ReactNode;
@@ -13,120 +13,120 @@ type Props = {
const buttonVariants = cva(
[
'button',
'transition-all',
'font-inter font-medium',
'cursor-pointer',
'inline-flex items-center justify-center',
'relative',
'whitespace-nowrap'
"button",
"transition-all",
"font-inter font-medium",
"cursor-pointer",
"inline-flex items-center justify-center",
"relative",
"whitespace-nowrap"
],
{
variants: {
colorSchema: {
primary: ['bg-primary', 'text-black', 'border-primary bg-opacity-90 hover:bg-opacity-100'],
secondary: ['bg-mineshaft', 'text-gray-300', 'border-mineshaft hover:bg-opacity-80'],
danger: ['bg-red', 'text-white', 'border-red hover:bg-opacity-90'],
gray: ['bg-bunker-500', 'text-bunker-200']
primary: ["bg-primary", "text-black", "border-primary bg-opacity-90 hover:bg-opacity-100"],
secondary: ["bg-mineshaft", "text-gray-300", "border-mineshaft hover:bg-opacity-80"],
danger: ["bg-red", "text-white", "border-red hover:bg-opacity-90"],
gray: ["bg-bunker-500", "text-bunker-200"]
},
variant: {
solid: '',
outline: ['bg-transparent', 'border-2', 'border-solid'],
plain: '',
selected: '',
outline_bg: '',
solid: "",
outline: ["bg-transparent", "border-2", "border-solid"],
plain: "",
selected: "",
outline_bg: "",
// a constant color not in use on hover or click goes colorSchema color
star: 'text-bunker-200 bg-mineshaft-700 border-mineshaft-600'
star: "text-bunker-200 bg-mineshaft-700 border-mineshaft-600"
},
isDisabled: {
true: 'bg-mineshaft-700 border border-mineshaft-600 text-white opacity-50 cursor-not-allowed',
false: 'border'
true: "bg-mineshaft-700 border border-mineshaft-600 text-white opacity-50 cursor-not-allowed",
false: "border"
},
isFullWidth: {
true: 'w-full',
false: ''
true: "w-full",
false: ""
},
isRounded: {
true: 'rounded-md',
false: ''
true: "rounded-md",
false: ""
},
size: {
xs: ['text-xs', 'py-1', 'px-1'],
sm: ['text-sm', 'py-2', 'px-2'],
md: ['text-md', 'py-2', 'px-4'],
lg: ['text-lg', 'py-2', 'px-8']
xs: ["text-xs", "py-1", "px-1"],
sm: ["text-sm", "py-2", "px-2"],
md: ["text-md", "py-2", "px-4"],
lg: ["text-lg", "py-2", "px-8"]
}
},
compoundVariants: [
{
colorSchema: 'primary',
variant: 'star',
className: 'bg-mineshaft-700 border border-mineshaft-600 hover:bg-primary hover:text-black hover:border-primary-400 duration-100'
colorSchema: "primary",
variant: "star",
className: "bg-mineshaft-700 border border-mineshaft-600 hover:bg-primary hover:text-black hover:border-primary-400 duration-100"
},
{
colorSchema: 'primary',
variant: 'solid',
className: 'bg-primary-500 bg-opacity-90 hover:bg-primary-500 hover:text-black'
colorSchema: "primary",
variant: "solid",
className: "bg-primary-500 bg-opacity-90 hover:bg-primary-500 hover:text-black"
},
{
colorSchema: 'primary',
variant: 'selected',
className: 'bg-primary/10 border border-primary/50 text-bunker-200'
colorSchema: "primary",
variant: "selected",
className: "bg-primary/10 border border-primary/50 text-bunker-200"
},
{
colorSchema: 'primary',
variant: 'outline_bg',
className: 'bg-mineshaft-600 border border-mineshaft-500 hover:bg-primary/[0.1] hover:border-primary/40 text-bunker-200'
colorSchema: "primary",
variant: "outline_bg",
className: "bg-mineshaft-600 border border-mineshaft-500 hover:bg-primary/[0.1] hover:border-primary/40 text-bunker-200"
},
{
colorSchema: 'secondary',
variant: 'star',
className: 'bg-mineshaft-700 border border-mineshaft-600 hover:bg-mineshaft hover:text-white'
colorSchema: "secondary",
variant: "star",
className: "bg-mineshaft-700 border border-mineshaft-600 hover:bg-mineshaft hover:text-white"
},
{
colorSchema: 'danger',
variant: 'star',
className: 'hover:bg-red hover:text-white'
colorSchema: "danger",
variant: "star",
className: "hover:bg-red hover:text-white"
},
{
colorSchema: 'primary',
variant: 'outline',
className: 'text-primary hover:bg-primary hover:text-black'
colorSchema: "primary",
variant: "outline",
className: "text-primary hover:bg-primary hover:text-black"
},
{
colorSchema: 'secondary',
variant: 'outline',
className: 'border-mineshaft-700 hover:border-mineshaft-500'
colorSchema: "secondary",
variant: "outline",
className: "border-mineshaft-700 hover:border-mineshaft-500"
},
{
colorSchema: 'danger',
variant: 'outline',
className: 'text-red hover:bg-red hover:text-black'
colorSchema: "danger",
variant: "outline",
className: "text-red hover:bg-red hover:text-black"
},
{
colorSchema: 'primary',
variant: 'plain',
className: 'text-primary'
colorSchema: "primary",
variant: "plain",
className: "text-primary"
},
{
colorSchema: 'gray',
variant: 'plain',
className: 'bg-transparent text-bunker-200'
colorSchema: "gray",
variant: "plain",
className: "bg-transparent text-bunker-200"
},
{
colorSchema: 'secondary',
variant: 'plain',
className: 'text-mineshaft-300 hover:text-mineshaft-200 border-none'
colorSchema: "secondary",
variant: "plain",
className: "text-mineshaft-300 hover:text-mineshaft-200 border-none"
},
{
colorSchema: 'danger',
variant: 'plain',
className: 'text-red'
colorSchema: "danger",
variant: "plain",
className: "text-red"
},
{
colorSchema: ['danger', 'primary', 'secondary'],
variant: ['plain'],
className: 'bg-transparent py-1 px-1'
colorSchema: ["danger", "primary", "secondary"],
variant: ["plain"],
className: "bg-transparent py-1 px-1"
}
]
}
@@ -141,20 +141,20 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
{
children,
isDisabled = false,
className = '',
size = 'sm',
variant = 'solid',
className = "",
size = "sm",
variant = "solid",
isFullWidth,
isRounded = true,
leftIcon,
rightIcon,
isLoading,
colorSchema = 'primary',
colorSchema = "primary",
...props
},
ref
): JSX.Element => {
const loadingToggleClass = isLoading ? 'opacity-0' : 'opacity-100';
const loadingToggleClass = isLoading ? "opacity-0" : "opacity-100";
return (
<button
@@ -185,20 +185,20 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
)}
<div
className={twMerge(
'inline-flex shrink-0 cursor-pointer items-center justify-center transition-all',
"inline-flex shrink-0 cursor-pointer items-center justify-center transition-all",
loadingToggleClass,
leftIcon && 'ml-2',
size === 'xs' ? 'mr-1' : 'mr-2'
leftIcon && "ml-2",
size === "xs" ? "mr-1" : "mr-2"
)}
>
{leftIcon}
</div>
<span className={twMerge('transition-all', isFullWidth ? 'w-full' : 'w-min', loadingToggleClass)}>{children}</span>
<span className={twMerge("transition-all", isFullWidth ? "w-full" : "w-min", loadingToggleClass)}>{children}</span>
<div
className={twMerge(
'inline-flex shrink-0 cursor-pointer items-center justify-center transition-all',
"inline-flex shrink-0 cursor-pointer items-center justify-center transition-all",
loadingToggleClass,
size === 'xs' ? 'ml-1' : 'ml-2'
size === "xs" ? "ml-1" : "ml-2"
)}
>
{rightIcon}
@@ -208,4 +208,4 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
}
);
Button.displayName = 'Button';
Button.displayName = "Button";

View File

@@ -1,2 +1,2 @@
export type { ButtonProps } from './Button';
export { Button } from './Button';
export type { ButtonProps } from "./Button";
export { Button } from "./Button";

View File

@@ -1,14 +1,14 @@
import type { Meta, StoryObj } from '@storybook/react';
import type { Meta, StoryObj } from "@storybook/react";
import { Card, CardBody, CardFooter, CardProps, CardTitle } from './Card';
import { Card, CardBody, CardFooter, CardProps, CardTitle } from "./Card";
const meta: Meta<typeof Card> = {
title: 'Components/Card',
title: "Components/Card",
component: Card,
tags: ['v2'],
tags: ["v2"],
argTypes: {
isRounded: {
type: 'boolean',
type: "boolean",
defaultValue: true
}
}

View File

@@ -1,5 +1,5 @@
import { forwardRef, ReactNode } from 'react';
import { twMerge } from 'tailwind-merge';
import { forwardRef, ReactNode } from "react";
import { twMerge } from "tailwind-merge";
export type CardTitleProps = {
children: ReactNode;
@@ -10,7 +10,7 @@ export type CardTitleProps = {
export const CardTitle = ({ children, className, subTitle }: CardTitleProps) => (
<div
className={twMerge(
'px-6 py-4 mb-5 font-sans text-lg font-normal border-b border-mineshaft-600 break-words',
"px-6 py-4 mb-5 font-sans text-lg font-normal border-b border-mineshaft-600 break-words",
className
)}
>
@@ -25,7 +25,7 @@ export type CardFooterProps = {
};
export const CardFooter = ({ children, className }: CardFooterProps) => (
<div className={twMerge('p-4 pt-0', className)}>{children}</div>
<div className={twMerge("p-4 pt-0", className)}>{children}</div>
);
export type CardBodyProps = {
@@ -34,7 +34,7 @@ export type CardBodyProps = {
};
export const CardBody = ({ children, className }: CardBodyProps) => (
<div className={twMerge('px-6 pb-6 pt-0', className)}>{children}</div>
<div className={twMerge("px-6 pb-6 pt-0", className)}>{children}</div>
);
export type CardProps = {
@@ -52,11 +52,11 @@ export const Card = forwardRef<HTMLDivElement, CardProps>(
<div
ref={ref}
className={twMerge(
'flex w-full flex-col bg-mineshaft-800 font-inter text-gray-200 shadow-md',
isFullHeight && 'h-full',
isRounded && 'rounded-md',
isPlain && 'shadow-none',
isHoverable && 'hover:shadow-xl',
"flex w-full flex-col bg-mineshaft-800 font-inter text-gray-200 shadow-md",
isFullHeight && "h-full",
isRounded && "rounded-md",
isPlain && "shadow-none",
isHoverable && "hover:shadow-xl",
className
)}
>
@@ -66,4 +66,4 @@ export const Card = forwardRef<HTMLDivElement, CardProps>(
}
);
Card.displayName = 'Card';
Card.displayName = "Card";

View File

@@ -1,2 +1,2 @@
export type { CardBodyProps, CardFooterProps, CardProps, CardTitleProps } from './Card';
export { Card, CardBody, CardFooter, CardTitle } from './Card';
export type { CardBodyProps, CardFooterProps, CardProps, CardTitleProps } from "./Card";
export { Card, CardBody, CardFooter, CardTitle } from "./Card";

View File

@@ -1,11 +1,11 @@
import type { Meta, StoryObj } from '@storybook/react';
import type { Meta, StoryObj } from "@storybook/react";
import { Checkbox } from './Checkbox';
import { Checkbox } from "./Checkbox";
const meta: Meta<typeof Checkbox> = {
title: 'Components/Checkbox',
title: "Components/Checkbox",
component: Checkbox,
tags: ['v2'],
tags: ["v2"],
argTypes: {}
};
@@ -15,20 +15,20 @@ type Story = StoryObj<typeof Checkbox>;
// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args
export const Simple: Story = {
args: {
children: 'Accept the condition'
children: "Accept the condition"
}
};
export const Disabled: Story = {
args: {
children: 'Accept the condition',
children: "Accept the condition",
isDisabled: true
}
};
export const Required: Story = {
args: {
children: 'Accept the condition',
children: "Accept the condition",
isRequired: true
}
};

View File

@@ -1,12 +1,12 @@
import { ReactNode } from 'react';
import { faCheck } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
import { twMerge } from 'tailwind-merge';
import { ReactNode } from "react";
import { faCheck } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
import { twMerge } from "tailwind-merge";
export type CheckboxProps = Omit<
CheckboxPrimitive.CheckboxProps,
'checked' | 'disabled' | 'required'
"checked" | "disabled" | "required"
> & {
children: ReactNode;
id: string;
@@ -28,9 +28,9 @@ export const Checkbox = ({
<div className="flex items-center font-inter text-bunker-300">
<CheckboxPrimitive.Root
className={twMerge(
'flex items-center justify-center w-4 h-4 mr-3 transition-all rounded shadow border border-mineshaft-400 hover:bg-mineshaft-500 bg-mineshaft-600',
isDisabled && 'bg-bunker-400 hover:bg-bunker-400',
isChecked && 'bg-primary hover:bg-primary',
"flex items-center justify-center w-4 h-4 mr-3 transition-all rounded shadow border border-mineshaft-400 hover:bg-mineshaft-500 bg-mineshaft-600",
isDisabled && "bg-bunker-400 hover:bg-bunker-400",
isChecked && "bg-primary hover:bg-primary",
className
)}
required={isRequired}

View File

@@ -1,2 +1,2 @@
export type { CheckboxProps } from './Checkbox';
export { Checkbox } from './Checkbox';
export type { CheckboxProps } from "./Checkbox";
export { Checkbox } from "./Checkbox";

View File

@@ -1,11 +1,11 @@
import { useEffect, useState } from 'react';
import { useEffect, useState } from "react";
import { useToggle } from '@app/hooks';
import { useToggle } from "@app/hooks";
import { Button } from '../Button';
import { FormControl } from '../FormControl';
import { Input } from '../Input';
import { Modal, ModalClose, ModalContent } from '../Modal';
import { Button } from "../Button";
import { FormControl } from "../FormControl";
import { Input } from "../Input";
import { Modal, ModalClose, ModalContent } from "../Modal";
type Props = {
isOpen?: boolean;
@@ -24,11 +24,11 @@ export const DeleteActionModal = ({
onDeleteApproved,
title
}: Props): JSX.Element => {
const [inputData, setInputData] = useState('');
const [inputData, setInputData] = useState("");
const [isLoading, setIsLoading] = useToggle();
useEffect(() => {
setInputData('');
setInputData("");
}, [isOpen]);
const onDelete = async () => {
@@ -46,7 +46,7 @@ export const DeleteActionModal = ({
<Modal
isOpen={isOpen}
onOpenChange={(isOpenState) => {
setInputData('');
setInputData("");
if (onChange) onChange(isOpenState);
}}
>
@@ -68,7 +68,7 @@ export const DeleteActionModal = ({
<Button variant="plain" colorSchema="secondary" onClick={onClose}>
Cancel
</Button>
</ModalClose>{' '}
</ModalClose>{" "}
</div>
}
onClose={onClose}

View File

@@ -1 +1 @@
export { DeleteActionModal } from './DeleteActionModal';
export { DeleteActionModal } from "./DeleteActionModal";

View File

@@ -1,12 +1,12 @@
import type { Meta, StoryObj } from '@storybook/react';
import type { Meta, StoryObj } from "@storybook/react";
import { Button } from '../Button';
import { Drawer, DrawerContent, DrawerContentProps, DrawerTrigger } from './Drawer';
import { Button } from "../Button";
import { Drawer, DrawerContent, DrawerContentProps, DrawerTrigger } from "./Drawer";
const meta: Meta<typeof Drawer> = {
title: 'Components/Drawer',
title: "Components/Drawer",
component: Drawer,
tags: ['v2'],
tags: ["v2"],
argTypes: {}
};
@@ -25,8 +25,8 @@ const Template = (args: DrawerContentProps) => (
export const Basic: Story = {
render: (args) => <Template {...args} />,
args: {
title: 'Title',
subTitle: 'Something as subtitle',
footerContent: 'footer content'
title: "Title",
subTitle: "Something as subtitle",
footerContent: "footer content"
}
};

View File

@@ -1,12 +1,12 @@
import { forwardRef, ReactNode } from 'react';
import { faTimes } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import * as DialogPrimitive from '@radix-ui/react-dialog';
import { cva, VariantProps } from 'cva';
import { twMerge } from 'tailwind-merge';
import { forwardRef, ReactNode } from "react";
import { faTimes } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import * as DialogPrimitive from "@radix-ui/react-dialog";
import { cva, VariantProps } from "cva";
import { twMerge } from "tailwind-merge";
import { Card, CardBody, CardFooter, CardTitle } from '../Card';
import { IconButton } from '../IconButton';
import { Card, CardBody, CardFooter, CardTitle } from "../Card";
import { IconButton } from "../IconButton";
export type DrawerContentProps = DialogPrimitive.DialogContentProps & {
title?: ReactNode;
@@ -16,14 +16,14 @@ export type DrawerContentProps = DialogPrimitive.DialogContentProps & {
} & VariantProps<typeof drawerContentVariation>;
const drawerContentVariation = cva(
'fixed ease-in-out duration-300 z-[90] border border-mineshaft-600 drop-shadow-2xl',
"fixed ease-in-out duration-300 z-[90] border border-mineshaft-600 drop-shadow-2xl",
{
variants: {
direction: {
right: [
'right-0 top-0',
'h-full w-96',
'data-[state=open]:animate-drawerRightIn data-[state=closed]:animate-drawerRightOut'
"right-0 top-0",
"h-full w-96",
"data-[state=open]:animate-drawerRightIn data-[state=closed]:animate-drawerRightOut"
]
}
}
@@ -32,13 +32,13 @@ const drawerContentVariation = cva(
export const DrawerContent = forwardRef<HTMLDivElement, DrawerContentProps>(
(
{ children, title, subTitle, className, footerContent, direction = 'right', onClose, ...props },
{ children, title, subTitle, className, footerContent, direction = "right", onClose, ...props },
forwardedRef
) => (
<DialogPrimitive.Portal>
<DialogPrimitive.Overlay
className="fixed inset-0 z-[70] h-full w-full"
style={{ backgroundColor: 'rgba(0, 0, 0, 0.7)' }}
style={{ backgroundColor: "rgba(0, 0, 0, 0.7)" }}
/>
<DialogPrimitive.Content
{...props}
@@ -54,7 +54,7 @@ export const DrawerContent = forwardRef<HTMLDivElement, DrawerContentProps>(
<CardBody className="flex-grow overflow-y-auto overflow-x-hidden px-4 dark:[color-scheme:dark]">
{children}
</CardBody>
{footerContent && <CardFooter>{footerContent}</CardFooter>}{' '}
{footerContent && <CardFooter>{footerContent}</CardFooter>}{" "}
<DialogPrimitive.Close aria-label="Close" asChild onClick={onClose}>
<IconButton
variant="plain"
@@ -70,9 +70,9 @@ export const DrawerContent = forwardRef<HTMLDivElement, DrawerContentProps>(
)
);
DrawerContent.displayName = 'ModalContent';
DrawerContent.displayName = "ModalContent";
export type DrawerProps = Omit<DialogPrimitive.DialogProps, 'open'> & { isOpen?: boolean };
export type DrawerProps = Omit<DialogPrimitive.DialogProps, "open"> & { isOpen?: boolean };
export const Drawer = ({ isOpen, ...props }: DrawerProps) => (
<DialogPrimitive.Root open={isOpen} {...props} />
);

View File

@@ -1 +1 @@
export { Drawer, DrawerClose,DrawerContent, DrawerTrigger } from './Drawer';
export { Drawer, DrawerClose,DrawerContent, DrawerTrigger } from "./Drawer";

View File

@@ -1,8 +1,8 @@
import { faPlus, faTrash, faUndo } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import type { Meta, StoryObj } from '@storybook/react';
import { faPlus, faTrash, faUndo } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import type { Meta, StoryObj } from "@storybook/react";
import { IconButton } from '../IconButton';
import { IconButton } from "../IconButton";
import {
DropdownMenu,
DropdownMenuContent,
@@ -11,12 +11,12 @@ import {
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger
} from './Dropdown';
} from "./Dropdown";
const meta: Meta<typeof DropdownMenu> = {
title: 'Components/DropdownMenu',
title: "Components/DropdownMenu",
component: DropdownMenu,
tags: ['v2'],
tags: ["v2"],
argTypes: {}
};

View File

@@ -1,6 +1,6 @@
import { ComponentPropsWithRef, ElementType, forwardRef, ReactNode, Ref } from 'react';
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
import { twMerge } from 'tailwind-merge';
import { ComponentPropsWithRef, ElementType, forwardRef, ReactNode, Ref } from "react";
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
import { twMerge } from "tailwind-merge";
// Main menu or parent container
export type DropdownMenuProps = DropdownMenuPrimitive.DropdownMenuProps;
@@ -21,7 +21,7 @@ export const DropdownMenuContent = forwardRef<HTMLDivElement, DropdownMenuConten
{...props}
ref={forwardedRef}
className={twMerge(
'min-w-[220px] bg-bunker will-change-auto text-bunker-300 rounded-md shadow data-[side=top]:animate-slideDownAndFade data-[side=left]:animate-slideRightAndFade data-[side=right]:animate-slideLeftAndFade data-[side=bottom]:animate-slideUpAndFade',
"min-w-[220px] bg-bunker will-change-auto text-bunker-300 rounded-md shadow data-[side=top]:animate-slideDownAndFade data-[side=left]:animate-slideRightAndFade data-[side=right]:animate-slideLeftAndFade data-[side=bottom]:animate-slideUpAndFade",
className
)}
>
@@ -32,14 +32,14 @@ export const DropdownMenuContent = forwardRef<HTMLDivElement, DropdownMenuConten
}
);
DropdownMenuContent.displayName = 'DropdownMenuContent';
DropdownMenuContent.displayName = "DropdownMenuContent";
// item label component
export type DropdownLabelProps = DropdownMenuPrimitive.MenuLabelProps;
export const DropdownMenuLabel = ({ className, ...props }: DropdownLabelProps) => (
<DropdownMenuPrimitive.Label
{...props}
className={twMerge('text-xs text-bunker-400 px-4 pt-2 pb-1', className)}
className={twMerge("text-xs text-bunker-400 px-4 pt-2 pb-1", className)}
/>
);
@@ -51,18 +51,18 @@ export type DropdownMenuItemProps<T extends ElementType> =
inputRef?: Ref<T>;
};
export const DropdownMenuItem = <T extends ElementType = 'button'>({
export const DropdownMenuItem = <T extends ElementType = "button">({
children,
inputRef,
className,
icon,
as: Item = 'button',
as: Item = "button",
...props
}: DropdownMenuItemProps<T> & ComponentPropsWithRef<T>) => (
<DropdownMenuPrimitive.Item
{...props}
className={twMerge(
'text-sm block font-inter px-4 py-2 data-[highlighted]:bg-gray-700 outline-none cursor-pointer',
"text-sm block font-inter px-4 py-2 data-[highlighted]:bg-gray-700 outline-none cursor-pointer",
className
)}
>
@@ -80,7 +80,7 @@ export const DropdownMenuGroup = forwardRef<HTMLDivElement, DropdownMenuGroupPro
({ ...props }, ref) => <DropdownMenuPrimitive.Group {...props} ref={ref} />
);
DropdownMenuGroup.displayName = 'DropdownMenuGroup';
DropdownMenuGroup.displayName = "DropdownMenuGroup";
// Divider
export const DropdownMenuSeparator = forwardRef<
@@ -90,8 +90,8 @@ export const DropdownMenuSeparator = forwardRef<
<DropdownMenuPrimitive.Separator
ref={ref}
{...props}
className={twMerge('h-[1px] bg-gray-700 m-1', className)}
className={twMerge("h-[1px] bg-gray-700 m-1", className)}
/>
));
DropdownMenuSeparator.displayName = 'DropdownMenuSeperator';
DropdownMenuSeparator.displayName = "DropdownMenuSeperator";

View File

@@ -5,7 +5,7 @@ export type {
DropdownMenuItemProps,
DropdownMenuProps,
DropdownMenuTriggerProps
} from './Dropdown';
} from "./Dropdown";
export {
DropdownMenu,
DropdownMenuContent,
@@ -14,4 +14,4 @@ export {
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger
} from './Dropdown';
} from "./Dropdown";

View File

@@ -1,5 +1,5 @@
import { Button } from '../Button';
import { Modal, ModalContent } from '../Modal';
import { Button } from "../Button";
import { Modal, ModalContent } from "../Modal";
type Props = {
isOpen?: boolean;

View File

@@ -1 +1 @@
export { EmailServiceSetupModal } from './EmailServiceSetupModal';
export { EmailServiceSetupModal } from "./EmailServiceSetupModal";

View File

@@ -1,14 +1,14 @@
import type { Meta, StoryObj } from '@storybook/react';
import type { Meta, StoryObj } from "@storybook/react";
import { EmptyState } from './EmptyState';
import { EmptyState } from "./EmptyState";
const meta: Meta<typeof EmptyState> = {
title: 'Components/EmptyState',
title: "Components/EmptyState",
component: EmptyState,
tags: ['v2'],
tags: ["v2"],
argTypes: {},
args: {
title: 'No members found'
title: "No members found"
}
};

View File

@@ -1,8 +1,8 @@
import { ReactNode } from 'react';
import { SizeProp } from '@fortawesome/fontawesome-svg-core';
import { faCubesStacked, IconDefinition } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { twMerge } from 'tailwind-merge';
import { ReactNode } from "react";
import { SizeProp } from "@fortawesome/fontawesome-svg-core";
import { faCubesStacked, IconDefinition } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { twMerge } from "tailwind-merge";
type Props = {
title: ReactNode;
@@ -17,11 +17,11 @@ export const EmptyState = ({
className,
children,
icon = faCubesStacked,
iconSize = '2x'
iconSize = "2x"
}: Props) => (
<div
className={twMerge(
'flex w-full flex-col items-center bg-mineshaft-800 px-2 pt-6 text-bunker-300',
"flex w-full flex-col items-center bg-mineshaft-800 px-2 pt-6 text-bunker-300",
className
)}
>

Some files were not shown because too many files have changed in this diff Show More