diff --git a/client/src/components/Labels.tsx b/client/src/components/Labels.tsx index 92b1f012..d4271344 100644 --- a/client/src/components/Labels.tsx +++ b/client/src/components/Labels.tsx @@ -14,7 +14,8 @@ import { import { ICustomPages } from '../../../shared/src/reducers/settingsReducer' import { getChannelLabel } from '../utils/labels' import { flushExtLabels, updateLabels } from '../../../shared/src/actions/faderActions' -import { storeFlushChLabels } from '../../../shared/src/actions/channelActions' +import { ChannelActionTypes, ChannelActions } from '../../../shared/src/actions/channelActions' +import { Dispatch } from '@reduxjs/toolkit' interface ILabelSettingsInjectProps { customPages: ICustomPages[] @@ -27,6 +28,7 @@ class LabelSettings extends React.PureComponent< state = { mutations: {} as Record } + dispatch: Dispatch = this.props.dispatch constructor(props: any) { super(props) @@ -57,7 +59,7 @@ class LabelSettings extends React.PureComponent< handleFlushLabels() { if (window.confirm('Flush all external (automation and channel) labels?')) { this.props.dispatch(flushExtLabels()) - this.props.dispatch(storeFlushChLabels()) + this.dispatch({ type: ChannelActionTypes.FLUSH_CHANNEL_LABELS }) window.socketIoClient.emit(SOCKET_FLUSH_LABELS) } } diff --git a/client/src/utils/SocketClientHandlers.ts b/client/src/utils/SocketClientHandlers.ts index 6beaebfd..39adebf5 100644 --- a/client/src/utils/SocketClientHandlers.ts +++ b/client/src/utils/SocketClientHandlers.ts @@ -4,8 +4,8 @@ import { storeVuReductionLevel, } from '../../../shared/src/actions/faderActions' import { - storeSetCompleteChState, - storeSetSingleChState, + ChannelActionTypes, + ChannelActions, } from '../../../shared/src/actions/channelActions' import { storeSetMixerOnline, @@ -29,10 +29,12 @@ import { } from '../../../shared/src/reducers/channelsReducer' import { VuType } from '../../../shared/src/utils/vu-server-types' import { IMixerSettings } from '../../../shared/src/reducers/settingsReducer' +import { Dispatch } from '@reduxjs/toolkit' export const vuMeters: number[][] = [] export const socketClientHandlers = () => { + const dispatch: Dispatch = window.storeRedux.dispatch window.socketIoClient .on('connect', () => { window.storeRedux.dispatch(storeSetServerOnline(true)) @@ -64,12 +66,11 @@ export const socketClientHandlers = () => { ] } ) - window.storeRedux.dispatch( - storeSetCompleteChState( - payload.channels[0], - numberOfChannels - ) - ) + dispatch({ + type: ChannelActionTypes.SET_COMPLETE_CH_STATE, + numberOfTypeChannels: numberOfChannels, + allState: payload.channels[0], + }) window.storeRedux.dispatch( storeSetCompleteFaderState( payload.faders[0], @@ -109,9 +110,11 @@ export const socketClientHandlers = () => { } }) .on(SOCKET_SET_STORE_CHANNEL, (payload: any) => { - window.storeRedux.dispatch( - storeSetSingleChState(payload.channelIndex, payload.state) - ) + dispatch({ + type: ChannelActionTypes.SET_SINGLE_CH_STATE, + channelIndex: payload.channelIndex, + state: payload.state, + }) }) .on(SOCKET_RETURN_SNAPSHOT_LIST, (payload: any) => { window.snapshotFileList = payload diff --git a/package.json b/package.json index ce535b26..2d341f82 100644 --- a/package.json +++ b/package.json @@ -70,6 +70,7 @@ ] }, "dependencies": { + "@reduxjs/toolkit": "^2.1.0", "cross-env": "^7.0.3" }, "devDependencies": { @@ -83,4 +84,4 @@ "xml2js": "^0.5.0", "socket.io-parser": "^4.2.3" } -} \ No newline at end of file +} diff --git a/server/src/MainThreadHandler.ts b/server/src/MainThreadHandler.ts index a0a20153..cfd1dfdf 100644 --- a/server/src/MainThreadHandler.ts +++ b/server/src/MainThreadHandler.ts @@ -11,7 +11,7 @@ import { socketServer } from './expressHandler' import { storeUpdateSettings } from '../../shared/src/actions/settingsActions' import * as IO from '../../shared/src/constants/SOCKET_IO_DISPATCHERS' import * as FADER_ACTIONS from '../../shared/src/actions/faderActions' -import * as CHANNEL_ACTIONS from '../../shared/src/actions/channelActions' +import { ChannelActionTypes, ChannelActions } from '../../shared/src/actions/channelActions' import { loadSettings, @@ -25,19 +25,17 @@ import { STORAGE_FOLDER, } from './utils/SettingsStorage' -import { - storeFlushChLabels, - storeSetAuxLevel, -} from '../../shared/src/actions/channelActions' import { logger } from './utils/logger' import { ICustomPages } from '../../shared/src/reducers/settingsReducer' import { fxParamsList } from '../../shared/src/constants/MixerProtocolInterface' import path from 'path' import { IChannel } from '../../shared/src/reducers/channelsReducer' import { IChannelReference } from '../../shared/src/reducers/fadersReducer' +import { Dispatch } from '@reduxjs/toolkit' export class MainThreadHandlers { snapshotHandler: SnapshotHandler + dispatch: Dispatch = store.dispatch constructor() { logger.info('Setting up MainThreadHandlers') @@ -85,13 +83,12 @@ export class MainThreadHandlers { }) state.faders[0].fader.forEach((fader, faderIndex) => { fader.assignedChannels?.forEach((channel: IChannelReference) => { - store.dispatch( - CHANNEL_ACTIONS.storeSetAssignedFader( - channel.mixerIndex, - channel.channelIndex, - faderIndex - ) - ) + this.dispatch({ + type: ChannelActionTypes.SET_ASSIGNED_FADER, + mixerIndex: channel.mixerIndex, + channel: channel.channelIndex, + faderNumber: faderIndex, + }) }) }) } @@ -294,14 +291,13 @@ export class MainThreadHandlers { logger.trace( `Set Auxlevel Channel: ${payload.channel} Auxindex : ${payload.auxIndex} level : ${payload.level}` ) - store.dispatch( - storeSetAuxLevel( - 0, - payload.channel, - payload.auxIndex, - payload.level - ) - ) + this.dispatch({ + type: ChannelActionTypes.SET_AUX_LEVEL, + mixerIndex: 0, + channel: payload.channel, + auxIndex: payload.auxIndex, + level: payload.level, + }) mixerGenericConnection.updateAuxLevel( payload.channel, payload.auxIndex @@ -438,7 +434,9 @@ export class MainThreadHandlers { }) .on(IO.SOCKET_FLUSH_LABELS, () => { store.dispatch(FADER_ACTIONS.flushExtLabels()) - store.dispatch(storeFlushChLabels()) + this.dispatch({ + type: ChannelActionTypes.FLUSH_CHANNEL_LABELS, + }) }) } } diff --git a/server/src/utils/MixerConnection.ts b/server/src/utils/MixerConnection.ts index 82f8b32a..640a69bf 100644 --- a/server/src/utils/MixerConnection.ts +++ b/server/src/utils/MixerConnection.ts @@ -20,19 +20,18 @@ import { LawoRubyMixerConnection } from './mixerConnections/LawoRubyConnection' import { StuderMixerConnection } from './mixerConnections/StuderMixerConnection' import { StuderVistaMixerConnection } from './mixerConnections/StuderVistaMixerConnection' import { CasparCGConnection } from './mixerConnections/CasparCGConnection' +import { IchMixerConnection } from '../../../shared/src/reducers/channelsReducer' import { - IchMixerConnection, -} from '../../../shared/src/reducers/channelsReducer' -import { - storeFadeActive, - storeSetOutputLevel, + ChannelActionTypes, + ChannelActions, } from '../../../shared/src/actions/channelActions' import { storeFaderLevel } from '../../../shared/src/actions/faderActions' import { AtemMixerConnection } from './mixerConnections/AtemConnection' import { IChannelReference } from '../../../shared/src/reducers/fadersReducer' +import { Dispatch } from 'redux' export class MixerGenericConnection { - store: any + dispatch: Dispatch = store.dispatch mixerProtocol: IMixerProtocolGeneric[] mixerConnection: any[] mixerTimers: { @@ -47,7 +46,7 @@ export class MixerGenericConnection { state.settings[0].mixers.forEach((none: any, index: number) => { this.mixerProtocol.push( MixerProtocolPresets[ - state.settings[0].mixers[index].mixerProtocol + state.settings[0].mixers[index].mixerProtocol ] || MixerProtocolPresets.sslSystemT ) this.mixerConnection.push({}) @@ -140,7 +139,12 @@ export class MixerGenericConnection { delayedFadeActiveDisable = (mixerIndex: number, channelIndex: number) => { this.mixerTimers[mixerIndex].fadeActiveTimer[channelIndex] = setTimeout( () => { - store.dispatch(storeFadeActive(mixerIndex, channelIndex, false)) + this.dispatch({ + type: ChannelActionTypes.FADE_ACTIVE, + mixerIndex: mixerIndex, + channel: channelIndex, + active: false, + }) }, state.settings[0].mixers[0].protocolLatency ) @@ -201,7 +205,6 @@ export class MixerGenericConnection { } } - state.faders[0].fader[faderIndex].assignedChannels?.forEach( (assignedChannel: IChannelReference) => { if (assignedChannel.mixerIndex !== mixerIndexToSkip) { @@ -209,7 +212,7 @@ export class MixerGenericConnection { assignedChannel.mixerIndex, assignedChannel.channelIndex, faderIndex, - fadeTime, + fadeTime ) } } @@ -227,10 +230,9 @@ export class MixerGenericConnection { let level = state.faders[0].fader[faderIndex].inputGain state.faders[0].fader[faderIndex].assignedChannels?.forEach( (assignedChannel: IChannelReference) => { - this.mixerConnection[assignedChannel.mixerIndex].updateInputGain( - assignedChannel.channelIndex, - level, - ) + this.mixerConnection[ + assignedChannel.mixerIndex + ].updateInputGain(assignedChannel.channelIndex, level) } ) } @@ -240,9 +242,11 @@ export class MixerGenericConnection { logger.trace(`${faderIndex} ${inputSelected}`) state.faders[0].fader[faderIndex].assignedChannels?.forEach( (assignedChannel: IChannelReference) => { - this.mixerConnection[assignedChannel.mixerIndex].updateInputSelector( + this.mixerConnection[ + assignedChannel.mixerIndex + ].updateInputSelector( assignedChannel.channelIndex, - inputSelected, + inputSelected ) } ) @@ -256,9 +260,11 @@ export class MixerGenericConnection { state.faders[0].fader[faderIndex].assignedChannels?.forEach( (assignedChannel: IChannelReference) => { if (assignedChannel.mixerIndex !== mixerIndexToSkip) { - this.mixerConnection[assignedChannel.mixerIndex].updateMuteState( + this.mixerConnection[ + assignedChannel.mixerIndex + ].updateMuteState( assignedChannel.channelIndex, - state.faders[0].fader[faderIndex].muteOn, + state.faders[0].fader[faderIndex].muteOn ) } } @@ -268,9 +274,11 @@ export class MixerGenericConnection { updateAMixState = (faderIndex: number) => { state.faders[0].fader[faderIndex].assignedChannels?.forEach( (assignedChannel: IChannelReference) => { - this.mixerConnection[assignedChannel.mixerIndex].updateAMixState( + this.mixerConnection[ + assignedChannel.mixerIndex + ].updateAMixState( assignedChannel.channelIndex, - state.faders[0].fader[faderIndex].amixOn, + state.faders[0].fader[faderIndex].amixOn ) } ) @@ -290,7 +298,7 @@ export class MixerGenericConnection { (assignedChannel: IChannelReference) => { this.mixerConnection[assignedChannel.mixerIndex].updateNextAux( assignedChannel.channelIndex, - level, + level ) } ) @@ -303,7 +311,7 @@ export class MixerGenericConnection { this.mixerConnection[assignedChannel.mixerIndex].updateFx( fxParam, assignedChannel.channelIndex, - level, + level ) } ) @@ -375,7 +383,7 @@ export class MixerGenericConnection { ) this.clearTimer(mixerIndex, channelIndex) } - store.dispatch(storeFadeActive(mixerIndex, channelIndex, true)) + this.dispatch({type: ChannelActionTypes.FADE_ACTIVE, mixerIndex: mixerIndex, channel: channelIndex, active: true}) if ( state.faders[0].fader[faderIndex].pgmOn || state.faders[0].fader[faderIndex].voOn @@ -458,9 +466,12 @@ export class MixerGenericConnection { endLevel ) this.clearTimer(mixerIndex, channelIndex) - store.dispatch( - storeSetOutputLevel(mixerIndex, channelIndex, endLevel) - ) + this.dispatch({ + type: ChannelActionTypes.SET_OUTPUT_LEVEL, + mixerIndex: mixerIndex, + channel: channelIndex, + level: endLevel, + }) this.delayedFadeActiveDisable(mixerIndex, channelIndex) return true } @@ -468,16 +479,19 @@ export class MixerGenericConnection { const currentOutputLevel = startLevel + (endLevel - startLevel) * - Math.max(0, Math.min(1, elapsedTimeMS / fadeTime)) + Math.max(0, Math.min(1, elapsedTimeMS / fadeTime)) this.mixerConnection[mixerIndex].updateFadeIOLevel( channelIndex, currentOutputLevel ) - store.dispatch( - storeSetOutputLevel(mixerIndex, channelIndex, currentOutputLevel) - ) + this.dispatch({ + type: ChannelActionTypes.SET_OUTPUT_LEVEL, + mixerIndex: mixerIndex, + channel: channelIndex, + level: currentOutputLevel, + }) } fadeDown = (mixerIndex: number, channelIndex: number, fadeTime: number) => { diff --git a/server/src/utils/SettingsStorage.ts b/server/src/utils/SettingsStorage.ts index 8be462c0..70910faa 100644 --- a/server/src/utils/SettingsStorage.ts +++ b/server/src/utils/SettingsStorage.ts @@ -9,7 +9,7 @@ import { store } from '../reducers/store' import { checkVersion } from './migrations' // Redux: -import { storeSetCompleteChState } from '../../../shared/src/actions/channelActions' +import { ChannelActionTypes, ChannelActions } from '../../../shared/src/actions/channelActions' import { storeSetCompleteFaderState } from '../../../shared/src/actions/faderActions' import { logger } from './logger' import { defaultFadersReducerState } from '../../../shared/src/reducers/fadersReducer' @@ -24,6 +24,7 @@ import { ISettings, } from '../../../shared/src/reducers/settingsReducer' import { IFaders } from '../../../shared/src/reducers/fadersReducer' +import { Dispatch } from '@reduxjs/toolkit' export interface IShotStorage { channelState: IChannels @@ -77,25 +78,23 @@ export const saveSettings = (settings: any) => { } export const loadSnapshotState = ( - stateSnapshot: IFaders, - stateChannelSnapshot: IChannels, numberOfChannels: InumberOfChannels[], numberOfFaders: number, fileName: string, loadAll: boolean ) => { try { + const dispatch: Dispatch = store.dispatch const stateFromFile: IShotStorage = JSON.parse( fs.readFileSync(fileName, 'utf8') ) if (loadAll) { - store.dispatch( - storeSetCompleteChState( - stateFromFile.channelState as IChannels, - numberOfChannels - ) - ) + dispatch({ + type: ChannelActionTypes.SET_COMPLETE_CH_STATE, + numberOfTypeChannels: numberOfChannels, + allState: stateFromFile.channelState as IChannels, + }) store.dispatch( storeSetCompleteFaderState( stateFromFile.faderState as IFaders, diff --git a/server/src/utils/mixerConnections/AtemConnection.ts b/server/src/utils/mixerConnections/AtemConnection.ts index ffc78a7e..1885e510 100644 --- a/server/src/utils/mixerConnections/AtemConnection.ts +++ b/server/src/utils/mixerConnections/AtemConnection.ts @@ -21,8 +21,9 @@ import { storeSetPgm, storeSetVo, } from '../../../../shared/src/actions/faderActions' -import { storeSetChLabel } from '../../../../shared/src/actions/channelActions' +import { ChannelActions, ChannelActionTypes } from '../../../../shared/src/actions/channelActions' import { FairlightAudioSource } from 'atem-connection/dist/state/fairlight' +import { Dispatch } from '@reduxjs/toolkit' enum TrackIndex { Stereo = '-65280', @@ -31,6 +32,7 @@ enum TrackIndex { } export class AtemMixerConnection { + dispatch: Dispatch = store.dispatch private _connection: Atem private _chNoToSource: Record = {} @@ -420,7 +422,12 @@ export class AtemMixerConnection { label: string, update: boolean = true ): void { - store.dispatch(storeSetChLabel(this.mixerIndex, channelIndex, label)) + this.dispatch({ + type: ChannelActionTypes.SET_CHANNEL_LABEL, + mixerIndex: this.mixerIndex, + channel: channelIndex, + label: label, + }) if (update) global.mainThreadHandler.updatePartialStore(channelIndex) } } diff --git a/server/src/utils/mixerConnections/CasparCGConnection.ts b/server/src/utils/mixerConnections/CasparCGConnection.ts index e70d3a27..12a008dd 100644 --- a/server/src/utils/mixerConnections/CasparCGConnection.ts +++ b/server/src/utils/mixerConnections/CasparCGConnection.ts @@ -14,8 +14,8 @@ import { } from '../../../../shared/src/constants/MixerProtocolInterface' import { IChannel } from '../../../../shared/src/reducers/channelsReducer' import { - storeSetChLabel, - storeSetChPrivate, + ChannelActionTypes, + ChannelActions } from '../../../../shared/src/actions/channelActions' import { logger } from '../logger' import { dbToFloat, floatToDB } from './LawoRubyConnection' @@ -23,6 +23,7 @@ import { IFader } from '../../../../shared/src/reducers/fadersReducer' import { sendVuLevel } from '../vuServer' import { VuType } from '../../../../shared/src/utils/vu-server-types' import { storeSetMixerOnline } from '../../../../shared/src/actions/settingsActions' +import { Dispatch } from '@reduxjs/toolkit' interface CommandChannelMap { [key: string]: number @@ -41,6 +42,7 @@ const OSC_PATH_PRODUCER_CHANNEL_LAYOUT = /\/channel\/(\d+)\/stage\/layer\/(\d+)\/producer\/channel_layout/ export class CasparCGConnection { + dispatch: Dispatch = store.dispatch mixerProtocol: ICasparCGMixerGeometry mixerIndex: number connection: CasparCG @@ -174,13 +176,13 @@ export class CasparCGConnection { i.layer === parseInt(m[5]) ) if (index >= 0) { - store.dispatch( - storeSetChPrivate( - index, - 'producer', - message.args[0] - ) - ) + this.dispatch({ + type: ChannelActionTypes.SET_PRIVATE, + mixerIndex: this.mixerIndex, + channel: index, + tag: 'producer', + value: message.args[0], + }) } } else if ( m[1] === 'channel' && @@ -194,13 +196,13 @@ export class CasparCGConnection { i.layer === parseInt(m[5]) ) if (index >= 0) { - store.dispatch( - storeSetChPrivate( - index, - 'channel_layout', - message.args[0] - ) - ) + this.dispatch({ + type: ChannelActionTypes.SET_PRIVATE, + mixerIndex: this.mixerIndex, + channel: index, + tag: 'channel_layout', + value: message.args[0], + }) } } else if ( m[1] === 'channel' && @@ -218,9 +220,13 @@ export class CasparCGConnection { typeof message.args[0] === 'string' ? message.args[0] : message.args[0].low - store.dispatch( - storeSetChPrivate(index, 'file_path', value) - ) + this.dispatch({ + type: ChannelActionTypes.SET_PRIVATE, + mixerIndex: this.mixerIndex, + channel: index, + tag: 'file_path', + value: value, + }) } } } @@ -248,9 +254,12 @@ export class CasparCGConnection { // Set source labels from geometry definition if (this.mixerProtocol.channelLabels) { this.mixerProtocol.channelLabels.forEach((label, channelIndex) => { - store.dispatch( - storeSetChLabel(this.mixerIndex, channelIndex, label) - ) + this.dispatch({ + type: ChannelActionTypes.SET_CHANNEL_LABEL, + mixerIndex: this.mixerIndex, + channel: channelIndex, + label: label, + }) }) } } diff --git a/server/src/utils/mixerConnections/EmberMixerConnection.ts b/server/src/utils/mixerConnections/EmberMixerConnection.ts index 9c2c7ed4..a17385a9 100644 --- a/server/src/utils/mixerConnections/EmberMixerConnection.ts +++ b/server/src/utils/mixerConnections/EmberMixerConnection.ts @@ -23,13 +23,14 @@ import { logger } from '../logger' import { LawoMC2 } from '../../../../shared/src/constants/mixerProtocols/LawoMC2' import { dbToFloat, floatToDB } from './LawoRubyConnection' import { - SET_OUTPUT_LEVEL, - storeSetChLabel, + ChannelActionTypes, ChannelActions } from '../../../../shared/src/actions/channelActions' import { storeSetMixerOnline } from '../../../../shared/src/actions/settingsActions' import { IChannelReference, IFader } from '../../../../shared/src/reducers/fadersReducer' +import { Dispatch } from '@reduxjs/toolkit' export class EmberMixerConnection { + dispatch: Dispatch = store.dispatch mixerProtocol: IMixerProtocol mixerIndex: number emberConnection: EmberClient @@ -288,13 +289,6 @@ export class EmberMixerConnection { store.dispatch( storeFaderLevel(assignedFaderIndex, level) ) - store.dispatch({ - type: SET_OUTPUT_LEVEL, - channel: assignedFaderIndex, - mixerIndex: this.mixerIndex, - level, - }) - // toggle pgm based on level logger.trace(`Set Channel ${ch} pgmOn ${level > 0}`) store.dispatch( @@ -336,26 +330,24 @@ export class EmberMixerConnection { logger.trace( `Receiving Label from Ch "${ch}", val: ${node.contents.description}` ) - store.dispatch( - storeSetChLabel( - this.mixerIndex, - channelTypeIndex, - node.contents.description - ) - ) + this.dispatch({ + type: ChannelActionTypes.SET_CHANNEL_LABEL, + mixerIndex: this.mixerIndex, + channel: channelTypeIndex, + label: node.contents.description, + }) } else { logger.trace( `Receiving Label from Ch "${ch}", val: ${ (node.contents as Model.Parameter).value }` ) - store.dispatch( - storeSetChLabel( - this.mixerIndex, - channelTypeIndex, - String((node.contents as Model.Parameter).value) - ) - ) + this.dispatch({ + type: ChannelActionTypes.SET_CHANNEL_LABEL, + mixerIndex: this.mixerIndex, + channel: channelTypeIndex, + label: String((node.contents as Model.Parameter).value), + }) } global.mainThreadHandler.updatePartialStore( assignedFaderIndex diff --git a/server/src/utils/mixerConnections/LawoRubyConnection.ts b/server/src/utils/mixerConnections/LawoRubyConnection.ts index 71ab7c3c..0ff2ca45 100644 --- a/server/src/utils/mixerConnections/LawoRubyConnection.ts +++ b/server/src/utils/mixerConnections/LawoRubyConnection.ts @@ -18,7 +18,8 @@ import { } from '../../../../shared/src/actions/faderActions' import { logger } from '../logger' import { storeSetMixerOnline } from '../../../../shared/src/actions/settingsActions' -import { storeSetChLabel } from '../../../../shared/src/actions/channelActions' +import { ChannelActions, ChannelActionTypes } from '../../../../shared/src/actions/channelActions' +import { Dispatch } from '@reduxjs/toolkit' // TODO - should these be util functions? export function floatToDB(f: number): number { @@ -52,6 +53,7 @@ export function dbToFloat(d: number): number { } export class LawoRubyMixerConnection { + dispatch: Dispatch = store.dispatch mixerProtocol: IMixerProtocol mixerIndex: number emberConnection: EmberClient @@ -155,13 +157,12 @@ export class LawoRubyMixerConnection { ) { if (this.faders[channelTypeIndex + 1]) { // enable - store.dispatch( - storeSetChLabel( - this.mixerIndex, - channelTypeIndex, - this.faders[channelTypeIndex + 1] - ) - ) + this.dispatch({ + type: ChannelActionTypes.SET_CHANNEL_LABEL, + mixerIndex: this.mixerIndex, + channel: channelTypeIndex, + label: this.faders[channelTypeIndex + 1], + }) store.dispatch( storeChannelDisabled(channelTypeIndex, false) ) @@ -171,13 +172,12 @@ export class LawoRubyMixerConnection { store.dispatch( storeChannelDisabled(channelTypeIndex, true) ) - store.dispatch( - storeSetChLabel( - this.mixerIndex, - channelTypeIndex, - '' - ) - ) + this.dispatch({ + type: ChannelActionTypes.SET_CHANNEL_LABEL, + mixerIndex: this.mixerIndex, + channel: channelTypeIndex, + label: '', + }) store.dispatch( storeShowChannel(channelTypeIndex, false) ) diff --git a/server/src/utils/mixerConnections/MidiMixerConnection.ts b/server/src/utils/mixerConnections/MidiMixerConnection.ts index 4627cb3d..7521bfbf 100644 --- a/server/src/utils/mixerConnections/MidiMixerConnection.ts +++ b/server/src/utils/mixerConnections/MidiMixerConnection.ts @@ -11,13 +11,23 @@ import { fxParamsList, IMixerProtocol, } from '../../../../shared/src/constants/MixerProtocolInterface' -import { storeSetOutputLevel } from '../../../../shared/src/actions/channelActions' -import { storeFaderLevel, storeTogglePgm } from '../../../../shared/src/actions/faderActions' +import { + ChannelActionTypes, + ChannelActions, +} from '../../../../shared/src/actions/channelActions' +import { + storeFaderLevel, + storeTogglePgm, +} from '../../../../shared/src/actions/faderActions' import { logger } from '../logger' -import { IChannelReference, IFader } from '../../../../shared/src/reducers/fadersReducer' +import { + IChannelReference, + IFader, +} from '../../../../shared/src/reducers/fadersReducer' +import { Dispatch } from '@reduxjs/toolkit' export class MidiMixerConnection { - store: any + dispatch: Dispatch = store.dispatch mixerProtocol: any mixerIndex: number midiInput: any @@ -35,12 +45,14 @@ export class MidiMixerConnection { logger.data(err).error('WebMidi could not be enabled.') } logger.info( - `Connecting Mixer Midi input on port: ${state.settings[0].mixers[this.mixerIndex].mixerMidiInputPort + `Connecting Mixer Midi input on port: ${ + state.settings[0].mixers[this.mixerIndex].mixerMidiInputPort }` ) logger.info( - `Connecting Mixer Midi output on port: ${state.settings[0].mixers[this.mixerIndex] - .mixerMidiOutputPort + `Connecting Mixer Midi output on port: ${ + state.settings[0].mixers[this.mixerIndex] + .mixerMidiOutputPort }` ) this.midiInput = WebMidi.getInputByName( @@ -55,9 +67,12 @@ export class MidiMixerConnection { } private getAssignedFaderIndex(channelIndex: number) { - return state.faders[0].fader.findIndex( - (fader: IFader) => fader.assignedChannels?.some((assigned: IChannelReference) => { - return (assigned.mixerIndex === this.mixerIndex && assigned.channelIndex === channelIndex) + return state.faders[0].fader.findIndex((fader: IFader) => + fader.assignedChannels?.some((assigned: IChannelReference) => { + return ( + assigned.mixerIndex === this.mixerIndex && + assigned.channelIndex === channelIndex + ) }) ) } @@ -67,16 +82,16 @@ export class MidiMixerConnection { logger.debug(`Received 'controlchange' message (${message.data}).`) if ( message.data[1] >= - parseInt( - this.mixerProtocol.channelTypes[0].fromMixer - .CHANNEL_OUT_GAIN[0].mixerMessage - ) && + parseInt( + this.mixerProtocol.channelTypes[0].fromMixer + .CHANNEL_OUT_GAIN[0].mixerMessage + ) && message.data[1] <= - parseInt( - this.mixerProtocol.channelTypes[0].fromMixer - .CHANNEL_OUT_GAIN[0].mixerMessage - ) + - 24 + parseInt( + this.mixerProtocol.channelTypes[0].fromMixer + .CHANNEL_OUT_GAIN[0].mixerMessage + ) + + 24 ) { let ch = 1 + @@ -90,11 +105,7 @@ export class MidiMixerConnection { storeFaderLevel(faderChannel - 1, message.data[2]) ) if (!state.faders[0].fader[faderChannel - 1].pgmOn) { - store.dispatch( - storeTogglePgm( - faderChannel - 1, - ) - ) + store.dispatch(storeTogglePgm(faderChannel - 1)) } if (remoteConnections) { remoteConnections.updateRemoteFaderState( @@ -103,10 +114,15 @@ export class MidiMixerConnection { ) } if (state.faders[0].fader[faderChannel - 1].pgmOn) { - state.faders[0].fader[faderChannel - 1].assignedChannels?.forEach( + state.faders[0].fader[ + faderChannel - 1 + ].assignedChannels?.forEach( (channel: IChannelReference) => { if (channel.mixerIndex === this.mixerIndex) { - this.updateOutLevel(channel.channelIndex, faderChannel - 1) + this.updateOutLevel( + channel.channelIndex, + faderChannel - 1 + ) } } ) @@ -142,13 +158,12 @@ export class MidiMixerConnection { updateOutLevel(channelIndex: number, faderIndex: number) { if (state.faders[0].fader[faderIndex].pgmOn) { - store.dispatch( - storeSetOutputLevel( - this.mixerIndex, - channelIndex, - state.faders[0].fader[faderIndex].faderLevel - ) - ) + this.dispatch({ + type: ChannelActionTypes.SET_OUTPUT_LEVEL, + mixerIndex: this.mixerIndex, + channel: channelIndex, + level: state.faders[0].fader[faderIndex].faderLevel, + }) } this.sendOutMessage( this.mixerProtocol.channelTypes[0].toMixer.CHANNEL_OUT_GAIN[0] @@ -228,7 +243,7 @@ export class MidiMixerConnection { ) } - loadMixerPreset(presetName: string) { } + loadMixerPreset(presetName: string) {} injectCommand(command: string[]) { return true diff --git a/server/src/utils/mixerConnections/OscMixerConnection.ts b/server/src/utils/mixerConnections/OscMixerConnection.ts index 10effbf1..cc6534a7 100644 --- a/server/src/utils/mixerConnections/OscMixerConnection.ts +++ b/server/src/utils/mixerConnections/OscMixerConnection.ts @@ -14,9 +14,8 @@ import { import { behringerXrMeter } from './productSpecific/behringerXr' import { midasMeter } from './productSpecific/midas' import { - storeSetAuxLevel, - storeSetChLabel, - storeSetOutputLevel, + ChannelActionTypes, + ChannelActions, } from '../../../../shared/src/actions/channelActions' import { storeFaderLevel, @@ -28,8 +27,12 @@ import { storeSetMixerOnline } from '../../../../shared/src/actions/settingsActi import { logger } from '../logger' import { sendVuLevel } from '../vuServer' import { VuType } from '../../../../shared/src/utils/vu-server-types' -import { IChannelReference, IFader } from '../../../../shared/src/reducers/fadersReducer' +import { + IChannelReference, + IFader, +} from '../../../../shared/src/reducers/fadersReducer' import { IChannel } from '../../../../shared/src/reducers/channelsReducer' +import { Dispatch } from '@reduxjs/toolkit' interface IOscCommand { address: string @@ -37,6 +40,7 @@ interface IOscCommand { } export class OscMixerConnection { + dispatch: Dispatch = store.dispatch mixerProtocol: IMixerProtocol mixerIndex: number cmdChannelIndex: number @@ -66,21 +70,22 @@ export class OscMixerConnection { .findIndex((ch) => ch === '{channel}') try { - this.oscConnection = new osc.UDPPort({ localAddress: state.settings[0].mixers[this.mixerIndex].localIp, localPort: parseInt( state.settings[0].mixers[this.mixerIndex].localOscPort + '' ), - remoteAddress: state.settings[0].mixers[this.mixerIndex].deviceIp, + remoteAddress: + state.settings[0].mixers[this.mixerIndex].deviceIp, remotePort: parseInt( state.settings[0].mixers[this.mixerIndex].devicePort + '' ), }) - } - catch (error) { + } catch (error) { logger.error( - `Error creating OSC connection to ${state.settings[0].mixers[this.mixerIndex].deviceIp}:${state.settings[0].mixers[this.mixerIndex].devicePort}` + `Error creating OSC connection to ${ + state.settings[0].mixers[this.mixerIndex].deviceIp + }:${state.settings[0].mixers[this.mixerIndex].devicePort}` ) logger.error(error) return @@ -95,9 +100,12 @@ export class OscMixerConnection { } private getAssignedFaderIndex(channelIndex: number): number { - return state.faders[0].fader.findIndex( - (fader: IFader) => fader.assignedChannels?.some((assigned: IChannelReference) => { - return (assigned.mixerIndex === this.mixerIndex && assigned.channelIndex === channelIndex) + return state.faders[0].fader.findIndex((fader: IFader) => + fader.assignedChannels?.some((assigned: IChannelReference) => { + return ( + assigned.mixerIndex === this.mixerIndex && + assigned.channelIndex === channelIndex + ) }) ) } @@ -142,7 +150,9 @@ export class OscMixerConnection { this.resetMixerTimeout() midasMeter(this.mixerIndex, message.args) } else { - const assignedFaderIndex = this.getAssignedFaderIndex(message.address.split('/')[this.cmdChannelIndex]) + const assignedFaderIndex = this.getAssignedFaderIndex( + message.address.split('/')[this.cmdChannelIndex] + ) let ch = message.address.split('/')[this.cmdChannelIndex] sendVuLevel( @@ -159,7 +169,9 @@ export class OscMixerConnection { .CHANNEL_VU_REDUCTION?.[0].mixerMessage ) ) { - const assignedFaderIndex = this.getAssignedFaderIndex(message.address.split('/')[this.cmdChannelIndex]) + const assignedFaderIndex = this.getAssignedFaderIndex( + message.address.split('/')[this.cmdChannelIndex] + ) sendVuLevel( assignedFaderIndex, @@ -175,7 +187,9 @@ export class OscMixerConnection { ) ) { let ch = message.address.split('/')[this.cmdChannelIndex] - const assignedFaderIndex = this.getAssignedFaderIndex(ch - 1) + const assignedFaderIndex = this.getAssignedFaderIndex( + ch - 1 + ) if ( assignedFaderIndex >= 0 && @@ -185,7 +199,7 @@ export class OscMixerConnection { if ( message.args[0] > this.mixerProtocol.fader.min || message.args[0] > - state.settings[0].autoResetLevel / 100 + state.settings[0].autoResetLevel / 100 ) { store.dispatch( storeFaderLevel( @@ -193,16 +207,21 @@ export class OscMixerConnection { message.args[0] ) ) - state.faders[0].fader[assignedFaderIndex].assignedChannels?.forEach( + state.faders[0].fader[ + assignedFaderIndex + ].assignedChannels?.forEach( (assignedChannel: IChannelReference) => { - if (assignedChannel.mixerIndex === this.mixerIndex) { - store.dispatch( - storeSetOutputLevel( - this.mixerIndex, + if ( + assignedChannel.mixerIndex === + this.mixerIndex + ) { + this.dispatch({ + type: ChannelActionTypes.SET_OUTPUT_LEVEL, + mixerIndex: this.mixerIndex, + channel: assignedChannel.channelIndex, - message.args[0] - ) - ) + level: message.args[0], + }) } } ) @@ -211,7 +230,7 @@ export class OscMixerConnection { ) { if ( message.args[0] > - this.mixerProtocol.fader.min || + this.mixerProtocol.fader.min || 0 ) { store.dispatch( @@ -229,16 +248,21 @@ export class OscMixerConnection { message.args[0] ) ) - state.faders[0].fader[assignedFaderIndex].assignedChannels?.forEach( + state.faders[0].fader[ + assignedFaderIndex + ].assignedChannels?.forEach( (assignedChannel: IChannelReference) => { - if (assignedChannel.mixerIndex === this.mixerIndex) { - store.dispatch( - storeSetOutputLevel( - this.mixerIndex, + if ( + assignedChannel.mixerIndex === + this.mixerIndex + ) { + this.dispatch({ + type: ChannelActionTypes.SET_OUTPUT_LEVEL, + mixerIndex: this.mixerIndex, + channel: assignedChannel.channelIndex, - message.args[0] - ) - ) + level: message.args[0], + }) } } ) @@ -289,14 +313,13 @@ export class OscMixerConnection { logger.trace( `Aux Message Channel: ${ch}\n Aux Index: ${auxIndex}\n Level: ${message.args[0]}` ) - store.dispatch( - storeSetAuxLevel( - this.mixerIndex, - ch - 1, - auxIndex, - message.args[0] - ) - ) + this.dispatch({ + type: ChannelActionTypes.SET_AUX_LEVEL, + mixerIndex: this.mixerIndex, + channel: ch - 1, + auxIndex: auxIndex, + level: message.args[0], + }) global.mainThreadHandler.updateFullClientStore() if (remoteConnections) { remoteConnections.updateRemoteAuxPanels() @@ -310,13 +333,12 @@ export class OscMixerConnection { ) ) { let ch = message.address.split('/')[this.cmdChannelIndex] - store.dispatch( - storeSetChLabel( - this.mixerIndex, - ch - 1, - message.args[0] - ) - ) + this.dispatch({ + type: ChannelActionTypes.SET_CHANNEL_LABEL, + mixerIndex: this.mixerIndex, + channel: ch - 1, + label: message.args[0], + }) global.mainThreadHandler.updatePartialStore( this.getAssignedFaderIndex(ch - 1) ) @@ -328,12 +350,11 @@ export class OscMixerConnection { ) ) { let ch = message.address.split('/')[this.cmdChannelIndex] - const assignedFaderIndex = this.getAssignedFaderIndex(ch - 1) + const assignedFaderIndex = this.getAssignedFaderIndex( + ch - 1 + ) store.dispatch( - storeSetMute( - assignedFaderIndex, - message.args[0] === 0 - ) + storeSetMute(assignedFaderIndex, message.args[0] === 0) ) mixerGenericConnection.updateMuteState( assignedFaderIndex, @@ -358,7 +379,8 @@ export class OscMixerConnection { this.oscConnection.open() logger.info( - `OSC listening on port ${state.settings[0].mixers[this.mixerIndex].localOscPort + `OSC listening on port ${ + state.settings[0].mixers[this.mixerIndex].localOscPort }` ) @@ -387,24 +409,30 @@ export class OscMixerConnection { if (item.type !== undefined && item.type === 'aux') { state.channels[0].chMixerConnection[ this.mixerIndex - ].channel.forEach((channel: IChannel, index: number) => { - const assignedFaderIndex = this.getAssignedFaderIndex(index) - if (assignedFaderIndex >= 0) { - channel.auxLevel.forEach( - (auxLevel: any, auxIndex: number) => { - setTimeout(() => { - this.sendOutRequestAux( - item.mixerMessage, - auxIndex + 1, - state.faders[0].fader[ - assignedFaderIndex - ].monitor - ) - }, state.faders[0].fader[assignedFaderIndex].monitor * 10 + auxIndex * 100) - } - ) + ].channel.forEach( + (channel: IChannel, index: number) => { + const assignedFaderIndex = + this.getAssignedFaderIndex(index) + if (assignedFaderIndex >= 0) { + channel.auxLevel.forEach( + ( + auxLevel: any, + auxIndex: number + ) => { + setTimeout(() => { + this.sendOutRequestAux( + item.mixerMessage, + auxIndex + 1, + state.faders[0].fader[ + assignedFaderIndex + ].monitor + ) + }, state.faders[0].fader[assignedFaderIndex].monitor * 10 + auxIndex * 100) + } + ) + } } - }) + ) } else { state.channels[0].chMixerConnection[ this.mixerIndex @@ -460,7 +488,7 @@ export class OscMixerConnection { let fxKey = keyName as keyof typeof fxParamsList let fxMessage = this.mixerProtocol.channelTypes[0].fromMixer[ - fxParamsList[fxKey] + fxParamsList[fxKey] ][0] let range: number = fxMessage.max - fxMessage.min || 1 if (this.checkOscCommand(message.address, fxMessage.mixerMessage)) { diff --git a/server/src/utils/mixerConnections/SSLMixerConnection.ts b/server/src/utils/mixerConnections/SSLMixerConnection.ts index fd86b375..fb09294a 100644 --- a/server/src/utils/mixerConnections/SSLMixerConnection.ts +++ b/server/src/utils/mixerConnections/SSLMixerConnection.ts @@ -8,7 +8,10 @@ import { fxParamsList, IMixerProtocol, } from '../../../../shared/src/constants/MixerProtocolInterface' -import { storeSetOutputLevel } from '../../../../shared/src/actions/channelActions' +import { + ChannelActionTypes, + ChannelActions, +} from '../../../../shared/src/actions/channelActions' import { storeFaderLevel, storeSetMute, @@ -16,9 +19,14 @@ import { } from '../../../../shared/src/actions/faderActions' import { storeSetMixerOnline } from '../../../../shared/src/actions/settingsActions' import { logger } from '../logger' -import { IChannelReference, IFader } from '../../../../shared/src/reducers/fadersReducer' +import { + IChannelReference, + IFader, +} from '../../../../shared/src/reducers/fadersReducer' +import { Dispatch } from '@reduxjs/toolkit' export class SSLMixerConnection { + dispatch: Dispatch = store.dispatch mixerProtocol: IMixerProtocol mixerIndex: number cmdChannelIndex: number @@ -59,9 +67,12 @@ export class SSLMixerConnection { } private getAssignedFaderIndex(channelIndex: number) { - return state.faders[0].fader.findIndex( - (fader: IFader) => fader.assignedChannels?.some((assigned: IChannelReference) => { - return (assigned.mixerIndex === this.mixerIndex && assigned.channelIndex === channelIndex) + return state.faders[0].fader.findIndex((fader: IFader) => + fader.assignedChannels?.some((assigned: IChannelReference) => { + return ( + assigned.mixerIndex === this.mixerIndex && + assigned.channelIndex === channelIndex + ) }) ) } @@ -70,23 +81,19 @@ export class SSLMixerConnection { try { let channelIndex = buffer[6] let value = buffer.readUInt16BE(7) / 1024 - const thisMixerChannels = state.channels[0].chMixerConnection[this.mixerIndex].channel + const thisMixerChannels = + state.channels[0].chMixerConnection[this.mixerIndex].channel const assignedFaderIndex = this.getAssignedFaderIndex(channelIndex) - if ( - !thisMixerChannels[channelIndex].fadeActive - ) { + if (!thisMixerChannels[channelIndex].fadeActive) { if ( value > this.mixerProtocol.fader.min + - (this.mixerProtocol.fader.max * - state.settings[0].autoResetLevel) / - 100 + (this.mixerProtocol.fader.max * + state.settings[0].autoResetLevel) / + 100 ) { - if ( - thisMixerChannels[channelIndex].outputLevel !== value - - ) { + if (thisMixerChannels[channelIndex].outputLevel !== value) { store.dispatch( storeFaderLevel(assignedFaderIndex, value) ) @@ -101,7 +108,9 @@ export class SSLMixerConnection { ) } if (state.faders[0].fader[assignedFaderIndex].pgmOn) { - state.faders[0].fader[assignedFaderIndex].assignedChannels?.forEach( + state.faders[0].fader[ + assignedFaderIndex + ].assignedChannels?.forEach( (item: IChannelReference) => { if (item.mixerIndex === this.mixerIndex) { this.updateOutLevel(item.channelIndex) @@ -115,22 +124,25 @@ export class SSLMixerConnection { state.faders[0].fader[assignedFaderIndex].voOn ) { store.dispatch(storeFaderLevel(assignedFaderIndex, value)) - state.faders[0].fader[assignedFaderIndex].assignedChannels?.forEach( - (item: IChannelReference) => { - if (item.mixerIndex === this.mixerIndex) { - store.dispatch( - storeSetOutputLevel( - this.mixerIndex, - item.channelIndex, - value - ) - ) - } + state.faders[0].fader[ + assignedFaderIndex + ].assignedChannels?.forEach((item: IChannelReference) => { + if (item.mixerIndex === this.mixerIndex) { + this.dispatch({ + type: ChannelActionTypes.SET_OUTPUT_LEVEL, + mixerIndex: this.mixerIndex, + channel: item.channelIndex, + level: value, + }) } - ) + }) } global.mainThreadHandler.updatePartialStore(assignedFaderIndex) - mixerGenericConnection.updateOutLevel(assignedFaderIndex, 0, this.mixerIndex) + mixerGenericConnection.updateOutLevel( + assignedFaderIndex, + 0, + this.mixerIndex + ) } } catch (error) { logger.error( @@ -165,12 +177,18 @@ export class SSLMixerConnection { state.faders[0].fader[assignedFaderIndex].assignedChannels?.forEach( (item: IChannelReference) => { - if (item.mixerIndex === this.mixerIndex && item.channelIndex !== channelIndex) { + if ( + item.mixerIndex === this.mixerIndex && + item.channelIndex !== channelIndex + ) { this.updateMuteState(item.channelIndex, value) } } ) - mixerGenericConnection.updateMuteState(assignedFaderIndex, this.mixerIndex) + mixerGenericConnection.updateMuteState( + assignedFaderIndex, + this.mixerIndex + ) global.mainThreadHandler.updatePartialStore(assignedFaderIndex) } @@ -326,15 +344,15 @@ export class SSLMixerConnection { sslMessage = sslMessage.replace( '{channel}', ('0' + channelByte[0].toString(16)).slice(-2) + - ' ' + - ('0' + channelByte[1].toString(16)).slice(-2) + ' ' + + ('0' + channelByte[1].toString(16)).slice(-2) ) sslMessage = sslMessage.replace( '{level}', ('0' + valueByte[0].toString(16)).slice(-2) + - ' ' + - ('0' + valueByte[1].toString(16)).slice(-2) + - ' ' + ' ' + + ('0' + valueByte[1].toString(16)).slice(-2) + + ' ' ) sslMessage = sslMessage + this.calculate_checksum8(sslMessage.slice(9)) let a = sslMessage.split(' ') @@ -357,8 +375,8 @@ export class SSLMixerConnection { sslMessage = sslMessage.replace( '{channel}', ('0' + channelByte[0].toString(16)).slice(-2) + - ' ' + - ('0' + channelByte[1].toString(16)).slice(-2) + ' ' + + ('0' + channelByte[1].toString(16)).slice(-2) ) sslMessage = sslMessage + ' ' + this.calculate_checksum8(sslMessage.slice(9)) @@ -400,13 +418,12 @@ export class SSLMixerConnection { const faderIndex = this.getAssignedFaderIndex(channelIndex) if (state.faders[0].fader[faderIndex].pgmOn) { - store.dispatch( - storeSetOutputLevel( - this.mixerIndex, - channelIndex, - state.faders[0].fader[faderIndex].faderLevel - ) - ) + this.dispatch({ + type: ChannelActionTypes.SET_OUTPUT_LEVEL, + mixerIndex: this.mixerIndex, + channel: channelIndex, + level: state.faders[0].fader[faderIndex].faderLevel, + }) } this.sendOutLevelMessage( this.mixerProtocol.channelTypes[channelType].toMixer @@ -509,7 +526,7 @@ export class SSLMixerConnection { return true } - loadMixerPreset(presetName: string) { } + loadMixerPreset(presetName: string) {} injectCommand(command: string[]) { return true diff --git a/server/src/utils/mixerConnections/StuderMixerConnection.ts b/server/src/utils/mixerConnections/StuderMixerConnection.ts index 6224de15..a052b54f 100644 --- a/server/src/utils/mixerConnections/StuderMixerConnection.ts +++ b/server/src/utils/mixerConnections/StuderMixerConnection.ts @@ -10,9 +10,11 @@ import { } from '../../../../shared/src/constants/MixerProtocolInterface' import { storeFaderLevel } from '../../../../shared/src/actions/faderActions' import { logger } from '../logger' -import { storeSetChLabel } from '../../../../shared/src/actions/channelActions' +import { ChannelActions, ChannelActionTypes } from '../../../../shared/src/actions/channelActions' +import { Dispatch } from '@reduxjs/toolkit' export class StuderMixerConnection { + dispatch: Dispatch = store.dispatch mixerProtocol: IMixerProtocol mixerIndex: number emberConnection: any @@ -156,13 +158,12 @@ export class StuderMixerConnection { ) .then((node: any) => { this.emberConnection.subscribe(node, () => { - store.dispatch( - storeSetChLabel( - this.mixerIndex, - ch - 1, - node.contents.value - ) - ) + this.dispatch({ + type: ChannelActionTypes.SET_CHANNEL_LABEL, + mixerIndex: this.mixerIndex, + channel: ch - 1, + label: node.contents.value, + }) }) }) } diff --git a/server/src/utils/mixerConnections/StuderVistaMixerConnection.ts b/server/src/utils/mixerConnections/StuderVistaMixerConnection.ts index ce7a1795..07888ae2 100644 --- a/server/src/utils/mixerConnections/StuderVistaMixerConnection.ts +++ b/server/src/utils/mixerConnections/StuderVistaMixerConnection.ts @@ -16,14 +16,19 @@ import { storeTogglePgm, } from '../../../../shared/src/actions/faderActions' import { - storeSetAuxLevel, - storeSetOutputLevel, + ChannelActionTypes, + ChannelActions, } from '../../../../shared/src/actions/channelActions' import { remoteConnections } from '../../mainClasses' -import { IChannelReference, IFader } from '../../../../shared/src/reducers/fadersReducer' +import { + IChannelReference, + IFader, +} from '../../../../shared/src/reducers/fadersReducer' import { IChannel } from '../../../../shared/src/reducers/channelsReducer' +import { Dispatch } from '@reduxjs/toolkit' export class StuderVistaMixerConnection { + dispatch: Dispatch mixerProtocol: IMixerProtocol mixerIndex: number deviceRoot: any @@ -50,7 +55,7 @@ export class StuderVistaMixerConnection { host: state.settings[0].mixers[this.mixerIndex].deviceIp, timeout: 1000, }, - () => { } + () => {} ) this.mixerConnection @@ -139,9 +144,12 @@ export class StuderVistaMixerConnection { } private getAssignedFaderIndex(channelIndex: number) { - return state.faders[0].fader.findIndex( - (fader: IFader) => fader.assignedChannels?.some((assigned: IChannelReference) => { - return (assigned.mixerIndex === this.mixerIndex && assigned.channelIndex === channelIndex) + return state.faders[0].fader.findIndex((fader: IFader) => + fader.assignedChannels?.some((assigned: IChannelReference) => { + return ( + assigned.mixerIndex === this.mixerIndex && + assigned.channelIndex === channelIndex + ) }) ) } @@ -212,9 +220,12 @@ export class StuderVistaMixerConnection { assignedChannel.mixerIndex === this.mixerIndex && assignedChannel.channelIndex !== channelArrayIndex ) { - store.dispatch( - storeSetOutputLevel(this.mixerIndex, assignedChannel.channelIndex, value) - ) + this.dispatch({ + type: ChannelActionTypes.SET_OUTPUT_LEVEL, + mixerIndex: this.mixerIndex, + channel: assignedChannel.channelIndex, + level: value, + }) } } ) @@ -252,14 +263,13 @@ export class StuderVistaMixerConnection { channelTypeIndex ) - store.dispatch( - storeSetAuxLevel( - this.mixerIndex, - channelArrayIndex, - auxIndex, - value - ) - ) + this.dispatch({ + type: ChannelActionTypes.SET_AUX_LEVEL, + mixerIndex: this.mixerIndex, + channel: channelArrayIndex, + auxIndex: auxIndex, + level: value, + }) global.mainThreadHandler.updateFullClientStore() remoteConnections.updateRemoteAuxPanels() @@ -281,7 +291,9 @@ export class StuderVistaMixerConnection { : false // Update store: - let assignedFader = this.getAssignedFaderIndex(this.findChannelInArray(channelType, channelTypeIndex)) + let assignedFader = this.getAssignedFaderIndex( + this.findChannelInArray(channelType, channelTypeIndex) + ) store.dispatch(storeSetMute(assignedFader, mute)) global.mainThreadHandler.updatePartialStore(assignedFader) @@ -372,34 +384,38 @@ export class StuderVistaMixerConnection { pingChannel(mixerMessage: string) { state.faders[0].fader.forEach((fader: IFader, index: number) => { - fader.assignedChannels?.forEach((channelReference: IChannelReference) => { - if (channelReference.mixerIndex === this.mixerIndex) { - const channel = state.channels[0].chMixerConnection[ - this.mixerIndex - ].channel[channelReference.channelIndex] - let message = mixerMessage - .replace( - '{ch-type}', - (channel.channelType + 1 + 160).toString(16) - ) - .replace( - '{channel}', - (channel.channelTypeIndex + 1 + 160).toString(16) - ) - if (message.includes('{aux}')) { - this.pingAuxSend(message) - } else { - let hexArray = message.split(' ') - let buf = Buffer.from( - hexArray.map((val: string) => { - return parseInt(val, 16) - }) - ) - // logger.debug(`Pinging: ${buf}`) - this.mixerConnection.write(buf) + fader.assignedChannels?.forEach( + (channelReference: IChannelReference) => { + if (channelReference.mixerIndex === this.mixerIndex) { + const channel = + state.channels[0].chMixerConnection[this.mixerIndex] + .channel[channelReference.channelIndex] + let message = mixerMessage + .replace( + '{ch-type}', + (channel.channelType + 1 + 160).toString(16) + ) + .replace( + '{channel}', + (channel.channelTypeIndex + 1 + 160).toString( + 16 + ) + ) + if (message.includes('{aux}')) { + this.pingAuxSend(message) + } else { + let hexArray = message.split(' ') + let buf = Buffer.from( + hexArray.map((val: string) => { + return parseInt(val, 16) + }) + ) + // logger.debug(`Pinging: ${buf}`) + this.mixerConnection.write(buf) + } } } - }) + ) }) } @@ -634,7 +650,7 @@ export class StuderVistaMixerConnection { return } - loadMixerPreset(presetName: string) { } + loadMixerPreset(presetName: string) {} injectCommand(command: string[]) { return true diff --git a/server/src/utils/mixerConnections/VMixMixerConnection.ts b/server/src/utils/mixerConnections/VMixMixerConnection.ts index f126c4af..070b2337 100644 --- a/server/src/utils/mixerConnections/VMixMixerConnection.ts +++ b/server/src/utils/mixerConnections/VMixMixerConnection.ts @@ -8,7 +8,7 @@ import { fxParamsList, IMixerProtocol, } from '../../../../shared/src/constants/MixerProtocolInterface' -import { SET_OUTPUT_LEVEL } from '../../../../shared/src/actions/channelActions' +import { ChannelActionTypes, ChannelActions } from '../../../../shared/src/actions/channelActions' import { storeFaderLevel, storeFaderFx, @@ -24,8 +24,10 @@ import { sendVuLevel } from '../vuServer' import { VuType } from '../../../../shared/src/utils/vu-server-types' import { dbToFloat } from './LawoRubyConnection' import { IChannelReference, IFader } from '../../../../shared/src/reducers/fadersReducer' +import { Dispatch } from '@reduxjs/toolkit' export class VMixMixerConnection { + dispatch: Dispatch = store.dispatch mixerProtocol: IMixerProtocol mixerIndex: number cmdChannelIndex: number @@ -214,7 +216,7 @@ export class VMixMixerConnection { storeFaderLevel(assignedFaderIndex, input.volume) ) store.dispatch({ - type: SET_OUTPUT_LEVEL, + type: ChannelActionTypes.SET_OUTPUT_LEVEL, channel: assignedFaderIndex, mixerIndex: this.mixerIndex, level: voOn @@ -229,7 +231,7 @@ export class VMixMixerConnection { if (!fadeActive && !pgmOn && !voOn) { dispatch(storeSetPgm(assignedFaderIndex, true)) store.dispatch({ - type: SET_OUTPUT_LEVEL, + type: ChannelActionTypes.SET_OUTPUT_LEVEL, channel: assignedFaderIndex, mixerIndex: this.mixerIndex, level: input.volume, diff --git a/server/src/utils/mixerConnections/YamahaQlClConnection.ts b/server/src/utils/mixerConnections/YamahaQlClConnection.ts index cff345ee..bb500ff2 100644 --- a/server/src/utils/mixerConnections/YamahaQlClConnection.ts +++ b/server/src/utils/mixerConnections/YamahaQlClConnection.ts @@ -8,7 +8,7 @@ import { fxParamsList, IMixerProtocol, } from '../../../../shared/src/constants/MixerProtocolInterface' -import { storeSetOutputLevel } from '../../../../shared/src/actions/channelActions' +import { ChannelActionTypes, ChannelActions } from '../../../../shared/src/actions/channelActions' import { storeFaderLevel, storeTogglePgm, @@ -19,8 +19,11 @@ import { storeSetMixerOnline } from '../../../../shared/src/actions/settingsActi import { sendVuLevel } from '../vuServer' import { VuType } from '../../../../shared/src/utils/vu-server-types' import { IChannelReference, IFader } from '../../../../shared/src/reducers/fadersReducer' +import { Dispatch } from '@reduxjs/toolkit' +import { Channel } from 'diagnostics_channel' export class QlClMixerConnection { + dispatch: Dispatch mixerProtocol: IMixerProtocol mixerIndex: number cmdChannelIndex: number @@ -306,13 +309,12 @@ export class QlClMixerConnection { ].channelTypeIndex let faderIndex = this.getAssignedFaderIndex(channelIndex) if (state.faders[0].fader[faderIndex].pgmOn) { - store.dispatch( - storeSetOutputLevel( - this.mixerIndex, - channelIndex, - state.faders[0].fader[faderIndex].faderLevel - ) - ) + this.dispatch({ + type: ChannelActionTypes.SET_OUTPUT_LEVEL, + mixerIndex: this.mixerIndex, + channel: channelIndex, + level: state.faders[0].fader[faderIndex].faderLevel, + }) } this.sendOutMessage( this.mixerProtocol.channelTypes[channelType].toMixer diff --git a/server/src/utils/remoteConnections/SkaarhojRemoteConnection.ts b/server/src/utils/remoteConnections/SkaarhojRemoteConnection.ts index 29ca4967..de8e1009 100644 --- a/server/src/utils/remoteConnections/SkaarhojRemoteConnection.ts +++ b/server/src/utils/remoteConnections/SkaarhojRemoteConnection.ts @@ -12,10 +12,11 @@ import { } from '../../../../shared/src/constants/remoteProtocols/SkaarhojProtocol' import { MixerProtocolPresets } from '../../../../shared/src/constants/MixerProtocolPresets' import { logger } from '../logger' -import { storeSetAuxLevel } from '../../../../shared/src/actions/channelActions' +import { ChannelActionTypes, ChannelActions } from '../../../../shared/src/actions/channelActions' +import { Dispatch } from '@reduxjs/toolkit' export class SkaarhojRemoteConnection { - store: any + dispatch: Dispatch = store.dispatch remoteProtocol: IRemoteProtocol mixerProtocol: any clientList: any[] @@ -188,7 +189,13 @@ export class SkaarhojRemoteConnection { chIndex + 1 } Level: ${level}` ) - store.dispatch(storeSetAuxLevel(0, chIndex, auxSendIndex, level)) + this.dispatch({ + type: ChannelActionTypes.SET_AUX_LEVEL, + mixerIndex: 0, + channel: chIndex, + auxIndex: auxSendIndex, + level: level, + }) mixerGenericConnection.updateAuxLevel(chIndex, auxSendIndex + 1) global.mainThreadHandler.updateFullClientStore() this.updateRemoteAuxPanel(panelNumber) diff --git a/shared/src/actions/channelActions.ts b/shared/src/actions/channelActions.ts index aaaa72d5..a0939ff4 100644 --- a/shared/src/actions/channelActions.ts +++ b/shared/src/actions/channelActions.ts @@ -1,115 +1,68 @@ -import { IChannel, IChannels, InumberOfChannels } from '../reducers/channelsReducer' +import { + IChannel, + IChannels, + InumberOfChannels, +} from '../reducers/channelsReducer' -export const SET_OUTPUT_LEVEL = 'SET_OUTPUT_LEVEL' -export const SET_AUX_LEVEL = 'SET_AUX_LEVEL' -export const SET_COMPLETE_CH_STATE = 'SET_COMPLETE_CH_STATE' -export const SET_SINGLE_CH_STATE = 'SET_SINGLE_CH_STATE' -export const FADE_ACTIVE = 'FADE_ACTIVE' -export const SET_ASSIGNED_FADER = 'SET_ASSIGNED_FADER' -export const SET_PRIVATE = 'SET_PRIVATE' -export const SET_CHANNEL_LABEL = 'SET_CHANNEL_LABEL' -export const FLUSH_CHANNEL_LABELS = 'FLUSH_CHANNEL_LABELS' - -export const storeSetOutputLevel = ( - mixerIndex: number, - channel: number, - level: number -) => { - return { - type: SET_OUTPUT_LEVEL, - mixerIndex: mixerIndex, - channel: channel, - level: level, - } -} - -export const storeSetAuxLevel = ( - mixerIndex: number, - channel: number, - auxIndex: number, - level: number -) => { - return { - type: SET_AUX_LEVEL, - mixerIndex: mixerIndex, - channel: channel, - auxIndex: auxIndex, - level: level, - } -} - -export const storeSetCompleteChState = ( - allState: IChannels, - numberOfChannels: InumberOfChannels[] -) => { - return { - type: SET_COMPLETE_CH_STATE, - allState: allState, - numberOfTypeChannels: numberOfChannels, - } -} - -export const storeSetSingleChState = ( - channelIndex: number, - state: IChannel -) => { - return { - type: SET_SINGLE_CH_STATE, - channelIndex: channelIndex, - state: state, - } -} - -export const storeFadeActive = ( - mixerIndex: number, - channelIndex: number, - active: boolean -) => { - return { - type: FADE_ACTIVE, - mixerIndex: mixerIndex, - channel: channelIndex, - active: active, - } -} - -export const storeSetAssignedFader = ( - mixerIndex: number, - channel: number, - faderNumber: number -) => { - return { - type: SET_ASSIGNED_FADER, - mixerIndex: mixerIndex, - channel: channel, - faderNumber: faderNumber, - } -} - -export const storeSetChPrivate = (channel: number, tag: string, value: any) => { - return { - type: SET_PRIVATE, - channel: channel, - tag: tag, - value: value, - } -} - -export const storeSetChLabel = ( - mixerIndex: number, - channel: number, - label: string -) => { - return { - type: SET_CHANNEL_LABEL, - mixerIndex: mixerIndex, - channel: channel, - label: label, - } +export enum ChannelActionTypes { + SET_OUTPUT_LEVEL = 'SET_OUTPUT_LEVEL', + SET_AUX_LEVEL = 'SET_AUX_LEVEL', + SET_COMPLETE_CH_STATE = 'SET_COMPLETE_CH_STATE', + SET_SINGLE_CH_STATE = 'SET_SINGLE_CH_STATE', + FADE_ACTIVE = 'FADE_ACTIVE', + SET_ASSIGNED_FADER = 'SET_ASSIGNED_FADER', + SET_PRIVATE = 'SET_PRIVATE', + SET_CHANNEL_LABEL = 'SET_CHANNEL_LABEL', + FLUSH_CHANNEL_LABELS = 'FLUSH_CHANNEL_LABELS', } -export const storeFlushChLabels = () => { - return { - type: FLUSH_CHANNEL_LABELS, - } -} +export type ChannelActions = + | { + type: ChannelActionTypes.SET_OUTPUT_LEVEL + mixerIndex: number + channel: number + level: number + } + | { + type: ChannelActionTypes.SET_COMPLETE_CH_STATE + numberOfTypeChannels: InumberOfChannels[] + allState: IChannels + } + | { + type: ChannelActionTypes.SET_SINGLE_CH_STATE + channelIndex: number + state: IChannel + } + | { + type: ChannelActionTypes.FADE_ACTIVE + mixerIndex: number + channel: number + active: boolean + } + | { + type: ChannelActionTypes.SET_ASSIGNED_FADER + mixerIndex: number + channel: number + faderNumber: number + } + | { + type: ChannelActionTypes.SET_AUX_LEVEL + mixerIndex: number + channel: number + auxIndex: number + level: number + } + | { + type: ChannelActionTypes.SET_PRIVATE + mixerIndex: number + channel: number + tag: string + value: string + } + | { + type: ChannelActionTypes.SET_CHANNEL_LABEL + mixerIndex: number + channel: number + label: string + } + | { type: ChannelActionTypes.FLUSH_CHANNEL_LABELS } diff --git a/shared/src/reducers/channelsReducer.ts b/shared/src/reducers/channelsReducer.ts index d0e13db8..5bf59404 100644 --- a/shared/src/reducers/channelsReducer.ts +++ b/shared/src/reducers/channelsReducer.ts @@ -1,13 +1,6 @@ import { - SET_OUTPUT_LEVEL, - SET_ASSIGNED_FADER, - SET_COMPLETE_CH_STATE, - SET_PRIVATE, - FADE_ACTIVE, - SET_AUX_LEVEL, - SET_SINGLE_CH_STATE, - SET_CHANNEL_LABEL, - FLUSH_CHANNEL_LABELS, + ChannelActions, + ChannelActionTypes, } from '../actions/channelActions' export interface IChannels { @@ -75,7 +68,7 @@ const defaultChannelsReducerState = ( export const channels = ( state = defaultChannelsReducerState([{ numberOfTypeInCh: [1] }]), - action: any + action: ChannelActions ): Array => { let nextState = [ { @@ -84,12 +77,12 @@ export const channels = ( ] switch (action.type) { - case SET_OUTPUT_LEVEL: + case ChannelActionTypes.SET_OUTPUT_LEVEL: nextState[0].chMixerConnection[action.mixerIndex].channel[ action.channel - ].outputLevel = parseFloat(action.level) + ].outputLevel = action.level return nextState - case SET_COMPLETE_CH_STATE: + case ChannelActionTypes.SET_COMPLETE_CH_STATE: nextState = defaultChannelsReducerState(action.numberOfTypeChannels) nextState[0].chMixerConnection.forEach( @@ -114,23 +107,23 @@ export const channels = ( ) return nextState - case SET_SINGLE_CH_STATE: + case ChannelActionTypes.SET_SINGLE_CH_STATE: nextState[0].chMixerConnection[0].channel[action.channelIndex] = action.state return nextState - case FADE_ACTIVE: + case ChannelActionTypes.FADE_ACTIVE: nextState[0].chMixerConnection[action.mixerIndex].channel[ action.channel ].fadeActive = !!action.active return nextState - case SET_ASSIGNED_FADER: + case ChannelActionTypes.SET_ASSIGNED_FADER: if (nextState[0].chMixerConnection[action.mixerIndex].channel.length > action.channel) { nextState[0].chMixerConnection[action.mixerIndex].channel[ action.channel ].assignedFader = action.faderNumber } return nextState - case SET_AUX_LEVEL: + case ChannelActionTypes.SET_AUX_LEVEL: let auxLevels = nextState[0].chMixerConnection[action.mixerIndex].channel[ action.channel @@ -142,12 +135,12 @@ export const channels = ( } } } - auxLevels[action.auxIndex] = parseFloat(action.level) + auxLevels[action.auxIndex] = action.level nextState[0].chMixerConnection[action.mixerIndex].channel[ action.channel ].auxLevel = auxLevels return nextState - case SET_PRIVATE: + case ChannelActionTypes.SET_PRIVATE: if ( !nextState[0].chMixerConnection[action.mixerIndex].channel[ action.channel @@ -161,12 +154,12 @@ export const channels = ( action.channel ].private![action.tag] = action.value return nextState - case SET_CHANNEL_LABEL: + case ChannelActionTypes.SET_CHANNEL_LABEL: nextState[0].chMixerConnection[action.mixerIndex].channel[ action.channel ].label = action.label return nextState - case FLUSH_CHANNEL_LABELS: + case ChannelActionTypes.FLUSH_CHANNEL_LABELS: for (const mixer of nextState[0].chMixerConnection) { for (const ch of mixer.channel) { ch.label = undefined diff --git a/shared/src/reducers/store.ts b/shared/src/reducers/store.ts index 8bb6e167..eaa80210 100644 --- a/shared/src/reducers/store.ts +++ b/shared/src/reducers/store.ts @@ -1,4 +1,4 @@ -import { createStore } from 'redux' +import { configureStore } from '@reduxjs/toolkit' import { IFaders } from './fadersReducer' import { IChannels } from './channelsReducer' import indexReducer from './indexReducer' @@ -10,5 +10,5 @@ export interface IStore { faders: Array } -export default createStore(indexReducer) +export default configureStore({reducer: indexReducer}) export { Store } from 'redux' \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 79e1f762..cb323681 100644 --- a/yarn.lock +++ b/yarn.lock @@ -935,6 +935,16 @@ resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== +"@reduxjs/toolkit@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-2.1.0.tgz#b613226669557080d5d683f3dbbd95462f94b965" + integrity sha512-nfJ/b4ZhzUevQ1ZPKjlDL6CMYxO4o7ZL7OSsvSOxzT/EN11LsBDgTqP7aedHtBrFSVoK7oTP1SbMWUwGb30NLg== + dependencies: + immer "^10.0.3" + redux "^5.0.1" + redux-thunk "^3.1.0" + reselect "^5.0.1" + "@serialport/binding-mock@10.2.2": version "10.2.2" resolved "https://registry.yarnpkg.com/@serialport/binding-mock/-/binding-mock-10.2.2.tgz#d322a8116a97806addda13c62f50e73d16125874" @@ -3981,6 +3991,11 @@ imaadpcm@^4.1.2: resolved "https://registry.yarnpkg.com/imaadpcm/-/imaadpcm-4.1.2.tgz#8757742610004bc2aba1181919f899abd6a9b413" integrity sha512-7gwxe6lKCGitmkMtGbm1ecnt0Q59KcWwo7AVi2RAd3lQ9VghVN5zX5x3oK6xNhfD9KUMbaYzku43UBn3Ix3RIA== +immer@^10.0.3: + version "10.0.3" + resolved "https://registry.yarnpkg.com/immer/-/immer-10.0.3.tgz#a8de42065e964aa3edf6afc282dfc7f7f34ae3c9" + integrity sha512-pwupu3eWfouuaowscykeckFmVTpqbzW+rXFCX8rQLkZzM9ftBmU/++Ra+o+L27mz03zJTlyV4UUr+fdKNffo4A== + import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" @@ -6105,13 +6120,23 @@ redis-parser@^3.0.0: dependencies: redis-errors "^1.0.0" -redux@^4.1.2, redux@^4.2.1: +redux-thunk@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-3.1.0.tgz#94aa6e04977c30e14e892eae84978c1af6058ff3" + integrity sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw== + +redux@^4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197" integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w== dependencies: "@babel/runtime" "^7.9.2" +redux@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/redux/-/redux-5.0.1.tgz#97fa26881ce5746500125585d5642c77b6e9447b" + integrity sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w== + reflect-metadata@0.1.13: version "0.1.13" resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" @@ -6157,6 +6182,11 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== +reselect@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-5.1.0.tgz#c479139ab9dd91be4d9c764a7f3868210ef8cd21" + integrity sha512-aw7jcGLDpSgNDyWBQLv2cedml85qd95/iszJjN988zX1t7AVRJi19d9kto5+W7oCfQ94gyo40dVbT6g2k4/kXg== + resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"