feat: adds response status select in filters (#6325)

This commit is contained in:
Piyush Gupta
2025-07-31 12:03:11 +05:30
committed by GitHub
parent 23c2d3dce9
commit 3527ac337b
18 changed files with 179 additions and 83 deletions

View File

@@ -28,7 +28,7 @@ const TestComponent = () => {
return (
<div>
<div data-testid="onlyComplete">{selectedFilter.onlyComplete.toString()}</div>
<div data-testid="responseStatus">{selectedFilter.responseStatus}</div>
<div data-testid="filterLength">{selectedFilter.filter.length}</div>
<div data-testid="questionOptionsLength">{selectedOptions.questionOptions.length}</div>
<div data-testid="questionFilterOptionsLength">{selectedOptions.questionFilterOptions.length}</div>
@@ -44,7 +44,7 @@ const TestComponent = () => {
filterType: { filterValue: "value1", filterComboBoxValue: "option1" },
},
],
onlyComplete: true,
responseStatus: "complete",
})
}>
Update Filter
@@ -81,7 +81,7 @@ describe("ResponseFilterContext", () => {
</ResponseFilterProvider>
);
expect(screen.getByTestId("onlyComplete").textContent).toBe("false");
expect(screen.getByTestId("responseStatus").textContent).toBe("all");
expect(screen.getByTestId("filterLength").textContent).toBe("0");
expect(screen.getByTestId("questionOptionsLength").textContent).toBe("0");
expect(screen.getByTestId("questionFilterOptionsLength").textContent).toBe("0");
@@ -99,7 +99,7 @@ describe("ResponseFilterContext", () => {
const updateButton = screen.getByText("Update Filter");
await userEvent.click(updateButton);
expect(screen.getByTestId("onlyComplete").textContent).toBe("true");
expect(screen.getByTestId("responseStatus").textContent).toBe("complete");
expect(screen.getByTestId("filterLength").textContent).toBe("1");
});

View File

@@ -16,9 +16,11 @@ export interface FilterValue {
};
}
export type TResponseStatus = "all" | "complete" | "partial";
export interface SelectedFilterValue {
filter: FilterValue[];
onlyComplete: boolean;
responseStatus: TResponseStatus;
}
interface SelectedFilterOptions {
@@ -47,7 +49,7 @@ const ResponseFilterProvider = ({ children }: { children: React.ReactNode }) =>
// state holds the filter selected value
const [selectedFilter, setSelectedFilter] = useState<SelectedFilterValue>({
filter: [],
onlyComplete: false,
responseStatus: "all",
});
// state holds all the options of the responses fetched
const [selectedOptions, setSelectedOptions] = useState<SelectedFilterOptions>({
@@ -67,7 +69,7 @@ const ResponseFilterProvider = ({ children }: { children: React.ReactNode }) =>
});
setSelectedFilter({
filter: [],
onlyComplete: false,
responseStatus: "all",
});
}, []);

View File

@@ -191,7 +191,7 @@ const mockSurvey = {
variables: [],
} as unknown as TSurvey;
const mockSelectedFilter = { filter: [], onlyComplete: false };
const mockSelectedFilter = { filter: [], responseStatus: "all" };
const mockSetSelectedFilter = vi.fn();
const defaultProps = {
@@ -309,17 +309,13 @@ describe("SummaryList", () => {
test("renders EmptySpaceFiller when responseCount is 0 and summary is not empty (no responses match filter)", () => {
const summaryWithItem = [createMockQuestionSummary("q1", TSurveyQuestionTypeEnum.OpenText)];
render(
<SummaryList {...defaultProps} summary={summaryWithItem} responseCount={0} totalResponseCount={10} />
);
render(<SummaryList {...defaultProps} summary={summaryWithItem} responseCount={0} />);
expect(screen.getByText("Mocked EmptySpaceFiller")).toBeInTheDocument();
});
test("renders EmptySpaceFiller when responseCount is 0 and totalResponseCount is 0 (no responses at all)", () => {
const summaryWithItem = [createMockQuestionSummary("q1", TSurveyQuestionTypeEnum.OpenText)];
render(
<SummaryList {...defaultProps} summary={summaryWithItem} responseCount={0} totalResponseCount={0} />
);
render(<SummaryList {...defaultProps} summary={summaryWithItem} responseCount={0} />);
expect(screen.getByText("Mocked EmptySpaceFiller")).toBeInTheDocument();
});
@@ -397,7 +393,7 @@ describe("SummaryList", () => {
},
},
],
onlyComplete: false,
responseStatus: "all",
});
// Ensure vi.mocked(toast.success) refers to the spy from the named export
expect(vi.mocked(toast).success).toHaveBeenCalledWith("Custom add message", { duration: 5000 });
@@ -425,7 +421,7 @@ describe("SummaryList", () => {
},
};
vi.mocked(useResponseFilter).mockReturnValue({
selectedFilter: { filter: [existingFilter], onlyComplete: false },
selectedFilter: { filter: [existingFilter], responseStatus: "all" },
setSelectedFilter: mockSetSelectedFilter,
resetFilter: vi.fn(),
} as any);
@@ -454,7 +450,7 @@ describe("SummaryList", () => {
},
},
],
onlyComplete: false,
responseStatus: "all",
});
expect(vi.mocked(toast.success)).toHaveBeenCalledWith(
"environments.surveys.summary.filter_updated_successfully",

View File

@@ -92,7 +92,7 @@ export const SummaryList = ({ summary, environment, responseCount, survey, local
setSelectedFilter({
filter: [...filterObject.filter],
onlyComplete: filterObject.onlyComplete,
responseStatus: filterObject.responseStatus,
});
};

View File

@@ -197,7 +197,7 @@ export const QuestionFilterComboBox = ({
</div>
<div className="relative mt-2 h-full">
{open && (
<div className="animate-in bg-popover absolute top-0 z-10 max-h-52 w-full overflow-auto rounded-md bg-white outline-none">
<div className="animate-in absolute top-0 z-10 max-h-52 w-full overflow-auto rounded-md bg-white outline-none">
<CommandList>
<div className="p-2">
<Input

View File

@@ -188,7 +188,7 @@ export const QuestionsComboBox = ({ options, selected, onChangeValue }: Question
</button>
<div className="relative mt-2 h-full">
{open && (
<div className="animate-in bg-popover absolute top-0 z-50 max-h-52 w-full overflow-auto rounded-md bg-white outline-none">
<div className="animate-in absolute top-0 z-50 w-full overflow-auto rounded-md bg-white outline-none">
<CommandList>
<CommandEmpty>{t("common.no_result_found")}</CommandEmpty>
{options?.map((data) => (

View File

@@ -30,6 +30,45 @@ vi.mock("@formkit/auto-animate/react", () => ({
useAutoAnimate: () => [[vi.fn()]],
}));
// Mock the Select components
const mockOnValueChange = vi.fn();
vi.mock("@/modules/ui/components/select", () => ({
Select: ({ children, onValueChange, defaultValue }) => {
// Store the onValueChange callback for testing
mockOnValueChange.mockImplementation(onValueChange);
return (
<div data-testid="select-root" data-default-value={defaultValue}>
{children}
</div>
);
},
SelectTrigger: ({ children, className }) => (
<div
role="combobox"
className={className}
data-testid="select-trigger"
tabIndex={0}
aria-expanded="false"
aria-haspopup="listbox">
{children}
</div>
),
SelectValue: () => <span>environments.surveys.filter.complete_and_partial_responses</span>,
SelectContent: ({ children }) => <div data-testid="select-content">{children}</div>,
SelectItem: ({ value, children, ...props }) => (
<div
data-testid={`select-item-${value}`}
data-value={value}
onClick={() => mockOnValueChange(value)}
onKeyDown={(e) => e.key === "Enter" && mockOnValueChange(value)}
role="option"
tabIndex={0}
{...props}>
{children}
</div>
),
}));
vi.mock("./QuestionsComboBox", () => ({
QuestionsComboBox: ({ onChangeValue }) => (
<div data-testid="questions-combo-box">
@@ -67,7 +106,7 @@ describe("ResponseFilter", () => {
const mockSelectedFilter = {
filter: [],
onlyComplete: false,
responseStatus: "all",
};
const mockSelectedOptions = {
@@ -145,7 +184,7 @@ describe("ResponseFilter", () => {
expect(
screen.getByText("environments.surveys.summary.show_all_responses_that_match")
).toBeInTheDocument();
expect(screen.getByText("environments.surveys.summary.only_completed")).toBeInTheDocument();
expect(screen.getByTestId("select-trigger")).toBeInTheDocument();
});
test("fetches filter data when opened", async () => {
@@ -160,7 +199,7 @@ describe("ResponseFilter", () => {
test("handles adding new filter", async () => {
// Start with an empty filter
vi.mocked(useResponseFilter).mockReturnValue({
selectedFilter: { filter: [], onlyComplete: false },
selectedFilter: { filter: [], responseStatus: "all" },
setSelectedFilter: mockSetSelectedFilter,
selectedOptions: mockSelectedOptions,
setSelectedOptions: mockSetSelectedOptions,
@@ -178,14 +217,38 @@ describe("ResponseFilter", () => {
expect(screen.getByTestId("questions-combo-box")).toBeInTheDocument();
});
test("handles only complete checkbox toggle", async () => {
test("handles response status filter change to complete", async () => {
render(<ResponseFilter survey={mockSurvey} />);
await userEvent.click(screen.getByText("Filter"));
await userEvent.click(screen.getByRole("checkbox"));
// Simulate selecting "complete" by calling the mock function
mockOnValueChange("complete");
await userEvent.click(screen.getByText("common.apply_filters"));
expect(mockSetSelectedFilter).toHaveBeenCalledWith({ filter: [], onlyComplete: true });
expect(mockSetSelectedFilter).toHaveBeenCalledWith(
expect.objectContaining({
responseStatus: "complete",
})
);
});
test("handles response status filter change to partial", async () => {
render(<ResponseFilter survey={mockSurvey} />);
await userEvent.click(screen.getByText("Filter"));
// Simulate selecting "partial" by calling the mock function
mockOnValueChange("partial");
await userEvent.click(screen.getByText("common.apply_filters"));
expect(mockSetSelectedFilter).toHaveBeenCalledWith(
expect.objectContaining({
responseStatus: "partial",
})
);
});
test("handles selecting question and filter options", async () => {
@@ -199,7 +262,7 @@ describe("ResponseFilter", () => {
filterType: { filterComboBoxValue: undefined, filterValue: undefined },
},
],
onlyComplete: false,
responseStatus: "all",
},
setSelectedFilter: setSelectedFilterMock,
selectedOptions: mockSelectedOptions,
@@ -228,6 +291,6 @@ describe("ResponseFilter", () => {
await userEvent.click(screen.getByText("Filter"));
await userEvent.click(screen.getByText("common.clear_all"));
expect(mockSetSelectedFilter).toHaveBeenCalledWith({ filter: [], onlyComplete: false });
expect(mockSetSelectedFilter).toHaveBeenCalledWith({ filter: [], responseStatus: "all" });
});
});

View File

@@ -2,17 +2,23 @@
import {
SelectedFilterValue,
TResponseStatus,
useResponseFilter,
} from "@/app/(app)/environments/[environmentId]/components/ResponseFilterContext";
import { getSurveyFilterDataAction } from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/actions";
import { QuestionFilterComboBox } from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/components/QuestionFilterComboBox";
import { generateQuestionAndFilterOptions } from "@/app/lib/surveys/surveys";
import { Button } from "@/modules/ui/components/button";
import { Checkbox } from "@/modules/ui/components/checkbox";
import { Popover, PopoverContent, PopoverTrigger } from "@/modules/ui/components/popover";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/modules/ui/components/select";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { useTranslate } from "@tolgee/react";
import clsx from "clsx";
import { ChevronDown, ChevronUp, Plus, TrashIcon } from "lucide-react";
import React, { useEffect, useState } from "react";
import { TSurvey, TSurveyQuestionTypeEnum } from "@formbricks/types/surveys/types";
@@ -72,7 +78,7 @@ export const ResponseFilter = ({ survey }: ResponseFilterProps) => {
)?.filterOptions[0],
},
};
setFilterValue({ filter: [...filterValue.filter], onlyComplete: filterValue.onlyComplete });
setFilterValue({ filter: [...filterValue.filter], responseStatus: filterValue.responseStatus });
} else {
// Update the existing value at the specified index
filterValue.filter[index].questionType = value;
@@ -93,7 +99,7 @@ export const ResponseFilter = ({ survey }: ResponseFilterProps) => {
// keep the filter if questionType is selected and filterComboBoxValue is selected
return s.questionType.hasOwnProperty("label") && s.filterType.filterComboBoxValue?.length;
}),
onlyComplete: filterValue.onlyComplete,
responseStatus: filterValue.responseStatus,
});
};
@@ -120,8 +126,8 @@ export const ResponseFilter = ({ survey }: ResponseFilterProps) => {
};
const handleClearAllFilters = () => {
setFilterValue((filterValue) => ({ ...filterValue, filter: [] }));
setSelectedFilter((selectedFilters) => ({ ...selectedFilters, filter: [] }));
setFilterValue((filterValue) => ({ ...filterValue, filter: [], responseStatus: "all" }));
setSelectedFilter((selectedFilters) => ({ ...selectedFilters, filter: [], responseStatus: "all" }));
setIsOpen(false);
};
@@ -158,8 +164,8 @@ export const ResponseFilter = ({ survey }: ResponseFilterProps) => {
setFilterValue({ ...filterValue });
};
const handleCheckOnlyComplete = (checked: boolean) => {
setFilterValue({ ...filterValue, onlyComplete: checked });
const handleResponseStatusChange = (responseStatus: TResponseStatus) => {
setFilterValue({ ...filterValue, responseStatus });
};
// remove the filter which has already been selected
@@ -203,8 +209,9 @@ export const ResponseFilter = ({ survey }: ResponseFilterProps) => {
</PopoverTrigger>
<PopoverContent
align="start"
className="w-[300px] border-slate-200 bg-slate-100 p-6 sm:w-[400px] md:w-[750px] lg:w-[1000px]">
<div className="mb-8 flex flex-wrap items-start justify-between">
className="w-[300px] border-slate-200 bg-slate-100 p-6 sm:w-[400px] md:w-[750px] lg:w-[1000px]"
onOpenAutoFocus={(event) => event.preventDefault()}>
<div className="mb-8 flex flex-wrap items-start justify-between gap-2">
<p className="text-slate800 hidden text-lg font-semibold sm:block">
{t("environments.surveys.summary.show_all_responses_that_match")}
</p>
@@ -212,16 +219,24 @@ export const ResponseFilter = ({ survey }: ResponseFilterProps) => {
{t("environments.surveys.summary.show_all_responses_where")}
</p>
<div className="flex items-center space-x-2">
<label className="text-sm font-normal text-slate-600">
{t("environments.surveys.summary.only_completed")}
</label>
<Checkbox
className={clsx("rounded-md", filterValue.onlyComplete && "bg-black text-white")}
checked={filterValue.onlyComplete}
onCheckedChange={(checked) => {
typeof checked === "boolean" && handleCheckOnlyComplete(checked);
<Select
onValueChange={(val) => {
handleResponseStatusChange(val as TResponseStatus);
}}
/>
defaultValue={filterValue.responseStatus}>
<SelectTrigger className="w-full bg-white">
<SelectValue />
</SelectTrigger>
<SelectContent position="popper">
<SelectItem value="all">
{t("environments.surveys.filter.complete_and_partial_responses")}
</SelectItem>
<SelectItem value="complete">
{t("environments.surveys.filter.complete_responses")}
</SelectItem>
<SelectItem value="partial">{t("environments.surveys.filter.partial_responses")}</SelectItem>
</SelectContent>
</Select>
</div>
</div>

View File

@@ -320,7 +320,7 @@ describe("surveys", () => {
test("should return empty filters when no selections", () => {
const selectedFilter: SelectedFilterValue = {
onlyComplete: false,
responseStatus: "all",
filter: [],
};
@@ -331,7 +331,7 @@ describe("surveys", () => {
test("should filter by completed responses", () => {
const selectedFilter: SelectedFilterValue = {
onlyComplete: true,
responseStatus: "complete",
filter: [],
};
@@ -342,7 +342,7 @@ describe("surveys", () => {
test("should filter by date range", () => {
const selectedFilter: SelectedFilterValue = {
onlyComplete: false,
responseStatus: "all",
filter: [],
};
@@ -355,7 +355,7 @@ describe("surveys", () => {
test("should filter by tags", () => {
const selectedFilter: SelectedFilterValue = {
onlyComplete: false,
responseStatus: "all",
filter: [
{
questionType: { type: "Tags", label: "Tag 1", id: "tag1" },
@@ -376,7 +376,7 @@ describe("surveys", () => {
test("should filter by open text questions", () => {
const selectedFilter: SelectedFilterValue = {
onlyComplete: false,
responseStatus: "all",
filter: [
{
questionType: {
@@ -397,7 +397,7 @@ describe("surveys", () => {
test("should filter by address questions", () => {
const selectedFilter: SelectedFilterValue = {
onlyComplete: false,
responseStatus: "all",
filter: [
{
questionType: {
@@ -418,7 +418,7 @@ describe("surveys", () => {
test("should filter by contact info questions", () => {
const selectedFilter: SelectedFilterValue = {
onlyComplete: false,
responseStatus: "all",
filter: [
{
questionType: {
@@ -439,7 +439,7 @@ describe("surveys", () => {
test("should filter by ranking questions", () => {
const selectedFilter: SelectedFilterValue = {
onlyComplete: false,
responseStatus: "all",
filter: [
{
questionType: {
@@ -460,7 +460,7 @@ describe("surveys", () => {
test("should filter by multiple choice single questions", () => {
const selectedFilter: SelectedFilterValue = {
onlyComplete: false,
responseStatus: "all",
filter: [
{
questionType: {
@@ -481,7 +481,7 @@ describe("surveys", () => {
test("should filter by multiple choice multi questions", () => {
const selectedFilter: SelectedFilterValue = {
onlyComplete: false,
responseStatus: "all",
filter: [
{
questionType: {
@@ -502,7 +502,7 @@ describe("surveys", () => {
test("should filter by NPS questions with different operations", () => {
const selectedFilter: SelectedFilterValue = {
onlyComplete: false,
responseStatus: "all",
filter: [
{
questionType: {
@@ -523,7 +523,7 @@ describe("surveys", () => {
test("should filter by rating questions with less than operation", () => {
const selectedFilter: SelectedFilterValue = {
onlyComplete: false,
responseStatus: "all",
filter: [
{
questionType: {
@@ -544,7 +544,7 @@ describe("surveys", () => {
test("should filter by CTA questions", () => {
const selectedFilter: SelectedFilterValue = {
onlyComplete: false,
responseStatus: "all",
filter: [
{
questionType: {
@@ -565,7 +565,7 @@ describe("surveys", () => {
test("should filter by consent questions", () => {
const selectedFilter: SelectedFilterValue = {
onlyComplete: false,
responseStatus: "all",
filter: [
{
questionType: {
@@ -586,7 +586,7 @@ describe("surveys", () => {
test("should filter by picture selection questions", () => {
const selectedFilter: SelectedFilterValue = {
onlyComplete: false,
responseStatus: "all",
filter: [
{
questionType: {
@@ -607,7 +607,7 @@ describe("surveys", () => {
test("should filter by matrix questions", () => {
const selectedFilter: SelectedFilterValue = {
onlyComplete: false,
responseStatus: "all",
filter: [
{
questionType: {
@@ -628,7 +628,7 @@ describe("surveys", () => {
test("should filter by hidden fields", () => {
const selectedFilter: SelectedFilterValue = {
onlyComplete: false,
responseStatus: "all",
filter: [
{
questionType: { type: "Hidden Fields", label: "plan", id: "plan" },
@@ -644,7 +644,7 @@ describe("surveys", () => {
test("should filter by attributes", () => {
const selectedFilter: SelectedFilterValue = {
onlyComplete: false,
responseStatus: "all",
filter: [
{
questionType: { type: "Attributes", label: "role", id: "role" },
@@ -660,7 +660,7 @@ describe("surveys", () => {
test("should filter by other filters", () => {
const selectedFilter: SelectedFilterValue = {
onlyComplete: false,
responseStatus: "all",
filter: [
{
questionType: { type: "Other Filters", label: "Language", id: "language" },
@@ -676,7 +676,7 @@ describe("surveys", () => {
test("should filter by meta fields", () => {
const selectedFilter: SelectedFilterValue = {
onlyComplete: false,
responseStatus: "all",
filter: [
{
questionType: { type: "Meta", label: "source", id: "source" },
@@ -692,7 +692,7 @@ describe("surveys", () => {
test("should handle multiple filters together", () => {
const selectedFilter: SelectedFilterValue = {
onlyComplete: true,
responseStatus: "complete",
filter: [
{
questionType: {

View File

@@ -242,8 +242,10 @@ export const getFormattedFilters = (
});
// for completed responses
if (selectedFilter.onlyComplete) {
if (selectedFilter.responseStatus === "complete") {
filters["finished"] = true;
} else if (selectedFilter.responseStatus === "partial") {
filters["finished"] = false;
}
// for date range responses

View File

@@ -510,13 +510,11 @@
"create_action": "Aktion erstellen",
"css_selector": "CSS-Selektor",
"delete_action_text": "Bist Du sicher, dass Du diese Aktion löschen möchtest? Dadurch wird diese Aktion auch als Auslöser aus all deinen Umfragen entfernt.",
"display_name": "Anzeigename",
"does_not_contain": "Enthält nicht",
"does_not_exactly_match": "Stimmt nicht genau überein",
"eg_clicked_download": "z.B. 'Herunterladen' geklickt",
"eg_download_cta_click_on_home": "z.B. Download-CTA-Klick auf der Startseite",
"eg_install_app": "z.B. App installieren",
"eg_user_clicked_download_button": "z.B. Benutzer hat auf 'Herunterladen' geklickt",
"ends_with": "endet mit",
"enter_a_url_to_see_if_a_user_visiting_it_would_be_tracked": "Teste eine URL, um zu sehen, ob der Nutzer deine Umfrage sehen würde.",
"enter_url": "z.B. https://app.com/dashboard",
@@ -1616,6 +1614,11 @@
"zip": "Postleitzahl"
},
"error_deleting_survey": "Beim Löschen der Umfrage ist ein Fehler aufgetreten",
"filter": {
"complete_and_partial_responses": "Vollständige und Teilantworten",
"complete_responses": "Vollständige Antworten",
"partial_responses": "Teilantworten"
},
"new_survey": "Neue Umfrage",
"no_surveys_created_yet": "Noch keine Umfragen erstellt",
"open_options": "Optionen öffnen",

View File

@@ -510,13 +510,11 @@
"create_action": "Create action",
"css_selector": "CSS Selector",
"delete_action_text": "Are you sure you want to delete this action? This also removes this action as a trigger from all your surveys.",
"display_name": "Display name",
"does_not_contain": "Does not contain",
"does_not_exactly_match": "Does not exactly match",
"eg_clicked_download": "E.g. Clicked Download",
"eg_download_cta_click_on_home": "e.g. download_cta_click_on_home",
"eg_install_app": "E.g. Install App",
"eg_user_clicked_download_button": "E.g. User clicked Download Button",
"ends_with": "Ends with",
"enter_a_url_to_see_if_a_user_visiting_it_would_be_tracked": "Enter a URL to see if a user visiting it would be tracked.",
"enter_url": "e.g. https://app.com/dashboard",
@@ -1616,6 +1614,11 @@
"zip": "Zip"
},
"error_deleting_survey": "An error occured while deleting survey",
"filter": {
"complete_and_partial_responses": "Complete and partial responses",
"complete_responses": "Complete responses",
"partial_responses": "Partial responses"
},
"new_survey": "New Survey",
"no_surveys_created_yet": "No surveys created yet",
"open_options": "Open options",

View File

@@ -510,13 +510,11 @@
"create_action": "Créer une action",
"css_selector": "Sélecteur CSS",
"delete_action_text": "Êtes-vous sûr de vouloir supprimer cette action ? Cela supprime également cette action en tant que déclencheur de toutes vos enquêtes.",
"display_name": "Nom d'affichage",
"does_not_contain": "Ne contient pas",
"does_not_exactly_match": "Ne correspond pas exactement",
"eg_clicked_download": "Par exemple, cliqué sur Télécharger",
"eg_download_cta_click_on_home": "Par exemple, cliquez sur le CTA de téléchargement sur la page d'accueil",
"eg_install_app": "Par exemple, installer l'application",
"eg_user_clicked_download_button": "Par exemple, l'utilisateur a cliqué sur le bouton de téléchargement.",
"ends_with": "Se termine par",
"enter_a_url_to_see_if_a_user_visiting_it_would_be_tracked": "Saisissez une URL pour voir si un utilisateur la visitant serait suivi.",
"enter_url": "par exemple https://app.com/dashboard",
@@ -1616,6 +1614,11 @@
"zip": "Zip"
},
"error_deleting_survey": "Une erreur est survenue lors de la suppression de l'enquête.",
"filter": {
"complete_and_partial_responses": "Réponses complètes et partielles",
"complete_responses": "Réponses complètes",
"partial_responses": "Réponses partielles"
},
"new_survey": "Nouveau Sondage",
"no_surveys_created_yet": "Aucun sondage créé pour le moment",
"open_options": "Ouvrir les options",

View File

@@ -510,13 +510,11 @@
"create_action": "criar ação",
"css_selector": "Seletor CSS",
"delete_action_text": "Tem certeza de que quer deletar essa ação? Isso também vai remover essa ação como gatilho de todas as suas pesquisas.",
"display_name": "Nome de exibição",
"does_not_contain": "não contém",
"does_not_exactly_match": "Não bate exatamente",
"eg_clicked_download": "Por exemplo, clicou em baixar",
"eg_download_cta_click_on_home": "e.g. download_cta_click_on_home",
"eg_install_app": "Ex: Instalar App",
"eg_user_clicked_download_button": "Por exemplo, usuário clicou no botão de download",
"ends_with": "Termina com",
"enter_a_url_to_see_if_a_user_visiting_it_would_be_tracked": "Digite uma URL para ver se um usuário que a visita seria rastreado.",
"enter_url": "ex.: https://app.com/dashboard",
@@ -1616,6 +1614,11 @@
"zip": "Fecho éclair"
},
"error_deleting_survey": "Ocorreu um erro ao deletar a pesquisa",
"filter": {
"complete_and_partial_responses": "Respostas completas e parciais",
"complete_responses": "Respostas completas",
"partial_responses": "Respostas parciais"
},
"new_survey": "Nova Pesquisa",
"no_surveys_created_yet": "Ainda não foram criadas pesquisas",
"open_options": "Abre opções",

View File

@@ -510,13 +510,11 @@
"create_action": "Criar ação",
"css_selector": "Seletor CSS",
"delete_action_text": "Tem a certeza de que deseja eliminar esta ação? Isto também remove esta ação como um gatilho de todos os seus inquéritos.",
"display_name": "Nome de exibição",
"does_not_contain": "Não contém",
"does_not_exactly_match": "Não corresponde exatamente",
"eg_clicked_download": "Por exemplo, Clicou em Descarregar",
"eg_download_cta_click_on_home": "por exemplo, descarregar_cta_clicar_em_home",
"eg_install_app": "Ex. Instalar App",
"eg_user_clicked_download_button": "Por exemplo, Utilizador clicou no Botão Descarregar",
"ends_with": "Termina com",
"enter_a_url_to_see_if_a_user_visiting_it_would_be_tracked": "Introduza um URL para ver se um utilizador que o visita seria rastreado.",
"enter_url": "por exemplo, https://app.com/dashboard",
@@ -1616,6 +1614,11 @@
"zip": "Comprimir"
},
"error_deleting_survey": "Ocorreu um erro ao eliminar o questionário",
"filter": {
"complete_and_partial_responses": "Respostas completas e parciais",
"complete_responses": "Respostas completas",
"partial_responses": "Respostas parciais"
},
"new_survey": "Novo inquérito",
"no_surveys_created_yet": "Ainda não foram criados questionários",
"open_options": "Abrir opções",

View File

@@ -510,13 +510,11 @@
"create_action": "建立操作",
"css_selector": "CSS 選取器",
"delete_action_text": "您確定要刪除此操作嗎?這也會從您的所有問卷中移除此操作作為觸發器。",
"display_name": "顯示名稱",
"does_not_contain": "不包含",
"does_not_exactly_match": "不完全相符",
"eg_clicked_download": "例如,點擊下載",
"eg_download_cta_click_on_home": "例如download_cta_click_on_home",
"eg_install_app": "例如,安裝應用程式",
"eg_user_clicked_download_button": "例如,使用者點擊了下載按鈕",
"ends_with": "結尾為",
"enter_a_url_to_see_if_a_user_visiting_it_would_be_tracked": "輸入網址以查看造訪該網址的使用者是否會被追蹤。",
"enter_url": "例如 https://app.com/dashboard",
@@ -1616,6 +1614,11 @@
"zip": "郵遞區號"
},
"error_deleting_survey": "刪除問卷時發生錯誤",
"filter": {
"complete_and_partial_responses": "完整 和 部分 回應",
"complete_responses": "完整回應",
"partial_responses": "部分回應"
},
"new_survey": "新增問卷",
"no_surveys_created_yet": "尚未建立任何問卷",
"open_options": "開啟選項",

View File

@@ -60,7 +60,7 @@ function CommandInput({
...props
}: React.ComponentProps<typeof CommandPrimitive.Input> & { hidden?: boolean }) {
return (
<div data-slot="command-input-wrapper" className={cn("flex h-11 items-center")}>
<div data-slot="command-input-wrapper" className={cn("flex items-center")}>
<SearchIcon className="h-4 w-4 shrink-0 text-slate-500" />
<CommandPrimitive.Input
data-slot="command-input"