Compare commits

..

13 Commits

Author SHA1 Message Date
cb828200e1 fix(server): updated secret rotation to pick on db host in validation 2024-03-19 13:56:21 +00:00
77d068ae2c Merge pull request #1599 from Infisical/daniel/improve-create-project
Fix: Remove required org slug from create project route
2024-03-19 18:31:16 +05:30
8702af671d Fix: Typings error 2024-03-19 13:45:57 +01:00
31c0fd96ea Update UserInfoStep.tsx 2024-03-19 13:39:34 +01:00
2c539697df Feat: Remove orgSlug from create project endpoint 2024-03-19 13:39:24 +01:00
ae97b74933 Feat: Improve create project, remove organization slug from frontend 2024-03-19 13:38:58 +01:00
3e6af2dae5 Merge pull request #1597 from Infisical/daniel/api-endpoint-fix
Fix: Mintlify interactive API docs defaulting to localhost server
2024-03-19 16:32:49 +05:30
3c91e1127f Fix: Mintlify docs defaulting to localhost endpoint 2024-03-19 11:58:01 +01:00
0e31a9146a Update ee.mdx 2024-03-18 22:10:09 -07:00
c91789e6d0 Merge pull request #1590 from Infisical/daniel/ts-comments
Fix: Github warnings / Lint warnings
2024-03-18 20:19:26 +05:30
f73c807aa0 Merge pull request #1589 from Infisical/daniel/ui-improvements
Fix: Select organization UX & project card enhancements
2024-03-18 20:14:39 +05:30
d1dacd81aa Chore: UX improvements to project cards 2024-03-18 15:36:59 +01:00
e8b635ce37 Fix: Code cleanup & truncate organization names 2024-03-18 15:36:01 +01:00
17 changed files with 77 additions and 111 deletions

View File

@ -9,6 +9,7 @@ import jmespath from "jmespath";
import knex from "knex";
import { getConfig } from "@app/lib/config/env";
import { getDbConnectionHost } from "@app/lib/knex";
import { alphaNumericNanoId } from "@app/lib/nanoid";
import { TAssignOp, TDbProviderClients, TDirectAssignOp, THttpProviderFunction } from "../templates/types";
@ -89,7 +90,7 @@ export const secretRotationDbFn = async ({
const appCfg = getConfig();
const ssl = ca ? { rejectUnauthorized: false, ca } : undefined;
if (host === "localhost" || host === "127.0.0.1" || appCfg.DB_CONNECTION_URI.includes(host))
if (host === "localhost" || host === "127.0.0.1" || getDbConnectionHost(appCfg.DB_CONNECTION_URI) === host)
throw new Error("Invalid db host");
const db = knex({

View File

@ -0,0 +1,11 @@
import { URL } from "url"; // Import the URL class
export const getDbConnectionHost = (urlString: string) => {
try {
const url = new URL(urlString);
// Split hostname and port (if provided)
return url.hostname.split(":")[0];
} catch (error) {
return null;
}
};

View File

@ -4,6 +4,7 @@ import { Tables } from "knex/types/tables";
import { DatabaseError } from "../errors";
export * from "./connection";
export * from "./join";
export * from "./select";

View File

@ -14,13 +14,13 @@ export const fastifySwagger = fp(async (fastify) => {
version: "0.0.1"
},
servers: [
{
url: "http://localhost:8080",
description: "Local server"
},
{
url: "https://app.infisical.com",
description: "Production server"
},
{
url: "http://localhost:8080",
description: "Local server"
}
],
components: {

View File

@ -150,8 +150,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
message: "Slug must be a valid slug"
})
.optional()
.describe(PROJECTS.CREATE.slug),
organizationSlug: z.string().trim().describe(PROJECTS.CREATE.organizationSlug)
.describe(PROJECTS.CREATE.slug)
}),
response: {
200: z.object({
@ -166,7 +165,6 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
actor: req.permission.type,
actorOrgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod,
orgSlug: req.body.organizationSlug,
workspaceName: req.body.projectName,
slug: req.body.slug
});

View File

@ -92,7 +92,6 @@ export const projectServiceFactory = ({
* Create workspace. Make user the admin
* */
const createProject = async ({
orgSlug,
actor,
actorId,
actorOrgId,
@ -100,13 +99,7 @@ export const projectServiceFactory = ({
workspaceName,
slug: projectSlug
}: TCreateProjectDTO) => {
if (!orgSlug) {
throw new BadRequestError({
message: "Must provide organization slug to create project"
});
}
const organization = await orgDAL.findOne({ slug: orgSlug });
const organization = await orgDAL.findOne({ id: actorOrgId });
const { permission, membership: orgMembership } = await permissionService.getOrgPermission(
actor,

View File

@ -24,7 +24,6 @@ export type TCreateProjectDTO = {
actorAuthMethod: ActorAuthMethod;
actorId: string;
actorOrgId?: string;
orgSlug: string;
workspaceName: string;
slug?: string;
};

View File

@ -9,7 +9,7 @@ This guide walks through how you can use these paid features in Infisical.
<Steps>
<Step title="Purchase a license">
Start by either signing up for a free demo [here](https://infisical.com/schedule-demo) or contacting team@infisical.com to purchase a license.
Start by either signing up for a free demo [here](https://infisical.com/schedule-demo) or contacting sales@infisical.com to purchase a license.
Once purchased, you will be issued a license key.
</Step>
@ -25,4 +25,4 @@ This guide walks through how you can use these paid features in Infisical.
Once the license expires, Infisical will continue to run, but EE features will be disabled until the license is renewed or a new one is purchased.
</Note>
</Step>
</Steps>
</Steps>

View File

@ -196,10 +196,8 @@ export default function UserInfoStep({
const userOrgs = await fetchOrganizations();
const orgSlug = userOrgs[0]?.slug;
const orgId = userOrgs[0]?.id;
const project = await ProjectService.initProject({
organizationSlug: orgSlug,
projectName: "Example Project"
});

View File

@ -77,18 +77,11 @@ const secretsToBeAdded = [
* @param {String} obj.projectName - name of new project
* @returns {Project} project - new project
*/
const initProjectHelper = async ({
organizationSlug,
projectName
}: {
organizationSlug: string;
projectName: string;
}) => {
const initProjectHelper = async ({ projectName }: { projectName: string }) => {
// create new project
const {
data: { project }
} = await createWorkspace({
organizationSlug,
projectName
});

View File

@ -199,19 +199,17 @@ export const useGetWorkspaceIntegrations = (workspaceId: string) =>
});
export const createWorkspace = ({
organizationSlug,
projectName
}: CreateWorkspaceDTO): Promise<{ data: { project: Workspace } }> => {
return apiRequest.post("/api/v2/workspace", { projectName, organizationSlug });
return apiRequest.post("/api/v2/workspace", { projectName });
};
export const useCreateWorkspace = () => {
const queryClient = useQueryClient();
return useMutation<{ data: { project: Workspace } }, {}, CreateWorkspaceDTO>({
mutationFn: async ({ organizationSlug, projectName }) =>
mutationFn: async ({ projectName }) =>
createWorkspace({
organizationSlug,
projectName
}),
onSuccess: () => {
@ -325,7 +323,13 @@ export const useDeleteUserFromWorkspace = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({ usernames, workspaceId }: { workspaceId: string; usernames: string[] }) => {
mutationFn: async ({
usernames,
workspaceId
}: {
workspaceId: string;
usernames: string[];
}) => {
const {
data: { deletedMembership }
} = await apiRequest.delete(`/api/v2/workspace/${workspaceId}/memberships`, {
@ -391,11 +395,7 @@ export const useAddIdentityToWorkspace = () => {
export const useUpdateIdentityWorkspaceRole = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({
identityId,
workspaceId,
roles
}:TUpdateWorkspaceIdentityRoleDTO)=> {
mutationFn: async ({ identityId, workspaceId, roles }: TUpdateWorkspaceIdentityRoleDTO) => {
const {
data: { identityMembership }
} = await apiRequest.patch(

View File

@ -45,7 +45,6 @@ export type TGetUpgradeProjectStatusDTO = {
// mutation dto
export type CreateWorkspaceDTO = {
projectName: string;
organizationSlug: string;
};
export type RenameWorkspaceDTO = { workspaceID: string; newWorkspaceName: string };
@ -82,16 +81,16 @@ export type TUpdateWorkspaceUserRoleDTO = {
workspaceId: string;
roles: (
| {
role: string;
isTemporary?: false;
}
role: string;
isTemporary?: false;
}
| {
role: string;
isTemporary: true;
temporaryMode: ProjectUserMembershipTemporaryMode;
temporaryRange: string;
temporaryAccessStartTime: string;
}
role: string;
isTemporary: true;
temporaryMode: ProjectUserMembershipTemporaryMode;
temporaryRange: string;
temporaryAccessStartTime: string;
}
)[];
};
@ -100,15 +99,15 @@ export type TUpdateWorkspaceIdentityRoleDTO = {
workspaceId: string;
roles: (
| {
role: string;
isTemporary?: false;
}
role: string;
isTemporary?: false;
}
| {
role: string;
isTemporary: true;
temporaryMode: ProjectUserMembershipTemporaryMode;
temporaryRange: string;
temporaryAccessStartTime: string;
}
role: string;
isTemporary: true;
temporaryMode: ProjectUserMembershipTemporaryMode;
temporaryRange: string;
temporaryAccessStartTime: string;
}
)[];
};

View File

@ -236,7 +236,6 @@ export const AppLayout = ({ children }: LayoutProps) => {
project: { id: newProjectId }
}
} = await createWs.mutateAsync({
organizationSlug: currentOrg.slug,
projectName: name
});

View File

@ -1,5 +1,3 @@
/* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable jsx-a11y/click-events-have-key-events */
import { useCallback, useEffect } from "react";
import { useTranslation } from "react-i18next";
import Head from "next/head";
@ -76,25 +74,18 @@ export default function LoginPage() {
if (callbackPort) {
const privateKey = localStorage.getItem("PRIVATE_KEY");
if (!privateKey) {
createNotification({
text: "Private key not found",
type: "error"
});
}
let error: string | null = null;
if (!user.email) {
createNotification({
text: "User email not found",
type: "error"
});
}
if (!privateKey) error = "Private key not found";
if (!user.email) error = "User email not found";
if (!token) error = "No token found";
if (!token) {
if (error) {
createNotification({
text: "No token found",
text: error,
type: "error"
});
return;
}
const payload = {
@ -177,33 +168,22 @@ export default function LoginPage() {
<Spinner />
) : (
organizations.data?.map((org) => (
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
<div
onClick={() => handleSelectOrganization(org)}
key={org.id}
className="group flex cursor-pointer items-center justify-between rounded-md bg-mineshaft-700 px-4 py-3 capitalize text-gray-200 shadow-md transition-colors hover:bg-mineshaft-600"
>
<p className="transition-colors">{org.name}</p>
<p className="truncate transition-colors">{org.name}</p>
<FontAwesomeIcon
icon={faArrowRight}
className="text-gray-400 transition-colors group-hover:text-primary-500"
className="text-gray-400 transition-all group-hover:translate-x-2 group-hover:text-primary-500"
/>
</div>
))
)}
</div>
<Button
className="mt-8"
colorSchema="primary"
isLoading={logout.isLoading}
isDisabled={logout.isLoading}
variant="solid"
size="lg"
onClick={handleLogout}
>
Logout
</Button>
</form>
</div>

View File

@ -454,7 +454,12 @@ const LearningItemSquare = ({
};
const formSchema = yup.object({
name: yup.string().required().label("Project Name").trim().max(64, "Too long, maximum length is 64 characters"),
name: yup
.string()
.required()
.label("Project Name")
.trim()
.max(64, "Too long, maximum length is 64 characters"),
addMembers: yup.bool().required().label("Add Members")
});
@ -507,7 +512,6 @@ const OrganizationPage = withPermission(
project: { id: newProjectId }
}
} = await createWs.mutateAsync({
organizationSlug: currentOrg.slug,
projectName: name
});
@ -631,22 +635,21 @@ const OrganizationPage = withPermission(
{orgWorkspaces
.filter((ws) => ws?.name?.toLowerCase().includes(searchFilter.toLowerCase()))
.map((workspace) => (
// eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events
<div
onClick={() => {
router.push(`/project/${workspace.id}/secrets/overview`);
localStorage.setItem("projectData.id", workspace.id);
}}
key={workspace.id}
className="min-w-72 flex h-40 flex-col justify-between rounded-md border border-mineshaft-600 bg-mineshaft-800 p-4"
className="min-w-72 group flex h-40 cursor-pointer flex-col justify-between rounded-md border border-mineshaft-600 bg-mineshaft-800 p-4"
>
<div className="mt-0 truncate text-lg text-mineshaft-100">{workspace.name}</div>
<div className="mt-0 pb-6 text-sm text-mineshaft-300">
{workspace.environments?.length || 0} environments
</div>
<button
type="button"
onClick={() => {
router.push(`/project/${workspace.id}/secrets/overview`);
localStorage.setItem("projectData.id", workspace.id);
}}
>
<div className="group ml-auto w-max cursor-pointer rounded-full border border-mineshaft-600 bg-mineshaft-900 py-2 px-4 text-sm text-mineshaft-300 hover:border-primary-500/80 hover:bg-primary-800/20 hover:text-mineshaft-200">
<button type="button">
<div className="group ml-auto w-max cursor-pointer rounded-full border border-mineshaft-600 bg-mineshaft-900 py-2 px-4 text-sm text-mineshaft-300 transition-all group-hover:border-primary-500/80 group-hover:bg-primary-800/20 group-hover:text-mineshaft-200">
Explore{" "}
<FontAwesomeIcon
icon={faArrowRight}
@ -693,7 +696,7 @@ const OrganizationPage = withPermission(
<a
target="_blank"
rel="noopener noreferrer"
className="group ml-auto w-max cursor-default rounded-full border border-mineshaft-600 bg-mineshaft-900 py-2 px-4 text-sm text-mineshaft-300 hover:border-primary-500/80 hover:bg-primary-800/20 hover:text-mineshaft-200"
className="group ml-auto w-max cursor-default rounded-full border border-mineshaft-600 bg-mineshaft-900 py-2 px-4 text-sm text-mineshaft-300 transition-all hover:border-primary-500/80 hover:bg-primary-800/20 hover:text-mineshaft-200"
href={feature.link}
>
Learn more{" "}

View File

@ -9,15 +9,8 @@ class ProjectService {
* @param {String} obj.projectName - name of new project
* @returns {Project} project - new project
*/
static async initProject({
organizationSlug,
projectName
}: {
organizationSlug: string;
projectName: string;
}) {
static async initProject({ projectName }: { projectName: string }) {
return initProjectHelper({
organizationSlug,
projectName
});
}

View File

@ -189,14 +189,12 @@ export const UserInfoSSOStep = ({
const userOrgs = await fetchOrganizations();
const orgId = userOrgs[0]?.id;
const orgSlug = userOrgs[0]?.slug;
await selectOrganization({
organizationId: orgId
});
const project = await ProjectService.initProject({
organizationSlug: orgSlug,
projectName: "Example Project"
});