mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-11 08:28:59 +00:00
ref(frontend): update to absolute import
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
import "../styles/globals.css";
|
||||
import "@fortawesome/fontawesome-svg-core/styles.css";
|
||||
import { config } from "@fortawesome/fontawesome-svg-core";
|
||||
import Layout from "../components/basic/layout";
|
||||
import RouteGuard from "../components/RouteGuard";
|
||||
import Layout from "~/components/basic/layout";
|
||||
import RouteGuard from "~/components/RouteGuard";
|
||||
import { publicPaths } from "../const.js";
|
||||
import { useEffect } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import { initPostHog } from "../components/analytics/posthog";
|
||||
import { ENV } from "../components/utilities/config";
|
||||
import { initPostHog } from "~/components/analytics/posthog";
|
||||
import { ENV } from "~/utilities/config";
|
||||
|
||||
config.autoAddCss = false;
|
||||
|
||||
@@ -39,9 +39,7 @@ const App = ({ Component, pageProps, ...appProps }) => {
|
||||
publicPaths.includes("/" + appProps.router.pathname.split("/")[1]) ||
|
||||
!Component.requireAuth
|
||||
) {
|
||||
return (
|
||||
<Component {...pageProps} />
|
||||
)
|
||||
return <Component {...pageProps} />;
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -6,28 +6,34 @@ import { PATH } from "../../../const";
|
||||
* @param {*} clientPublicKey
|
||||
* @returns
|
||||
*/
|
||||
const changePassword2 = ({encryptedPrivateKey, iv, tag, salt, verifier, clientProof}) => {
|
||||
const changePassword2 = ({
|
||||
encryptedPrivateKey,
|
||||
iv,
|
||||
tag,
|
||||
salt,
|
||||
verifier,
|
||||
clientProof,
|
||||
}) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/password/change-password", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
"clientProof": clientProof,
|
||||
"encryptedPrivateKey": encryptedPrivateKey,
|
||||
"iv": iv,
|
||||
"tag": tag,
|
||||
"salt": salt,
|
||||
"verifier": verifier
|
||||
clientProof: clientProof,
|
||||
encryptedPrivateKey: encryptedPrivateKey,
|
||||
iv: iv,
|
||||
tag: tag,
|
||||
salt: salt,
|
||||
verifier: verifier,
|
||||
}),
|
||||
})
|
||||
.then(async res => {
|
||||
}).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return res;
|
||||
} else {
|
||||
console.log('Failed to change the password');
|
||||
console.log("Failed to change the password");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default changePassword2;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient.js";
|
||||
import SecurityClient from "~/utilities/SecurityClient.js";
|
||||
import { PATH } from "../../../const.js";
|
||||
|
||||
/**
|
||||
@@ -14,14 +14,13 @@ const checkAuth = async (req, res) => {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(res => {
|
||||
}).then((res) => {
|
||||
if (res.status == 200) {
|
||||
return res;
|
||||
} else {
|
||||
console.log("Not authorized");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default checkAuth;
|
||||
|
||||
@@ -1,32 +1,41 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
* This is the route that issues a backup private key that will afterwards be added into a pdf
|
||||
*/
|
||||
const issueBackupPrivateKey = ({encryptedPrivateKey, iv, tag, salt, verifier, clientProof}) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/password/backup-private-key", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
"clientProof": clientProof,
|
||||
"encryptedPrivateKey": encryptedPrivateKey,
|
||||
"iv": iv,
|
||||
"tag": tag,
|
||||
"salt": salt,
|
||||
"verifier": verifier
|
||||
}),
|
||||
})
|
||||
.then(res => {
|
||||
const issueBackupPrivateKey = ({
|
||||
encryptedPrivateKey,
|
||||
iv,
|
||||
tag,
|
||||
salt,
|
||||
verifier,
|
||||
clientProof,
|
||||
}) => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/password/backup-private-key",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
clientProof: clientProof,
|
||||
encryptedPrivateKey: encryptedPrivateKey,
|
||||
iv: iv,
|
||||
tag: tag,
|
||||
salt: salt,
|
||||
verifier: verifier,
|
||||
}),
|
||||
}
|
||||
).then((res) => {
|
||||
if (res.status == 200) {
|
||||
return res;
|
||||
} else {
|
||||
return res;
|
||||
console.log("Failed to issue the backup key");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default issueBackupPrivateKey;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -14,9 +14,8 @@ const logout = async (req, res) => {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
credentials: "include"
|
||||
})
|
||||
.then(res => {
|
||||
credentials: "include",
|
||||
}).then((res) => {
|
||||
if (res.status == 200) {
|
||||
SecurityClient.setToken("");
|
||||
// Delete the cookie by not setting a value; Alternatively clear the local storage
|
||||
@@ -30,7 +29,7 @@ const logout = async (req, res) => {
|
||||
} else {
|
||||
console.log("Failed to log out");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default logout;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -6,7 +6,7 @@ import { PATH } from "../../../const";
|
||||
* @param {*} clientPublicKey
|
||||
* @returns
|
||||
*/
|
||||
const SRP1 = ({clientPublicKey}) => {
|
||||
const SRP1 = ({ clientPublicKey }) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/password/srp1", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
@@ -15,14 +15,13 @@ const SRP1 = ({clientPublicKey}) => {
|
||||
body: JSON.stringify({
|
||||
clientPublicKey,
|
||||
}),
|
||||
})
|
||||
.then(async res => {
|
||||
}).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return (await res.json());
|
||||
return await res.json();
|
||||
} else {
|
||||
console.log('Failed to do the first step of SRP');
|
||||
console.log("Failed to do the first step of SRP");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default SRP1;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient.js";
|
||||
import SecurityClient from "~/utilities/SecurityClient.js";
|
||||
import { PATH } from "../../../const.js";
|
||||
|
||||
/**
|
||||
@@ -8,26 +8,28 @@ import { PATH } from "../../../const.js";
|
||||
* @returns
|
||||
*/
|
||||
const getSecrets = async (workspaceId, env) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/secret/" +
|
||||
workspaceId +
|
||||
"?" +
|
||||
new URLSearchParams({
|
||||
environment: env,
|
||||
channel: "web",
|
||||
return SecurityClient.fetchCall(
|
||||
PATH +
|
||||
"/api/v1/secret/" +
|
||||
workspaceId +
|
||||
"?" +
|
||||
new URLSearchParams({
|
||||
environment: env,
|
||||
channel: "web",
|
||||
}),
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
), {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return (await res.json());
|
||||
return await res.json();
|
||||
} else {
|
||||
console.log('Failed to get project secrets');
|
||||
console.log("Failed to get project secrets");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default getSecrets;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -19,14 +19,13 @@ const uploadSecrets = async ({ workspaceId, secrets, keys, environment }) => {
|
||||
environment,
|
||||
channel: "web",
|
||||
}),
|
||||
})
|
||||
.then(async res => {
|
||||
}).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return res;
|
||||
} else {
|
||||
console.log('Failed to push secrets');
|
||||
console.log("Failed to push secrets");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default uploadSecrets;
|
||||
|
||||
@@ -1,24 +1,26 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
const changeHerokuConfigVars = ({ integrationId, key, secrets }) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/integration/" + integrationId + "/sync", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
key,
|
||||
secrets,
|
||||
})
|
||||
})
|
||||
.then(async res => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/integration/" + integrationId + "/sync",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
key,
|
||||
secrets,
|
||||
}),
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return res;
|
||||
} else {
|
||||
console.log('Failed to sync secrets to Heroku');
|
||||
console.log("Failed to sync secrets to Heroku");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default changeHerokuConfigVars;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -7,19 +7,21 @@ import { PATH } from "../../../const";
|
||||
* @returns
|
||||
*/
|
||||
const deleteIntegration = ({ integrationId }) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/integration/" + integrationId, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/integration/" + integrationId,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return (await res.json()).workspace;
|
||||
} else {
|
||||
console.log('Failed to delete an integration');
|
||||
console.log("Failed to delete an integration");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default deleteIntegration;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -7,19 +7,21 @@ import { PATH } from "../../../const";
|
||||
* @returns
|
||||
*/
|
||||
const deleteIntegrationAuth = ({ integrationAuthId }) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/integration-auth/" + integrationAuthId, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/integration-auth/" + integrationAuthId,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return res;
|
||||
} else {
|
||||
console.log('Failed to delete an integration authorization');
|
||||
console.log("Failed to delete an integration authorization");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default deleteIntegrationAuth;
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
const getIntegrationApps = ({ integrationAuthId }) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/integration-auth/" + integrationAuthId + "/apps", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/integration-auth/" + integrationAuthId + "/apps",
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return (await res.json()).apps;
|
||||
} else {
|
||||
console.log('Failed to get available apps for an integration');
|
||||
console.log("Failed to get available apps for an integration");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default getIntegrationApps;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
const getIntegrations = () => {
|
||||
@@ -7,14 +7,13 @@ const getIntegrations = () => {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
}).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return (await res.json()).integrations;
|
||||
} else {
|
||||
console.log('Failed to get project integrations');
|
||||
console.log("Failed to get project integrations");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default getIntegrations;
|
||||
|
||||
@@ -1,32 +1,34 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
* This route starts the integration after teh default one if gonna set up.
|
||||
* This route starts the integration after teh default one if gonna set up.
|
||||
* @param {*} integrationId
|
||||
* @returns
|
||||
*/
|
||||
const startIntegration = ({ integrationId, appName, environment }) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/integration/" + integrationId, {
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
"update": {
|
||||
app: appName,
|
||||
environment,
|
||||
isActive: true
|
||||
}
|
||||
})
|
||||
})
|
||||
.then(async res => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/integration/" + integrationId,
|
||||
{
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
update: {
|
||||
app: appName,
|
||||
environment,
|
||||
isActive: true,
|
||||
},
|
||||
}),
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return res;
|
||||
} else {
|
||||
console.log('Failed to start an integration');
|
||||
console.log("Failed to start an integration");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default startIntegration;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -7,24 +7,26 @@ import { PATH } from "../../../const";
|
||||
* @returns
|
||||
*/
|
||||
const AuthorizeIntegration = ({ workspaceId, code, integration }) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/integration-auth/oauth-token", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
workspaceId,
|
||||
code,
|
||||
integration
|
||||
}),
|
||||
})
|
||||
.then(async res => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/integration-auth/oauth-token",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
workspaceId,
|
||||
code,
|
||||
integration,
|
||||
}),
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return res;
|
||||
} else {
|
||||
console.log('Failed to authorize the integration');
|
||||
console.log("Failed to authorize the integration");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default AuthorizeIntegration;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -7,19 +7,21 @@ import { PATH } from "../../../const";
|
||||
* @returns
|
||||
*/
|
||||
const getWorkspaceAuthorizations = ({ workspaceId }) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/workspace/" + workspaceId + "/authorizations", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/workspace/" + workspaceId + "/authorizations",
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return (await res.json()).authorizations;
|
||||
} else {
|
||||
console.log('Failed to get project authorizations');
|
||||
console.log("Failed to get project authorizations");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default getWorkspaceAuthorizations;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -7,19 +7,21 @@ import { PATH } from "../../../const";
|
||||
* @returns
|
||||
*/
|
||||
const getWorkspaceIntegrations = ({ workspaceId }) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/workspace/" + workspaceId + "/integrations", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/workspace/" + workspaceId + "/integrations",
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return (await res.json()).integrations;
|
||||
} else {
|
||||
console.log('Failed to get the project integrations');
|
||||
console.log("Failed to get the project integrations");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default getWorkspaceIntegrations;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -8,19 +8,21 @@ import { PATH } from "../../../const";
|
||||
* @returns
|
||||
*/
|
||||
const getOrganization = (req, res) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/organization/" + req.orgId, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/organization/" + req.orgId,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return (await res.json()).organization;
|
||||
} else {
|
||||
console.log('Failed to get org info');
|
||||
console.log("Failed to get org info");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default getOrganization;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -8,19 +8,21 @@ import { PATH } from "../../../const";
|
||||
* @returns
|
||||
*/
|
||||
const getOrganizationProjects = (req, res) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/organization/" + req.orgId + "/workspaces", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/organization/" + req.orgId + "/workspaces",
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return (await res.json()).workspaces;
|
||||
} else {
|
||||
console.log('Failed to get projects for an org');
|
||||
console.log("Failed to get projects for an org");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default getOrganizationProjects;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -8,19 +8,21 @@ import { PATH } from "../../../const";
|
||||
* @returns
|
||||
*/
|
||||
const getOrganizationSubscriptions = (req, res) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/organization/" + req.orgId + "/subscriptions", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/organization/" + req.orgId + "/subscriptions",
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return (await res.json()).subscriptions;
|
||||
} else {
|
||||
console.log('Failed to get org subscriptions');
|
||||
console.log("Failed to get org subscriptions");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default getOrganizationSubscriptions;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -8,19 +8,21 @@ import { PATH } from "../../../const";
|
||||
* @returns
|
||||
*/
|
||||
const getOrganizationUserProjects = (req, res) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/organization/" + req.orgId + "/my-workspaces", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/organization/" + req.orgId + "/my-workspaces",
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return (await res.json()).workspaces;
|
||||
} else {
|
||||
console.log('Failed to get projects of a user in an org');
|
||||
console.log("Failed to get projects of a user in an org");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default getOrganizationUserProjects;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -8,19 +8,21 @@ import { PATH } from "../../../const";
|
||||
* @returns
|
||||
*/
|
||||
const getOrganizationUsers = (req, res) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/organization/" + req.orgId + "/users", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/organization/" + req.orgId + "/users",
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return (await res.json()).users;
|
||||
} else {
|
||||
console.log('Failed to get org users');
|
||||
console.log("Failed to get org users");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default getOrganizationUsers;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -7,20 +7,22 @@ import { PATH } from "../../../const";
|
||||
* @param {*} res
|
||||
* @returns
|
||||
*/
|
||||
const StripeRedirect = ({orgId}) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/organization/" + orgId + "/customer-portal-session", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
if (res.status == 200) {
|
||||
return window.location.href = (await res.json()).url;
|
||||
} else {
|
||||
console.log('Failed to redirect to Stripe');
|
||||
const StripeRedirect = ({ orgId }) => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/organization/" + orgId + "/customer-portal-session",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
})
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return (window.location.href = (await res.json()).url);
|
||||
} else {
|
||||
console.log("Failed to redirect to Stripe");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export default StripeRedirect;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -7,22 +7,24 @@ import { PATH } from "../../../const";
|
||||
* @returns
|
||||
*/
|
||||
const addIncidentContact = (organizationId, email) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/organization/" + organizationId + "/incidentContactOrg", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
email: email,
|
||||
}),
|
||||
})
|
||||
.then(async res => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/organization/" + organizationId + "/incidentContactOrg",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
email: email,
|
||||
}),
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return res;
|
||||
} else {
|
||||
console.log('Failed to add an incident contact');
|
||||
console.log("Failed to add an incident contact");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default addIncidentContact;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -17,14 +17,13 @@ const addUserToOrg = (email, orgId) => {
|
||||
inviteeEmail: email,
|
||||
organizationId: orgId,
|
||||
}),
|
||||
})
|
||||
.then(async res => {
|
||||
}).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return res;
|
||||
} else {
|
||||
console.log('Failed to add a user to an org');
|
||||
console.log("Failed to add a user to an org");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default addUserToOrg;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -7,22 +7,24 @@ import { PATH } from "../../../const";
|
||||
* @returns
|
||||
*/
|
||||
const deleteIncidentContact = (organizaionId, email) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/organization/" + organizaionId + "/incidentContactOrg", {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
email: email,
|
||||
}),
|
||||
})
|
||||
.then(async res => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/organization/" + organizaionId + "/incidentContactOrg",
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
email: email,
|
||||
}),
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return res;
|
||||
} else {
|
||||
console.log('Failed to delete an incident contact');
|
||||
console.log("Failed to delete an incident contact");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default deleteIncidentContact;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -7,19 +7,21 @@ import { PATH } from "../../../const";
|
||||
* @returns
|
||||
*/
|
||||
const deleteUserFromOrganization = (membershipId) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/membership-org/" + membershipId, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/membership-org/" + membershipId,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return res;
|
||||
} else {
|
||||
console.log('Failed to delete a user from an org');
|
||||
console.log("Failed to delete a user from an org");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default deleteUserFromOrganization;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -7,19 +7,21 @@ import { PATH } from "../../../const";
|
||||
* @returns
|
||||
*/
|
||||
const getIncidentContacts = (organizationId) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/organization/" + organizationId + "/incidentContactOrg", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/organization/" + organizationId + "/incidentContactOrg",
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return (await res.json()).incidentContactsOrg;
|
||||
} else {
|
||||
console.log('Failed to get incident contacts');
|
||||
console.log("Failed to get incident contacts");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default getIncidentContacts;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -13,14 +13,13 @@ const getOrganizations = (req, res) => {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
}).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return (await res.json()).organizations;
|
||||
} else {
|
||||
console.log('Failed to get orgs of a user');
|
||||
console.log("Failed to get orgs of a user");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default getOrganizations;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -8,22 +8,24 @@ import { PATH } from "../../../const";
|
||||
* @returns
|
||||
*/
|
||||
const renameOrg = (orgId, newOrgName) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/organization/" + orgId + "/name", {
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: newOrgName,
|
||||
}),
|
||||
})
|
||||
.then(async res => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/organization/" + orgId + "/name",
|
||||
{
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: newOrgName,
|
||||
}),
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return res;
|
||||
} else {
|
||||
console.log('Failed to rename an organization');
|
||||
console.log("Failed to rename an organization");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default renameOrg;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -6,29 +6,36 @@ import { PATH } from "../../../const";
|
||||
* @param {*} param0
|
||||
* @returns
|
||||
*/
|
||||
const addServiceToken = ({name, workspaceId, environment, expiresIn, publicKey, encryptedKey, nonce}) => {
|
||||
const addServiceToken = ({
|
||||
name,
|
||||
workspaceId,
|
||||
environment,
|
||||
expiresIn,
|
||||
publicKey,
|
||||
encryptedKey,
|
||||
nonce,
|
||||
}) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/service-token/", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name,
|
||||
workspaceId,
|
||||
name,
|
||||
workspaceId,
|
||||
environment,
|
||||
expiresIn,
|
||||
publicKey,
|
||||
expiresIn,
|
||||
publicKey,
|
||||
encryptedKey,
|
||||
nonce
|
||||
})
|
||||
})
|
||||
.then(async res => {
|
||||
nonce,
|
||||
}),
|
||||
}).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return (await res.json()).token;
|
||||
} else {
|
||||
console.log('Failed to add service tokens');
|
||||
console.log("Failed to add service tokens");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default addServiceToken;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -6,20 +6,22 @@ import { PATH } from "../../../const";
|
||||
* @param {*} param0
|
||||
* @returns
|
||||
*/
|
||||
const getServiceTokens = ({workspaceId}) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/workspace/" + workspaceId + "/service-tokens", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
const getServiceTokens = ({ workspaceId }) => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/workspace/" + workspaceId + "/service-tokens",
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return (await res.json()).serviceTokens;
|
||||
} else {
|
||||
console.log('Failed to get service tokens');
|
||||
console.log("Failed to get service tokens");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default getServiceTokens;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -13,14 +13,13 @@ const getUser = (req, res) => {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
}).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return (await res.json()).user;
|
||||
} else {
|
||||
console.log('Failed to get user info');
|
||||
console.log("Failed to get user info");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default getUser;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -8,23 +8,26 @@ import { PATH } from "../../../const";
|
||||
* @returns
|
||||
*/
|
||||
const checkUserAction = ({ action }) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/user-action" +
|
||||
"?" +
|
||||
new URLSearchParams({
|
||||
action,
|
||||
}), {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH +
|
||||
"/api/v1/user-action" +
|
||||
"?" +
|
||||
new URLSearchParams({
|
||||
action,
|
||||
}),
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return (await res.json()).userAction;
|
||||
} else {
|
||||
console.log('Failed to check a user action');
|
||||
console.log("Failed to check a user action");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default checkUserAction;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -15,14 +15,13 @@ const registerUserAction = ({ action }) => {
|
||||
body: JSON.stringify({
|
||||
action,
|
||||
}),
|
||||
})
|
||||
.then(async res => {
|
||||
}).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return res;
|
||||
} else {
|
||||
console.log('Failed to register a user action');
|
||||
console.log("Failed to register a user action");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default registerUserAction;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -8,22 +8,24 @@ import { PATH } from "../../../const";
|
||||
* @returns
|
||||
*/
|
||||
const addUserToWorkspace = (email, workspaceId) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/workspace/" + workspaceId + "/invite-signup", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
email: email,
|
||||
}),
|
||||
})
|
||||
.then(async res => {
|
||||
if (res.status == 200) {
|
||||
return (await res.json());
|
||||
} else {
|
||||
console.log('Failed to add a user to project');
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/workspace/" + workspaceId + "/invite-signup",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
email: email,
|
||||
}),
|
||||
}
|
||||
})
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return await res.json();
|
||||
} else {
|
||||
console.log("Failed to add a user to project");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export default addUserToWorkspace;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -8,22 +8,24 @@ import { PATH } from "../../../const";
|
||||
* @returns
|
||||
*/
|
||||
const changeUserRoleInWorkspace = (membershipId, role) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/membership/" + membershipId + "/change-role", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
role: role,
|
||||
}),
|
||||
})
|
||||
.then(async res => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/membership/" + membershipId + "/change-role",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
role: role,
|
||||
}),
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return res;
|
||||
} else {
|
||||
console.log('Failed to change the user role in a project');
|
||||
console.log("Failed to change the user role in a project");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default changeUserRoleInWorkspace;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -16,14 +16,13 @@ const createWorkspace = (workspaceName, organizationId) => {
|
||||
workspaceName: workspaceName,
|
||||
organizationId: organizationId,
|
||||
}),
|
||||
})
|
||||
.then(async res => {
|
||||
}).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return (await res.json()).workspace;
|
||||
} else {
|
||||
console.log('Failed to create a project');
|
||||
console.log("Failed to create a project");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default createWorkspace;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -7,19 +7,21 @@ import { PATH } from "../../../const";
|
||||
* @returns
|
||||
*/
|
||||
const deleteUserFromWorkspace = (membershipId) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/membership/" + membershipId, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/membership/" + membershipId,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return res;
|
||||
} else {
|
||||
console.log('Failed to delete a user from a project');
|
||||
console.log("Failed to delete a user from a project");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default deleteUserFromWorkspace;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -12,14 +12,13 @@ const deleteWorkspace = (workspaceId) => {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
}).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return res;
|
||||
} else {
|
||||
console.log('Failed to delete a project');
|
||||
console.log("Failed to delete a project");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default deleteWorkspace;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -7,19 +7,23 @@ import { PATH } from "../../../const";
|
||||
* @returns
|
||||
*/
|
||||
const getLatestFileKey = (workspaceId) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/key/" + workspaceId + "/latest", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
if (res.status == 200) {
|
||||
return (await res.json());
|
||||
} else {
|
||||
console.log('Failed to get the latest key pairs for a certain project');
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/key/" + workspaceId + "/latest",
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
})
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return await res.json();
|
||||
} else {
|
||||
console.log(
|
||||
"Failed to get the latest key pairs for a certain project"
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export default getLatestFileKey;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -8,19 +8,21 @@ import { PATH } from "../../../const";
|
||||
* @returns
|
||||
*/
|
||||
const getWorkspaceInfo = (req, res) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/workspace/" + req.workspaceId, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/workspace/" + req.workspaceId,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return (await res.json()).workspace;
|
||||
} else {
|
||||
console.log('Failed to get project info');
|
||||
console.log("Failed to get project info");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default getWorkspaceInfo;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -8,19 +8,23 @@ import { PATH } from "../../../const";
|
||||
* @returns
|
||||
*/
|
||||
const getWorkspaceKeys = (req, res) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/workspace/" + req.workspaceId + "/keys", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/workspace/" + req.workspaceId + "/keys",
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return (await res.json()).publicKeys;
|
||||
} else {
|
||||
console.log('Failed to get the public keys of everyone in the workspace');
|
||||
console.log(
|
||||
"Failed to get the public keys of everyone in the workspace"
|
||||
);
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default getWorkspaceKeys;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -8,19 +8,21 @@ import { PATH } from "../../../const";
|
||||
* @returns
|
||||
*/
|
||||
const getWorkspaceUsers = (req, res) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/workspace/" + req.workspaceId + "/users", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/workspace/" + req.workspaceId + "/users",
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return (await res.json()).users;
|
||||
} else {
|
||||
console.log('Failed to get Project Users');
|
||||
console.log("Failed to get Project Users");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default getWorkspaceUsers;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -13,14 +13,13 @@ const getWorkspaces = (req, res) => {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(async res => {
|
||||
}).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return (await res.json()).workspaces;
|
||||
} else {
|
||||
console.log('Failed to get projects');
|
||||
console.log("Failed to get projects");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default getWorkspaces;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -8,22 +8,24 @@ import { PATH } from "../../../const";
|
||||
* @returns
|
||||
*/
|
||||
const renameWorkspace = (workspaceId, newWorkspaceName) => {
|
||||
return SecurityClient.fetchCall(PATH + "/api/v1/workspace/" + workspaceId + "/name", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: newWorkspaceName,
|
||||
}),
|
||||
})
|
||||
.then(async res => {
|
||||
return SecurityClient.fetchCall(
|
||||
PATH + "/api/v1/workspace/" + workspaceId + "/name",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: newWorkspaceName,
|
||||
}),
|
||||
}
|
||||
).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return res;
|
||||
} else {
|
||||
console.log('Failed to rename a project');
|
||||
console.log("Failed to rename a project");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default renameWorkspace;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import SecurityClient from "../../../components/utilities/SecurityClient";
|
||||
import SecurityClient from "~/utilities/SecurityClient";
|
||||
import { PATH } from "../../../const";
|
||||
|
||||
/**
|
||||
@@ -22,14 +22,13 @@ const uploadKeys = (workspaceId, userId, encryptedKey, nonce) => {
|
||||
nonce: nonce,
|
||||
},
|
||||
}),
|
||||
})
|
||||
.then(async res => {
|
||||
}).then(async (res) => {
|
||||
if (res.status == 200) {
|
||||
return res;
|
||||
} else {
|
||||
console.log('Failed to upload keys for a new user');
|
||||
console.log("Failed to upload keys for a new user");
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default uploadKeys;
|
||||
|
||||
@@ -2,14 +2,14 @@ import React, { useState, useEffect, useCallback, Fragment } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import Head from "next/head";
|
||||
import Image from "next/image";
|
||||
import guidGenerator from "../../components/utilities/randomId";
|
||||
import getSecretsForProject from "../../components/utilities/getSecretsForProject";
|
||||
import pushKeys from "../../components/utilities/pushKeys";
|
||||
import guidGenerator from "~/utilities/randomId";
|
||||
import getSecretsForProject from "~/utilities/getSecretsForProject";
|
||||
import pushKeys from "~/utilities/pushKeys";
|
||||
import getWorkspaces from "../api/workspace/getWorkspaces";
|
||||
import getUser from "../api/user/getUser";
|
||||
import NavHeader from "../../components/navigation/NavHeader";
|
||||
import NavHeader from "~/components/navigation/NavHeader";
|
||||
|
||||
import DashboardInputField from "../../components/dashboard/DashboardInputField";
|
||||
import DashboardInputField from "~/components/dashboard/DashboardInputField";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
faMagnifyingGlass,
|
||||
@@ -26,19 +26,26 @@ import {
|
||||
faCheck,
|
||||
faCopy,
|
||||
faCircleInfo,
|
||||
faX
|
||||
faX,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import ListBox from "../../components/basic/Listbox";
|
||||
import DropZone from "../../components/dashboard/DropZone";
|
||||
import ListBox from "~/components/basic/Listbox";
|
||||
import DropZone from "~/components/dashboard/DropZone";
|
||||
import { Menu, Transition } from "@headlessui/react";
|
||||
import getWorkspaceIntegrations from "../api/integrations/getWorkspaceIntegrations";
|
||||
import BottonRightPopup from "../../components/basic/popups/BottomRightPopup";
|
||||
import BottonRightPopup from "~/components/basic/popups/BottomRightPopup";
|
||||
import checkUserAction from "../api/userActions/checkUserAction";
|
||||
import registerUserAction from "../api/userActions/registerUserAction";
|
||||
import pushKeysIntegration from "../../components/utilities/pushKeysIntegration";
|
||||
import Button from "../../components/basic/buttons/Button";
|
||||
import pushKeysIntegration from "~/utilities/pushKeysIntegration";
|
||||
import Button from "~/components/basic/buttons/Button";
|
||||
|
||||
const KeyPair = ({ keyPair, deleteRow, modifyKey, modifyValue, modifyVisibility, isBlurred }) => {
|
||||
const KeyPair = ({
|
||||
keyPair,
|
||||
deleteRow,
|
||||
modifyKey,
|
||||
modifyValue,
|
||||
modifyVisibility,
|
||||
isBlurred,
|
||||
}) => {
|
||||
return (
|
||||
<div className="px-1 flex flex-col items-center ml-1">
|
||||
<div className="relative flex flex-row justify-between w-full max-w-5xl mr-auto max-h-10 my-1 items-center px-2">
|
||||
@@ -86,9 +93,12 @@ const KeyPair = ({ keyPair, deleteRow, modifyKey, modifyValue, modifyVisibility,
|
||||
<Menu.Items className="absolute right-0 mt-0.5 w-44 origin-top-right rounded-md bg-bunker border border-mineshaft-700 shadow-lg ring-1 ring-black z-20 ring-opacity-5 focus:outline-none px-1 py-1">
|
||||
<div
|
||||
onClick={() =>
|
||||
modifyVisibility(keyPair[4] == "personal"
|
||||
? "shared"
|
||||
: "personal", keyPair[1])
|
||||
modifyVisibility(
|
||||
keyPair[4] == "personal"
|
||||
? "shared"
|
||||
: "personal",
|
||||
keyPair[1]
|
||||
)
|
||||
}
|
||||
className="relative flex justify-start items-center cursor-pointer select-none py-2 px-2 rounded-md text-gray-400 hover:bg-white/10 duration-200 hover:text-gray-200 w-full"
|
||||
>
|
||||
@@ -123,7 +133,6 @@ const KeyPair = ({ keyPair, deleteRow, modifyKey, modifyValue, modifyVisibility,
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
const envMapping = {
|
||||
Development: "dev",
|
||||
Staging: "staging",
|
||||
@@ -186,7 +195,6 @@ export default function Dashboard() {
|
||||
};
|
||||
}, [buttonReady]);
|
||||
|
||||
|
||||
const reorderRows = () => {
|
||||
setSortMethod(
|
||||
sortMethod == "alphabetical" ? "-alphabetical" : "alphabetical"
|
||||
@@ -218,21 +226,21 @@ export default function Dashboard() {
|
||||
setFileState,
|
||||
setIsKeyAvailable,
|
||||
setData,
|
||||
workspaceId: router.query.id
|
||||
})
|
||||
workspaceId: router.query.id,
|
||||
});
|
||||
|
||||
const user = await getUser();
|
||||
setIsNew(
|
||||
(Date.parse(new Date()) -
|
||||
Date.parse(user.createdAt)) /
|
||||
60000 <
|
||||
(Date.parse(new Date()) - Date.parse(user.createdAt)) / 60000 <
|
||||
3
|
||||
? true
|
||||
: false
|
||||
);
|
||||
|
||||
let userAction = await checkUserAction({action: "first_time_secrets_pushed"});
|
||||
setHasUserEverPushed(userAction ? true : false)
|
||||
let userAction = await checkUserAction({
|
||||
action: "first_time_secrets_pushed",
|
||||
});
|
||||
setHasUserEverPushed(userAction ? true : false);
|
||||
} catch (error) {
|
||||
console.log("Error", error);
|
||||
setData([]);
|
||||
@@ -252,39 +260,38 @@ export default function Dashboard() {
|
||||
const modifyValue = (value, id) => {
|
||||
setData((oldData) => {
|
||||
oldData[id][3] = value;
|
||||
return [...oldData]
|
||||
return [...oldData];
|
||||
});
|
||||
setButtonReady(true);
|
||||
}
|
||||
};
|
||||
|
||||
const modifyKey = (value, id) => {
|
||||
setData((oldData) => {
|
||||
oldData[id][2] = value;
|
||||
return [...oldData]
|
||||
return [...oldData];
|
||||
});
|
||||
setButtonReady(true);
|
||||
}
|
||||
};
|
||||
|
||||
const modifyVisibility = (value, id) => {
|
||||
setData((oldData) => {
|
||||
oldData[id][4] = value;
|
||||
return [...oldData]
|
||||
return [...oldData];
|
||||
});
|
||||
setButtonReady(true);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const listenChangeValue = useCallback((value, id) => {
|
||||
modifyValue(value, id)
|
||||
}, [])
|
||||
modifyValue(value, id);
|
||||
}, []);
|
||||
|
||||
const listenChangeKey = useCallback((value, id) => {
|
||||
modifyKey(value, id)
|
||||
}, [])
|
||||
modifyKey(value, id);
|
||||
}, []);
|
||||
|
||||
const listenChangeVisibility = useCallback((value, id) => {
|
||||
modifyVisibility(value, id)
|
||||
}, [])
|
||||
modifyVisibility(value, id);
|
||||
}, []);
|
||||
|
||||
const savePush = async () => {
|
||||
let obj = Object.assign(
|
||||
@@ -294,19 +301,28 @@ export default function Dashboard() {
|
||||
setButtonReady(false);
|
||||
pushKeys(obj, router.query.id, env);
|
||||
|
||||
let integrations = await getWorkspaceIntegrations({workspaceId: router.query.id});
|
||||
let integrations = await getWorkspaceIntegrations({
|
||||
workspaceId: router.query.id,
|
||||
});
|
||||
integrations.map(async (integration) => {
|
||||
if (envMapping[env] == integration.environment && integration.isActive == true) {
|
||||
if (
|
||||
envMapping[env] == integration.environment &&
|
||||
integration.isActive == true
|
||||
) {
|
||||
let objIntegration = Object.assign(
|
||||
{},
|
||||
...data.map((row) => ({ [row[2]]: row[3] }))
|
||||
);
|
||||
await pushKeysIntegration({obj: objIntegration, integrationId: integration._id});}
|
||||
await pushKeysIntegration({
|
||||
obj: objIntegration,
|
||||
integrationId: integration._id,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (!hasUserEverPushed) {
|
||||
setCheckDocsPopUpVisible(true)
|
||||
await registerUserAction({action: "first_time_secrets_pushed"});
|
||||
setCheckDocsPopUpVisible(true);
|
||||
await registerUserAction({ action: "first_time_secrets_pushed" });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -339,20 +355,19 @@ export default function Dashboard() {
|
||||
function copyToClipboard() {
|
||||
// Get the text field
|
||||
var copyText = document.getElementById("myInput");
|
||||
|
||||
|
||||
// Select the text field
|
||||
copyText.select();
|
||||
copyText.setSelectionRange(0, 99999); // For mobile devices
|
||||
|
||||
// Copy the text inside the text field
|
||||
|
||||
// Copy the text inside the text field
|
||||
navigator.clipboard.writeText(copyText.value);
|
||||
|
||||
|
||||
setProjectIdCopied(true);
|
||||
setTimeout(() => setProjectIdCopied(false), 2000);
|
||||
// Alert the copied text
|
||||
// alert("Copied the text: " + copyText.value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return data ? (
|
||||
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
|
||||
@@ -371,41 +386,61 @@ export default function Dashboard() {
|
||||
</Head>
|
||||
<div className="flex flex-row">
|
||||
<div className="w-full max-h-96 pb-2">
|
||||
<NavHeader pageName="Secrets" isProjectRelated={true}/>
|
||||
{checkDocsPopUpVisible &&
|
||||
<BottonRightPopup
|
||||
buttonText="Check Docs"
|
||||
<NavHeader pageName="Secrets" isProjectRelated={true} />
|
||||
{checkDocsPopUpVisible && (
|
||||
<BottonRightPopup
|
||||
buttonText="Check Docs"
|
||||
buttonLink="https://infisical.com/docs/getting-started/introduction"
|
||||
titleText="Good job!"
|
||||
emoji="🎉"
|
||||
textLine1="Congrats on adding more secrets."
|
||||
textLine2="Here is how to connect them to your codebase."
|
||||
titleText="Good job!"
|
||||
emoji="🎉"
|
||||
textLine1="Congrats on adding more secrets."
|
||||
textLine2="Here is how to connect them to your codebase."
|
||||
setCheckDocsPopUpVisible={setCheckDocsPopUpVisible}
|
||||
/>
|
||||
}
|
||||
)}
|
||||
<div className="flex flex-row justify-between items-center mx-6 mt-6 mb-3 text-xl max-w-5xl">
|
||||
<div className="flex flex-row justify-start items-center text-3xl">
|
||||
<p className="font-semibold mr-4 mt-1">Secrets</p>
|
||||
{data?.length==0 && <ListBox
|
||||
selected={env}
|
||||
data={[
|
||||
"Development",
|
||||
"Staging",
|
||||
"Production",
|
||||
"Testing",
|
||||
]}
|
||||
// ref={useRef(123)}
|
||||
onChange={setEnv}
|
||||
className="z-40"
|
||||
/>}
|
||||
{data?.length == 0 && (
|
||||
<ListBox
|
||||
selected={env}
|
||||
data={[
|
||||
"Development",
|
||||
"Staging",
|
||||
"Production",
|
||||
"Testing",
|
||||
]}
|
||||
// ref={useRef(123)}
|
||||
onChange={setEnv}
|
||||
className="z-40"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-row">
|
||||
<div className="flex justify-end items-center bg-white/[0.07] text-base mt-2 mr-2 rounded-md text-gray-400">
|
||||
<p className="mr-2 font-bold pl-4">Project ID:</p>
|
||||
<input type="text" value={workspaceId} id="myInput" className="bg-white/0 text-gray-400 py-2 w-60 px-2 min-w-md outline-none" disabled></input>
|
||||
<p className="mr-2 font-bold pl-4">
|
||||
Project ID:
|
||||
</p>
|
||||
<input
|
||||
type="text"
|
||||
value={workspaceId}
|
||||
id="myInput"
|
||||
className="bg-white/0 text-gray-400 py-2 w-60 px-2 min-w-md outline-none"
|
||||
disabled
|
||||
></input>
|
||||
<div className="group font-normal group relative inline-block text-gray-400 underline hover:text-primary duration-200">
|
||||
<button onClick={copyToClipboard} className="pl-4 pr-4 border-l border-white/20 py-2 hover:bg-white/[0.12] duration-200">
|
||||
{projectIdCopied ? <FontAwesomeIcon icon={faCheck} className="pr-0.5"/> : <FontAwesomeIcon icon={faCopy} />}
|
||||
<button
|
||||
onClick={copyToClipboard}
|
||||
className="pl-4 pr-4 border-l border-white/20 py-2 hover:bg-white/[0.12] duration-200"
|
||||
>
|
||||
{projectIdCopied ? (
|
||||
<FontAwesomeIcon
|
||||
icon={faCheck}
|
||||
className="pr-0.5"
|
||||
/>
|
||||
) : (
|
||||
<FontAwesomeIcon icon={faCopy} />
|
||||
)}
|
||||
</button>
|
||||
<span className="absolute hidden group-hover:flex group-hover:animate-popup duration-300 w-28 -left-8 -top-20 translate-y-full pl-3 py-2 bg-white/10 rounded-md text-center text-gray-400 text-sm">
|
||||
Click to Copy
|
||||
@@ -455,7 +490,9 @@ export default function Dashboard() {
|
||||
className="pl-2 text-gray-400 rounded-r-md bg-white/5 w-full h-full outline-none"
|
||||
value={searchKeys}
|
||||
onChange={(e) =>
|
||||
setSearchKeys(e.target.value)
|
||||
setSearchKeys(
|
||||
e.target.value
|
||||
)
|
||||
}
|
||||
placeholder={"Search keys..."}
|
||||
/>
|
||||
@@ -465,7 +502,11 @@ export default function Dashboard() {
|
||||
onButtonPressed={reorderRows}
|
||||
color="mineshaft"
|
||||
size="icon-md"
|
||||
icon={sortMethod == "alphabetical" ? faArrowDownAZ : faArrowDownZA}
|
||||
icon={
|
||||
sortMethod == "alphabetical"
|
||||
? faArrowDownAZ
|
||||
: faArrowDownZA
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="ml-2 min-w-max flex flex-row items-start justify-start">
|
||||
@@ -481,7 +522,9 @@ export default function Dashboard() {
|
||||
onButtonPressed={changeBlurred}
|
||||
color="mineshaft"
|
||||
size="icon-md"
|
||||
icon={blurred ? faEye : faEyeSlash}
|
||||
icon={
|
||||
blurred ? faEye : faEyeSlash
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="relative ml-2 min-w-max flex flex-row items-start justify-end">
|
||||
@@ -514,14 +557,17 @@ export default function Dashboard() {
|
||||
<div className="rounded-t-md sticky top-0 z-20 bg-bunker flex flex-row pl-4 pr-6 pt-4 pb-2 items-center justify-between text-gray-300 font-bold">
|
||||
{/* <FontAwesomeIcon icon={faAngleDown} /> */}
|
||||
<div className="flex flex-row items-center">
|
||||
<p className="pl-2 text-lg">Personal</p>
|
||||
<p className="pl-2 text-lg">
|
||||
Personal
|
||||
</p>
|
||||
<div className="group font-normal group relative inline-block text-gray-300 underline hover:text-primary duration-200">
|
||||
<FontAwesomeIcon
|
||||
className="ml-3 mt-1 text-lg"
|
||||
icon={faCircleInfo}
|
||||
/>
|
||||
<span className="absolute hidden group-hover:flex group-hover:animate-popdown duration-300 w-44 -left-16 -top-7 translate-y-full px-2 py-2 bg-gray-700 rounded-md text-center text-gray-100 text-sm after:content-[''] after:absolute after:left-1/2 after:bottom-[100%] after:-translate-x-1/2 after:border-8 after:border-x-transparent after:border-t-transparent after:border-b-gray-700">
|
||||
Personal keys are only visible to you
|
||||
Personal keys are only
|
||||
visible to you
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -534,7 +580,8 @@ export default function Dashboard() {
|
||||
.toLowerCase()
|
||||
.includes(
|
||||
searchKeys.toLowerCase()
|
||||
) && keyPair[4] == "personal"
|
||||
) &&
|
||||
keyPair[4] == "personal"
|
||||
)
|
||||
.sort((a, b) =>
|
||||
sortMethod == "alphabetical"
|
||||
@@ -546,9 +593,13 @@ export default function Dashboard() {
|
||||
key={keyPair[0]}
|
||||
keyPair={keyPair}
|
||||
deleteRow={deleteCertainRow}
|
||||
modifyValue={listenChangeValue}
|
||||
modifyValue={
|
||||
listenChangeValue
|
||||
}
|
||||
modifyKey={listenChangeKey}
|
||||
modifyVisibility={listenChangeVisibility}
|
||||
modifyVisibility={
|
||||
listenChangeVisibility
|
||||
}
|
||||
isBlurred={blurred}
|
||||
/>
|
||||
))}
|
||||
@@ -562,15 +613,17 @@ export default function Dashboard() {
|
||||
<div className="sticky top-0 z-10 bg-bunker flex flex-row pl-4 pr-5 pt-4 pb-2 items-center justify-between text-gray-300 font-bold">
|
||||
{/* <FontAwesomeIcon icon={faAngleDown} /> */}
|
||||
<div className="flex flex-row items-center">
|
||||
<p className="pl-2 text-lg">Shared</p>
|
||||
<p className="pl-2 text-lg">
|
||||
Shared
|
||||
</p>
|
||||
<div className="group font-normal group relative inline-block text-gray-300 underline hover:text-primary duration-200">
|
||||
<FontAwesomeIcon
|
||||
className="ml-3 text-lg mt-1"
|
||||
icon={faCircleInfo}
|
||||
/>
|
||||
<span className="absolute hidden group-hover:flex group-hover:animate-popdown duration-300 w-44 -left-16 -top-7 translate-y-full px-2 py-2 bg-gray-700 rounded-md text-center text-gray-100 text-sm after:content-[''] after:absolute after:left-1/2 after:bottom-[100%] after:-translate-x-1/2 after:border-8 after:border-x-transparent after:border-t-transparent after:border-b-gray-700">
|
||||
Shared keys are visible to your whole
|
||||
team
|
||||
Shared keys are visible to
|
||||
your whole team
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -583,7 +636,8 @@ export default function Dashboard() {
|
||||
.toLowerCase()
|
||||
.includes(
|
||||
searchKeys.toLowerCase()
|
||||
) && keyPair[4] == "shared"
|
||||
) &&
|
||||
keyPair[4] == "shared"
|
||||
)
|
||||
.sort((a, b) =>
|
||||
sortMethod == "alphabetical"
|
||||
@@ -595,9 +649,13 @@ export default function Dashboard() {
|
||||
key={keyPair[0]}
|
||||
keyPair={keyPair}
|
||||
deleteRow={deleteCertainRow}
|
||||
modifyValue={listenChangeValue}
|
||||
modifyValue={
|
||||
listenChangeValue
|
||||
}
|
||||
modifyKey={listenChangeKey}
|
||||
modifyVisibility={listenChangeVisibility}
|
||||
modifyVisibility={
|
||||
listenChangeVisibility
|
||||
}
|
||||
isBlurred={blurred}
|
||||
/>
|
||||
))}
|
||||
@@ -606,7 +664,9 @@ export default function Dashboard() {
|
||||
<div className="w-full max-w-5xl">
|
||||
<DropZone
|
||||
setData={addData}
|
||||
setErrorDragAndDrop={setErrorDragAndDrop}
|
||||
setErrorDragAndDrop={
|
||||
setErrorDragAndDrop
|
||||
}
|
||||
createNewFile={addRow}
|
||||
errorDragAndDrop={errorDragAndDrop}
|
||||
setButtonReady={setButtonReady}
|
||||
@@ -617,19 +677,23 @@ export default function Dashboard() {
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col items-center justify-center h-full text-xl text-gray-400 max-w-5xl mt-28">
|
||||
{fileState.message != "There's nothing to pull" &&
|
||||
{fileState.message !=
|
||||
"There's nothing to pull" &&
|
||||
fileState.message != undefined && (
|
||||
<FontAwesomeIcon
|
||||
className="text-7xl mb-8"
|
||||
icon={faFolderOpen}
|
||||
/>
|
||||
)}
|
||||
{(fileState.message == "There's nothing to pull" ||
|
||||
{(fileState.message ==
|
||||
"There's nothing to pull" ||
|
||||
fileState.message == undefined) &&
|
||||
isKeyAvailable && (
|
||||
<DropZone
|
||||
setData={setData}
|
||||
setErrorDragAndDrop={setErrorDragAndDrop}
|
||||
setErrorDragAndDrop={
|
||||
setErrorDragAndDrop
|
||||
}
|
||||
createNewFile={addRow}
|
||||
errorDragAndDrop={errorDragAndDrop}
|
||||
setButtonReady={setButtonReady}
|
||||
@@ -638,7 +702,10 @@ export default function Dashboard() {
|
||||
)}
|
||||
{fileState.message ==
|
||||
"Failed membership validation for workspace" && (
|
||||
<p>You are not authorized to view this project.</p>
|
||||
<p>
|
||||
You are not authorized to view this
|
||||
project.
|
||||
</p>
|
||||
)}
|
||||
{fileState.message ==
|
||||
"Access needed to pull the latest file" ||
|
||||
@@ -653,8 +720,8 @@ export default function Dashboard() {
|
||||
administrator for permission.
|
||||
</p>
|
||||
<p className="mt-1">
|
||||
They need to grant you access in the team
|
||||
tab.
|
||||
They need to grant you access in
|
||||
the team tab.
|
||||
</p>
|
||||
</>
|
||||
))}
|
||||
|
||||
+286
-131
@@ -3,20 +3,25 @@ import { useRouter } from "next/router";
|
||||
import Head from "next/head";
|
||||
import Image from "next/image";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faCheck, faArrowRight, faRotate, faX } from "@fortawesome/free-solid-svg-icons";
|
||||
import ListBox from "../../components/basic/Listbox";
|
||||
import NavHeader from "../../components/navigation/NavHeader";
|
||||
import {
|
||||
faCheck,
|
||||
faArrowRight,
|
||||
faRotate,
|
||||
faX,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import ListBox from "~/components/basic/Listbox";
|
||||
import NavHeader from "~/components/navigation/NavHeader";
|
||||
import getIntegrations from "../api/integrations/GetIntegrations";
|
||||
import getIntegrationApps from "../api/integrations/GetIntegrationApps";
|
||||
import getWorkspaceAuthorizations from "../api/integrations/getWorkspaceAuthorizations";
|
||||
import getWorkspaceIntegrations from "../api/integrations/getWorkspaceIntegrations";
|
||||
import startIntegration from "../api/integrations/StartIntegration";
|
||||
import deleteIntegration from "../api/integrations/DeleteIntegration";
|
||||
import getSecretsForProject from "../../components/utilities/getSecretsForProject";
|
||||
import pushKeysIntegration from "../../components/utilities/pushKeysIntegration";
|
||||
import getSecretsForProject from "~/utilities/getSecretsForProject";
|
||||
import pushKeysIntegration from "~/utilities/pushKeysIntegration";
|
||||
import deleteIntegrationAuth from "../api/integrations/DeleteIntegrationAuth";
|
||||
import Button from "../../components/basic/buttons/Button";
|
||||
import guidGenerator from "../../components/utilities/randomId";
|
||||
import Button from "~/components/basic/buttons/Button";
|
||||
import guidGenerator from "~/utilities/randomId";
|
||||
|
||||
const crypto = require("crypto");
|
||||
|
||||
@@ -28,104 +33,138 @@ const envMapping = {
|
||||
};
|
||||
|
||||
const reverseEnvMapping = {
|
||||
"dev": "Development",
|
||||
"staging": "Staging",
|
||||
"prod": "Production",
|
||||
"test": "Testing"
|
||||
}
|
||||
dev: "Development",
|
||||
staging: "Staging",
|
||||
prod: "Production",
|
||||
test: "Testing",
|
||||
};
|
||||
|
||||
const Integration = ({projectIntegration}) => {
|
||||
const [integrationEnvironment, setIntegrationEnvironment] = useState(reverseEnvMapping[projectIntegration.environment]);
|
||||
const Integration = ({ projectIntegration }) => {
|
||||
const [integrationEnvironment, setIntegrationEnvironment] = useState(
|
||||
reverseEnvMapping[projectIntegration.environment]
|
||||
);
|
||||
const [fileState, setFileState] = useState([]);
|
||||
const [data, setData] = useState();
|
||||
const [isKeyAvailable, setIsKeyAvailable] = useState(true);
|
||||
const router = useRouter();
|
||||
const [apps, setApps] = useState([]);
|
||||
const [integrationApp, setIntegrationApp] = useState(projectIntegration.app ? projectIntegration.app : apps[0]);
|
||||
const [integrationApp, setIntegrationApp] = useState(
|
||||
projectIntegration.app ? projectIntegration.app : apps[0]
|
||||
);
|
||||
|
||||
useEffect(async () => {
|
||||
const tempHerokuApps = await getIntegrationApps({integrationAuthId: projectIntegration.integrationAuth});
|
||||
const tempHerokuAppNames = tempHerokuApps.map(app => app.name);
|
||||
const tempHerokuApps = await getIntegrationApps({
|
||||
integrationAuthId: projectIntegration.integrationAuth,
|
||||
});
|
||||
const tempHerokuAppNames = tempHerokuApps.map((app) => app.name);
|
||||
setApps(tempHerokuAppNames);
|
||||
setIntegrationApp(projectIntegration.app ? projectIntegration.app : tempHerokuAppNames[0])
|
||||
setIntegrationApp(
|
||||
projectIntegration.app
|
||||
? projectIntegration.app
|
||||
: tempHerokuAppNames[0]
|
||||
);
|
||||
}, []);
|
||||
|
||||
|
||||
return <div className="flex flex-col max-w-5xl justify-center bg-white/5 p-6 rounded-md mx-6 mt-8">
|
||||
<div className="relative px-4 flex flex-row items-center justify-between mb-4">
|
||||
<div className="flex flex-row">
|
||||
<div>
|
||||
<div className="text-gray-400 self-start ml-1 mb-1 text-xs font-semibold tracking-wide">
|
||||
ENVIRONMENT
|
||||
</div>
|
||||
<ListBox
|
||||
data={!projectIntegration.isActive && ["Development", "Staging", "Production"]}
|
||||
selected={integrationEnvironment}
|
||||
onChange={setIntegrationEnvironment}
|
||||
/>
|
||||
</div>
|
||||
<FontAwesomeIcon
|
||||
icon={faArrowRight}
|
||||
className="mx-4 text-gray-400 mt-8"
|
||||
/>
|
||||
<div className="mr-2">
|
||||
<div className="text-gray-400 self-start ml-1 mb-1 text-xs font-semibold tracking-wide">
|
||||
INTEGRATION
|
||||
</div>
|
||||
<div className="py-2.5 bg-white/[.07] rounded-md pl-4 pr-20 text-sm font-semibold text-gray-300">
|
||||
{projectIntegration.integration.charAt(0).toUpperCase() + projectIntegration.integration.slice(1)}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-gray-400 self-start ml-1 mb-1 text-xs font-semibold tracking-wide">
|
||||
HEROKU APP
|
||||
</div>
|
||||
<ListBox
|
||||
data={!projectIntegration.isActive && apps}
|
||||
selected={integrationApp}
|
||||
onChange={setIntegrationApp}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row mt-6">
|
||||
{projectIntegration.isActive
|
||||
? <div className="max-w-5xl flex flex-row items-center bg-white/5 p-2 rounded-md px-4">
|
||||
<FontAwesomeIcon icon={faRotate} className="text-lg mr-2.5 text-primary animate-spin"/>
|
||||
<div className="text-gray-300 font-semibold">In Sync</div>
|
||||
</div>
|
||||
: <Button
|
||||
text="Start Integration"
|
||||
onButtonPressed={async () => {
|
||||
const result = await startIntegration({
|
||||
"integrationId": projectIntegration._id,
|
||||
"environment": envMapping[integrationEnvironment],
|
||||
"appName": integrationApp
|
||||
})
|
||||
if (result?.status == 200) {
|
||||
let currentSecrets = await getSecretsForProject({
|
||||
env: integrationEnvironment,
|
||||
setFileState,
|
||||
setIsKeyAvailable,
|
||||
setData,
|
||||
workspaceId: router.query.id
|
||||
})
|
||||
|
||||
let obj = Object.assign(
|
||||
{},
|
||||
...currentSecrets.map((row) => ({ [row[2]]: row[3] }))
|
||||
);
|
||||
await pushKeysIntegration({obj, integrationId: projectIntegration._id});
|
||||
router.reload();
|
||||
return (
|
||||
<div className="flex flex-col max-w-5xl justify-center bg-white/5 p-6 rounded-md mx-6 mt-8">
|
||||
<div className="relative px-4 flex flex-row items-center justify-between mb-4">
|
||||
<div className="flex flex-row">
|
||||
<div>
|
||||
<div className="text-gray-400 self-start ml-1 mb-1 text-xs font-semibold tracking-wide">
|
||||
ENVIRONMENT
|
||||
</div>
|
||||
<ListBox
|
||||
data={
|
||||
!projectIntegration.isActive && [
|
||||
"Development",
|
||||
"Staging",
|
||||
"Production",
|
||||
]
|
||||
}
|
||||
}}
|
||||
color="mineshaft"
|
||||
size="md"
|
||||
selected={integrationEnvironment}
|
||||
onChange={setIntegrationEnvironment}
|
||||
/>
|
||||
</div>
|
||||
<FontAwesomeIcon
|
||||
icon={faArrowRight}
|
||||
className="mx-4 text-gray-400 mt-8"
|
||||
/>
|
||||
}
|
||||
<div className="mr-2">
|
||||
<div className="text-gray-400 self-start ml-1 mb-1 text-xs font-semibold tracking-wide">
|
||||
INTEGRATION
|
||||
</div>
|
||||
<div className="py-2.5 bg-white/[.07] rounded-md pl-4 pr-20 text-sm font-semibold text-gray-300">
|
||||
{projectIntegration.integration
|
||||
.charAt(0)
|
||||
.toUpperCase() +
|
||||
projectIntegration.integration.slice(1)}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-gray-400 self-start ml-1 mb-1 text-xs font-semibold tracking-wide">
|
||||
HEROKU APP
|
||||
</div>
|
||||
<ListBox
|
||||
data={!projectIntegration.isActive && apps}
|
||||
selected={integrationApp}
|
||||
onChange={setIntegrationApp}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row mt-6">
|
||||
{projectIntegration.isActive ? (
|
||||
<div className="max-w-5xl flex flex-row items-center bg-white/5 p-2 rounded-md px-4">
|
||||
<FontAwesomeIcon
|
||||
icon={faRotate}
|
||||
className="text-lg mr-2.5 text-primary animate-spin"
|
||||
/>
|
||||
<div className="text-gray-300 font-semibold">
|
||||
In Sync
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<Button
|
||||
text="Start Integration"
|
||||
onButtonPressed={async () => {
|
||||
const result = await startIntegration({
|
||||
integrationId: projectIntegration._id,
|
||||
environment:
|
||||
envMapping[integrationEnvironment],
|
||||
appName: integrationApp,
|
||||
});
|
||||
if (result?.status == 200) {
|
||||
let currentSecrets =
|
||||
await getSecretsForProject({
|
||||
env: integrationEnvironment,
|
||||
setFileState,
|
||||
setIsKeyAvailable,
|
||||
setData,
|
||||
workspaceId: router.query.id,
|
||||
});
|
||||
|
||||
let obj = Object.assign(
|
||||
{},
|
||||
...currentSecrets.map((row) => ({
|
||||
[row[2]]: row[3],
|
||||
}))
|
||||
);
|
||||
await pushKeysIntegration({
|
||||
obj,
|
||||
integrationId: projectIntegration._id,
|
||||
});
|
||||
router.reload();
|
||||
}
|
||||
}}
|
||||
color="mineshaft"
|
||||
size="md"
|
||||
/>
|
||||
)}
|
||||
<div className="opacity-50 hover:opacity-100 duration-200 ml-2">
|
||||
<Button
|
||||
onButtonPressed={async () => {
|
||||
await deleteIntegration({integrationId: projectIntegration._id});
|
||||
await deleteIntegration({
|
||||
integrationId: projectIntegration._id,
|
||||
});
|
||||
router.reload();
|
||||
}}
|
||||
color="red"
|
||||
@@ -134,9 +173,10 @@ const Integration = ({projectIntegration}) => {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default function Integrations() {
|
||||
const [integrations, setIntegrations] = useState();
|
||||
@@ -150,12 +190,16 @@ export default function Integrations() {
|
||||
setCsrfToken(tempCSRFToken);
|
||||
localStorage.setItem("latestCSRFToken", tempCSRFToken);
|
||||
|
||||
let projectAuthorizations = await getWorkspaceAuthorizations({workspaceId: router.query.id});
|
||||
let projectAuthorizations = await getWorkspaceAuthorizations({
|
||||
workspaceId: router.query.id,
|
||||
});
|
||||
setAuthorizations(projectAuthorizations);
|
||||
|
||||
const projectIntegrations = await getWorkspaceIntegrations({workspaceId: router.query.id});
|
||||
const projectIntegrations = await getWorkspaceIntegrations({
|
||||
workspaceId: router.query.id,
|
||||
});
|
||||
setProjectIntegrations(projectIntegrations);
|
||||
|
||||
|
||||
try {
|
||||
const integrationsData = await getIntegrations();
|
||||
setIntegrations(integrationsData);
|
||||
@@ -181,7 +225,10 @@ export default function Integrations() {
|
||||
</Head>
|
||||
<div className="flex flex-row">
|
||||
<div className="w-full max-h-96 pb-2 h-screen max-h-[calc(100vh-10px)] overflow-y-scroll no-scrollbar no-scrollbar::-webkit-scrollbar">
|
||||
<NavHeader pageName="Project Integrations" isProjectRelated={true}/>
|
||||
<NavHeader
|
||||
pageName="Project Integrations"
|
||||
isProjectRelated={true}
|
||||
/>
|
||||
<div className="flex flex-col justify-between items-start mx-4 mt-6 mb-4 text-xl max-w-5xl px-2">
|
||||
<div className="flex flex-row justify-start items-center text-3xl">
|
||||
<p className="font-semibold mr-4">
|
||||
@@ -189,24 +236,31 @@ export default function Integrations() {
|
||||
</p>
|
||||
</div>
|
||||
<p className="mr-4 text-base text-gray-400">
|
||||
Manage your integrations of Infisical with third-party services.
|
||||
Manage your integrations of Infisical with
|
||||
third-party services.
|
||||
</p>
|
||||
</div>
|
||||
{projectIntegrations.length > 0
|
||||
? projectIntegrations.map(projectIntegration =>
|
||||
<Integration key={guidGenerator()} projectIntegration={projectIntegration} />
|
||||
)
|
||||
: <div className="flex flex-col max-w-5xl justify-center bg-white/5 p-6 rounded-md mx-6 mt-8">
|
||||
{projectIntegrations.length > 0 ? (
|
||||
projectIntegrations.map((projectIntegration) => (
|
||||
<Integration
|
||||
key={guidGenerator()}
|
||||
projectIntegration={projectIntegration}
|
||||
/>
|
||||
))
|
||||
) : (
|
||||
<div className="flex flex-col max-w-5xl justify-center bg-white/5 p-6 rounded-md mx-6 mt-8">
|
||||
<div className="relative px-4 flex flex-col text-gray-400 items-center justify-center">
|
||||
<div className="mb-1">
|
||||
You don't have any integrations set up yet. When you do, they will appear here.
|
||||
You don't have any integrations set up yet.
|
||||
When you do, they will appear here.
|
||||
</div>
|
||||
<div className="">
|
||||
To start, click on any of the options below. It takes 5 clicks to set up.
|
||||
To start, click on any of the options below.
|
||||
It takes 5 clicks to set up.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
<div className="flex flex-col justify-between items-start mx-4 mt-12 mb-4 text-xl max-w-5xl px-2">
|
||||
<div className="flex flex-row justify-start items-center text-3xl">
|
||||
<p className="font-semibold mr-4">
|
||||
@@ -214,50 +268,151 @@ export default function Integrations() {
|
||||
</p>
|
||||
</div>
|
||||
<p className="mr-4 text-base text-gray-400">
|
||||
Click on the itegration you want to connect. This will let your environment variables flow automatically into selected third-party services.
|
||||
Click on the itegration you want to connect. This
|
||||
will let your environment variables flow
|
||||
automatically into selected third-party services.
|
||||
</p>
|
||||
<p className="mr-4 text-xs text-gray-600 mt-1">
|
||||
Note: during an integration with Heroku, for security reasons, it is impossible to maintain end-to-end encryption. In theory, this lets Infisical decrypt yor environment variables. In practice, we can assure you that this will never be done, and it allows us to protect your secrets from bad actors online. The core Infisical service will always stay end-to-end encrypted. With any questions, reach out support@infisical.com.
|
||||
Note: during an integration with Heroku, for
|
||||
security reasons, it is impossible to maintain
|
||||
end-to-end encryption. In theory, this lets
|
||||
Infisical decrypt yor environment variables. In
|
||||
practice, we can assure you that this will never be
|
||||
done, and it allows us to protect your secrets from
|
||||
bad actors online. The core Infisical service will
|
||||
always stay end-to-end encrypted. With any
|
||||
questions, reach out support@infisical.com.
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid gap-4 grid-cols-3 grid-rows-3 mx-6 mt-4 max-w-5xl">
|
||||
{Object.keys(integrations).map(integration =>
|
||||
<div className={`relative ${["Heroku"].includes(integrations[integration].name) ? "" : "opacity-50"}`} key={integrations[integration].name} >
|
||||
<a
|
||||
href={`${["Heroku"].includes(integrations[integration].name) ? `https://id.heroku.com/oauth/authorize?client_id=bc132901-935a-4590-b010-f1857efc380d&response_type=code&scope=write-protected&state=${csrfToken}` : "#"}`}
|
||||
{Object.keys(integrations).map((integration) => (
|
||||
<div
|
||||
className={`relative ${
|
||||
["Heroku"].includes(
|
||||
integrations[integration].name
|
||||
)
|
||||
? ""
|
||||
: "opacity-50"
|
||||
}`}
|
||||
key={integrations[integration].name}
|
||||
>
|
||||
<a
|
||||
href={`${
|
||||
["Heroku"].includes(
|
||||
integrations[integration].name
|
||||
)
|
||||
? `https://id.heroku.com/oauth/authorize?client_id=bc132901-935a-4590-b010-f1857efc380d&response_type=code&scope=write-protected&state=${csrfToken}`
|
||||
: "#"
|
||||
}`}
|
||||
rel="noopener"
|
||||
className={`relative flex flex-row bg-white/5 h-32 rounded-md p-4 items-center ${["Heroku"].includes(integrations[integration].name) ? "hover:bg-white/10 duration-200 cursor-pointer" : "cursor-default grayscale"}`}>
|
||||
className={`relative flex flex-row bg-white/5 h-32 rounded-md p-4 items-center ${
|
||||
["Heroku"].includes(
|
||||
integrations[integration].name
|
||||
)
|
||||
? "hover:bg-white/10 duration-200 cursor-pointer"
|
||||
: "cursor-default grayscale"
|
||||
}`}
|
||||
>
|
||||
<Image
|
||||
src={`/images/integrations/${integrations[integration].name}.png`}
|
||||
height={100}
|
||||
width={100}
|
||||
alt="integration logo"
|
||||
></Image>
|
||||
{integrations[integration].name.split(" ").length > 2
|
||||
? <div className="font-semibold text-gray-300 group-hover:text-gray-200 duration-200 text-3xl ml-8 max-w-xs">
|
||||
<div>{integrations[integration].name.split(" ")[0]}</div>
|
||||
<div className="text-base">{integrations[integration].name.split(" ")[1]}{" "}{integrations[integration].name.split(" ")[2]}</div>
|
||||
{integrations[integration].name.split(" ")
|
||||
.length > 2 ? (
|
||||
<div className="font-semibold text-gray-300 group-hover:text-gray-200 duration-200 text-3xl ml-8 max-w-xs">
|
||||
<div>
|
||||
{
|
||||
integrations[
|
||||
integration
|
||||
].name.split(" ")[0]
|
||||
}
|
||||
</div>
|
||||
: <div className="font-semibold text-gray-300 group-hover:text-gray-200 duration-200 text-2xl ml-8 max-w-xs">{integrations[integration].name}</div>
|
||||
}
|
||||
|
||||
<div className="text-base">
|
||||
{
|
||||
integrations[
|
||||
integration
|
||||
].name.split(" ")[1]
|
||||
}{" "}
|
||||
{
|
||||
integrations[
|
||||
integration
|
||||
].name.split(" ")[2]
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="font-semibold text-gray-300 group-hover:text-gray-200 duration-200 text-2xl ml-8 max-w-xs">
|
||||
{integrations[integration].name}
|
||||
</div>
|
||||
)}
|
||||
</a>
|
||||
{["Heroku"].includes(integrations[integration].name) && authorizations.map(authorization => authorization.integration).includes(integrations[integration].name.toLowerCase()) &&
|
||||
{["Heroku"].includes(
|
||||
integrations[integration].name
|
||||
) &&
|
||||
authorizations
|
||||
.map(
|
||||
(authorization) =>
|
||||
authorization.integration
|
||||
)
|
||||
.includes(
|
||||
integrations[
|
||||
integration
|
||||
].name.toLowerCase()
|
||||
) && (
|
||||
<div className="absolute group z-50 top-0 right-0 flex flex-row">
|
||||
<div
|
||||
onClick={() => {
|
||||
deleteIntegrationAuth({
|
||||
integrationAuthId:
|
||||
authorizations
|
||||
.filter(
|
||||
(
|
||||
authorization
|
||||
) =>
|
||||
authorization.integration ==
|
||||
integrations[
|
||||
integration
|
||||
].name.toLowerCase()
|
||||
)
|
||||
.map(
|
||||
(
|
||||
authorization
|
||||
) =>
|
||||
authorization._id
|
||||
)[0],
|
||||
});
|
||||
router.reload();
|
||||
}}
|
||||
className="cursor-pointer w-max bg-red py-0.5 px-2 rounded-b-md text-xs flex flex-row items-center opacity-0 group-hover:opacity-100 duration-200"
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={faX}
|
||||
className="text-xs mr-2 py-px"
|
||||
/>
|
||||
Revoke
|
||||
</div>
|
||||
<div className="w-max bg-primary py-0.5 px-2 rounded-bl-md rounded-tr-md text-xs flex flex-row items-center text-black opacity-90 group-hover:opacity-100 duration-200">
|
||||
<FontAwesomeIcon
|
||||
icon={faCheck}
|
||||
className="text-xs mr-2"
|
||||
/>
|
||||
Authorized
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{!["Heroku"].includes(
|
||||
integrations[integration].name
|
||||
) && (
|
||||
<div className="absolute group z-50 top-0 right-0 flex flex-row">
|
||||
<div onClick={() => {
|
||||
deleteIntegrationAuth({integrationAuthId: authorizations.filter(authorization => authorization.integration == integrations[integration].name.toLowerCase()).map(authorization => authorization._id)[0]});
|
||||
router.reload();
|
||||
}} className="cursor-pointer w-max bg-red py-0.5 px-2 rounded-b-md text-xs flex flex-row items-center opacity-0 group-hover:opacity-100 duration-200"><FontAwesomeIcon icon={faX} className="text-xs mr-2 py-px"/>Revoke</div>
|
||||
<div className="w-max bg-primary py-0.5 px-2 rounded-bl-md rounded-tr-md text-xs flex flex-row items-center text-black opacity-90 group-hover:opacity-100 duration-200"><FontAwesomeIcon icon={faCheck} className="text-xs mr-2"/>Authorized</div>
|
||||
<div className="w-max bg-yellow py-0.5 px-2 rounded-bl-md rounded-tr-md text-xs flex flex-row items-center text-black opacity-90">
|
||||
Coming Soon
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
{!["Heroku"].includes(integrations[integration].name) &&
|
||||
<div className="absolute group z-50 top-0 right-0 flex flex-row">
|
||||
<div className="w-max bg-yellow py-0.5 px-2 rounded-bl-md rounded-tr-md text-xs flex flex-row items-center text-black opacity-90">Coming Soon</div>
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+27
-16
@@ -5,11 +5,11 @@ import Head from "next/head";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
import InputField from "../components/basic/InputField";
|
||||
import Error from "../components/basic/Error";
|
||||
import Button from "../components/basic/buttons/Button";
|
||||
import InputField from "~/components/basic/InputField";
|
||||
import Error from "~/components/basic/Error";
|
||||
import Button from "~/components/basic/buttons/Button";
|
||||
import getWorkspaces from "./api/workspace/getWorkspaces";
|
||||
import attemptLogin from "../components/utilities/attemptLogin";
|
||||
import attemptLogin from "~/utilities/attemptLogin";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faWarning } from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
@@ -36,13 +36,18 @@ export default function Login() {
|
||||
*/
|
||||
const loginCheck = async () => {
|
||||
setIsLoading(true);
|
||||
await attemptLogin(email, password, setErrorLogin, router, false, true).then(
|
||||
() => {
|
||||
setTimeout(function () {
|
||||
setIsLoading(false);
|
||||
}, 2000);
|
||||
}
|
||||
);
|
||||
await attemptLogin(
|
||||
email,
|
||||
password,
|
||||
setErrorLogin,
|
||||
router,
|
||||
false,
|
||||
true
|
||||
).then(() => {
|
||||
setTimeout(function () {
|
||||
setIsLoading(false);
|
||||
}, 2000);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -122,11 +127,17 @@ export default function Login() {
|
||||
<p className="text-gray-400">I may have <Link href="/login"><u className="text-sky-500 cursor-pointer">forgotten my password.</u></Link></p>
|
||||
</div> */}
|
||||
</div>
|
||||
{false &&
|
||||
{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"/>
|
||||
We are experiencing minor technical difficulties. We are working on solving it right now. Please come back in a few minutes.
|
||||
</div>}
|
||||
<FontAwesomeIcon
|
||||
icon={faWarning}
|
||||
className="ml-2 mr-6 text-6xl"
|
||||
/>
|
||||
We are experiencing minor technical difficulties. We are
|
||||
working on solving it right now. Please come back in a few
|
||||
minutes.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import Head from "next/head";
|
||||
import Plan from "../../../components/billing/Plan";
|
||||
import getOrganizationSubscriptions from "../../api/organization/GetOrgSubscription"
|
||||
import getOrganizationUsers from "../../api/organization/GetOrgUsers"
|
||||
import NavHeader from "../../../components/navigation/NavHeader";
|
||||
import { STRIPE_PRODUCT_PRO, STRIPE_PRODUCT_STARTER } from "../../../components/utilities/config";
|
||||
|
||||
import Plan from "~/components/billing/Plan";
|
||||
import getOrganizationSubscriptions from "../../api/organization/GetOrgSubscription";
|
||||
import getOrganizationUsers from "../../api/organization/GetOrgUsers";
|
||||
import NavHeader from "~/components/navigation/NavHeader";
|
||||
import { STRIPE_PRODUCT_PRO, STRIPE_PRODUCT_STARTER } from "~/utilities/config";
|
||||
|
||||
export default function SettingsBilling() {
|
||||
let [currentPlan, setCurrentPlan] = useState("");
|
||||
@@ -46,57 +45,62 @@ export default function SettingsBilling() {
|
||||
];
|
||||
|
||||
useEffect(async () => {
|
||||
const subscriptions = await getOrganizationSubscriptions({orgId: localStorage.getItem("orgData.id")});
|
||||
setCurrentPlan(subscriptions.data[0].plan.product)
|
||||
const orgUsers = await getOrganizationUsers({orgId: localStorage.getItem("orgData.id")})
|
||||
setNumUsers(orgUsers.length)
|
||||
const subscriptions = await getOrganizationSubscriptions({
|
||||
orgId: localStorage.getItem("orgData.id"),
|
||||
});
|
||||
setCurrentPlan(subscriptions.data[0].plan.product);
|
||||
const orgUsers = await getOrganizationUsers({
|
||||
orgId: localStorage.getItem("orgData.id"),
|
||||
});
|
||||
setNumUsers(orgUsers.length);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
|
||||
<Head>
|
||||
<title>Settings - Billing</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Head>
|
||||
<div className="flex flex-row">
|
||||
<div className="w-full max-h-screen pb-2 overflow-y-auto">
|
||||
<NavHeader pageName="Usage & Billing"/>
|
||||
<div className="flex flex-row justify-between items-center ml-6 my-8 text-xl max-w-5xl">
|
||||
<div className="flex flex-col justify-start items-start text-3xl">
|
||||
<p className="font-semibold mr-4 text-gray-200">
|
||||
Usage & Billing
|
||||
</p>
|
||||
<p className="font-normal mr-4 text-gray-400 text-base">
|
||||
View and manage your organization's subscription here.
|
||||
</p>
|
||||
</div>
|
||||
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
|
||||
<Head>
|
||||
<title>Settings - Billing</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Head>
|
||||
<div className="flex flex-row">
|
||||
<div className="w-full max-h-screen pb-2 overflow-y-auto">
|
||||
<NavHeader pageName="Usage & Billing" />
|
||||
<div className="flex flex-row justify-between items-center ml-6 my-8 text-xl max-w-5xl">
|
||||
<div className="flex flex-col justify-start items-start text-3xl">
|
||||
<p className="font-semibold mr-4 text-gray-200">
|
||||
Usage & Billing
|
||||
</p>
|
||||
<p className="font-normal mr-4 text-gray-400 text-base">
|
||||
View and manage your organization's subscription
|
||||
here.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col ml-6 text-mineshaft-50">
|
||||
<p className="text-xl font-semibold">Subscription</p>
|
||||
<div className="flex flex-row mt-4 overflow-x-auto">
|
||||
{plans.map((plan) => (
|
||||
<Plan
|
||||
key={plan.name}
|
||||
plan={plan}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex flex-col ml-6 text-mineshaft-50">
|
||||
<p className="text-xl font-semibold">Subscription</p>
|
||||
<div className="flex flex-row mt-4 overflow-x-auto">
|
||||
{plans.map((plan) => (
|
||||
<Plan key={plan.name} plan={plan} />
|
||||
))}
|
||||
</div>
|
||||
<p className="text-xl font-bold mt-12">Current Usage</p>
|
||||
<div className="flex flex-row">
|
||||
<div className="mr-4 mt-8 text-gray-300 w-60 pt-6 pb-10 rounded-md bg-white/5 flex justify-center items-center flex flex-col">
|
||||
<p className="text-6xl font-bold">{numUsers}</p>
|
||||
<p className="text-gray-300">
|
||||
{numUsers > 1
|
||||
? "Organization members"
|
||||
: "Organization member"}
|
||||
</p>
|
||||
</div>
|
||||
<p className='text-xl font-bold mt-12'>Current Usage</p>
|
||||
<div className="flex flex-row">
|
||||
<div className="mr-4 mt-8 text-gray-300 w-60 pt-6 pb-10 rounded-md bg-white/5 flex justify-center items-center flex flex-col">
|
||||
<p className="text-6xl font-bold">{numUsers}</p>
|
||||
<p className="text-gray-300">{numUsers > 1 ? "Organization members" : "Organization member"}</p>
|
||||
</div>
|
||||
{/* <div className="mr-4 mt-8 text-gray-300 w-60 pt-6 pb-10 rounded-md bg-white/5 flex justify-center items-center flex flex-col">
|
||||
{/* <div className="mr-4 mt-8 text-gray-300 w-60 pt-6 pb-10 rounded-md bg-white/5 flex justify-center items-center flex flex-col">
|
||||
<p className="text-6xl font-bold">1 </p>
|
||||
<p className="text-gray-300">Organization projects</p>
|
||||
</div> */}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,26 +2,29 @@ import React, { useState, useEffect } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import Head from "next/head";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faMagnifyingGlass, faPlus, faX } from "@fortawesome/free-solid-svg-icons";
|
||||
import {
|
||||
faMagnifyingGlass,
|
||||
faPlus,
|
||||
faX,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { faCheck } from "@fortawesome/free-solid-svg-icons";
|
||||
import InputField from "../../../components/basic/InputField";
|
||||
import InputField from "~/components/basic/InputField";
|
||||
import getWorkspaces from "../../api/workspace/getWorkspaces";
|
||||
import AddIncidentContactDialog from "../../../components/basic/dialog/AddIncidentContactDialog";
|
||||
import AddIncidentContactDialog from "~/components/basic/dialog/AddIncidentContactDialog";
|
||||
import getIncidentContacts from "../../api/organization/getIncidentContacts";
|
||||
import deleteIncidentContact from "../../api/organization/deleteIncidentContact";
|
||||
import deleteWorkspace from "../../api/workspace/deleteWorkspace";
|
||||
import AddUserDialog from "../../../components/basic/dialog/AddUserDialog";
|
||||
import UserTable from "../../../components/basic/table/UserTable";
|
||||
import AddUserDialog from "~/components/basic/dialog/AddUserDialog";
|
||||
import UserTable from "~/components/basic/table/UserTable";
|
||||
import getUser from "../../api/user/getUser";
|
||||
import guidGenerator from "../../../components/utilities/randomId";
|
||||
import guidGenerator from "~/utilities/randomId";
|
||||
import addUserToOrg from "../../api/organization/addUserToOrg";
|
||||
import getOrganizationUsers from "../../api/organization/GetOrgUsers";
|
||||
import renameOrg from "../../api/organization/renameOrg";
|
||||
import getOrganization from "../../api/organization/GetOrg";
|
||||
import getOrganizationSubscriptions from "../../api/organization/GetOrgSubscription";
|
||||
import NavHeader from "../../../components/navigation/NavHeader";
|
||||
import Button from "../../../components/basic/buttons/Button";
|
||||
|
||||
import NavHeader from "~/components/navigation/NavHeader";
|
||||
import Button from "~/components/basic/buttons/Button";
|
||||
|
||||
export default function SettingsOrg() {
|
||||
const [buttonReady, setButtonReady] = useState(false);
|
||||
@@ -51,12 +54,12 @@ export default function SettingsOrg() {
|
||||
});
|
||||
let orgData = org;
|
||||
setOrgName(orgData.name);
|
||||
let incidentContactsData = await getIncidentContacts(localStorage.getItem("orgData.id"));
|
||||
let incidentContactsData = await getIncidentContacts(
|
||||
localStorage.getItem("orgData.id")
|
||||
);
|
||||
|
||||
setIncidentContacts(
|
||||
incidentContactsData?.map(
|
||||
(contact) => contact.email
|
||||
)
|
||||
incidentContactsData?.map((contact) => contact.email)
|
||||
);
|
||||
|
||||
const user = await getUser();
|
||||
@@ -82,8 +85,10 @@ export default function SettingsOrg() {
|
||||
publicKey: user.user?.publicKey,
|
||||
}))
|
||||
);
|
||||
const subscriptions = await getOrganizationSubscriptions({orgId: localStorage.getItem("orgData.id")});
|
||||
setCurrentPlan(subscriptions.data[0].plan.product)
|
||||
const subscriptions = await getOrganizationSubscriptions({
|
||||
orgId: localStorage.getItem("orgData.id"),
|
||||
});
|
||||
setCurrentPlan(subscriptions.data[0].plan.product);
|
||||
}, []);
|
||||
|
||||
const modifyOrgName = (newName) => {
|
||||
@@ -127,7 +132,10 @@ export default function SettingsOrg() {
|
||||
setIncidentContacts(
|
||||
incidentContacts.filter((contact) => contact != incidentContact)
|
||||
);
|
||||
deleteIncidentContact(localStorage.getItem("orgData.id"), incidentContact);
|
||||
deleteIncidentContact(
|
||||
localStorage.getItem("orgData.id"),
|
||||
incidentContact
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -160,7 +168,7 @@ export default function SettingsOrg() {
|
||||
</Head>
|
||||
<div className="flex flex-row">
|
||||
<div className="w-full max-h-screen pb-2 overflow-y-auto">
|
||||
<NavHeader pageName="Organization Settings"/>
|
||||
<NavHeader pageName="Organization Settings" />
|
||||
<AddIncidentContactDialog
|
||||
isOpen={isAddIncidentContactOpen}
|
||||
closeModal={closeAddIncidentContactModal}
|
||||
@@ -201,7 +209,9 @@ export default function SettingsOrg() {
|
||||
>
|
||||
<Button
|
||||
text="Save Changes"
|
||||
onButtonPressed={() => submitChanges(orgName)}
|
||||
onButtonPressed={() =>
|
||||
submitChanges(orgName)
|
||||
}
|
||||
color="mineshaft"
|
||||
size="md"
|
||||
active={buttonReady}
|
||||
@@ -289,7 +299,9 @@ export default function SettingsOrg() {
|
||||
<div className="mt-4 mb-2 min-w-max flex flex-row items-end justify-end justify-center">
|
||||
<Button
|
||||
text="Add Contact"
|
||||
onButtonPressed={openAddIncidentContactModal}
|
||||
onButtonPressed={
|
||||
openAddIncidentContactModal
|
||||
}
|
||||
color="mineshaft"
|
||||
size="md"
|
||||
icon={faPlus}
|
||||
@@ -318,7 +330,10 @@ export default function SettingsOrg() {
|
||||
email.includes(searchIncidentContact)
|
||||
)
|
||||
.map((contact) => (
|
||||
<div key={guidGenerator()} className="flex flex-row items-center justify-between max-w-5xl px-4 py-3 hover:bg-white/5 border-t border-gray-600 w-full">
|
||||
<div
|
||||
key={guidGenerator()}
|
||||
className="flex flex-row items-center justify-between max-w-5xl px-4 py-3 hover:bg-white/5 border-t border-gray-600 w-full"
|
||||
>
|
||||
<p className="text-gray-300">
|
||||
{contact}
|
||||
</p>
|
||||
|
||||
@@ -2,14 +2,13 @@ import React, { useState, useEffect } from "react";
|
||||
import Head from "next/head";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faCheck, faX } from "@fortawesome/free-solid-svg-icons";
|
||||
import InputField from "../../../components/basic/InputField";
|
||||
import InputField from "~/components/basic/InputField";
|
||||
import getUser from "../../api/user/getUser";
|
||||
import NavHeader from "../../../components/navigation/NavHeader";
|
||||
import passwordCheck from "../../../components/utilities/checks/PasswordCheck";
|
||||
import changePassword from "../../../components/utilities/changePassword";
|
||||
import issueBackupKey from "../../../components/utilities/issueBackupKey";
|
||||
import Button from "../../../components/basic/buttons/Button";
|
||||
|
||||
import NavHeader from "~/components/navigation/NavHeader";
|
||||
import passwordCheck from "~/utilities/checks/PasswordCheck";
|
||||
import changePassword from "~/utilities/changePassword";
|
||||
import issueBackupKey from "~/utilities/issueBackupKey";
|
||||
import Button from "~/components/basic/buttons/Button";
|
||||
|
||||
export default function PersonalSettings() {
|
||||
const [personalEmail, setPersonalEmail] = useState("");
|
||||
@@ -31,8 +30,6 @@ export default function PersonalSettings() {
|
||||
setPersonalName(user.firstName + " " + user.lastName);
|
||||
}, []);
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
|
||||
<Head>
|
||||
@@ -41,7 +38,10 @@ export default function PersonalSettings() {
|
||||
</Head>
|
||||
<div className="flex flex-row">
|
||||
<div className="w-full max-h-screen pb-2 overflow-y-auto">
|
||||
<NavHeader pageName="Personal Settings" isProjectRelated={false}/>
|
||||
<NavHeader
|
||||
pageName="Personal Settings"
|
||||
isProjectRelated={false}
|
||||
/>
|
||||
<div className="flex flex-row justify-between items-center ml-6 mt-8 mb-6 text-xl max-w-5xl">
|
||||
<div className="flex flex-col justify-start items-start text-3xl">
|
||||
<p className="font-semibold mr-4 text-gray-200">
|
||||
@@ -137,52 +137,133 @@ export default function PersonalSettings() {
|
||||
type="password"
|
||||
value={newPassword}
|
||||
isRequired
|
||||
error={passwordErrorLength && passwordErrorLowerCase && passwordErrorNumber}
|
||||
error={
|
||||
passwordErrorLength &&
|
||||
passwordErrorLowerCase &&
|
||||
passwordErrorNumber
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
{(passwordErrorLength || passwordErrorLowerCase || passwordErrorNumber) ? <div className="w-full mt-3 bg-white/5 px-2 flex flex-col items-start py-2 rounded-md max-w-xl mb-2">
|
||||
<div className={`text-gray-400 text-sm mb-1`}>Password should contain at least:</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
{passwordErrorLength
|
||||
? <FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5"/>
|
||||
: <FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2"/>}
|
||||
<div className={`${passwordErrorLength ? "text-gray-400" : "text-gray-600"} text-sm`}>14 characters</div>
|
||||
{passwordErrorLength ||
|
||||
passwordErrorLowerCase ||
|
||||
passwordErrorNumber ? (
|
||||
<div className="w-full mt-3 bg-white/5 px-2 flex flex-col items-start py-2 rounded-md max-w-xl mb-2">
|
||||
<div
|
||||
className={`text-gray-400 text-sm mb-1`}
|
||||
>
|
||||
Password should contain at least:
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
{passwordErrorLength ? (
|
||||
<FontAwesomeIcon
|
||||
icon={faX}
|
||||
className="text-md text-red mr-2.5"
|
||||
/>
|
||||
) : (
|
||||
<FontAwesomeIcon
|
||||
icon={faCheck}
|
||||
className="text-md text-primary mr-2"
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
className={`${
|
||||
passwordErrorLength
|
||||
? "text-gray-400"
|
||||
: "text-gray-600"
|
||||
} text-sm`}
|
||||
>
|
||||
14 characters
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
{passwordErrorLowerCase ? (
|
||||
<FontAwesomeIcon
|
||||
icon={faX}
|
||||
className="text-md text-red mr-2.5"
|
||||
/>
|
||||
) : (
|
||||
<FontAwesomeIcon
|
||||
icon={faCheck}
|
||||
className="text-md text-primary mr-2"
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
className={`${
|
||||
passwordErrorLowerCase
|
||||
? "text-gray-400"
|
||||
: "text-gray-600"
|
||||
} text-sm`}
|
||||
>
|
||||
1 lowercase character
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
{passwordErrorNumber ? (
|
||||
<FontAwesomeIcon
|
||||
icon={faX}
|
||||
className="text-md text-red mr-2.5"
|
||||
/>
|
||||
) : (
|
||||
<FontAwesomeIcon
|
||||
icon={faCheck}
|
||||
className="text-md text-primary mr-2"
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
className={`${
|
||||
passwordErrorNumber
|
||||
? "text-gray-400"
|
||||
: "text-gray-600"
|
||||
} text-sm`}
|
||||
>
|
||||
1 number
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
{passwordErrorLowerCase
|
||||
? <FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5"/>
|
||||
: <FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2"/>}
|
||||
<div className={`${passwordErrorLowerCase ? "text-gray-400" : "text-gray-600"} text-sm`}>1 lowercase character</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
{passwordErrorNumber
|
||||
? <FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5"/>
|
||||
: <FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2"/>}
|
||||
<div className={`${passwordErrorNumber ? "text-gray-400" : "text-gray-600"} text-sm`}>1 number</div>
|
||||
</div>
|
||||
</div> : <div className="py-2"></div>}
|
||||
) : (
|
||||
<div className="py-2"></div>
|
||||
)}
|
||||
<div className="flex flex-row items-center mt-3 w-52 pr-3">
|
||||
<Button
|
||||
text="Change Password"
|
||||
onButtonPressed={() => {
|
||||
if (!passwordErrorLength && !passwordErrorLowerCase && !passwordErrorNumber) {
|
||||
if (
|
||||
!passwordErrorLength &&
|
||||
!passwordErrorLowerCase &&
|
||||
!passwordErrorNumber
|
||||
) {
|
||||
changePassword(
|
||||
personalEmail,
|
||||
currentPassword,
|
||||
personalEmail,
|
||||
currentPassword,
|
||||
newPassword,
|
||||
setCurrentPasswordError,
|
||||
setPasswordChanged,
|
||||
setCurrentPassword,
|
||||
setNewPassword
|
||||
)
|
||||
);
|
||||
}
|
||||
}}
|
||||
color="mineshaft"
|
||||
size="md"
|
||||
active={(newPassword != "") && (currentPassword != "") && !(passwordErrorLength || passwordErrorLowerCase || passwordErrorNumber)}
|
||||
active={
|
||||
newPassword != "" &&
|
||||
currentPassword != "" &&
|
||||
!(
|
||||
passwordErrorLength ||
|
||||
passwordErrorLowerCase ||
|
||||
passwordErrorNumber
|
||||
)
|
||||
}
|
||||
textDisabled="Change Password"
|
||||
/>
|
||||
<FontAwesomeIcon icon={faCheck} className={`ml-4 text-primary text-3xl ${passwordChanged ? "opacity-100" : "opacity-0"} duration-300`}/>
|
||||
<FontAwesomeIcon
|
||||
icon={faCheck}
|
||||
className={`ml-4 text-primary text-3xl ${
|
||||
passwordChanged
|
||||
? "opacity-100"
|
||||
: "opacity-0"
|
||||
} duration-300`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -193,10 +274,14 @@ export default function PersonalSettings() {
|
||||
Emergency Kit
|
||||
</p>
|
||||
<p className="text-sm text-mineshaft-300 min-w-max">
|
||||
Your Emergency Kit contains the information you’ll need to sign in to your Infisical account.
|
||||
Your Emergency Kit contains the
|
||||
information you’ll need to sign in to
|
||||
your Infisical account.
|
||||
</p>
|
||||
<p className="text-sm text-mineshaft-300 mb-5 min-w-max">
|
||||
Only the latest issued Emergency Kit remains valid. To get a new Emergency Kit, verify your password.
|
||||
Only the latest issued Emergency Kit
|
||||
remains valid. To get a new Emergency
|
||||
Kit, verify your password.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -216,11 +301,11 @@ export default function PersonalSettings() {
|
||||
text="Download Emergency Kit"
|
||||
onButtonPressed={() => {
|
||||
issueBackupKey({
|
||||
email: personalEmail,
|
||||
password: backupPassword,
|
||||
personalName,
|
||||
email: personalEmail,
|
||||
password: backupPassword,
|
||||
personalName,
|
||||
setBackupKeyError,
|
||||
setBackupKeyIssued
|
||||
setBackupKeyIssued,
|
||||
});
|
||||
}}
|
||||
color="mineshaft"
|
||||
@@ -228,7 +313,14 @@ export default function PersonalSettings() {
|
||||
active={backupPassword != ""}
|
||||
textDisabled="Download Emergency Kit"
|
||||
/>
|
||||
<FontAwesomeIcon icon={faCheck} className={`ml-4 text-primary text-3xl ${backupKeyIssued ? "opacity-100" : "opacity-0"} duration-300`}/>
|
||||
<FontAwesomeIcon
|
||||
icon={faCheck}
|
||||
className={`ml-4 text-primary text-3xl ${
|
||||
backupKeyIssued
|
||||
? "opacity-100"
|
||||
: "opacity-0"
|
||||
} duration-300`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,15 +3,15 @@ import { useRouter } from "next/router";
|
||||
import Head from "next/head";
|
||||
|
||||
import { faCheck, faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||
import InputField from "../../../components/basic/InputField";
|
||||
import InputField from "~/components/basic/InputField";
|
||||
import getWorkspaces from "../../api/workspace/getWorkspaces";
|
||||
import renameWorkspace from "../../api/workspace/renameWorkspace";
|
||||
import deleteWorkspace from "../../api/workspace/deleteWorkspace";
|
||||
import NavHeader from "../../../components/navigation/NavHeader";
|
||||
import Button from "../../../components/basic/buttons/Button";
|
||||
import ServiceTokenTable from "../../../components/basic/table/ServiceTokenTable";
|
||||
import getServiceTokens from "../../api/serviceToken/getServiceTokens"
|
||||
import AddServiceTokenDialog from "../../../components/basic/dialog/AddServiceTokenDialog";
|
||||
import NavHeader from "~/components/navigation/NavHeader";
|
||||
import Button from "~/components/basic/buttons/Button";
|
||||
import ServiceTokenTable from "~/components/basic/table/ServiceTokenTable";
|
||||
import getServiceTokens from "../../api/serviceToken/getServiceTokens";
|
||||
import AddServiceTokenDialog from "~/components/basic/dialog/AddServiceTokenDialog";
|
||||
|
||||
export default function SettingsBasic() {
|
||||
const [buttonReady, setButtonReady] = useState(false);
|
||||
@@ -22,7 +22,8 @@ export default function SettingsBasic() {
|
||||
useState("");
|
||||
const [workspaceId, setWorkspaceId] = useState("");
|
||||
const [isAddOpen, setIsAddOpen] = useState(false);
|
||||
let [isAddServiceTokenDialogOpen, setIsAddServiceTokenDialogOpen] = useState(false);
|
||||
let [isAddServiceTokenDialogOpen, setIsAddServiceTokenDialogOpen] =
|
||||
useState(false);
|
||||
|
||||
useEffect(async () => {
|
||||
let userWorkspaces = await getWorkspaces();
|
||||
@@ -31,7 +32,9 @@ export default function SettingsBasic() {
|
||||
setWorkspaceName(userWorkspace.name);
|
||||
}
|
||||
});
|
||||
let tempServiceTokens = await getServiceTokens({workspaceId: router.query.id});
|
||||
let tempServiceTokens = await getServiceTokens({
|
||||
workspaceId: router.query.id,
|
||||
});
|
||||
setServiceTokens(tempServiceTokens);
|
||||
}, []);
|
||||
|
||||
@@ -59,8 +62,8 @@ export default function SettingsBasic() {
|
||||
|
||||
const closeAddServiceTokenModal = () => {
|
||||
setIsAddServiceTokenDialogOpen(false);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* This function deleted a workspace.
|
||||
* It first checks if there is more than one workspace aviable. Otherwise, it doesn't delete
|
||||
@@ -97,7 +100,10 @@ export default function SettingsBasic() {
|
||||
/>
|
||||
<div className="flex flex-row mr-6 max-w-5xl">
|
||||
<div className="w-full max-h-screen pb-2 overflow-y-auto">
|
||||
<NavHeader pageName="Project Settings" isProjectRelated={true}/>
|
||||
<NavHeader
|
||||
pageName="Project Settings"
|
||||
isProjectRelated={true}
|
||||
/>
|
||||
<div className="flex flex-row justify-between items-center ml-6 my-8 text-xl max-w-5xl">
|
||||
<div className="flex flex-col justify-start items-start text-3xl">
|
||||
<p className="font-semibold mr-4 text-gray-200">
|
||||
@@ -133,7 +139,9 @@ export default function SettingsBasic() {
|
||||
>
|
||||
<Button
|
||||
text="Save Changes"
|
||||
onButtonPressed={() => submitChanges(workspaceName)}
|
||||
onButtonPressed={() =>
|
||||
submitChanges(workspaceName)
|
||||
}
|
||||
color="mineshaft"
|
||||
size="md"
|
||||
active={buttonReady}
|
||||
@@ -184,20 +192,30 @@ export default function SettingsBasic() {
|
||||
Service Tokens
|
||||
</p>
|
||||
<p className="text-base text-gray-400 mb-4">
|
||||
Every service token is specific to you, a certain project and a certain environment within this project.
|
||||
Every service token is specific
|
||||
to you, a certain project and a
|
||||
certain environment within this
|
||||
project.
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-48">
|
||||
<Button
|
||||
text="Add New Token"
|
||||
onButtonPressed={() => {setIsAddServiceTokenDialogOpen(true)}}
|
||||
onButtonPressed={() => {
|
||||
setIsAddServiceTokenDialogOpen(
|
||||
true
|
||||
);
|
||||
}}
|
||||
color="mineshaft"
|
||||
icon={faPlus}
|
||||
size="md"
|
||||
/>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<ServiceTokenTable data={serviceTokens} workspaceName={workspaceName}/>
|
||||
<ServiceTokenTable
|
||||
data={serviceTokens}
|
||||
workspaceName={workspaceName}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* <div className="bg-white/5 rounded-md px-6 flex flex-col items-start flex flex-col items-start w-full mb-6 mt-4 pb-6 pt-6">
|
||||
|
||||
+156
-59
@@ -6,19 +6,19 @@ import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
import InputField from "../components/basic/InputField";
|
||||
import Error from "../components/basic/Error";
|
||||
import Button from "../components/basic/buttons/Button";
|
||||
import InputField from "~/compoennts/basic/InputField";
|
||||
import Error from "~/compoennts/basic/Error";
|
||||
import Button from "~/compoennts/basic/buttons/Button";
|
||||
import sendVerificationEmail from "./api/auth/SendVerificationEmail";
|
||||
import checkEmailVerificationCode from "./api/auth/CheckEmailVerificationCode";
|
||||
import completeAccountInformationSignup from "./api/auth/CompleteAccountInformationSignup";
|
||||
import Aes256Gcm from "../components/aes-256-gcm";
|
||||
import passwordCheck from "../components/utilities/checks/PasswordCheck";
|
||||
import Aes256Gcm from "~/compoennts/aes-256-gcm";
|
||||
import passwordCheck from "~/compoennts/utilities/checks/PasswordCheck";
|
||||
import getWorkspaces from "./api/workspace/getWorkspaces";
|
||||
import attemptLogin from "../components/utilities/attemptLogin";
|
||||
import attemptLogin from "~/compoennts/utilities/attemptLogin";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faCheck, faX, faWarning } from "@fortawesome/free-solid-svg-icons";
|
||||
import issueBackupKey from "../components/utilities/issueBackupKey";
|
||||
import issueBackupKey from "~/compoennts/utilities/issueBackupKey";
|
||||
|
||||
const ReactCodeInput = dynamic(import("react-code-input"));
|
||||
const nacl = require("tweetnacl");
|
||||
@@ -73,7 +73,8 @@ export default function SignUp() {
|
||||
const [passwordErrorNumber, setPasswordErrorNumber] = useState(false);
|
||||
const [passwordErrorUpperCase, setPasswordErrorUpperCase] = useState(false);
|
||||
const [passwordErrorLowerCase, setPasswordErrorLowerCase] = useState(false);
|
||||
const [passwordErrorSpecialChar, setPasswordErrorSpecialChar] = useState(false);
|
||||
const [passwordErrorSpecialChar, setPasswordErrorSpecialChar] =
|
||||
useState(false);
|
||||
const [emailError, setEmailError] = useState(false);
|
||||
const [emailErrorMessage, setEmailErrorMessage] = useState("");
|
||||
const [step, setStep] = useState(1);
|
||||
@@ -108,7 +109,7 @@ export default function SignUp() {
|
||||
// Checking if the code matches the email.
|
||||
const response = await checkEmailVerificationCode(email, code);
|
||||
if (response.status == "200" || code == "111222") {
|
||||
setVerificationToken((await response.json()).token)
|
||||
setVerificationToken((await response.json()).token);
|
||||
setStep(3);
|
||||
} else {
|
||||
setCodeError(true);
|
||||
@@ -180,7 +181,14 @@ export default function SignUp() {
|
||||
|
||||
const { ciphertext, iv, tag } = Aes256Gcm.encrypt(
|
||||
PRIVATE_KEY,
|
||||
password.slice(0, 32).padStart(32 + (password.slice(0, 32).length - new Blob([password]).size), "0")
|
||||
password
|
||||
.slice(0, 32)
|
||||
.padStart(
|
||||
32 +
|
||||
(password.slice(0, 32).length -
|
||||
new Blob([password]).size),
|
||||
"0"
|
||||
)
|
||||
);
|
||||
localStorage.setItem("PRIVATE_KEY", PRIVATE_KEY);
|
||||
|
||||
@@ -191,19 +199,21 @@ export default function SignUp() {
|
||||
},
|
||||
async () => {
|
||||
client.createVerifier(async (err, result) => {
|
||||
const response = await completeAccountInformationSignup({
|
||||
email,
|
||||
firstName,
|
||||
lastName,
|
||||
organizationName: firstName + "'s organization",
|
||||
publicKey: PUBLIC_KEY,
|
||||
ciphertext,
|
||||
iv,
|
||||
tag,
|
||||
salt: result.salt,
|
||||
verifier: result.verifier,
|
||||
token: verificationToken
|
||||
});
|
||||
const response = await completeAccountInformationSignup(
|
||||
{
|
||||
email,
|
||||
firstName,
|
||||
lastName,
|
||||
organizationName: firstName + "'s organization",
|
||||
publicKey: PUBLIC_KEY,
|
||||
ciphertext,
|
||||
iv,
|
||||
tag,
|
||||
salt: result.salt,
|
||||
verifier: result.verifier,
|
||||
token: verificationToken,
|
||||
}
|
||||
);
|
||||
|
||||
// if everything works, go the main dashboard page.
|
||||
if (!errorCheck && response.status == "200") {
|
||||
@@ -276,7 +286,11 @@ export default function SignUp() {
|
||||
and acknowledged the Privacy Policy.
|
||||
</p>
|
||||
<div className="text-l mt-6 m-2 md:m-8 px-8 py-1 text-lg">
|
||||
<Button text="Get Started" onButtonPressed={emailCheck} size="lg"/>
|
||||
<Button
|
||||
text="Get Started"
|
||||
onButtonPressed={emailCheck}
|
||||
size="lg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -313,7 +327,11 @@ export default function SignUp() {
|
||||
<Error text="Oops. Your code is wrong. Please try again." />
|
||||
)}
|
||||
<div className="flex max-w-min flex-col items-center justify-center md:p-2 max-h-24 max-w-md mx-auto text-lg px-4 mt-4 mb-2">
|
||||
<Button text="Verify" onButtonPressed={incrementStep} size="lg"/>
|
||||
<Button
|
||||
text="Verify"
|
||||
onButtonPressed={incrementStep}
|
||||
size="lg"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col items-center justify-center w-full max-h-24 max-w-md mx-auto pt-2">
|
||||
{/* <Link href="/login">
|
||||
@@ -374,37 +392,101 @@ export default function SignUp() {
|
||||
type="password"
|
||||
value={password}
|
||||
isRequired
|
||||
error={passwordErrorLength && passwordErrorNumber && passwordErrorLowerCase}
|
||||
error={
|
||||
passwordErrorLength &&
|
||||
passwordErrorNumber &&
|
||||
passwordErrorLowerCase
|
||||
}
|
||||
/>
|
||||
{(passwordErrorLength || passwordErrorLowerCase || passwordErrorNumber) ? <div className="w-full mt-4 bg-white/5 px-2 flex flex-col items-start py-2 rounded-md">
|
||||
<div className={`text-gray-400 text-sm mb-1`}>Password should contain at least:</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
{passwordErrorLength
|
||||
? <FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5"/>
|
||||
: <FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2"/>}
|
||||
<div className={`${passwordErrorLength ? "text-gray-400" : "text-gray-600"} text-sm`}>14 characters</div>
|
||||
{passwordErrorLength ||
|
||||
passwordErrorLowerCase ||
|
||||
passwordErrorNumber ? (
|
||||
<div className="w-full mt-4 bg-white/5 px-2 flex flex-col items-start py-2 rounded-md">
|
||||
<div className={`text-gray-400 text-sm mb-1`}>
|
||||
Password should contain at least:
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
{passwordErrorLength ? (
|
||||
<FontAwesomeIcon
|
||||
icon={faX}
|
||||
className="text-md text-red mr-2.5"
|
||||
/>
|
||||
) : (
|
||||
<FontAwesomeIcon
|
||||
icon={faCheck}
|
||||
className="text-md text-primary mr-2"
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
className={`${
|
||||
passwordErrorLength
|
||||
? "text-gray-400"
|
||||
: "text-gray-600"
|
||||
} text-sm`}
|
||||
>
|
||||
14 characters
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
{passwordErrorLowerCase ? (
|
||||
<FontAwesomeIcon
|
||||
icon={faX}
|
||||
className="text-md text-red mr-2.5"
|
||||
/>
|
||||
) : (
|
||||
<FontAwesomeIcon
|
||||
icon={faCheck}
|
||||
className="text-md text-primary mr-2"
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
className={`${
|
||||
passwordErrorLowerCase
|
||||
? "text-gray-400"
|
||||
: "text-gray-600"
|
||||
} text-sm`}
|
||||
>
|
||||
1 lowercase character
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
{passwordErrorNumber ? (
|
||||
<FontAwesomeIcon
|
||||
icon={faX}
|
||||
className="text-md text-red mr-2.5"
|
||||
/>
|
||||
) : (
|
||||
<FontAwesomeIcon
|
||||
icon={faCheck}
|
||||
className="text-md text-primary mr-2"
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
className={`${
|
||||
passwordErrorNumber
|
||||
? "text-gray-400"
|
||||
: "text-gray-600"
|
||||
} text-sm`}
|
||||
>
|
||||
1 number
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
{passwordErrorLowerCase
|
||||
? <FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5"/>
|
||||
: <FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2"/>}
|
||||
<div className={`${passwordErrorLowerCase ? "text-gray-400" : "text-gray-600"} text-sm`}>1 lowercase character</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
{passwordErrorNumber
|
||||
? <FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5"/>
|
||||
: <FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2"/>}
|
||||
<div className={`${passwordErrorNumber ? "text-gray-400" : "text-gray-600"} text-sm`}>1 number</div>
|
||||
</div>
|
||||
</div> : <div className="py-2"></div>}
|
||||
) : (
|
||||
<div className="py-2"></div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col items-center justify-center md:p-2 max-h-48 max-w-max mx-auto text-lg px-2 py-3">
|
||||
<Button text="Sign Up" loading={isLoading} onButtonPressed={signupErrorCheck} size="lg" />
|
||||
<Button
|
||||
text="Sign Up"
|
||||
loading={isLoading}
|
||||
onButtonPressed={signupErrorCheck}
|
||||
size="lg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
// Step 4 of the sign up process (download the emergency kit pdf)
|
||||
const step4 = (
|
||||
<div className="bg-bunker flex flex-col items-center w-full max-w-xs md:max-w-lg mx-auto h-7/12 py-8 px-4 md:px-6 mx-1 mb-36 md:mb-16 rounded-xl drop-shadow-xl">
|
||||
@@ -412,23 +494,32 @@ export default function SignUp() {
|
||||
Save your Emergency Kit
|
||||
</p>
|
||||
<div className="flex flex-col items-center justify-center w-full mt-4 md:mt-8 max-w-md text-gray-400 text-md rounded-md px-2">
|
||||
<div>If you get locked out of your account, your Emergency Kit is the only way to sign in.</div>
|
||||
<div className="mt-3">We recommend you download it and keep it somewhere safe.</div>
|
||||
<div>
|
||||
If you get locked out of your account, your Emergency Kit is
|
||||
the only way to sign in.
|
||||
</div>
|
||||
<div className="mt-3">
|
||||
We recommend you download it and keep it somewhere safe.
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full p-2 flex flex-row items-center bg-white/10 text-gray-400 rounded-md max-w-xs md:max-w-md mx-auto mt-4">
|
||||
<FontAwesomeIcon icon={faWarning} className="ml-2 mr-4 text-4xl"/>
|
||||
It contains your Secret Key which we cannot access or recover for you if you lose it.
|
||||
<FontAwesomeIcon
|
||||
icon={faWarning}
|
||||
className="ml-2 mr-4 text-4xl"
|
||||
/>
|
||||
It contains your Secret Key which we cannot access or recover
|
||||
for you if you lose it.
|
||||
</div>
|
||||
<div className="flex flex-row items-center justify-center w-3/4 md:w-full md:p-2 max-h-28 max-w-max mx-auto mt-6 py-1 md:mt-4 text-lg text-center md:text-left">
|
||||
<Button
|
||||
text="Download PDF"
|
||||
<Button
|
||||
text="Download PDF"
|
||||
onButtonPressed={async () => {
|
||||
await issueBackupKey({
|
||||
email,
|
||||
password,
|
||||
personalName: (firstName + " " + lastName),
|
||||
email,
|
||||
password,
|
||||
personalName: firstName + " " + lastName,
|
||||
setBackupKeyError,
|
||||
setBackupKeyIssued
|
||||
setBackupKeyIssued,
|
||||
});
|
||||
router.push("/dashboard/");
|
||||
}}
|
||||
@@ -476,7 +567,13 @@ export default function SignUp() {
|
||||
/>
|
||||
</div>
|
||||
</Link>
|
||||
{step == 1 ? step1 : step == 2 ? step2 : step == 3 ? step3 : step4}
|
||||
{step == 1
|
||||
? step1
|
||||
: step == 2
|
||||
? step2
|
||||
: step == 3
|
||||
? step3
|
||||
: step4}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
+133
-56
@@ -5,15 +5,15 @@ import Head from "next/head";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
import InputField from "../components/basic/InputField";
|
||||
import Button from "../components/basic/buttons/Button";
|
||||
import InputField from "~/components/basic/InputField";
|
||||
import Button from "~/components/basic/buttons/Button";
|
||||
import completeAccountInformationSignupInvite from "./api/auth/CompleteAccountInformationSignupInvite";
|
||||
import Aes256Gcm from "../components/aes-256-gcm";
|
||||
import passwordCheck from "../components/utilities/checks/PasswordCheck";
|
||||
import attemptLogin from "../components/utilities/attemptLogin";
|
||||
import Aes256Gcm from "~/components/aes-256-gcm";
|
||||
import passwordCheck from "~/utilities/checks/PasswordCheck";
|
||||
import attemptLogin from "~/utilities/attemptLogin";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faCheck, faX, faWarning } from "@fortawesome/free-solid-svg-icons";
|
||||
import issueBackupKey from "../components/utilities/issueBackupKey";
|
||||
import issueBackupKey from "~/utilities/issueBackupKey";
|
||||
import verifySignupInvite from "./api/auth/VerifySignupInvite";
|
||||
|
||||
const nacl = require("tweetnacl");
|
||||
@@ -76,7 +76,14 @@ export default function SignupInvite() {
|
||||
|
||||
const { ciphertext, iv, tag } = Aes256Gcm.encrypt(
|
||||
PRIVATE_KEY,
|
||||
password.slice(0, 32).padStart(32 + (password.slice(0, 32).length - new Blob([password]).size), "0")
|
||||
password
|
||||
.slice(0, 32)
|
||||
.padStart(
|
||||
32 +
|
||||
(password.slice(0, 32).length -
|
||||
new Blob([password]).size),
|
||||
"0"
|
||||
)
|
||||
);
|
||||
localStorage.setItem("PRIVATE_KEY", PRIVATE_KEY);
|
||||
|
||||
@@ -87,18 +94,19 @@ export default function SignupInvite() {
|
||||
},
|
||||
async () => {
|
||||
client.createVerifier(async (err, result) => {
|
||||
const response = await completeAccountInformationSignupInvite({
|
||||
email,
|
||||
firstName,
|
||||
lastName,
|
||||
publicKey: PUBLIC_KEY,
|
||||
ciphertext,
|
||||
iv,
|
||||
tag,
|
||||
salt: result.salt,
|
||||
verifier: result.verifier,
|
||||
token: verificationToken
|
||||
});
|
||||
const response =
|
||||
await completeAccountInformationSignupInvite({
|
||||
email,
|
||||
firstName,
|
||||
lastName,
|
||||
publicKey: PUBLIC_KEY,
|
||||
ciphertext,
|
||||
iv,
|
||||
tag,
|
||||
salt: result.salt,
|
||||
verifier: result.verifier,
|
||||
token: verificationToken,
|
||||
});
|
||||
|
||||
// if everything works, go the main dashboard page.
|
||||
if (!errorCheck && response.status == "200") {
|
||||
@@ -148,19 +156,19 @@ export default function SignupInvite() {
|
||||
alt="verify email"
|
||||
></Image>
|
||||
<div className="flex flex-row items-center justify-center w-3/4 md:w-full md:p-2 max-h-28 max-w-xs md:max-w-md mx-auto text-lg py-1 text-center md:text-left">
|
||||
<Button
|
||||
<Button
|
||||
text="Confirm Email"
|
||||
onButtonPressed={async () => {
|
||||
const response = await verifySignupInvite({
|
||||
email,
|
||||
code: token
|
||||
email,
|
||||
code: token,
|
||||
});
|
||||
if (response.status == 200) {
|
||||
setVerificationToken((await response.json()).token)
|
||||
setVerificationToken((await response.json()).token);
|
||||
setStep(2);
|
||||
} else {
|
||||
console.log("ERROR", response)
|
||||
router.push("/requestnewinvite")
|
||||
console.log("ERROR", response);
|
||||
router.push("/requestnewinvite");
|
||||
}
|
||||
}}
|
||||
size="lg"
|
||||
@@ -213,29 +221,89 @@ export default function SignupInvite() {
|
||||
type="password"
|
||||
value={password}
|
||||
isRequired
|
||||
error={passwordErrorLength && passwordErrorNumber && passwordErrorLowerCase}
|
||||
error={
|
||||
passwordErrorLength &&
|
||||
passwordErrorNumber &&
|
||||
passwordErrorLowerCase
|
||||
}
|
||||
/>
|
||||
{(passwordErrorLength || passwordErrorLowerCase || passwordErrorNumber) ? <div className="w-full mt-4 bg-white/5 px-2 flex flex-col items-start py-2 rounded-md">
|
||||
<div className={`text-gray-400 text-sm mb-1`}>Password should contain at least:</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
{passwordErrorLength
|
||||
? <FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5"/>
|
||||
: <FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2"/>}
|
||||
<div className={`${passwordErrorLength ? "text-gray-400" : "text-gray-600"} text-sm`}>14 characters</div>
|
||||
{passwordErrorLength ||
|
||||
passwordErrorLowerCase ||
|
||||
passwordErrorNumber ? (
|
||||
<div className="w-full mt-4 bg-white/5 px-2 flex flex-col items-start py-2 rounded-md">
|
||||
<div className={`text-gray-400 text-sm mb-1`}>
|
||||
Password should contain at least:
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
{passwordErrorLength ? (
|
||||
<FontAwesomeIcon
|
||||
icon={faX}
|
||||
className="text-md text-red mr-2.5"
|
||||
/>
|
||||
) : (
|
||||
<FontAwesomeIcon
|
||||
icon={faCheck}
|
||||
className="text-md text-primary mr-2"
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
className={`${
|
||||
passwordErrorLength
|
||||
? "text-gray-400"
|
||||
: "text-gray-600"
|
||||
} text-sm`}
|
||||
>
|
||||
14 characters
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
{passwordErrorLowerCase ? (
|
||||
<FontAwesomeIcon
|
||||
icon={faX}
|
||||
className="text-md text-red mr-2.5"
|
||||
/>
|
||||
) : (
|
||||
<FontAwesomeIcon
|
||||
icon={faCheck}
|
||||
className="text-md text-primary mr-2"
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
className={`${
|
||||
passwordErrorLowerCase
|
||||
? "text-gray-400"
|
||||
: "text-gray-600"
|
||||
} text-sm`}
|
||||
>
|
||||
1 lowercase character
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
{passwordErrorNumber ? (
|
||||
<FontAwesomeIcon
|
||||
icon={faX}
|
||||
className="text-md text-red mr-2.5"
|
||||
/>
|
||||
) : (
|
||||
<FontAwesomeIcon
|
||||
icon={faCheck}
|
||||
className="text-md text-primary mr-2"
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
className={`${
|
||||
passwordErrorNumber
|
||||
? "text-gray-400"
|
||||
: "text-gray-600"
|
||||
} text-sm`}
|
||||
>
|
||||
1 number
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
{passwordErrorLowerCase
|
||||
? <FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5"/>
|
||||
: <FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2"/>}
|
||||
<div className={`${passwordErrorLowerCase ? "text-gray-400" : "text-gray-600"} text-sm`}>1 lowercase character</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
{passwordErrorNumber
|
||||
? <FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5"/>
|
||||
: <FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2"/>}
|
||||
<div className={`${passwordErrorNumber ? "text-gray-400" : "text-gray-600"} text-sm`}>1 number</div>
|
||||
</div>
|
||||
</div> : <div className="py-2"></div>}
|
||||
) : (
|
||||
<div className="py-2"></div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col items-center justify-center w-full md:px-4 md:py-5 mt-2 px-2 py-3 max-h-24 max-w-md mx-auto text-lg">
|
||||
<Button
|
||||
@@ -257,23 +325,32 @@ export default function SignupInvite() {
|
||||
Save your Emergency Kit
|
||||
</p>
|
||||
<div className="flex flex-col items-center justify-center w-full mt-4 md:mt-8 max-w-md text-gray-400 text-md rounded-md px-2">
|
||||
<div>If you get locked out of your account, your Emergency Kit is the only way to sign in.</div>
|
||||
<div className="mt-3">We recommend you download it and keep it somewhere safe.</div>
|
||||
<div>
|
||||
If you get locked out of your account, your Emergency Kit is
|
||||
the only way to sign in.
|
||||
</div>
|
||||
<div className="mt-3">
|
||||
We recommend you download it and keep it somewhere safe.
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full p-2 flex flex-row items-center bg-white/10 text-gray-400 rounded-md max-w-xs md:max-w-md mx-auto mt-4">
|
||||
<FontAwesomeIcon icon={faWarning} className="ml-2 mr-4 text-4xl"/>
|
||||
It contains your Secret Key which we cannot access or recover for you if you lose it.
|
||||
<FontAwesomeIcon
|
||||
icon={faWarning}
|
||||
className="ml-2 mr-4 text-4xl"
|
||||
/>
|
||||
It contains your Secret Key which we cannot access or recover
|
||||
for you if you lose it.
|
||||
</div>
|
||||
<div className="flex flex-row items-center justify-center w-3/4 md:w-full md:p-2 max-h-28 max-w-xs md:max-w-md mx-auto mt-6 md:mt-8 py-1 text-lg text-center md:text-left">
|
||||
<Button
|
||||
text="Download PDF"
|
||||
<Button
|
||||
text="Download PDF"
|
||||
onButtonPressed={async () => {
|
||||
await issueBackupKey({
|
||||
email,
|
||||
password,
|
||||
personalName: (firstName + " " + lastName),
|
||||
email,
|
||||
password,
|
||||
personalName: firstName + " " + lastName,
|
||||
setBackupKeyError,
|
||||
setBackupKeyIssued
|
||||
setBackupKeyIssued,
|
||||
});
|
||||
router.push("/dashboard/");
|
||||
}}
|
||||
|
||||
@@ -5,17 +5,17 @@ import Image from "next/image";
|
||||
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faMagnifyingGlass, faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||
import UserTable from "../../components/basic/table/UserTable";
|
||||
import UserTable from "~/components/basic/table/UserTable";
|
||||
import getWorkspaceUsers from "../api/workspace/getWorkspaceUsers";
|
||||
import guidGenerator from "../../components/utilities/randomId";
|
||||
import AddProjectMemberDialog from "../../components/basic/dialog/AddProjectMemberDialog";
|
||||
// import DeleteUserDialog from '../../components/basic/dialog/DeleteUserDialog';
|
||||
import guidGenerator from "~/utilities/randomId";
|
||||
import AddProjectMemberDialog from "~/components/basic/dialog/AddProjectMemberDialog";
|
||||
// import DeleteUserDialog from '~/components/basic/dialog/DeleteUserDialog';
|
||||
import addUserToWorkspace from "../api/workspace/addUserToWorkspace";
|
||||
import getUser from "../api/user/getUser";
|
||||
import uploadKeys from "../api/workspace/uploadKeys";
|
||||
import getOrganizationUsers from "../api/organization/GetOrgUsers";
|
||||
import NavHeader from "../../components/navigation/NavHeader";
|
||||
import Button from "../../components/basic/buttons/Button";
|
||||
import NavHeader from "~/components/navigation/NavHeader";
|
||||
import Button from "~/components/basic/buttons/Button";
|
||||
|
||||
// #TODO: Update all the workspaceIds
|
||||
const crypto = require("crypto");
|
||||
@@ -98,15 +98,13 @@ export default function Users() {
|
||||
firstName: user.user?.firstName,
|
||||
lastName: user.user?.lastName,
|
||||
email:
|
||||
user.user?.email == null
|
||||
? user.inviteEmail
|
||||
: user.user?.email,
|
||||
user.user?.email == null ? user.inviteEmail : user.user?.email,
|
||||
role: user?.role,
|
||||
status: user?.status,
|
||||
userId: user.user?._id,
|
||||
membershipId: user._id,
|
||||
publicKey: user.user?.publicKey,
|
||||
}))
|
||||
}));
|
||||
setUserList(tempUserList);
|
||||
const orgUsers = await getOrganizationUsers({
|
||||
orgId: localStorage.getItem("orgData.id"),
|
||||
@@ -114,15 +112,15 @@ export default function Users() {
|
||||
setOrgUserList(orgUsers);
|
||||
setEmail(
|
||||
orgUsers
|
||||
?.filter((user) => user.status == "accepted")
|
||||
.map((user) => user.user.email)
|
||||
.filter(
|
||||
(email) =>
|
||||
!tempUserList
|
||||
?.map((user1) => user1.email)
|
||||
.includes(email)
|
||||
)[0]
|
||||
)
|
||||
?.filter((user) => user.status == "accepted")
|
||||
.map((user) => user.user.email)
|
||||
.filter(
|
||||
(email) =>
|
||||
!tempUserList
|
||||
?.map((user1) => user1.email)
|
||||
.includes(email)
|
||||
)[0]
|
||||
);
|
||||
}, []);
|
||||
|
||||
return userList ? (
|
||||
@@ -131,7 +129,7 @@ export default function Users() {
|
||||
<title>Users</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Head>
|
||||
<NavHeader pageName="Project Members" isProjectRelated={true}/>
|
||||
<NavHeader pageName="Project Members" isProjectRelated={true} />
|
||||
<div className="flex flex-col justify-start items-start px-6 py-6 pb-4 text-3xl">
|
||||
<p className="font-semibold mr-4 text-white">Project Members</p>
|
||||
<p className="mr-4 text-base text-gray-400">
|
||||
|
||||
Reference in New Issue
Block a user