From 4a9bb64b287b8eb0d4ad94111e2eefc0edb5a19e Mon Sep 17 00:00:00 2001 From: asapovk Date: Sat, 27 Jul 2024 20:45:57 +0300 Subject: [PATCH] feature afterEffects ch rules integrate af finish af done af check af check af 2 fix playground --- .husky/pre-commit | 2 +- packages/core-v1/index.ts | 2 +- packages/core-v1/lib/AfterEffects.ts | 95 +++++++++++++++++++ packages/core-v1/lib/System.ts | 12 ++- packages/core-v1/lib/configureRoot.ts | 33 ------- packages/core-v1/lib/createMiddleware.ts | 21 +++- .../core-v1/lib/interfaces/EffectiveScript.ts | 19 ++++ .../lib/processor/createProcessorInstance.ts | 29 ++++++ .../lib/processor/lifecycle/AfterEffects.ts | 20 ++++ packages/core-v1/lib/processor/opts/drop.ts | 3 +- .../core-v1/lib/processor/opts/setState.ts | 20 ++++ .../lib/processor/opts/setStateNoEffect.ts | 22 +++++ .../lib/processor/prepareInstanceOpts.ts | 15 ++- packages/core-v1/lib/types.ts | 3 +- playground/src/_redux/index.ts | 9 +- .../compose/scripts/PreventClose.script.ts | 2 +- .../src/compose/scripts/SetContent.script.ts | 24 +++-- 17 files changed, 272 insertions(+), 59 deletions(-) create mode 100644 packages/core-v1/lib/AfterEffects.ts delete mode 100644 packages/core-v1/lib/configureRoot.ts create mode 100644 packages/core-v1/lib/interfaces/EffectiveScript.ts create mode 100644 packages/core-v1/lib/processor/lifecycle/AfterEffects.ts create mode 100644 packages/core-v1/lib/processor/opts/setState.ts create mode 100644 packages/core-v1/lib/processor/opts/setStateNoEffect.ts diff --git a/.husky/pre-commit b/.husky/pre-commit index 5a182ef..d4b08c6 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1,4 @@ #!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" -yarn lint-staged +#yarn lint-staged diff --git a/packages/core-v1/index.ts b/packages/core-v1/index.ts index ba7f901..c604c73 100644 --- a/packages/core-v1/index.ts +++ b/packages/core-v1/index.ts @@ -2,8 +2,8 @@ export {Slice} from './lib/Slice'; export {Bite} from './lib/Bite'; export {Script} from './lib/Script'; +export {EffectiveScript} from './lib/interfaces/EffectiveScript'; export {useSystem, type System} from './lib/System'; -export {configureRoot} from './lib/configureRoot'; export {getTriggerAndStatus, getActionType} from './lib/utils'; export type { UpdateOnType, diff --git a/packages/core-v1/lib/AfterEffects.ts b/packages/core-v1/lib/AfterEffects.ts new file mode 100644 index 0000000..d0d76f3 --- /dev/null +++ b/packages/core-v1/lib/AfterEffects.ts @@ -0,0 +1,95 @@ +import { getTriggerAndStatus } from "./utils"; +import { UpdateOnType } from "./types"; + +/** + * + * key object (__ISALL__: boolean) + * other keys are statuses from array + * value of status keys or __ISALL__ key are biteNames array (to which trigger __afterEffects__ event) + */ + +/* +** +*/ + +export class AfterEffects { + private finalMap: any = {}; + private removeCheckMap: any = {}; + constructor(private getCurrentTask: () => {type: string, payload: string}) {} + + public handleAfterEffect = (dispather: (action) => void) => { + const currentTask = this.getCurrentTask(); + const dispatchPayload = currentTask; + if(currentTask) { + const {trigger, status} = getTriggerAndStatus(currentTask.type); + if(this.finalMap[trigger]) { + for( let key in this.finalMap[trigger]) { + if(this.finalMap[trigger][key] === '_ALLSTATUSES_') { + setTimeout(()=> { + dispather({ + type: `${key}/__AFTEREFFECTS__`, + payload: dispatchPayload + }) + }) + } + else if(this.finalMap[trigger][key] === status ) { + setTimeout(()=> { + dispather({ + type: `${key}/__AFTEREFFECTS__`, + payload: dispatchPayload + })}) + } + else if(this.finalMap[trigger][key].includes(status)) { + setTimeout(() => { + dispather({ + type: `${key}/__AFTEREFFECTS__`, + payload: dispatchPayload + }) + }) + } + } + } + //TODO + } + //check if current task has after effects + //if is => dispatch after effects + + } + + public removeAfterEffect = (biteName:string) => { + if(this.removeCheckMap[biteName]) { + for(let r of this.removeCheckMap[biteName]) { + if(typeof r === 'string') { + delete this.finalMap[r][biteName] + } + else { + const objectkey = Object.keys(r)[0]; + delete this.finalMap[objectkey][biteName] + } + } + } + delete this.removeCheckMap[biteName] + } + + public addAfterEffect = (updateOn: UpdateOnType, biteName: string) => { + + //add to remove map array + this.removeCheckMap[biteName] = updateOn; + for (let uo of updateOn) { + if(!this.finalMap[uo]) { + this.finalMap[uo] = {} + } + if(typeof uo === 'string') { + this.finalMap[uo][biteName] = '_ALLSTATUSES_' + } + else { + const objectkey = Object.keys(uo)[0]; + const objectValues = uo[objectkey]; + this.finalMap[objectkey][biteName] = objectValues; + } + } + console.log(this.finalMap); + console.log(this.removeCheckMap); + + } +} \ No newline at end of file diff --git a/packages/core-v1/lib/System.ts b/packages/core-v1/lib/System.ts index 8c87a11..b38f96a 100644 --- a/packages/core-v1/lib/System.ts +++ b/packages/core-v1/lib/System.ts @@ -1,5 +1,6 @@ -import {TaskQueue} from './TaskQueue'; -import type {SystemConfig} from './types'; +import { AfterEffects } from "./AfterEffects"; +import { TaskQueue } from "./TaskQueue"; +import { SystemConfig } from "./types"; interface ProcessorOpts { propagate: boolean; @@ -19,16 +20,19 @@ export class System { }; public taksQueue: TaskQueue; + public afterEffects: AfterEffects; constructor() { - this.taksQueue = new TaskQueue(); + this.taksQueue = new TaskQueue() + this.afterEffects = new AfterEffects(() => this.taksQueue.getCurrentTask()) } public setConfig(conf: SystemConfig) { this.config = conf; } - public afterHandlers: Array = []; + + //public afterHandlers: Array = [] public context: {[triggerer: string]: any} = {}; diff --git a/packages/core-v1/lib/configureRoot.ts b/packages/core-v1/lib/configureRoot.ts deleted file mode 100644 index f7aadb9..0000000 --- a/packages/core-v1/lib/configureRoot.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { - createStore, - applyMiddleware, - compose, - type Reducer, - type Middleware, -} from 'redux'; -import {useSystem} from './System'; - -export function configureRoot(args: { - rootReducer: Reducer; - middlewares: Array; -}) { - const store = createStore( - args.rootReducer, - compose(applyMiddleware(...args.middlewares)), - ); - const system = useSystem(); - - store.subscribe(() => { - system.afterHandlers.forEach((s) => s()); - }); - // store.subscribe(() => { - // // const nextTask = system.taksQueue.popTask(); - // // if(nextTask) { - // // store.dispatch({ - // // type: - // // }) - // // } - // }); - - return store; -} diff --git a/packages/core-v1/lib/createMiddleware.ts b/packages/core-v1/lib/createMiddleware.ts index 6c4a517..f8fba5f 100644 --- a/packages/core-v1/lib/createMiddleware.ts +++ b/packages/core-v1/lib/createMiddleware.ts @@ -8,6 +8,8 @@ import {matchInitTrigger} from './processor/matchInitTrigger'; import {matchUpdateTrigger} from './processor/matchUpdateTrigger'; import {prepareOpts} from './processor/prepareInstanceOpts'; import {useSystem} from './System'; +import { AfterEffects } from './processor/lifecycle/AfterEffects'; +import { getTriggerAndStatus } from './utils'; export const makeProcMiddleware = ( configs, @@ -35,11 +37,11 @@ export const makeProcMiddleware = ( if (instance) { onInit(instance, actionPayload); + if(instance.afterEffects) { + system.afterEffects.addAfterEffect(initConfig.config.watchScope, initConfig.trigger) + } } - if (instance?.watchAfter) { - system.afterHandlers.push(() => instance.watchAfter); - } }; const handleUpdate = (store, action, skipUpdate) => { @@ -79,6 +81,7 @@ export const makeProcMiddleware = ( opts, } = action; const isBiteHit = matchBiteName(configs, actionType); + const { trigger, status } = getTriggerAndStatus(actionType); const ignore = sliceConfig?.ignoreExternal && (sliceConfig.ignoreExternal === 'ignoreAll' || @@ -92,7 +95,17 @@ export const makeProcMiddleware = ( handleInit(store, actionType, actionPayload, opts?.noInit); - const forceStopPropagate = handleUpdate(store, action, opts?.noUpdate); + let forceStopPropagate = handleUpdate(store, action, opts?.noUpdate); + + if(status === '__AFTEREFFECTS__' && isBiteHit) { + forceStopPropagate = true; + const afInstances = getInstance(configs[trigger], trigger, system); + if(afInstances) { + afInstances.forEach( afi => + AfterEffects(afi, action, sliceName) + ) + } + } const processorOpts = system.getProcessorInfo(action.type); system.resolveWait(action.type, actionPayload); diff --git a/packages/core-v1/lib/interfaces/EffectiveScript.ts b/packages/core-v1/lib/interfaces/EffectiveScript.ts new file mode 100644 index 0000000..f08858d --- /dev/null +++ b/packages/core-v1/lib/interfaces/EffectiveScript.ts @@ -0,0 +1,19 @@ +import { WatchArgsType,ScriptOptsType, InitArgsType, TriggerPhaseKeys} from "../types"; + + +export abstract class EffectiveScript, Inj=unknown> { + + constructor (opts) { + this.opts = opts + } + + protected opts: ScriptOptsType; + + abstract watch?(args: WatchArgsType): void + + abstract afterEffects?(args: WatchArgsType): void + + abstract init(args: InitArgsType): void + + +} \ No newline at end of file diff --git a/packages/core-v1/lib/processor/createProcessorInstance.ts b/packages/core-v1/lib/processor/createProcessorInstance.ts index 2f6b66b..c696203 100644 --- a/packages/core-v1/lib/processor/createProcessorInstance.ts +++ b/packages/core-v1/lib/processor/createProcessorInstance.ts @@ -63,3 +63,32 @@ function refreshingMode(system, config, opt, actionType) { return newInstance; //.init(actionPayload); } + +///on init instance => add to system configure {trigger => []} +///on drop instance => remove from system's map +// for s of config.config.watchScope, +// s. +// +/** + * store.subscribe(() => { + * /// call for check => + * const currentTask = system.taskQueue.currentTask + * const afterEffectsMap = system.afterEffectsMap + * if(match(currentTask, afterEffectsMap)) { + * store.dispatch({ + * type: biteName/__AFTER_EFFECTS__, + * payload: { + * taskTrigger: + * taskStatus: + * taskPayload: + * taskSourceBite: + * taskSourceSlice: + * } + * }) + * } + * }) + * + * + * + * + */ \ No newline at end of file diff --git a/packages/core-v1/lib/processor/lifecycle/AfterEffects.ts b/packages/core-v1/lib/processor/lifecycle/AfterEffects.ts new file mode 100644 index 0000000..92ccb5a --- /dev/null +++ b/packages/core-v1/lib/processor/lifecycle/AfterEffects.ts @@ -0,0 +1,20 @@ +import { getTriggerAndStatus } from "../../utils"; + +export function AfterEffects (instance, action, sliceName) { + const actionPayload = action.payload; + const effectType = actionPayload.type; + const effectPayload = actionPayload.payload; + if(instance.afterEffects) { + const { trigger, status } = getTriggerAndStatus(effectType); + const afterEffectsArgs = { + payload: effectPayload, + trigger, + status, + source: action.source, + sourceSlice: sliceName, + }; + instance.afterEffects(afterEffectsArgs) + + } + +} \ No newline at end of file diff --git a/packages/core-v1/lib/processor/opts/drop.ts b/packages/core-v1/lib/processor/opts/drop.ts index c3feca5..411e428 100644 --- a/packages/core-v1/lib/processor/opts/drop.ts +++ b/packages/core-v1/lib/processor/opts/drop.ts @@ -4,6 +4,7 @@ export function Drop(system, config) { const actionType = getActionType(config.trigger, config.config.initOn); return () => { + system.afterEffects.removeAfterEffect(config.trigger) system.downProcess(actionType); }; -} +} \ No newline at end of file diff --git a/packages/core-v1/lib/processor/opts/setState.ts b/packages/core-v1/lib/processor/opts/setState.ts new file mode 100644 index 0000000..f1b5dd8 --- /dev/null +++ b/packages/core-v1/lib/processor/opts/setState.ts @@ -0,0 +1,20 @@ +import { getActionType } from '../../utils'; + +export function SetState(store, config, system, uid, sourceSlice) { + + return (status, args) => { + const process = system.findProcessByUid(uid); + if (process.length) { + store.dispatch({ + type: getActionType(config.trigger, status), + payload: args, + source: `${config.trigger}:${uid}`, + sourceSlice, + opts: { + noInit: true, + noUpdate: true, + }, + }); + } + }; +} diff --git a/packages/core-v1/lib/processor/opts/setStateNoEffect.ts b/packages/core-v1/lib/processor/opts/setStateNoEffect.ts new file mode 100644 index 0000000..7022219 --- /dev/null +++ b/packages/core-v1/lib/processor/opts/setStateNoEffect.ts @@ -0,0 +1,22 @@ + +import { getActionType } from '../../utils'; + +export function SetStateNoEffect(store, config, system, uid, sourceSlice) { + + return (status, args) => { + const process = system.findProcessByUid(uid); + if (process.length) { + store.dispatch({ + type: getActionType(config.trigger, status), + payload: args, + source: `${config.trigger}:${uid}`, + sourceSlice, + opts: { + notEffect: true, + noInit: true, + noUpdate: true, + }, + }); + } + }; +} diff --git a/packages/core-v1/lib/processor/prepareInstanceOpts.ts b/packages/core-v1/lib/processor/prepareInstanceOpts.ts index 0e3225f..55213f3 100644 --- a/packages/core-v1/lib/processor/prepareInstanceOpts.ts +++ b/packages/core-v1/lib/processor/prepareInstanceOpts.ts @@ -2,12 +2,14 @@ import {v4} from 'uuid'; import {Drop} from './opts/drop'; import {SetStatus} from './opts/setStatus'; import {Trigger} from './opts/trigger'; - +// // import { Save } from './opts/save'; // import { TriggerOnly } from './opts/triggerOnly'; -import {Wait} from './opts/wait'; -import {Hook} from './opts/hook'; -import {Bind} from './opts/bind'; +import { Wait } from './opts/wait'; +import { Hook } from './opts/hook'; +import { Bind } from './opts/bind'; +import { SetStateNoEffect } from './opts/setStateNoEffect'; +import { SetState } from './opts/setState'; export function prepareOpts(config, store, system, sliceName, injected) { const processUid = v4(); @@ -15,7 +17,8 @@ export function prepareOpts(config, store, system, sliceName, injected) { const setStatus = SetStatus(store, config, system, processUid, sliceName); //const save = Save(store, config, system, processUid); - //const triggerOnly = TriggerOnly(store, config, system, processUid); + const setStateNoEffect = SetStateNoEffect(store, config, system, processUid, sliceName); + const setState = SetState(store, config, system, processUid, sliceName); const drop = Drop(system, config); //const state = store.getState(); const getCurrentState = store.getState; @@ -39,6 +42,8 @@ export function prepareOpts(config, store, system, sliceName, injected) { injected, addOpts: config.config.addOpts, bind, + setState, + setStateNoEffect, catchStatus: (status, args) => { if (status === args.status && config.trigger === args.trigger) { return { diff --git a/packages/core-v1/lib/types.ts b/packages/core-v1/lib/types.ts index 076c3d9..82b77ed 100644 --- a/packages/core-v1/lib/types.ts +++ b/packages/core-v1/lib/types.ts @@ -112,11 +112,12 @@ type DefautOpts< dispatch: Dispatch; subscribe: Store['subscribe']; setStatus: SetStatusType; + setState: SetStatusType; + setStateNoEffect: SetStatusType; trigger: DispatcherType; wait: WaiterType; hook: HookerType; addOpts?: unknown; - save: DispatcherType; biteName: keyof IRootTrigger; uid: string; getCurrentState: () => IState; diff --git a/playground/src/_redux/index.ts b/playground/src/_redux/index.ts index d693bd9..9d44d7b 100644 --- a/playground/src/_redux/index.ts +++ b/playground/src/_redux/index.ts @@ -6,6 +6,7 @@ import {notificationSlice} from '../notification/notification.config'; import {popupSlice} from '../popup/popup.config'; import {settingsSlice} from '../settings/settings.config'; import {rootReducer} from './reducer'; +const system = useSystem(); composeSlice.inject({ someData: 'someData For Testing', @@ -26,11 +27,17 @@ function configureStore() { popupSlice.middleware, ]; - return createStore(rootReducer, compose(applyMiddleware(...middlewares))); + const store = createStore(rootReducer, compose(applyMiddleware(...middlewares))); + + return store } export const store = configureStore(); +store.subscribe(()=> { + system.afterEffects.handleAfterEffect(store.dispatch) +}) + store.dispatch({ type: 'setContent/init', payload: null, diff --git a/playground/src/compose/scripts/PreventClose.script.ts b/playground/src/compose/scripts/PreventClose.script.ts index bd3b0d9..72b36b0 100644 --- a/playground/src/compose/scripts/PreventClose.script.ts +++ b/playground/src/compose/scripts/PreventClose.script.ts @@ -86,7 +86,7 @@ export class PreventCloseScript extends Script< const setEvent = this.opts.catchStatus('set', args); if (setEvent.isCatched) { - this.handleSet(setEvent.payload); + this.handleSet(args); } } } diff --git a/playground/src/compose/scripts/SetContent.script.ts b/playground/src/compose/scripts/SetContent.script.ts index 799211c..8afb452 100644 --- a/playground/src/compose/scripts/SetContent.script.ts +++ b/playground/src/compose/scripts/SetContent.script.ts @@ -1,8 +1,9 @@ import { useSystem, - Script, + EffectiveScript, type InitArgsType, type ScriptOptsType, + type WatchArgsType, } from '@reflexio/core-v1'; import type {IState, ITriggers} from '_redux/types'; import type {IComposeTriggers} from '../compose.config'; @@ -11,7 +12,7 @@ import type {IComposeTriggers} from '../compose.config'; ** This script is responsible for opening ** and closing window, managing form content. */ -export class SetContentScript extends Script< +export class SetContentScript extends EffectiveScript< ITriggers, IState, 'setContent', @@ -19,9 +20,9 @@ export class SetContentScript extends Script< Record > { constructor( - public opts: ScriptOptsType, + opts: ScriptOptsType, ) { - super(); + super(opts); } private forms: {[key: string]: {subject: string; body: string}} = {}; @@ -67,6 +68,15 @@ export class SetContentScript extends Script< } } } + afterEffects(args: WatchArgsType): void { + console.log(args); + console.log('this is after effect'); + console.log(this.opts.getCurrentState()) + if(!this.opts.getCurrentState().compose.openedComposeId) { + this.opts.trigger('showNotification', 'init', 'After effect'); + } + + } // when window is getting opened we need this to restore saved state private handleOpenFromList(args) { @@ -182,8 +192,8 @@ export class SetContentScript extends Script< if (args.status === 'commitFormContent') { this.handleCommitFormContent(args); } - // if(args.status === 'openFromList') { - // this.handleOpenFromList(args as any) - // } + if(args.status === 'openFromList') { + this.handleOpenFromList(args as any) + } } }