chore: UX Fixes (#26643)
* Copy changes
* Move search bar inline with new button
* Get rid of no more results message
* Change hidden badge to (hidden)
* Remove Cal.ai badge from sidebar
* Add dropdown to create button when there is multiple options
* Fix delete dialog
* Saved filters updates
* More string fixes
* Switch members table to use names
* Fix member spacing
* Fix routing form identifier field
* Fix routing forms stuff
* Only show SMS hint on SMS options
* Make workflow delete button minimal
* Fix padding on workflow steps
* Remove min width on workflow title
* Fix delete workflow PR
* Fix org profile buttons
* Fix org profile screen partially scrolled down
* Improve logos & banner uploads
* Personal profile fixes
* Fix settings general view stuff
* Sentence case consistency
* Fix stuff I broke
* Fix fab
* Fix hidden translation string
* Fix text fields
* Make button small for solo users too
* fix: update E2E tests to match sentence case labels in routing forms
* fix: update tests to match sentence case label changes
- insights.e2e.ts: chart titles (14 strings)
- event-types.e2e.ts: Organizer phone number location
- EditLocationDialog.test.tsx: phone number labels
* fix: address Cubic AI review feedback (confidence 9+)
- Replace hardcoded text-gray-500 with text-muted in TextField.tsx hint section
- Replace text locator with data-testid in E2E test for location select
Co-Authored-By: unknown <>
* fix: update E2E tests for sentence case label changes
- Use data-testid selectors for location options (more reliable than text)
- Update field identifiers in routing-forms tests to match new labels
- Fix Long text selector in manage-booking-questions test
* fix: replace text locator with data-testid in manage-booking-questions E2E test
Replace fragile text="Long text" locator with resilient
page.getByTestId("select-option-textarea") selector per E2E best practices.
Addresses Cubic AI review feedback (confidence 9/10).
Co-Authored-By: unknown <>
* fix: use .last() for multiple location select items
---------
Co-authored-by: Pedro Castro <pedro@cal.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
unknown <>
Pedro Castro
Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
parent
32d97fbea4
commit
7c66f33de2
@@ -13,7 +13,11 @@ import { ALLOWED_FORM_WORKFLOW_ACTIONS } from "@calcom/features/ee/workflows/lib
|
||||
import emailReminderTemplate from "@calcom/features/ee/workflows/lib/reminders/templates/emailReminderTemplate";
|
||||
import type { FormValues } from "@calcom/features/ee/workflows/lib/types";
|
||||
import type { WorkflowPermissions } from "@calcom/features/workflows/repositories/WorkflowPermissionsRepository";
|
||||
import { SENDER_ID, SENDER_NAME, SCANNING_WORKFLOW_STEPS } from "@calcom/lib/constants";
|
||||
import {
|
||||
SENDER_ID,
|
||||
SENDER_NAME,
|
||||
SCANNING_WORKFLOW_STEPS,
|
||||
} from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat";
|
||||
import { WorkflowActions } from "@calcom/prisma/enums";
|
||||
@@ -23,7 +27,10 @@ import { Button } from "@calcom/ui/components/button";
|
||||
import { FormCard, FormCardBody } from "@calcom/ui/components/card";
|
||||
import type { MultiSelectCheckboxesOptionType as Option } from "@calcom/ui/components/form";
|
||||
import { Icon } from "@calcom/ui/components/icon";
|
||||
import { useHasPaidPlan, useHasActiveTeamPlan } from "@calcom/web/modules/billing/hooks/useHasPaidPlan";
|
||||
import {
|
||||
useHasPaidPlan,
|
||||
useHasActiveTeamPlan,
|
||||
} from "@calcom/web/modules/billing/hooks/useHasPaidPlan";
|
||||
|
||||
import { AddActionDialog } from "./AddActionDialog";
|
||||
import WorkflowStepContainer from "./WorkflowStepContainer";
|
||||
@@ -70,20 +77,28 @@ export default function WorkflowDetailsPage(props: Props) {
|
||||
const eventTypeId = searchParams?.get("eventTypeId");
|
||||
|
||||
// Get base action options and transform them for form triggers
|
||||
const { data: baseActionOptions } = trpc.viewer.workflows.getWorkflowActionOptions.useQuery();
|
||||
const { data: baseActionOptions } =
|
||||
trpc.viewer.workflows.getWorkflowActionOptions.useQuery();
|
||||
|
||||
const transformedActionOptions = baseActionOptions
|
||||
? baseActionOptions
|
||||
.filter((option) => {
|
||||
const isFormWorkflowWithInvalidSteps =
|
||||
isFormTrigger(form.getValues("trigger")) &&
|
||||
!ALLOWED_FORM_WORKFLOW_ACTIONS.some((action) => action === option.value);
|
||||
!ALLOWED_FORM_WORKFLOW_ACTIONS.some(
|
||||
(action) => action === option.value
|
||||
);
|
||||
|
||||
const isSelectAllCalAiAction = isCalAIAction(option.value) && form.watch("selectAll");
|
||||
const isSelectAllCalAiAction =
|
||||
isCalAIAction(option.value) && form.watch("selectAll");
|
||||
|
||||
const isOrgCalAiAction = isCalAIAction(option.value) && isOrg;
|
||||
|
||||
if (isFormWorkflowWithInvalidSteps || isSelectAllCalAiAction || isOrgCalAiAction) {
|
||||
if (
|
||||
isFormWorkflowWithInvalidSteps ||
|
||||
isSelectAllCalAiAction ||
|
||||
isOrgCalAiAction
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -100,7 +115,8 @@ export default function WorkflowDetailsPage(props: Props) {
|
||||
}
|
||||
}
|
||||
|
||||
const needsTeamsUpgrade = isFormTrigger(form.getValues("trigger")) && !hasActiveTeamPlan;
|
||||
const needsTeamsUpgrade =
|
||||
isFormTrigger(form.getValues("trigger")) && !hasActiveTeamPlan;
|
||||
|
||||
return {
|
||||
...option,
|
||||
@@ -117,8 +133,13 @@ export default function WorkflowDetailsPage(props: Props) {
|
||||
: [];
|
||||
|
||||
useEffect(() => {
|
||||
const matchingOption = allOptions.find((option) => option.value === eventTypeId);
|
||||
if (matchingOption && !selectedOptions.find((option) => option.value === eventTypeId)) {
|
||||
const matchingOption = allOptions.find(
|
||||
(option) => option.value === eventTypeId
|
||||
);
|
||||
if (
|
||||
matchingOption &&
|
||||
!selectedOptions.find((option) => option.value === eventTypeId)
|
||||
) {
|
||||
const newOptions = [...selectedOptions, matchingOption];
|
||||
setSelectedOptions(newOptions);
|
||||
form.setValue("activeOn", newOptions);
|
||||
@@ -141,7 +162,9 @@ export default function WorkflowDetailsPage(props: Props) {
|
||||
})[0].id - 1
|
||||
: 0;
|
||||
|
||||
const timeFormat = getTimeFormatStringFromUserTimeFormat(props.user.timeFormat);
|
||||
const timeFormat = getTimeFormatStringFromUserTimeFormat(
|
||||
props.user.timeFormat
|
||||
);
|
||||
|
||||
const template = isFormTrigger(form.getValues("trigger"))
|
||||
? WorkflowTemplates.CUSTOM
|
||||
@@ -174,7 +197,9 @@ export default function WorkflowDetailsPage(props: Props) {
|
||||
template,
|
||||
numberRequired: numberRequired || false,
|
||||
sender: isSMSAction(action) ? sender || SENDER_ID : SENDER_ID,
|
||||
senderName: !isSMSAction(action) ? senderName || SENDER_NAME : SENDER_NAME,
|
||||
senderName: !isSMSAction(action)
|
||||
? senderName || SENDER_NAME
|
||||
: SENDER_NAME,
|
||||
numberVerificationPending: false,
|
||||
includeCalendarEvent: false,
|
||||
verifiedAt: SCANNING_WORKFLOW_STEPS ? null : new Date(),
|
||||
@@ -185,8 +210,10 @@ export default function WorkflowDetailsPage(props: Props) {
|
||||
form.setValue("steps", steps);
|
||||
};
|
||||
|
||||
const { outboundAgentQueries: agentQueriesTrpc, inboundAgentQueries: inboundAgentQueriesTrpc } =
|
||||
useAgentsData(form);
|
||||
const {
|
||||
outboundAgentQueries: agentQueriesTrpc,
|
||||
inboundAgentQueries: inboundAgentQueriesTrpc,
|
||||
} = useAgentsData(form);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -199,9 +226,12 @@ export default function WorkflowDetailsPage(props: Props) {
|
||||
<div className="border-subtle text-subtle ml-1 rounded-lg border p-1">
|
||||
<Icon name="zap" size="16" />
|
||||
</div>
|
||||
<div className="text-sm font-medium leading-none">{t("trigger")}</div>
|
||||
<div className="text-sm font-medium leading-none">
|
||||
{t("trigger")}
|
||||
</div>
|
||||
</div>
|
||||
}>
|
||||
}
|
||||
>
|
||||
<FormCardBody className="border-muted">
|
||||
<WorkflowStepContainer
|
||||
form={form}
|
||||
@@ -228,7 +258,8 @@ export default function WorkflowDetailsPage(props: Props) {
|
||||
const agentData = agentQueriesTrpc[index]?.data;
|
||||
const isAgentLoading = agentQueriesTrpc[index]?.isPending;
|
||||
const inboundAgentData = inboundAgentQueriesTrpc[index]?.data;
|
||||
const isInboundAgentLoading = inboundAgentQueriesTrpc[index]?.isPending;
|
||||
const isInboundAgentLoading =
|
||||
inboundAgentQueriesTrpc[index]?.isPending;
|
||||
|
||||
return (
|
||||
<div key={index}>
|
||||
@@ -241,13 +272,15 @@ export default function WorkflowDetailsPage(props: Props) {
|
||||
<div className="border-subtle text-subtle rounded-lg border p-1">
|
||||
<Icon name="arrow-right" size="16" />
|
||||
</div>
|
||||
<div className="text-sm font-medium leading-none">{t("action")}</div>
|
||||
<div className="text-sm font-medium leading-none">
|
||||
{t("action")}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
deleteField={
|
||||
!permissions.readOnly
|
||||
? {
|
||||
color: "destructive",
|
||||
color: "minimal",
|
||||
check: () => true,
|
||||
disabled: !permissions.canUpdate,
|
||||
fn: () => {
|
||||
@@ -260,11 +293,16 @@ export default function WorkflowDetailsPage(props: Props) {
|
||||
} else {
|
||||
const steps = form.getValues("steps");
|
||||
const updatedSteps = steps
|
||||
?.filter((currStep) => currStep.id !== step.id)
|
||||
?.filter(
|
||||
(currStep) => currStep.id !== step.id
|
||||
)
|
||||
.map((s) => {
|
||||
const updatedStep = s;
|
||||
if (step.stepNumber < updatedStep.stepNumber) {
|
||||
updatedStep.stepNumber = updatedStep.stepNumber - 1;
|
||||
if (
|
||||
step.stepNumber < updatedStep.stepNumber
|
||||
) {
|
||||
updatedStep.stepNumber =
|
||||
updatedStep.stepNumber - 1;
|
||||
}
|
||||
return updatedStep;
|
||||
});
|
||||
@@ -276,7 +314,8 @@ export default function WorkflowDetailsPage(props: Props) {
|
||||
},
|
||||
}
|
||||
: null
|
||||
}>
|
||||
}
|
||||
>
|
||||
<FormCardBody className="border-muted">
|
||||
<WorkflowStepContainer
|
||||
form={form}
|
||||
@@ -316,7 +355,8 @@ export default function WorkflowDetailsPage(props: Props) {
|
||||
type="button"
|
||||
onClick={() => setIsAddActionDialogOpen(true)}
|
||||
color="secondary"
|
||||
className="bg-default">
|
||||
className="bg-default"
|
||||
>
|
||||
{t("add_action")}
|
||||
</Button>
|
||||
</>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user