Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
import { _generateMetadata, getTranslate } from "app/_utils";
import MoveTeamToOrgView from "~/settings/admin/org-migrations/move-team-to-org-view";

export const generateMetadata = async () =>
await _generateMetadata(
(t) => t("organization_migration_move_team"),
(t) => t("organization_migration_move_team_description"),
undefined,
undefined,
"/settings/admin/migrations/move-team-to-org"
);

const Page = async (): Promise<React.ReactNode> => {
const t = await getTranslate();
return (
<SettingsHeader
title={t("organization_migration_move_team")}
description={t("organization_migration_move_team_description")}>
<MoveTeamToOrgView />
</SettingsHeader>
);
};

export default Page;
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,12 @@ const getTabs = (orgBranding: OrganizationBranding | null) => {
},
...(HAS_USER_OPT_IN_FEATURES
? [
{
name: "features",
href: "/settings/my-account/features",
trackingMetadata: { section: "my_account", page: "features" },
},
]
{
name: "features",
href: "/settings/my-account/features",
trackingMetadata: { section: "my_account", page: "features" },
},
]
: []),
// TODO
// { name: "referrals", href: "/settings/my-account/referrals" },
Expand Down Expand Up @@ -181,13 +181,13 @@ const getTabs = (orgBranding: OrganizationBranding | null) => {
},
...(orgBranding
? [
{
name: "members",
href: `${WEBAPP_URL}/settings/organizations/${orgBranding.slug}/members`,
isExternalLink: true,
trackingMetadata: { section: "organization", page: "members" },
},
]
{
name: "members",
href: `${WEBAPP_URL}/settings/organizations/${orgBranding.slug}/members`,
isExternalLink: true,
trackingMetadata: { section: "organization", page: "members" },
},
]
: []),
{
name: "privacy_and_security",
Expand All @@ -212,12 +212,12 @@ const getTabs = (orgBranding: OrganizationBranding | null) => {
},
...(HAS_ORG_OPT_IN_FEATURES
? [
{
name: "features",
href: "/settings/organizations/features",
trackingMetadata: { section: "organization", page: "features" },
},
]
{
name: "features",
href: "/settings/organizations/features",
trackingMetadata: { section: "organization", page: "features" },
},
]
: []),
],
},
Expand Down Expand Up @@ -274,6 +274,11 @@ const getTabs = (orgBranding: OrganizationBranding | null) => {
href: "/settings/admin/organizations",
trackingMetadata: { section: "admin", page: "organizations" },
},
{
name: "migrations",
href: "/settings/admin/migrations/move-team-to-org",
trackingMetadata: { section: "admin", page: "migrations" },
},
{
name: "lockedSMS",
href: "/settings/admin/lockedSMS",
Expand Down Expand Up @@ -610,17 +615,16 @@ const TeamListCollapsible = ({ teamFeatures }: { teamFeatures?: Record<number, T
setTeamMenuState(newTeamMenuState);
}
}}
aria-label={`${team.name} ${
teamMenuState[index].teamMenuOpen ? t("collapse_menu") : t("expand_menu")
}`}>
aria-label={`${team.name} ${teamMenuState[index].teamMenuOpen ? t("collapse_menu") : t("expand_menu")
}`}>
<div className="me-3">
{teamMenuState[index].teamMenuOpen ? (
<ChevronDownIcon className="h-4 w-4" />
) : (
<ChevronRightIcon className="h-4 w-4" />
)}
</div>
{}
{ }
{!team.parentId && (
<Avatar
size="xs"
Expand Down Expand Up @@ -662,55 +666,55 @@ const TeamListCollapsible = ({ teamFeatures }: { teamFeatures?: Record<number, T
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error this exists wtf?
(team.isOrgAdmin && team.isOrgAdmin)) && (
<>
{/* TODO */}
{/* <VerticalTabItem
<>
{/* TODO */}
{/* <VerticalTabItem
name={t("general")}
href={`${WEBAPP_URL}/settings/my-account/appearance`}
textClassNames="px-3 text-emphasis font-medium text-sm"
disableChevron
/> */}
<VerticalTabItem
name={t("appearance")}
href={`/settings/teams/${team.id}/appearance`}
textClassNames="px-3 text-emphasis font-medium text-sm"
trackingMetadata={{ section: "team", page: "appearance", teamId: team.id }}
className="px-2! me-5 h-7 w-auto"
disableChevron
/>
{HAS_TEAM_OPT_IN_FEATURES && (
<VerticalTabItem
name={t("features")}
href={`/settings/teams/${team.id}/features`}
name={t("appearance")}
href={`/settings/teams/${team.id}/appearance`}
textClassNames="px-3 text-emphasis font-medium text-sm"
trackingMetadata={{ section: "team", page: "features", teamId: team.id }}
trackingMetadata={{ section: "team", page: "appearance", teamId: team.id }}
className="px-2! me-5 h-7 w-auto"
disableChevron
/>
)}
{/* Hide if there is a parent ID */}
{!team.parentId ? (
<>
{HAS_TEAM_OPT_IN_FEATURES && (
<VerticalTabItem
name={t("billing")}
href={`/settings/teams/${team.id}/billing`}
name={t("features")}
href={`/settings/teams/${team.id}/features`}
textClassNames="px-3 text-emphasis font-medium text-sm"
trackingMetadata={{ section: "team", page: "billing", teamId: team.id }}
trackingMetadata={{ section: "team", page: "features", teamId: team.id }}
className="px-2! me-5 h-7 w-auto"
disableChevron
/>
</>
) : null}
<VerticalTabItem
name={t("settings")}
href={`/settings/teams/${team.id}/settings`}
textClassNames="px-3 text-emphasis font-medium text-sm"
trackingMetadata={{ section: "team", page: "settings", teamId: team.id }}
className="px-2! me-5 h-7 w-auto"
disableChevron
/>
</>
)}
)}
{/* Hide if there is a parent ID */}
{!team.parentId ? (
<>
<VerticalTabItem
name={t("billing")}
href={`/settings/teams/${team.id}/billing`}
textClassNames="px-3 text-emphasis font-medium text-sm"
trackingMetadata={{ section: "team", page: "billing", teamId: team.id }}
className="px-2! me-5 h-7 w-auto"
disableChevron
/>
</>
) : null}
<VerticalTabItem
name={t("settings")}
href={`/settings/teams/${team.id}/settings`}
textClassNames="px-3 text-emphasis font-medium text-sm"
trackingMetadata={{ section: "team", page: "settings", teamId: team.id }}
className="px-2! me-5 h-7 w-auto"
disableChevron
/>
</>
)}
</CollapsibleContent>
</Collapsible>
);
Expand Down Expand Up @@ -810,7 +814,7 @@ const SettingsSidebarContainer = ({
className="text-subtle h-[16px] w-[16px] stroke-[2px] ltr:mr-3 rtl:ml-3 md:mt-0"
/>
)}
{}
{ }
{!tab.icon && tab?.avatar && (
<Avatar
size="xs"
Expand Down Expand Up @@ -953,19 +957,18 @@ const SettingsSidebarContainer = ({
setOtherTeamMenuState(newOtherTeamMenuState);
}
}}
aria-label={`${otherTeam.name} ${
otherTeamMenuState[index].teamMenuOpen
? t("collapse_menu")
: t("expand_menu")
}`}>
aria-label={`${otherTeam.name} ${otherTeamMenuState[index].teamMenuOpen
? t("collapse_menu")
: t("expand_menu")
}`}>
<div className="me-3">
{otherTeamMenuState[index].teamMenuOpen ? (
<ChevronDownIcon className="h-4 w-4" />
) : (
<ChevronRightIcon className="h-4 w-4" />
)}
</div>
{}
{ }
{!otherTeam.parentId && (
<Avatar
size="xs"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
"use client";

import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import { Alert } from "@calcom/ui/components/alert";
import { Button } from "@calcom/ui/components/button";
import { Form, TextField } from "@calcom/ui/components/form";
import { showToast } from "@calcom/ui/components/toast";
import { zodResolver } from "@hookform/resolvers/zod";
import type { TFunction } from "next-i18next";
import { useForm } from "react-hook-form";
import { z } from "zod";

export const getFormSchema = (t: TFunction) => {
return z.object({
teamId: z.number(),
targetOrgId: z.number(),
teamSlugInOrganization: z.string().min(1),
});
};

export default function MoveTeamToOrgView() {
const { t } = useLocale();
const formSchema = getFormSchema(t);
const formMethods = useForm({
mode: "onSubmit",
resolver: zodResolver(formSchema),
});

const moveTeamMutation = trpc.viewer.admin.moveTeamToOrg.useMutation({
onSuccess: (data) => {
showToast(t(data.message), "success", 10000);
},
onError: (error) => {
showToast(t(error.message), "error", 10000);
},
});

const { register } = formMethods;
return (
<div className="space-y-3">
<Form
className="space-y-3"
noValidate={true}
form={formMethods}
handleSubmit={async (values) => {
const parsedValues = formSchema.parse(values);
moveTeamMutation.mutate(parsedValues);
}}>
<div className="space-y-3">
<TextField
{...register("teamId", { valueAsNumber: true })}
type="number"
label={t("team_id")}
required
placeholder={t("move_team_to_org_team_id_placeholder")}
/>
<TextField
{...register("teamSlugInOrganization")}
label={t("move_team_to_org_new_slug")}
required
placeholder={t("move_team_to_org_new_slug_placeholder")}
/>
<TextField
{...register("targetOrgId", { valueAsNumber: true })}
type="number"
label={t("move_team_to_org_target_org_id")}
required
placeholder={t("move_team_to_org_target_org_id_placeholder")}
/>
<div className="mt-2 text-gray-600 text-sm">
{t("organization_migration_move_team_footnote")}
</div>
</div>
<Button type="submit" loading={moveTeamMutation.isPending}>
{t("organization_migration_move_team")}
</Button>
</Form>

{moveTeamMutation.isSuccess && moveTeamMutation.data && (
<Alert
className="mt-6"
severity="info"
CustomIcon="check"
title={t("move_team_to_org_migration_successful")}
message={
<div className="space-y-1">
<p>
<span className="font-medium">{t("team_id")}:</span> {moveTeamMutation.data.teamId}
</p>
{moveTeamMutation.data.oldTeamSlug && (
<p>
<span className="font-medium">{t("move_team_to_org_old_slug")}:</span>{" "}
{moveTeamMutation.data.oldTeamSlug}
</p>
)}
{moveTeamMutation.data.newTeamSlug && (
<p>
<span className="font-medium">{t("move_team_to_org_new_slug")}:</span>{" "}
{moveTeamMutation.data.newTeamSlug}
</p>
)}
<p>
<span className="font-medium">{t("organization_id")}:</span>{" "}
{moveTeamMutation.data.organizationId}
</p>
{moveTeamMutation.data.organizationSlug && (
<p>
<span className="font-medium">{t("move_team_to_org_organization_slug")}:</span>{" "}
{moveTeamMutation.data.organizationSlug}
</p>
)}
</div>
}
/>
)}
</div>
);
}
Loading
Loading