mirror of
https://github.com/RSSNext/Folo.git
synced 2026-10-17 05:08:13 +08:00
fix(actions): reset the operator and value when a condition changes field type
Changing a rule condition's field only merged the new field, so a "title contains foo" condition switched to "Subscription view" kept the text operator and value. The operator select showed nothing and the rule saved an invalid condition. Desktop and mobile now go through changeConditionField, which keeps the operator and value only when the new field has the same type. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -90,7 +90,12 @@ export const WhenSection = ({ index }: WhenSectionProps) => {
|
||||
placeholder={t("actions.action_card.select_field")}
|
||||
disabled={disabled}
|
||||
value={item.field}
|
||||
onValueChange={(value) => change("field", value as ActionFeedField)}
|
||||
onValueChange={(value) =>
|
||||
actionActions.changeConditionField(
|
||||
actionConditionIndex,
|
||||
value as ActionFeedField,
|
||||
)
|
||||
}
|
||||
items={filterFieldOptions.map((option) => ({
|
||||
...option,
|
||||
label: t(option.label),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { filterFieldOptions, filterOperatorOptions } from "@follow/store/action/constant"
|
||||
import { useActionRuleCondition } from "@follow/store/action/hooks"
|
||||
import { actionActions } from "@follow/store/action/store"
|
||||
import type { ActionConditionIndex } from "@follow-app/client-sdk"
|
||||
import type { ActionConditionIndex, ActionFeedField } from "@follow-app/client-sdk"
|
||||
import { useMemo } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { View } from "react-native"
|
||||
@@ -72,9 +72,7 @@ function ConditionForm({ index }: { index: ActionConditionIndex }) {
|
||||
}))}
|
||||
value={currentField?.value}
|
||||
onValueChange={(value) => {
|
||||
actionActions.pathCondition(index, {
|
||||
field: value as any,
|
||||
})
|
||||
actionActions.changeConditionField(index, value as ActionFeedField)
|
||||
}}
|
||||
wrapperClassName="min-w-48"
|
||||
/>
|
||||
|
||||
@@ -72,6 +72,9 @@ const filterFieldOptionsMap: {
|
||||
|
||||
export const filterFieldOptions = Object.values(filterFieldOptionsMap)
|
||||
|
||||
export const getFilterFieldType = (field: ActionFeedField | undefined) =>
|
||||
(field && filterFieldOptionsMap[field]?.type) || "text"
|
||||
|
||||
const filterOperatorOptionsMap: {
|
||||
[K in ActionOperation]: {
|
||||
label: Extract<ParseKeys<"settings">, `actions.action_card.operation_options.${string}`>
|
||||
|
||||
@@ -30,4 +30,21 @@ describe("actionActions", () => {
|
||||
|
||||
expect(useActionStore.getState().rules.map((rule) => rule.index)).toEqual([0, 1])
|
||||
})
|
||||
|
||||
test("clears the operator and value when the field type changes", () => {
|
||||
actionActions.addRule((index) => `Action ${index}`)
|
||||
actionActions.toggleRuleFilter(0)
|
||||
const index = { ruleIndex: 0, groupIndex: 0, conditionIndex: 0 }
|
||||
actionActions.pathCondition(index, { field: "entry_title", operator: "contains", value: "foo" })
|
||||
|
||||
actionActions.changeConditionField(index, "entry_content")
|
||||
expect(useActionStore.getState().rules[0]!.condition[0]![0]).toEqual({
|
||||
field: "entry_content",
|
||||
operator: "contains",
|
||||
value: "foo",
|
||||
})
|
||||
|
||||
actionActions.changeConditionField(index, "view")
|
||||
expect(useActionStore.getState().rules[0]!.condition[0]![0]).toEqual({ field: "view" })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { SyncMetaService } from "@follow/database/services/sync-meta"
|
||||
import type {
|
||||
ActionConditionIndex,
|
||||
ActionFeedField,
|
||||
ActionFilterItem,
|
||||
ActionId,
|
||||
ActionItem as ActionItemRes,
|
||||
@@ -13,6 +14,7 @@ import type { Hydratable, Resetable } from "../../lib/base"
|
||||
import { createImmerSetter, createZustandStore } from "../../lib/helper"
|
||||
import { registerSyncModel } from "../../sync/model-registry"
|
||||
import { ensureSyncedThroughEngine } from "../../sync/sync-status"
|
||||
import { getFilterFieldType } from "./constant"
|
||||
|
||||
export type ActionItem = Omit<ActionItemRes, "condition"> & {
|
||||
condition: ActionFilterItem[][]
|
||||
@@ -183,6 +185,20 @@ class ActionActions implements Hydratable, Resetable {
|
||||
})
|
||||
}
|
||||
|
||||
changeConditionField(index: ActionConditionIndex, field: ActionFeedField) {
|
||||
immerSet((state) => {
|
||||
const group = state.rules[index.ruleIndex]?.condition[index.groupIndex]
|
||||
const item = group?.[index.conditionIndex]
|
||||
if (!group || !item) return
|
||||
// The operator and value only make sense for the previous field type
|
||||
group[index.conditionIndex] =
|
||||
getFilterFieldType(item.field) === getFilterFieldType(field)
|
||||
? { ...item, field }
|
||||
: { field }
|
||||
state.isDirty = true
|
||||
})
|
||||
}
|
||||
|
||||
addConditionItem(index: Omit<ActionConditionIndex, "conditionIndex">) {
|
||||
immerSet((state) => {
|
||||
const rule = state.rules[index.ruleIndex]
|
||||
|
||||
Reference in New Issue
Block a user