diff --git a/.changeset/light-chefs-applaud.md b/.changeset/light-chefs-applaud.md
new file mode 100644
index 000000000..acf642284
--- /dev/null
+++ b/.changeset/light-chefs-applaud.md
@@ -0,0 +1,5 @@
+---
+'@farfetched/core': patch
+---
+
+Support `enabled` in `keepFresh`
diff --git a/apps/website/docs/api/operators/keep_fresh.md b/apps/website/docs/api/operators/keep_fresh.md
index fae79fc53..615daa719 100644
--- a/apps/website/docs/api/operators/keep_fresh.md
+++ b/apps/website/docs/api/operators/keep_fresh.md
@@ -14,6 +14,7 @@ Config fields:
- `automatically?`: _true_ to refresh the data in a [_Query_](/api/primitives/query) automatically if any [_Store_](https://effector.dev/docs/api/effector/store) that is used in the [_Query_](/api/primitives/query) creation is changed.
- `triggers?`: _Array_ of [_Events_](https://effector.dev/docs/api/effector/event) after which operator starts refreshing the data in the [_Query_](/api/primitives/query).
+- `enabled?`: [_Store_](https://effector.dev/docs/api/effector/store) with the current enabled state. Disabled _keepFresh_ will not execute queries, instead, they will be treated as skipped. Can be `true` or `false`.
```ts
import { keepFresh } from '@farfetched/core';
diff --git a/packages/core/src/trigger_api/__test__/keep_fresh.test-d.ts b/packages/core/src/trigger_api/__test__/keep_fresh.test-d.ts
index a4f895923..fc9ead679 100644
--- a/packages/core/src/trigger_api/__test__/keep_fresh.test-d.ts
+++ b/packages/core/src/trigger_api/__test__/keep_fresh.test-d.ts
@@ -1,4 +1,4 @@
-import { Event } from 'effector';
+import { createStore, Event } from 'effector';
import { describe, test } from 'vitest';
import { Query } from '../../query/type';
@@ -11,6 +11,13 @@ describe('keepFresh', () => {
keepFresh(q, { automatically: true });
keepFresh(q, { triggers: [] });
keepFresh(q, { automatically: true, triggers: [] });
+ keepFresh(q, { automatically: true, enabled: createStore(true) });
+ keepFresh(q, { triggers: [], enabled: createStore(true) });
+ keepFresh(q, {
+ automatically: true,
+ triggers: [],
+ enabled: createStore(true),
+ });
});
test('supports any Event as trigger', () => {
diff --git a/packages/core/src/trigger_api/__test__/keep_fresh.triggers.test.ts b/packages/core/src/trigger_api/__test__/keep_fresh.triggers.test.ts
index 32ca7773a..efe8368ad 100644
--- a/packages/core/src/trigger_api/__test__/keep_fresh.triggers.test.ts
+++ b/packages/core/src/trigger_api/__test__/keep_fresh.triggers.test.ts
@@ -214,4 +214,56 @@ describe('keepFresh, triggers as TriggerProtocol', () => {
// 1 initial + 1 after enabling
expect(setupListener).toBeCalledTimes(2);
});
+
+ test('call teardown after config disabling and call start again after enabling', async () => {
+ const trigger = {
+ setup: createEvent(),
+ teardown: createEvent(),
+ fired: createEvent(),
+ };
+
+ const scope = fork();
+
+ const $enabled = createStore(true);
+
+ const teardownListener = vi.fn();
+
+ createWatch({
+ unit: trigger.teardown,
+ fn: teardownListener,
+ scope,
+ });
+
+ const setupListener = vi.fn();
+
+ createWatch({
+ unit: trigger.setup,
+ fn: setupListener,
+ scope,
+ });
+
+ const query = createQuery({
+ handler: vi.fn(),
+ });
+
+ keepFresh(query, {
+ enabled: $enabled,
+ triggers: [
+ {
+ '@@trigger': () => trigger,
+ },
+ ],
+ });
+
+ await allSettled(query.refresh, { scope });
+
+ await allSettled($enabled, { scope, params: false });
+
+ expect(teardownListener).toBeCalled();
+
+ await allSettled($enabled, { scope, params: true });
+
+ // 1 initial + 1 after enabling
+ expect(setupListener).toBeCalledTimes(2);
+ });
});
diff --git a/packages/core/src/trigger_api/keep_fresh.ts b/packages/core/src/trigger_api/keep_fresh.ts
index 7b80cbb06..bb7f5edd9 100644
--- a/packages/core/src/trigger_api/keep_fresh.ts
+++ b/packages/core/src/trigger_api/keep_fresh.ts
@@ -5,6 +5,7 @@ import {
sample,
is,
createStore,
+ Store,
} from 'effector';
import { type Query } from '../query/type';
@@ -15,6 +16,7 @@ import {
syncBatch,
normalizeSourced,
extractSource,
+ every,
} from '../libs/patronus';
import { type TriggerProtocol } from './trigger_protocol';
@@ -22,6 +24,7 @@ export function keepFresh(
query: Query,
config: {
automatically: true;
+ enabled?: Store;
}
): void;
@@ -29,6 +32,7 @@ export function keepFresh(
query: Query,
config: {
triggers: Array | TriggerProtocol>;
+ enabled?: Store;
}
): void;
@@ -37,6 +41,7 @@ export function keepFresh(
config: {
automatically: true;
triggers: Array | TriggerProtocol>;
+ enabled?: Store;
}
): void;
@@ -45,6 +50,7 @@ export function keepFresh(
config: {
automatically?: true;
triggers?: Array | TriggerProtocol>;
+ enabled?: Store;
}
): void {
const triggers: Array> = [];
@@ -56,6 +62,16 @@ export function keepFresh(
triggers.push(...triggerEvents);
+ const enabledParamStores = [query.$enabled];
+ if (config.enabled !== undefined) {
+ enabledParamStores.push(config.enabled);
+ }
+
+ const $enabled = every({
+ predicate: Boolean,
+ stores: enabledParamStores,
+ });
+
if (protocolCompatibleObjects.length > 0) {
const triggersByProtocol = protocolCompatibleObjects.map((trigger) =>
trigger['@@trigger']()
@@ -71,15 +87,15 @@ export function keepFresh(
sample({
clock: [
query.finished.success,
- sample({ clock: query.$enabled.updates, filter: query.$enabled }),
+ sample({ clock: $enabled.updates, filter: $enabled }),
],
filter: not($alreadySetup),
target: [...triggersByProtocol.map(get('setup')), setup],
});
sample({
- clock: query.$enabled.updates,
- filter: and($alreadySetup, not(query.$enabled)),
+ clock: $enabled.updates,
+ filter: and($alreadySetup, not($enabled)),
target: [...triggersByProtocol.map(get('teardown')), teardown],
});
@@ -103,7 +119,7 @@ export function keepFresh(
source: $partialSources,
fn: (partialSources, clock) =>
partialSources.map((partialSource) => partialSource(clock)),
- filter: query.$enabled,
+ filter: $enabled,
target: $previousSources,
});
@@ -124,17 +140,14 @@ export function keepFresh(
triggers.push(
sample({
- clock: [
- $nextSources.updates,
- query.$enabled.updates.filter({ fn: Boolean }),
- ],
+ clock: [$nextSources.updates, $enabled.updates.filter({ fn: Boolean })],
source: [$nextSources, $previousSources] as const,
filter: ([next, prev]) => !isEqual(next, prev),
})
);
}
- const forceFresh = sample({ clock: triggers, filter: query.$enabled });
+ const forceFresh = sample({ clock: triggers, filter: $enabled });
sample({
clock: forceFresh,