fix(ui): migrate redux state that has models

With the change to model identifiers from v3 to v4, if a user had persisted redux state with the old format, we could get unexpected runtime errors when rehydrating state if we try to access model attributes that no longer exist.

For example, the CLIP Skip component does this:

```ts
CLIP_SKIP_MAP[model.base].maxClip
```

In v3, models had a `base_type` attribute, but it is renamed to `base` in v4. This code therefore causes a runtime error:
- `model.base` is `undefined`
- `CLIP_SKIP_MAP[undefined]` is also undefined
- `undefined.maxClip` is a runtime error!

Resolved by adding a migration for the redux slices that have model identifiers. The migration simply resets the slice or the part of the slice that is affected, when it's simple to do a partial reset.

Closes #6000
This commit is contained in:
psychedelicious 2024-03-21 15:20:19 +11:00
parent 9eacc0c189
commit 6e869e6038
5 changed files with 25 additions and 8 deletions

View File

@ -37,10 +37,10 @@ export const {
} = caAdapterSelectors; } = caAdapterSelectors;
const initialControlAdaptersState: ControlAdaptersState = caAdapter.getInitialState<{ const initialControlAdaptersState: ControlAdaptersState = caAdapter.getInitialState<{
_version: 1; _version: 2;
pendingControlImages: string[]; pendingControlImages: string[];
}>({ }>({
_version: 1, _version: 2,
pendingControlImages: [], pendingControlImages: [],
}); });
@ -405,6 +405,9 @@ const migrateControlAdaptersState = (state: any): any => {
if (!('_version' in state)) { if (!('_version' in state)) {
state._version = 1; state._version = 1;
} }
if (state._version === 1) {
state = cloneDeep(initialControlAdaptersState);
}
return state; return state;
}; };

View File

@ -18,12 +18,12 @@ export const defaultLoRAConfig: Pick<LoRA, 'weight' | 'isEnabled'> = {
}; };
type LoraState = { type LoraState = {
_version: 1; _version: 2;
loras: Record<string, LoRA>; loras: Record<string, LoRA>;
}; };
const initialLoraState: LoraState = { const initialLoraState: LoraState = {
_version: 1, _version: 2,
loras: {}, loras: {},
}; };
@ -72,6 +72,10 @@ const migrateLoRAState = (state: any): any => {
if (!('_version' in state)) { if (!('_version' in state)) {
state._version = 1; state._version = 1;
} }
if (state._version === 1) {
// Model type has changed, so we need to reset the state - too risky to migrate
state = cloneDeep(initialLoraState);
}
return state; return state;
}; };

View File

@ -24,7 +24,7 @@ import type { ImageDTO } from 'services/api/types';
import type { GenerationState } from './types'; import type { GenerationState } from './types';
const initialGenerationState: GenerationState = { const initialGenerationState: GenerationState = {
_version: 1, _version: 2,
cfgScale: 7.5, cfgScale: 7.5,
cfgRescaleMultiplier: 0, cfgRescaleMultiplier: 0,
height: 512, height: 512,
@ -276,6 +276,11 @@ const migrateGenerationState = (state: any): GenerationState => {
state._version = 1; state._version = 1;
state.aspectRatio = initialAspectRatioState; state.aspectRatio = initialAspectRatioState;
} }
if (state._version === 1) {
// The signature of the model has changed, so we need to reset it
state._version = 2;
state.model = null;
}
return state; return state;
}; };

View File

@ -19,7 +19,7 @@ import type {
} from 'features/parameters/types/parameterSchemas'; } from 'features/parameters/types/parameterSchemas';
export interface GenerationState { export interface GenerationState {
_version: 1; _version: 2;
cfgScale: ParameterCFGScale; cfgScale: ParameterCFGScale;
cfgRescaleMultiplier: ParameterCFGRescaleMultiplier; cfgRescaleMultiplier: ParameterCFGRescaleMultiplier;
height: ParameterHeight; height: ParameterHeight;

View File

@ -9,7 +9,7 @@ import type {
} from 'features/parameters/types/parameterSchemas'; } from 'features/parameters/types/parameterSchemas';
type SDXLState = { type SDXLState = {
_version: 1; _version: 2;
positiveStylePrompt: ParameterPositiveStylePromptSDXL; positiveStylePrompt: ParameterPositiveStylePromptSDXL;
negativeStylePrompt: ParameterNegativeStylePromptSDXL; negativeStylePrompt: ParameterNegativeStylePromptSDXL;
shouldConcatSDXLStylePrompt: boolean; shouldConcatSDXLStylePrompt: boolean;
@ -23,7 +23,7 @@ type SDXLState = {
}; };
const initialSDXLState: SDXLState = { const initialSDXLState: SDXLState = {
_version: 1, _version: 2,
positiveStylePrompt: '', positiveStylePrompt: '',
negativeStylePrompt: '', negativeStylePrompt: '',
shouldConcatSDXLStylePrompt: true, shouldConcatSDXLStylePrompt: true,
@ -93,6 +93,11 @@ const migrateSDXLState = (state: any): any => {
if (!('_version' in state)) { if (!('_version' in state)) {
state._version = 1; state._version = 1;
} }
if (state._version === 1) {
// Model type has changed, so we need to reset the state - too risky to migrate
state._version = 2;
state.refinerModel = null;
}
return state; return state;
}; };