2022-07-14 00:10:45 +00:00
|
|
|
import { useSession } from "next-auth/react";
|
2023-08-02 09:35:48 +00:00
|
|
|
import { useRouter } from "next/navigation";
|
2023-02-27 07:24:43 +00:00
|
|
|
import type { Dispatch, SetStateAction } from "react";
|
2023-06-26 10:37:59 +00:00
|
|
|
import { useState } from "react";
|
2022-07-14 00:10:45 +00:00
|
|
|
|
2023-01-10 15:39:29 +00:00
|
|
|
import Shell from "@calcom/features/shell/Shell";
|
2023-02-27 07:24:43 +00:00
|
|
|
import { classNames } from "@calcom/lib";
|
2023-04-02 10:21:58 +00:00
|
|
|
import { WEBAPP_URL } from "@calcom/lib/constants";
|
2022-07-15 16:55:59 +00:00
|
|
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
2023-08-02 09:35:48 +00:00
|
|
|
import { useRouterQuery } from "@calcom/lib/hooks/useRouterQuery";
|
2022-11-23 02:55:25 +00:00
|
|
|
import { HttpError } from "@calcom/lib/http-error";
|
2022-07-22 17:27:06 +00:00
|
|
|
import { trpc } from "@calcom/trpc/react";
|
2023-08-02 09:35:48 +00:00
|
|
|
import { AnimatedPopover, Avatar, CreateButtonWithTeamsList, showToast } from "@calcom/ui";
|
2022-07-14 00:10:45 +00:00
|
|
|
|
2023-06-26 10:37:59 +00:00
|
|
|
import { FilterResults } from "../../../filters/components/FilterResults";
|
|
|
|
import { TeamsFilter } from "../../../filters/components/TeamsFilter";
|
|
|
|
import { getTeamsFiltersFromQuery } from "../../../filters/lib/getTeamsFiltersFromQuery";
|
2023-04-19 14:15:08 +00:00
|
|
|
import LicenseRequired from "../../common/components/LicenseRequired";
|
2023-06-26 10:37:59 +00:00
|
|
|
import EmptyScreen from "../components/EmptyScreen";
|
2022-11-23 02:55:25 +00:00
|
|
|
import SkeletonLoader from "../components/SkeletonLoaderList";
|
2022-07-28 19:58:26 +00:00
|
|
|
import WorkflowList from "../components/WorkflowListPage";
|
2022-07-14 00:10:45 +00:00
|
|
|
|
|
|
|
function WorkflowsPage() {
|
|
|
|
const { t } = useLocale();
|
|
|
|
const session = useSession();
|
2022-11-23 02:55:25 +00:00
|
|
|
const router = useRouter();
|
2023-08-02 09:35:48 +00:00
|
|
|
const routerQuery = useRouterQuery();
|
|
|
|
const filters = getTeamsFiltersFromQuery(routerQuery);
|
2022-07-14 00:10:45 +00:00
|
|
|
|
2023-06-26 10:37:59 +00:00
|
|
|
const queryRes = trpc.viewer.workflows.filteredList.useQuery({
|
|
|
|
filters,
|
|
|
|
});
|
2022-07-14 00:10:45 +00:00
|
|
|
|
2023-02-27 07:24:43 +00:00
|
|
|
const createMutation = trpc.viewer.workflows.create.useMutation({
|
2022-11-23 02:55:25 +00:00
|
|
|
onSuccess: async ({ workflow }) => {
|
|
|
|
await router.replace("/workflows/" + workflow.id);
|
|
|
|
},
|
|
|
|
onError: (err) => {
|
|
|
|
if (err instanceof HttpError) {
|
|
|
|
const message = `${err.statusCode}: ${err.message}`;
|
|
|
|
showToast(message, "error");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err.data?.code === "UNAUTHORIZED") {
|
2023-06-23 05:03:45 +00:00
|
|
|
const message = `${err.data.code}: ${t("error_workflow_unauthorized_create")}`;
|
2022-11-23 02:55:25 +00:00
|
|
|
showToast(message, "error");
|
|
|
|
}
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2022-12-07 20:53:44 +00:00
|
|
|
return (
|
2022-07-14 00:10:45 +00:00
|
|
|
<Shell
|
2022-12-07 20:53:44 +00:00
|
|
|
heading={t("workflows")}
|
2022-11-23 02:55:25 +00:00
|
|
|
title={t("workflows")}
|
2022-12-07 20:53:44 +00:00
|
|
|
subtitle={t("workflows_to_automate_notifications")}
|
2023-04-19 20:17:54 +00:00
|
|
|
hideHeadingOnMobile
|
2022-11-23 02:55:25 +00:00
|
|
|
CTA={
|
2023-06-26 10:37:59 +00:00
|
|
|
session.data?.hasValidLicense ? (
|
|
|
|
<CreateButtonWithTeamsList
|
2023-02-27 07:24:43 +00:00
|
|
|
subtitle={t("new_workflow_subtitle").toUpperCase()}
|
|
|
|
createFunction={(teamId?: number) => {
|
|
|
|
createMutation.mutate({ teamId });
|
|
|
|
}}
|
|
|
|
isLoading={createMutation.isLoading}
|
|
|
|
disableMobileButton={true}
|
2023-06-26 10:37:59 +00:00
|
|
|
onlyShowWithNoTeams={true}
|
2023-02-27 07:24:43 +00:00
|
|
|
/>
|
2023-04-03 09:50:39 +00:00
|
|
|
) : null
|
2022-11-23 02:55:25 +00:00
|
|
|
}>
|
2022-07-14 00:10:45 +00:00
|
|
|
<LicenseRequired>
|
2023-06-26 10:37:59 +00:00
|
|
|
<>
|
|
|
|
{queryRes.data?.totalCount ? (
|
|
|
|
<div className="flex">
|
|
|
|
<TeamsFilter />
|
|
|
|
<div className="ml-auto">
|
|
|
|
<CreateButtonWithTeamsList
|
|
|
|
subtitle={t("new_workflow_subtitle").toUpperCase()}
|
|
|
|
createFunction={(teamId?: number) => createMutation.mutate({ teamId })}
|
|
|
|
isLoading={createMutation.isLoading}
|
|
|
|
disableMobileButton={true}
|
|
|
|
onlyShowWithTeams={true}
|
2023-04-03 09:50:39 +00:00
|
|
|
/>
|
|
|
|
</div>
|
2023-06-26 10:37:59 +00:00
|
|
|
</div>
|
|
|
|
) : null}
|
|
|
|
<FilterResults
|
|
|
|
queryRes={queryRes}
|
|
|
|
emptyScreen={<EmptyScreen isFilteredView={false} />}
|
|
|
|
noResultsScreen={<EmptyScreen isFilteredView={true} />}
|
|
|
|
SkeletonLoader={SkeletonLoader}>
|
|
|
|
<WorkflowList workflows={queryRes.data?.filtered} />
|
|
|
|
</FilterResults>
|
|
|
|
</>
|
2022-07-14 00:10:45 +00:00
|
|
|
</LicenseRequired>
|
|
|
|
</Shell>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-02-27 07:24:43 +00:00
|
|
|
const Filter = (props: {
|
|
|
|
profiles: {
|
|
|
|
readOnly?: boolean | undefined;
|
|
|
|
slug: string | null;
|
|
|
|
name: string | null;
|
|
|
|
teamId: number | null | undefined;
|
2023-04-02 10:21:58 +00:00
|
|
|
image?: string | undefined | null;
|
2023-02-27 07:24:43 +00:00
|
|
|
}[];
|
|
|
|
checked: {
|
|
|
|
userId: number | null;
|
|
|
|
teamIds: number[];
|
|
|
|
};
|
|
|
|
setChecked: Dispatch<
|
|
|
|
SetStateAction<{
|
|
|
|
userId: number | null;
|
|
|
|
teamIds: number[];
|
|
|
|
}>
|
|
|
|
>;
|
|
|
|
}) => {
|
|
|
|
const session = useSession();
|
|
|
|
const userId = session.data?.user.id || 0;
|
2023-04-02 10:21:58 +00:00
|
|
|
const user = session.data?.user.name || "";
|
|
|
|
const userName = session.data?.user.username;
|
|
|
|
const userAvatar = WEBAPP_URL + "/" + userName + "/avatar.png";
|
2023-02-27 07:24:43 +00:00
|
|
|
|
|
|
|
const teams = props.profiles.filter((profile) => !!profile.teamId);
|
|
|
|
const { checked, setChecked } = props;
|
|
|
|
|
|
|
|
const [noFilter, setNoFilter] = useState(true);
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div className={classNames("-mb-2", noFilter ? "w-16" : "w-[100px]")}>
|
|
|
|
<AnimatedPopover text={noFilter ? "All" : "Filtered"}>
|
2023-04-05 18:14:46 +00:00
|
|
|
<div className="item-center focus-within:bg-subtle hover:bg-muted flex px-4 py-[6px] hover:cursor-pointer">
|
2023-02-27 07:24:43 +00:00
|
|
|
<Avatar
|
2023-04-02 10:21:58 +00:00
|
|
|
imageSrc={userAvatar || ""}
|
2023-02-27 07:24:43 +00:00
|
|
|
size="sm"
|
2023-04-02 10:21:58 +00:00
|
|
|
alt={`${user} Avatar`}
|
2023-02-27 07:24:43 +00:00
|
|
|
gravatarFallbackMd5="fallback"
|
|
|
|
className="self-center"
|
|
|
|
asChild
|
|
|
|
/>
|
|
|
|
<label
|
|
|
|
htmlFor="yourWorkflows"
|
2023-04-05 18:14:46 +00:00
|
|
|
className="text-default ml-2 mr-auto self-center truncate text-sm font-medium">
|
2023-04-02 10:21:58 +00:00
|
|
|
{user}
|
2023-02-27 07:24:43 +00:00
|
|
|
</label>
|
|
|
|
|
|
|
|
<input
|
|
|
|
id="yourWorkflows"
|
|
|
|
type="checkbox"
|
2023-04-05 18:14:46 +00:00
|
|
|
className="text-primary-600 focus:ring-primary-500 border-default inline-flex h-4 w-4 place-self-center justify-self-end rounded "
|
2023-02-27 07:24:43 +00:00
|
|
|
checked={!!checked.userId}
|
|
|
|
onChange={(e) => {
|
|
|
|
if (e.target.checked) {
|
|
|
|
setChecked({ userId: userId, teamIds: checked.teamIds });
|
|
|
|
if (checked.teamIds.length === teams.length) {
|
|
|
|
setNoFilter(true);
|
|
|
|
}
|
|
|
|
} else if (!e.target.checked) {
|
|
|
|
setChecked({ userId: null, teamIds: checked.teamIds });
|
|
|
|
|
|
|
|
setNoFilter(false);
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
{teams.map((profile) => (
|
|
|
|
<div
|
2023-04-05 18:14:46 +00:00
|
|
|
className="item-center focus-within:bg-subtle hover:bg-muted flex px-4 py-[6px] hover:cursor-pointer"
|
2023-02-27 07:24:43 +00:00
|
|
|
key={`${profile.teamId || 0}`}>
|
|
|
|
<Avatar
|
2023-04-02 10:21:58 +00:00
|
|
|
imageSrc={profile.image || ""}
|
2023-02-27 07:24:43 +00:00
|
|
|
size="sm"
|
|
|
|
alt={`${profile.slug} Avatar`}
|
|
|
|
gravatarFallbackMd5="fallback"
|
|
|
|
className="self-center"
|
|
|
|
asChild
|
|
|
|
/>
|
|
|
|
<label
|
|
|
|
htmlFor={profile.slug || ""}
|
2023-04-05 18:14:46 +00:00
|
|
|
className="text-default ml-2 mr-auto select-none self-center truncate text-sm font-medium hover:cursor-pointer">
|
2023-02-27 07:24:43 +00:00
|
|
|
{profile.slug}
|
|
|
|
</label>
|
|
|
|
|
|
|
|
<input
|
|
|
|
id={profile.slug || ""}
|
|
|
|
name={profile.slug || ""}
|
|
|
|
type="checkbox"
|
|
|
|
checked={checked.teamIds?.includes(profile.teamId || 0)}
|
|
|
|
onChange={(e) => {
|
|
|
|
if (e.target.checked) {
|
|
|
|
const updatedChecked = checked;
|
|
|
|
updatedChecked.teamIds.push(profile.teamId || 0);
|
|
|
|
setChecked({ userId: checked.userId, teamIds: [...updatedChecked.teamIds] });
|
|
|
|
|
|
|
|
if (checked.userId && updatedChecked.teamIds.length === teams.length) {
|
|
|
|
setNoFilter(true);
|
|
|
|
} else {
|
|
|
|
setNoFilter(false);
|
|
|
|
}
|
|
|
|
} else if (!e.target.checked) {
|
|
|
|
const index = checked.teamIds.indexOf(profile.teamId || 0);
|
|
|
|
if (index !== -1) {
|
|
|
|
const updatedChecked = checked;
|
|
|
|
updatedChecked.teamIds.splice(index, 1);
|
|
|
|
setChecked({ userId: checked.userId, teamIds: [...updatedChecked.teamIds] });
|
|
|
|
|
|
|
|
if (checked.userId && updatedChecked.teamIds.length === teams.length) {
|
|
|
|
setNoFilter(true);
|
|
|
|
} else {
|
|
|
|
setNoFilter(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}}
|
2023-04-05 18:14:46 +00:00
|
|
|
className="text-primary-600 focus:ring-primary-500 border-default inline-flex h-4 w-4 place-self-center justify-self-end rounded "
|
2023-02-27 07:24:43 +00:00
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
))}
|
|
|
|
</AnimatedPopover>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2022-07-14 00:10:45 +00:00
|
|
|
export default WorkflowsPage;
|