mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
Add eslint rule and fix as many issues as possible
This commit is contained in:
@@ -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"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"singleQuote": false,
|
||||
"printWidth": 100,
|
||||
"trailingComma": "none",
|
||||
"tabWidth": 2,
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
});
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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>
|
||||
)}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
</>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
}`}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Notification, { TNotification } from './Notification';
|
||||
import Notification, { TNotification } from "./Notification";
|
||||
|
||||
interface NoticationsProps {
|
||||
notifications: Required<TNotification>[];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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 };
|
||||
})
|
||||
);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
/>
|
||||
|
||||
@@ -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 ">
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
) : (
|
||||
|
||||
@@ -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) => (
|
||||
|
||||
@@ -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 && (
|
||||
|
||||
@@ -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) => (
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import IntegrationTile from './Integration';
|
||||
import IntegrationTile from "./Integration";
|
||||
|
||||
interface Props {
|
||||
integrations: any;
|
||||
|
||||
@@ -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'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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
)}
|
||||
|
||||
@@ -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>
|
||||
)}
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 [];
|
||||
};
|
||||
|
||||
@@ -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" />
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export type { ButtonProps } from './Button';
|
||||
export { Button } from './Button';
|
||||
export type { ButtonProps } from "./Button";
|
||||
export { Button } from "./Button";
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export type { CheckboxProps } from './Checkbox';
|
||||
export { Checkbox } from './Checkbox';
|
||||
export type { CheckboxProps } from "./Checkbox";
|
||||
export { Checkbox } from "./Checkbox";
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -1 +1 @@
|
||||
export { DeleteActionModal } from './DeleteActionModal';
|
||||
export { DeleteActionModal } from "./DeleteActionModal";
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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} />
|
||||
);
|
||||
|
||||
@@ -1 +1 @@
|
||||
export { Drawer, DrawerClose,DrawerContent, DrawerTrigger } from './Drawer';
|
||||
export { Drawer, DrawerClose,DrawerContent, DrawerTrigger } from "./Drawer";
|
||||
|
||||
@@ -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: {}
|
||||
};
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1 +1 @@
|
||||
export { EmailServiceSetupModal } from './EmailServiceSetupModal';
|
||||
export { EmailServiceSetupModal } from "./EmailServiceSetupModal";
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user