mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): upgrade redux and RTK
There are a few breaking changes, which I've addressed. The vast majority of changes are related to new handling of `reselect`'s `createSelector` options. For better or worse, we memoize just about all our selectors using lodash `isEqual` for `resultEqualityCheck`. The upgrade requires we explicitly set the `memoize` option to `lruMemoize` to continue using lodash here. Doing that required changing our `defaultSelectorOptions`. Instead of changing that and finding dozens of instances where we weren't using that and instead were defining selector options manually, I've created a pre-configured selector: `createMemoizedSelector`. This is now used everywhere instead of `createSelector`.
This commit is contained in:
parent
99f14b1dfe
commit
72cb8b83fe
@ -65,7 +65,7 @@
|
|||||||
"@mantine/form": "^6.0.19",
|
"@mantine/form": "^6.0.19",
|
||||||
"@mantine/hooks": "^6.0.19",
|
"@mantine/hooks": "^6.0.19",
|
||||||
"@nanostores/react": "^0.7.1",
|
"@nanostores/react": "^0.7.1",
|
||||||
"@reduxjs/toolkit": "^1.9.7",
|
"@reduxjs/toolkit": "^2.0.1",
|
||||||
"@roarr/browser-log-writer": "^1.3.0",
|
"@roarr/browser-log-writer": "^1.3.0",
|
||||||
"@storybook/manager-api": "^7.6.4",
|
"@storybook/manager-api": "^7.6.4",
|
||||||
"@storybook/theming": "^7.6.4",
|
"@storybook/theming": "^7.6.4",
|
||||||
@ -92,7 +92,7 @@
|
|||||||
"react-i18next": "^13.5.0",
|
"react-i18next": "^13.5.0",
|
||||||
"react-icons": "^4.12.0",
|
"react-icons": "^4.12.0",
|
||||||
"react-konva": "^18.2.10",
|
"react-konva": "^18.2.10",
|
||||||
"react-redux": "^8.1.3",
|
"react-redux": "^9.0.2",
|
||||||
"react-resizable-panels": "^0.0.55",
|
"react-resizable-panels": "^0.0.55",
|
||||||
"react-use": "^17.4.2",
|
"react-use": "^17.4.2",
|
||||||
"react-virtuoso": "^4.6.2",
|
"react-virtuoso": "^4.6.2",
|
||||||
@ -130,7 +130,6 @@
|
|||||||
"@types/node": "^20.9.0",
|
"@types/node": "^20.9.0",
|
||||||
"@types/react": "^18.2.37",
|
"@types/react": "^18.2.37",
|
||||||
"@types/react-dom": "^18.2.17",
|
"@types/react-dom": "^18.2.17",
|
||||||
"@types/react-redux": "^7.1.32",
|
|
||||||
"@types/uuid": "^9.0.7",
|
"@types/uuid": "^9.0.7",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.13.2",
|
"@typescript-eslint/eslint-plugin": "^6.13.2",
|
||||||
"@typescript-eslint/parser": "^6.13.2",
|
"@typescript-eslint/parser": "^6.13.2",
|
||||||
|
95
invokeai/frontend/web/pnpm-lock.yaml
generated
95
invokeai/frontend/web/pnpm-lock.yaml
generated
@ -57,8 +57,8 @@ dependencies:
|
|||||||
specifier: ^0.7.1
|
specifier: ^0.7.1
|
||||||
version: 0.7.1(nanostores@0.9.5)(react@18.2.0)
|
version: 0.7.1(nanostores@0.9.5)(react@18.2.0)
|
||||||
'@reduxjs/toolkit':
|
'@reduxjs/toolkit':
|
||||||
specifier: ^1.9.7
|
specifier: ^2.0.1
|
||||||
version: 1.9.7(react-redux@8.1.3)(react@18.2.0)
|
version: 2.0.1(react-redux@9.0.2)(react@18.2.0)
|
||||||
'@roarr/browser-log-writer':
|
'@roarr/browser-log-writer':
|
||||||
specifier: ^1.3.0
|
specifier: ^1.3.0
|
||||||
version: 1.3.0
|
version: 1.3.0
|
||||||
@ -138,8 +138,8 @@ dependencies:
|
|||||||
specifier: ^18.2.10
|
specifier: ^18.2.10
|
||||||
version: 18.2.10(konva@9.2.3)(react-dom@18.2.0)(react@18.2.0)
|
version: 18.2.10(konva@9.2.3)(react-dom@18.2.0)(react@18.2.0)
|
||||||
react-redux:
|
react-redux:
|
||||||
specifier: ^8.1.3
|
specifier: ^9.0.2
|
||||||
version: 8.1.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0)(redux@4.2.1)
|
version: 9.0.2(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0)(redux@5.0.0)
|
||||||
react-resizable-panels:
|
react-resizable-panels:
|
||||||
specifier: ^0.0.55
|
specifier: ^0.0.55
|
||||||
version: 0.0.55(react-dom@18.2.0)(react@18.2.0)
|
version: 0.0.55(react-dom@18.2.0)(react@18.2.0)
|
||||||
@ -157,7 +157,7 @@ dependencies:
|
|||||||
version: 2.2.0
|
version: 2.2.0
|
||||||
redux-remember:
|
redux-remember:
|
||||||
specifier: ^4.2.2
|
specifier: ^4.2.2
|
||||||
version: 4.2.2(redux@4.2.1)
|
version: 4.2.2(redux@5.0.0)
|
||||||
roarr:
|
roarr:
|
||||||
specifier: ^7.21.0
|
specifier: ^7.21.0
|
||||||
version: 7.21.0
|
version: 7.21.0
|
||||||
@ -226,9 +226,6 @@ devDependencies:
|
|||||||
'@types/react-dom':
|
'@types/react-dom':
|
||||||
specifier: ^18.2.17
|
specifier: ^18.2.17
|
||||||
version: 18.2.17
|
version: 18.2.17
|
||||||
'@types/react-redux':
|
|
||||||
specifier: ^7.1.32
|
|
||||||
version: 7.1.32
|
|
||||||
'@types/uuid':
|
'@types/uuid':
|
||||||
specifier: ^9.0.7
|
specifier: ^9.0.7
|
||||||
version: 9.0.7
|
version: 9.0.7
|
||||||
@ -4493,23 +4490,23 @@ packages:
|
|||||||
- immer
|
- immer
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@reduxjs/toolkit@1.9.7(react-redux@8.1.3)(react@18.2.0):
|
/@reduxjs/toolkit@2.0.1(react-redux@9.0.2)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-t7v8ZPxhhKgOKtU+uyJT13lu4vL7az5aFi4IdoDs/eS548edn2M8Ik9h8fxgvMjGoAUVFSt6ZC1P5cWmQ014QQ==}
|
resolution: {integrity: sha512-fxIjrR9934cmS8YXIGd9e7s1XRsEU++aFc9DVNMFMRTM5Vtsg2DCRMj21eslGtDt43IUf9bJL3h5bwUlZleibA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^16.9.0 || ^17.0.0 || ^18
|
react: ^16.9.0 || ^17.0.0 || ^18
|
||||||
react-redux: ^7.2.1 || ^8.0.2
|
react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
react:
|
react:
|
||||||
optional: true
|
optional: true
|
||||||
react-redux:
|
react-redux:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
immer: 9.0.21
|
immer: 10.0.3
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
react-redux: 8.1.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0)(redux@4.2.1)
|
react-redux: 9.0.2(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0)(redux@5.0.0)
|
||||||
redux: 4.2.1
|
redux: 5.0.0
|
||||||
redux-thunk: 2.4.2(redux@4.2.1)
|
redux-thunk: 3.1.0(redux@5.0.0)
|
||||||
reselect: 4.1.8
|
reselect: 5.0.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@roarr/browser-log-writer@1.3.0:
|
/@roarr/browser-log-writer@1.3.0:
|
||||||
@ -5802,12 +5799,6 @@ packages:
|
|||||||
'@types/node': 20.10.4
|
'@types/node': 20.10.4
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@types/hoist-non-react-statics@3.3.1:
|
|
||||||
resolution: {integrity: sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==}
|
|
||||||
dependencies:
|
|
||||||
'@types/react': 18.2.42
|
|
||||||
hoist-non-react-statics: 3.3.2
|
|
||||||
|
|
||||||
/@types/http-errors@2.0.4:
|
/@types/http-errors@2.0.4:
|
||||||
resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
|
resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
|
||||||
|
|
||||||
@ -5922,15 +5913,6 @@ packages:
|
|||||||
'@types/react': 18.2.42
|
'@types/react': 18.2.42
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@types/react-redux@7.1.32:
|
|
||||||
resolution: {integrity: sha512-YJYV0M27cyHHJIacaRsZRx5OETzK8KWjEGnix7UH3ngItYo4It0MUBzU6WNwqnwhbrPw5wx9KXluuoTZ85Gg7A==}
|
|
||||||
dependencies:
|
|
||||||
'@types/hoist-non-react-statics': 3.3.1
|
|
||||||
'@types/react': 18.2.42
|
|
||||||
hoist-non-react-statics: 3.3.2
|
|
||||||
redux: 4.2.1
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@types/react@18.2.42:
|
/@types/react@18.2.42:
|
||||||
resolution: {integrity: sha512-c1zEr96MjakLYus/wPnuWDo1/zErfdU9rNsIGmE+NV71nx88FG9Ttgo5dqorXTu/LImX2f63WBP986gJkMPNbA==}
|
resolution: {integrity: sha512-c1zEr96MjakLYus/wPnuWDo1/zErfdU9rNsIGmE+NV71nx88FG9Ttgo5dqorXTu/LImX2f63WBP986gJkMPNbA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -8959,6 +8941,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
|
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
react-is: 16.13.1
|
react-is: 16.13.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/hosted-git-info@2.8.9:
|
/hosted-git-info@2.8.9:
|
||||||
resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==}
|
resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==}
|
||||||
@ -9049,8 +9032,8 @@ packages:
|
|||||||
engines: {node: '>= 4'}
|
engines: {node: '>= 4'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/immer@9.0.21:
|
/immer@10.0.3:
|
||||||
resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==}
|
resolution: {integrity: sha512-pwupu3eWfouuaowscykeckFmVTpqbzW+rXFCX8rQLkZzM9ftBmU/++Ra+o+L27mz03zJTlyV4UUr+fdKNffo4A==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/import-fresh@3.3.0:
|
/import-fresh@3.3.0:
|
||||||
@ -11029,6 +11012,7 @@ packages:
|
|||||||
|
|
||||||
/react-is@18.2.0:
|
/react-is@18.2.0:
|
||||||
resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
|
resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/react-konva@18.2.10(konva@9.2.3)(react-dom@18.2.0)(react@18.2.0):
|
/react-konva@18.2.10(konva@9.2.3)(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-ohcX1BJINL43m4ynjZ24MxFI1syjBdrXhqVxYVDw2rKgr3yuS0x/6m1Y2Z4sl4T/gKhfreBx8KHisd0XC6OT1g==}
|
resolution: {integrity: sha512-ohcX1BJINL43m4ynjZ24MxFI1syjBdrXhqVxYVDw2rKgr3yuS0x/6m1Y2Z4sl4T/gKhfreBx8KHisd0XC6OT1g==}
|
||||||
@ -11057,15 +11041,15 @@ packages:
|
|||||||
scheduler: 0.23.0
|
scheduler: 0.23.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/react-redux@8.1.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0)(redux@4.2.1):
|
/react-redux@9.0.2(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0)(redux@5.0.0):
|
||||||
resolution: {integrity: sha512-n0ZrutD7DaX/j9VscF+uTALI3oUPa/pO4Z3soOBIjuRn/FzVu6aehhysxZCLi6y7duMf52WNZGMl7CtuK5EnRw==}
|
resolution: {integrity: sha512-34EI42cYZxJF59Iht6RDM5xDun5EdhV8CbJcTe+mYx97XMHLNYA6RrH9r/ZOZX3CetVCYfBEU9oAY9h3sZarsw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@types/react': ^16.8 || ^17.0 || ^18.0
|
'@types/react': ^18.2.41
|
||||||
'@types/react-dom': ^16.8 || ^17.0 || ^18.0
|
'@types/react-dom': ^18.2.17
|
||||||
react: ^16.8 || ^17.0 || ^18.0
|
react: ^18.0
|
||||||
react-dom: ^16.8 || ^17.0 || ^18.0
|
react-dom: ^18.0
|
||||||
react-native: '>=0.59'
|
react-native: '>=0.71'
|
||||||
redux: ^4 || ^5.0.0-beta.0
|
redux: ^5.0.0
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
'@types/react':
|
'@types/react':
|
||||||
optional: true
|
optional: true
|
||||||
@ -11078,16 +11062,12 @@ packages:
|
|||||||
redux:
|
redux:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.23.5
|
|
||||||
'@types/hoist-non-react-statics': 3.3.1
|
|
||||||
'@types/react': 18.2.42
|
'@types/react': 18.2.42
|
||||||
'@types/react-dom': 18.2.17
|
'@types/react-dom': 18.2.17
|
||||||
'@types/use-sync-external-store': 0.0.3
|
'@types/use-sync-external-store': 0.0.3
|
||||||
hoist-non-react-statics: 3.3.2
|
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
react-dom: 18.2.0(react@18.2.0)
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
react-is: 18.2.0
|
redux: 5.0.0
|
||||||
redux: 4.2.1
|
|
||||||
use-sync-external-store: 1.2.0(react@18.2.0)
|
use-sync-external-store: 1.2.0(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
@ -11329,26 +11309,25 @@ packages:
|
|||||||
resolution: {integrity: sha512-GHESQC+Y0PV98ZBoaC6br6cDOsNiM1Cu4UleGMqMWCXX03jIr3BoozYVrRkLVVAl4sC216chakMnZOu6SwNdGA==}
|
resolution: {integrity: sha512-GHESQC+Y0PV98ZBoaC6br6cDOsNiM1Cu4UleGMqMWCXX03jIr3BoozYVrRkLVVAl4sC216chakMnZOu6SwNdGA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/redux-remember@4.2.2(redux@4.2.1):
|
/redux-remember@4.2.2(redux@5.0.0):
|
||||||
resolution: {integrity: sha512-1pY3FNk70uZ7Djya/SXkwL13hu0T6iVYSVMFqUApR4n3BDoGYmmaSouX8T3Y1Rg2pmZFaWw7e8ZaOAH82s8IiA==}
|
resolution: {integrity: sha512-1pY3FNk70uZ7Djya/SXkwL13hu0T6iVYSVMFqUApR4n3BDoGYmmaSouX8T3Y1Rg2pmZFaWw7e8ZaOAH82s8IiA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
redux: '*'
|
redux: '*'
|
||||||
dependencies:
|
dependencies:
|
||||||
redux: 4.2.1
|
redux: 5.0.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/redux-thunk@2.4.2(redux@4.2.1):
|
/redux-thunk@3.1.0(redux@5.0.0):
|
||||||
resolution: {integrity: sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==}
|
resolution: {integrity: sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
redux: ^4
|
redux: ^5.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
redux: 4.2.1
|
redux: 5.0.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/redux@4.2.1:
|
/redux@5.0.0:
|
||||||
resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==}
|
resolution: {integrity: sha512-blLIYmYetpZMET6Q6uCY7Jtl/Im5OBldy+vNPauA8vvsdqyt66oep4EUpAMWNHauTC6xa9JuRPhRB72rY82QGA==}
|
||||||
dependencies:
|
dev: false
|
||||||
'@babel/runtime': 7.23.5
|
|
||||||
|
|
||||||
/reflect.getprototypeof@1.0.3:
|
/reflect.getprototypeof@1.0.3:
|
||||||
resolution: {integrity: sha512-TTAOZpkJ2YLxl7mVHWrNo3iDMEkYlva/kgFcXndqMgbo/AZUmmavEkdXV+hXtE4P8xdyEKRzalaFqZVuwIk/Nw==}
|
resolution: {integrity: sha512-TTAOZpkJ2YLxl7mVHWrNo3iDMEkYlva/kgFcXndqMgbo/AZUmmavEkdXV+hXtE4P8xdyEKRzalaFqZVuwIk/Nw==}
|
||||||
@ -11452,8 +11431,8 @@ packages:
|
|||||||
hasBin: true
|
hasBin: true
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/reselect@4.1.8:
|
/reselect@5.0.1:
|
||||||
resolution: {integrity: sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==}
|
resolution: {integrity: sha512-D72j2ubjgHpvuCiORWkOUxndHJrxDaSolheiz5CO+roz8ka97/4msh2E8F5qay4GawR5vzBt5MkbDHT+Rdy/Wg==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/resize-observer-polyfill@1.5.1:
|
/resize-observer-polyfill@1.5.1:
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { useQueueBack } from 'features/queue/hooks/useQueueBack';
|
import { useQueueBack } from 'features/queue/hooks/useQueueBack';
|
||||||
@ -9,20 +9,14 @@ import {
|
|||||||
shiftKeyPressed,
|
shiftKeyPressed,
|
||||||
} from 'features/ui/store/hotkeysSlice';
|
} from 'features/ui/store/hotkeysSlice';
|
||||||
import { setActiveTab } from 'features/ui/store/uiSlice';
|
import { setActiveTab } from 'features/ui/store/uiSlice';
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
import React, { memo } from 'react';
|
import React, { memo } from 'react';
|
||||||
import { isHotkeyPressed, useHotkeys } from 'react-hotkeys-hook';
|
import { isHotkeyPressed, useHotkeys } from 'react-hotkeys-hook';
|
||||||
|
|
||||||
const globalHotkeysSelector = createSelector(
|
const globalHotkeysSelector = createMemoizedSelector(
|
||||||
[stateSelector],
|
[stateSelector],
|
||||||
({ hotkeys }) => {
|
({ hotkeys }) => {
|
||||||
const { shift, ctrl, meta } = hotkeys;
|
const { shift, ctrl, meta } = hotkeys;
|
||||||
return { shift, ctrl, meta };
|
return { shift, ctrl, meta };
|
||||||
},
|
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
|
||||||
import { createLogWriter } from '@roarr/browser-log-writer';
|
import { createLogWriter } from '@roarr/browser-log-writer';
|
||||||
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
import { useEffect, useMemo } from 'react';
|
import { useEffect, useMemo } from 'react';
|
||||||
import { ROARR, Roarr } from 'roarr';
|
import { ROARR, Roarr } from 'roarr';
|
||||||
import {
|
import {
|
||||||
@ -13,22 +12,14 @@ import {
|
|||||||
logger,
|
logger,
|
||||||
} from './logger';
|
} from './logger';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(stateSelector, ({ system }) => {
|
||||||
stateSelector,
|
const { consoleLogLevel, shouldLogToConsole } = system;
|
||||||
({ system }) => {
|
|
||||||
const { consoleLogLevel, shouldLogToConsole } = system;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
consoleLogLevel,
|
consoleLogLevel,
|
||||||
shouldLogToConsole,
|
shouldLogToConsole,
|
||||||
};
|
};
|
||||||
},
|
});
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export const useLogger = (namespace: LoggerNamespace) => {
|
export const useLogger = (namespace: LoggerNamespace) => {
|
||||||
const { consoleLogLevel, shouldLogToConsole } = useAppSelector(selector);
|
const { consoleLogLevel, shouldLogToConsole } = useAppSelector(selector);
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
import { createSelectorCreator, lruMemoize } from '@reduxjs/toolkit';
|
||||||
|
import { isEqual } from 'lodash-es';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A memoized selector creator that uses LRU cache and lodash's isEqual for equality check.
|
||||||
|
*/
|
||||||
|
export const createMemoizedSelector = createSelectorCreator({
|
||||||
|
memoize: lruMemoize,
|
||||||
|
memoizeOptions: {
|
||||||
|
resultEqualityCheck: isEqual,
|
||||||
|
},
|
||||||
|
});
|
@ -1,10 +1,10 @@
|
|||||||
import { AnyAction } from '@reduxjs/toolkit';
|
import { UnknownAction } from '@reduxjs/toolkit';
|
||||||
import { isAnyGraphBuilt } from 'features/nodes/store/actions';
|
import { isAnyGraphBuilt } from 'features/nodes/store/actions';
|
||||||
import { nodeTemplatesBuilt } from 'features/nodes/store/nodesSlice';
|
import { nodeTemplatesBuilt } from 'features/nodes/store/nodesSlice';
|
||||||
import { receivedOpenAPISchema } from 'services/api/thunks/schema';
|
import { receivedOpenAPISchema } from 'services/api/thunks/schema';
|
||||||
import { Graph } from 'services/api/types';
|
import { Graph } from 'services/api/types';
|
||||||
|
|
||||||
export const actionSanitizer = <A extends AnyAction>(action: A): A => {
|
export const actionSanitizer = <A extends UnknownAction>(action: A): A => {
|
||||||
if (isAnyGraphBuilt(action)) {
|
if (isAnyGraphBuilt(action)) {
|
||||||
if (action.payload.nodes) {
|
if (action.payload.nodes) {
|
||||||
const sanitizedNodes: Graph['nodes'] = {};
|
const sanitizedNodes: Graph['nodes'] = {};
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import type { TypedAddListener, TypedStartListening } from '@reduxjs/toolkit';
|
import type { TypedAddListener, TypedStartListening } from '@reduxjs/toolkit';
|
||||||
import {
|
import {
|
||||||
AnyAction,
|
UnknownAction,
|
||||||
ListenerEffect,
|
ListenerEffect,
|
||||||
addListener,
|
addListener,
|
||||||
createListenerMiddleware,
|
createListenerMiddleware,
|
||||||
} from '@reduxjs/toolkit';
|
} from '@reduxjs/toolkit';
|
||||||
|
|
||||||
import type { AppDispatch, RootState } from 'app/store/store';
|
import type { AppDispatch, RootState } from 'app/store/store';
|
||||||
import { addCommitStagingAreaImageListener } from './listeners/addCommitStagingAreaImageListener';
|
import { addCommitStagingAreaImageListener } from './listeners/addCommitStagingAreaImageListener';
|
||||||
import { addFirstListImagesListener } from './listeners/addFirstListImagesListener.ts';
|
import { addFirstListImagesListener } from './listeners/addFirstListImagesListener.ts';
|
||||||
@ -87,7 +86,7 @@ export const addAppListener = addListener as TypedAddListener<
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
export type AppListenerEffect = ListenerEffect<
|
export type AppListenerEffect = ListenerEffect<
|
||||||
AnyAction,
|
UnknownAction,
|
||||||
RootState,
|
RootState,
|
||||||
AppDispatch
|
AppDispatch
|
||||||
>;
|
>;
|
||||||
|
@ -52,7 +52,11 @@ export const addBoardIdSelectedListener = () => {
|
|||||||
const { data: boardImagesData } =
|
const { data: boardImagesData } =
|
||||||
imagesApi.endpoints.listImages.select(queryArgs)(getState());
|
imagesApi.endpoints.listImages.select(queryArgs)(getState());
|
||||||
|
|
||||||
if (boardImagesData) {
|
if (
|
||||||
|
boardImagesData &&
|
||||||
|
boardIdSelected.match(action) &&
|
||||||
|
action.payload.selectedImageName
|
||||||
|
) {
|
||||||
const firstImage = imagesSelectors.selectAll(boardImagesData)[0];
|
const firstImage = imagesSelectors.selectAll(boardImagesData)[0];
|
||||||
const selectedImage = imagesSelectors.selectById(
|
const selectedImage = imagesSelectors.selectById(
|
||||||
boardImagesData,
|
boardImagesData,
|
||||||
|
@ -24,7 +24,7 @@ export const addSocketQueueItemStatusChangedEventListener = () => {
|
|||||||
dispatch(
|
dispatch(
|
||||||
queueApi.util.updateQueryData('listQueueItems', undefined, (draft) => {
|
queueApi.util.updateQueryData('listQueueItems', undefined, (draft) => {
|
||||||
queueItemsAdapter.updateOne(draft, {
|
queueItemsAdapter.updateOne(draft, {
|
||||||
id: queue_item.item_id,
|
id: String(queue_item.item_id),
|
||||||
changes: queue_item,
|
changes: queue_item,
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
AnyAction,
|
|
||||||
ThunkDispatch,
|
ThunkDispatch,
|
||||||
|
UnknownAction,
|
||||||
autoBatchEnhancer,
|
autoBatchEnhancer,
|
||||||
combineReducers,
|
combineReducers,
|
||||||
configureStore,
|
configureStore,
|
||||||
@ -27,7 +27,6 @@ import { createStore as createIDBKeyValStore, get, set } from 'idb-keyval';
|
|||||||
import dynamicMiddlewares from 'redux-dynamic-middlewares';
|
import dynamicMiddlewares from 'redux-dynamic-middlewares';
|
||||||
import { Driver, rememberEnhancer, rememberReducer } from 'redux-remember';
|
import { Driver, rememberEnhancer, rememberReducer } from 'redux-remember';
|
||||||
import { api } from 'services/api';
|
import { api } from 'services/api';
|
||||||
import { authToastMiddleware } from 'services/api/authToastMiddleware';
|
|
||||||
import { STORAGE_PREFIX } from './constants';
|
import { STORAGE_PREFIX } from './constants';
|
||||||
import { serialize } from './enhancers/reduxRemember/serialize';
|
import { serialize } from './enhancers/reduxRemember/serialize';
|
||||||
import { unserialize } from './enhancers/reduxRemember/unserialize';
|
import { unserialize } from './enhancers/reduxRemember/unserialize';
|
||||||
@ -90,8 +89,16 @@ const idbKeyValDriver: Driver = {
|
|||||||
export const createStore = (uniqueStoreKey?: string, persist = true) =>
|
export const createStore = (uniqueStoreKey?: string, persist = true) =>
|
||||||
configureStore({
|
configureStore({
|
||||||
reducer: rememberedRootReducer,
|
reducer: rememberedRootReducer,
|
||||||
enhancers: (existingEnhancers) => {
|
middleware: (getDefaultMiddleware) =>
|
||||||
const _enhancers = existingEnhancers.concat(autoBatchEnhancer());
|
getDefaultMiddleware({
|
||||||
|
serializableCheck: false,
|
||||||
|
immutableCheck: false,
|
||||||
|
})
|
||||||
|
.concat(api.middleware)
|
||||||
|
.concat(dynamicMiddlewares)
|
||||||
|
.prepend(listenerMiddleware.middleware),
|
||||||
|
enhancers: (getDefaultEnhancers) => {
|
||||||
|
const _enhancers = getDefaultEnhancers().concat(autoBatchEnhancer());
|
||||||
if (persist) {
|
if (persist) {
|
||||||
_enhancers.push(
|
_enhancers.push(
|
||||||
rememberEnhancer(idbKeyValDriver, rememberedKeys, {
|
rememberEnhancer(idbKeyValDriver, rememberedKeys, {
|
||||||
@ -106,15 +113,6 @@ export const createStore = (uniqueStoreKey?: string, persist = true) =>
|
|||||||
}
|
}
|
||||||
return _enhancers;
|
return _enhancers;
|
||||||
},
|
},
|
||||||
middleware: (getDefaultMiddleware) =>
|
|
||||||
getDefaultMiddleware({
|
|
||||||
serializableCheck: false,
|
|
||||||
immutableCheck: false,
|
|
||||||
})
|
|
||||||
.concat(api.middleware)
|
|
||||||
.concat(dynamicMiddlewares)
|
|
||||||
.concat(authToastMiddleware)
|
|
||||||
.prepend(listenerMiddleware.middleware),
|
|
||||||
devTools: {
|
devTools: {
|
||||||
actionSanitizer,
|
actionSanitizer,
|
||||||
stateSanitizer,
|
stateSanitizer,
|
||||||
@ -145,6 +143,6 @@ export type AppGetState = ReturnType<
|
|||||||
>;
|
>;
|
||||||
export type RootState = ReturnType<ReturnType<typeof createStore>['getState']>;
|
export type RootState = ReturnType<ReturnType<typeof createStore>['getState']>;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export type AppThunkDispatch = ThunkDispatch<RootState, any, AnyAction>;
|
export type AppThunkDispatch = ThunkDispatch<RootState, any, UnknownAction>;
|
||||||
export type AppDispatch = ReturnType<typeof createStore>['dispatch'];
|
export type AppDispatch = ReturnType<typeof createStore>['dispatch'];
|
||||||
export const stateSelector = (state: RootState) => state;
|
export const stateSelector = (state: RootState) => state;
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
import { isEqual } from 'lodash-es';
|
|
||||||
|
|
||||||
export const defaultSelectorOptions = {
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
};
|
|
@ -12,7 +12,6 @@
|
|||||||
* - increment it in `onPaneClick`
|
* - increment it in `onPaneClick`
|
||||||
* - `useEffect()` to close the menu when `globalContextMenuCloseTrigger` changes
|
* - `useEffect()` to close the menu when `globalContextMenuCloseTrigger` changes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Menu,
|
Menu,
|
||||||
MenuButton,
|
MenuButton,
|
||||||
|
@ -19,7 +19,6 @@ import { useAppDispatch } from 'app/store/storeHooks';
|
|||||||
import { stopPastePropagation } from 'common/util/stopPastePropagation';
|
import { stopPastePropagation } from 'common/util/stopPastePropagation';
|
||||||
import { shiftKeyPressed } from 'features/ui/store/hotkeysSlice';
|
import { shiftKeyPressed } from 'features/ui/store/hotkeysSlice';
|
||||||
import { clamp } from 'lodash-es';
|
import { clamp } from 'lodash-es';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
FocusEvent,
|
FocusEvent,
|
||||||
KeyboardEvent,
|
KeyboardEvent,
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import { Box } from '@chakra-ui/react';
|
import { Box } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
|
||||||
import { useAppToaster } from 'app/components/Toaster';
|
import { useAppToaster } from 'app/components/Toaster';
|
||||||
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||||
import { AnimatePresence, motion } from 'framer-motion';
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
import {
|
import {
|
||||||
@ -20,7 +19,7 @@ import { useUploadImageMutation } from 'services/api/endpoints/images';
|
|||||||
import { PostUploadAction } from 'services/api/types';
|
import { PostUploadAction } from 'services/api/types';
|
||||||
import ImageUploadOverlay from './ImageUploadOverlay';
|
import ImageUploadOverlay from './ImageUploadOverlay';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(
|
||||||
[stateSelector, activeTabNameSelector],
|
[stateSelector, activeTabNameSelector],
|
||||||
({ gallery }, activeTabName) => {
|
({ gallery }, activeTabName) => {
|
||||||
let postUploadAction: PostUploadAction = { type: 'TOAST' };
|
let postUploadAction: PostUploadAction = { type: 'TOAST' };
|
||||||
@ -39,8 +38,7 @@ const selector = createSelector(
|
|||||||
autoAddBoardId,
|
autoAddBoardId,
|
||||||
postUploadAction,
|
postUploadAction,
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
);
|
||||||
|
|
||||||
type ImageUploaderProps = {
|
type ImageUploaderProps = {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import { selectControlAdapterAll } from 'features/controlAdapters/store/controlAdaptersSlice';
|
import { selectControlAdapterAll } from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||||
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
||||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||||
@ -10,7 +9,7 @@ import i18n from 'i18next';
|
|||||||
import { forEach } from 'lodash-es';
|
import { forEach } from 'lodash-es';
|
||||||
import { getConnectedEdges } from 'reactflow';
|
import { getConnectedEdges } from 'reactflow';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(
|
||||||
[stateSelector, activeTabNameSelector],
|
[stateSelector, activeTabNameSelector],
|
||||||
(
|
(
|
||||||
{ controlAdapters, generation, system, nodes, dynamicPrompts },
|
{ controlAdapters, generation, system, nodes, dynamicPrompts },
|
||||||
@ -125,8 +124,7 @@ const selector = createSelector(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return { isReady: !reasons.length, reasons };
|
return { isReady: !reasons.length, reasons };
|
||||||
},
|
}
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
);
|
||||||
|
|
||||||
export const useIsReadyToEnqueue = () => {
|
export const useIsReadyToEnqueue = () => {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
// https://stackoverflow.com/a/73731908
|
// https://stackoverflow.com/a/73731908
|
||||||
|
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
export function useSingleAndDoubleClick(
|
export function useSingleAndDoubleClick(
|
||||||
|
@ -1,16 +1,7 @@
|
|||||||
import { Box, chakra, Flex } from '@chakra-ui/react';
|
import { Box, chakra, Flex } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import {
|
|
||||||
canvasSelector,
|
|
||||||
isStagingSelector,
|
|
||||||
} from 'features/canvas/store/canvasSelectors';
|
|
||||||
import Konva from 'konva';
|
|
||||||
import { KonvaEventObject } from 'konva/lib/Node';
|
|
||||||
import { Vector2d } from 'konva/lib/types';
|
|
||||||
import { memo, useCallback, useEffect, useRef } from 'react';
|
|
||||||
import { Layer, Stage } from 'react-konva';
|
|
||||||
import useCanvasDragMove from 'features/canvas/hooks/useCanvasDragMove';
|
import useCanvasDragMove from 'features/canvas/hooks/useCanvasDragMove';
|
||||||
import useCanvasHotkeys from 'features/canvas/hooks/useCanvasHotkeys';
|
import useCanvasHotkeys from 'features/canvas/hooks/useCanvasHotkeys';
|
||||||
import useCanvasMouseDown from 'features/canvas/hooks/useCanvasMouseDown';
|
import useCanvasMouseDown from 'features/canvas/hooks/useCanvasMouseDown';
|
||||||
@ -18,11 +9,17 @@ import useCanvasMouseMove from 'features/canvas/hooks/useCanvasMouseMove';
|
|||||||
import useCanvasMouseOut from 'features/canvas/hooks/useCanvasMouseOut';
|
import useCanvasMouseOut from 'features/canvas/hooks/useCanvasMouseOut';
|
||||||
import useCanvasMouseUp from 'features/canvas/hooks/useCanvasMouseUp';
|
import useCanvasMouseUp from 'features/canvas/hooks/useCanvasMouseUp';
|
||||||
import useCanvasWheel from 'features/canvas/hooks/useCanvasZoom';
|
import useCanvasWheel from 'features/canvas/hooks/useCanvasZoom';
|
||||||
|
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
||||||
import { canvasResized } from 'features/canvas/store/canvasSlice';
|
import { canvasResized } from 'features/canvas/store/canvasSlice';
|
||||||
import {
|
import {
|
||||||
setCanvasBaseLayer,
|
setCanvasBaseLayer,
|
||||||
setCanvasStage,
|
setCanvasStage,
|
||||||
} from 'features/canvas/util/konvaInstanceProvider';
|
} from 'features/canvas/util/konvaInstanceProvider';
|
||||||
|
import Konva from 'konva';
|
||||||
|
import { KonvaEventObject } from 'konva/lib/Node';
|
||||||
|
import { Vector2d } from 'konva/lib/types';
|
||||||
|
import { memo, useCallback, useEffect, useRef } from 'react';
|
||||||
|
import { Layer, Stage } from 'react-konva';
|
||||||
import IAICanvasBoundingBoxOverlay from './IAICanvasBoundingBoxOverlay';
|
import IAICanvasBoundingBoxOverlay from './IAICanvasBoundingBoxOverlay';
|
||||||
import IAICanvasGrid from './IAICanvasGrid';
|
import IAICanvasGrid from './IAICanvasGrid';
|
||||||
import IAICanvasIntermediateImage from './IAICanvasIntermediateImage';
|
import IAICanvasIntermediateImage from './IAICanvasIntermediateImage';
|
||||||
@ -35,9 +32,9 @@ import IAICanvasStatusText from './IAICanvasStatusText';
|
|||||||
import IAICanvasBoundingBox from './IAICanvasToolbar/IAICanvasBoundingBox';
|
import IAICanvasBoundingBox from './IAICanvasToolbar/IAICanvasBoundingBox';
|
||||||
import IAICanvasToolPreview from './IAICanvasToolPreview';
|
import IAICanvasToolPreview from './IAICanvasToolPreview';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(
|
||||||
[canvasSelector, isStagingSelector],
|
[stateSelector, isStagingSelector],
|
||||||
(canvas, isStaging) => {
|
({ canvas }, isStaging) => {
|
||||||
const {
|
const {
|
||||||
isMaskEnabled,
|
isMaskEnabled,
|
||||||
stageScale,
|
stageScale,
|
||||||
@ -83,8 +80,7 @@ const selector = createSelector(
|
|||||||
shouldShowIntermediates,
|
shouldShowIntermediates,
|
||||||
shouldAntialias,
|
shouldAntialias,
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const ChakraStage = chakra(Stage, {
|
const ChakraStage = chakra(Stage, {
|
||||||
|
@ -1,38 +1,28 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
|
|
||||||
import { Group, Rect } from 'react-konva';
|
|
||||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
import { Group, Rect } from 'react-konva';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(stateSelector, ({ canvas }) => {
|
||||||
canvasSelector,
|
const {
|
||||||
(canvas) => {
|
boundingBoxCoordinates,
|
||||||
const {
|
boundingBoxDimensions,
|
||||||
boundingBoxCoordinates,
|
stageDimensions,
|
||||||
boundingBoxDimensions,
|
stageScale,
|
||||||
stageDimensions,
|
shouldDarkenOutsideBoundingBox,
|
||||||
stageScale,
|
stageCoordinates,
|
||||||
shouldDarkenOutsideBoundingBox,
|
} = canvas;
|
||||||
stageCoordinates,
|
|
||||||
} = canvas;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
boundingBoxCoordinates,
|
boundingBoxCoordinates,
|
||||||
boundingBoxDimensions,
|
boundingBoxDimensions,
|
||||||
shouldDarkenOutsideBoundingBox,
|
shouldDarkenOutsideBoundingBox,
|
||||||
stageCoordinates,
|
stageCoordinates,
|
||||||
stageDimensions,
|
stageDimensions,
|
||||||
stageScale,
|
stageScale,
|
||||||
};
|
};
|
||||||
},
|
});
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const IAICanvasBoundingBoxOverlay = () => {
|
const IAICanvasBoundingBoxOverlay = () => {
|
||||||
const {
|
const {
|
||||||
boundingBoxCoordinates,
|
boundingBoxCoordinates,
|
||||||
|
@ -1,26 +1,16 @@
|
|||||||
// Grid drawing adapted from https://longviewcoder.com/2021/12/08/konva-a-better-grid/
|
// Grid drawing adapted from https://longviewcoder.com/2021/12/08/konva-a-better-grid/
|
||||||
|
|
||||||
import { useColorMode, useToken } from '@chakra-ui/react';
|
import { useColorMode, useToken } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
import { range } from 'lodash-es';
|
||||||
import { isEqual, range } from 'lodash-es';
|
|
||||||
|
|
||||||
import { ReactNode, memo, useCallback, useLayoutEffect, useState } from 'react';
|
import { ReactNode, memo, useCallback, useLayoutEffect, useState } from 'react';
|
||||||
import { Group, Line as KonvaLine } from 'react-konva';
|
import { Group, Line as KonvaLine } from 'react-konva';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector([stateSelector], ({ canvas }) => {
|
||||||
[canvasSelector],
|
const { stageScale, stageCoordinates, stageDimensions } = canvas;
|
||||||
(canvas) => {
|
return { stageScale, stageCoordinates, stageDimensions };
|
||||||
const { stageScale, stageCoordinates, stageDimensions } = canvas;
|
});
|
||||||
return { stageScale, stageCoordinates, stageDimensions };
|
|
||||||
},
|
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const IAICanvasGrid = () => {
|
const IAICanvasGrid = () => {
|
||||||
const { stageScale, stageCoordinates, stageDimensions } =
|
const { stageScale, stageCoordinates, stageDimensions } =
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { skipToken } from '@reduxjs/toolkit/dist/query';
|
import { skipToken } from '@reduxjs/toolkit/query';
|
||||||
import { $authToken } from 'app/store/nanostores/authToken';
|
import { $authToken } from 'app/store/nanostores/authToken';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import { Image } from 'react-konva';
|
import { Image } from 'react-konva';
|
||||||
|
@ -2,31 +2,22 @@ import { createSelector } from '@reduxjs/toolkit';
|
|||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { ImageConfig } from 'konva/lib/shapes/Image';
|
import { ImageConfig } from 'konva/lib/shapes/Image';
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
import { memo, useEffect, useState } from 'react';
|
import { memo, useEffect, useState } from 'react';
|
||||||
import { Image as KonvaImage } from 'react-konva';
|
import { Image as KonvaImage } from 'react-konva';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector([stateSelector], ({ system, canvas }) => {
|
||||||
[stateSelector],
|
const { denoiseProgress } = system;
|
||||||
({ system, canvas }) => {
|
const { boundingBox } = canvas.layerState.stagingArea;
|
||||||
const { denoiseProgress } = system;
|
const { batchIds } = canvas;
|
||||||
const { boundingBox } = canvas.layerState.stagingArea;
|
|
||||||
const { batchIds } = canvas;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
boundingBox,
|
boundingBox,
|
||||||
progressImage:
|
progressImage:
|
||||||
denoiseProgress && batchIds.includes(denoiseProgress.batch_id)
|
denoiseProgress && batchIds.includes(denoiseProgress.batch_id)
|
||||||
? denoiseProgress.progress_image
|
? denoiseProgress.progress_image
|
||||||
: undefined,
|
: undefined,
|
||||||
};
|
};
|
||||||
},
|
});
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
type Props = Omit<ImageConfig, 'image'>;
|
type Props = Omit<ImageConfig, 'image'>;
|
||||||
|
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
|
||||||
import { RectConfig } from 'konva/lib/shapes/Rect';
|
|
||||||
import { Rect } from 'react-konva';
|
|
||||||
|
|
||||||
import { rgbaColorToString } from 'features/canvas/util/colorToString';
|
import { rgbaColorToString } from 'features/canvas/util/colorToString';
|
||||||
import Konva from 'konva';
|
import Konva from 'konva';
|
||||||
|
import { RectConfig } from 'konva/lib/shapes/Rect';
|
||||||
import { isNumber } from 'lodash-es';
|
import { isNumber } from 'lodash-es';
|
||||||
import { memo, useCallback, useEffect, useRef, useState } from 'react';
|
import { memo, useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
import { Rect } from 'react-konva';
|
||||||
|
|
||||||
export const canvasMaskCompositerSelector = createSelector(
|
export const canvasMaskCompositerSelector = createMemoizedSelector(
|
||||||
canvasSelector,
|
stateSelector,
|
||||||
(canvas) => {
|
({ canvas }) => {
|
||||||
const { maskColor, stageCoordinates, stageDimensions, stageScale } = canvas;
|
const { maskColor, stageCoordinates, stageDimensions, stageScale } = canvas;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -1,22 +1,15 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
|
||||||
import { GroupConfig } from 'konva/lib/Group';
|
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
|
|
||||||
import { Group, Line } from 'react-konva';
|
|
||||||
import { isCanvasMaskLine } from 'features/canvas/store/canvasTypes';
|
import { isCanvasMaskLine } from 'features/canvas/store/canvasTypes';
|
||||||
|
import { GroupConfig } from 'konva/lib/Group';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
import { Group, Line } from 'react-konva';
|
||||||
|
|
||||||
export const canvasLinesSelector = createSelector(
|
export const canvasLinesSelector = createMemoizedSelector(
|
||||||
[canvasSelector],
|
[stateSelector],
|
||||||
(canvas) => {
|
({ canvas }) => {
|
||||||
return { objects: canvas.layerState.objects };
|
return { objects: canvas.layerState.objects };
|
||||||
},
|
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,35 +1,25 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
|
||||||
import { rgbaColorToString } from 'features/canvas/util/colorToString';
|
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
|
|
||||||
import { Group, Line, Rect } from 'react-konva';
|
|
||||||
import {
|
import {
|
||||||
isCanvasBaseImage,
|
isCanvasBaseImage,
|
||||||
isCanvasBaseLine,
|
isCanvasBaseLine,
|
||||||
isCanvasEraseRect,
|
isCanvasEraseRect,
|
||||||
isCanvasFillRect,
|
isCanvasFillRect,
|
||||||
} from 'features/canvas/store/canvasTypes';
|
} from 'features/canvas/store/canvasTypes';
|
||||||
import IAICanvasImage from './IAICanvasImage';
|
import { rgbaColorToString } from 'features/canvas/util/colorToString';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
import { Group, Line, Rect } from 'react-konva';
|
||||||
|
import IAICanvasImage from './IAICanvasImage';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector([stateSelector], ({ canvas }) => {
|
||||||
[canvasSelector],
|
const {
|
||||||
(canvas) => {
|
layerState: { objects },
|
||||||
const {
|
} = canvas;
|
||||||
layerState: { objects },
|
return {
|
||||||
} = canvas;
|
objects,
|
||||||
return {
|
};
|
||||||
objects,
|
});
|
||||||
};
|
|
||||||
},
|
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const IAICanvasObjectRenderer = () => {
|
const IAICanvasObjectRenderer = () => {
|
||||||
const { objects } = useAppSelector(selector);
|
const { objects } = useAppSelector(selector);
|
||||||
|
@ -1,46 +1,37 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
|
||||||
import { GroupConfig } from 'konva/lib/Group';
|
import { GroupConfig } from 'konva/lib/Group';
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import { Group, Rect } from 'react-konva';
|
import { Group, Rect } from 'react-konva';
|
||||||
import IAICanvasImage from './IAICanvasImage';
|
import IAICanvasImage from './IAICanvasImage';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector([stateSelector], ({ canvas }) => {
|
||||||
[canvasSelector],
|
const {
|
||||||
(canvas) => {
|
layerState,
|
||||||
const {
|
shouldShowStagingImage,
|
||||||
layerState,
|
shouldShowStagingOutline,
|
||||||
shouldShowStagingImage,
|
boundingBoxCoordinates: stageBoundingBoxCoordinates,
|
||||||
shouldShowStagingOutline,
|
boundingBoxDimensions: stageBoundingBoxDimensions,
|
||||||
boundingBoxCoordinates: stageBoundingBoxCoordinates,
|
} = canvas;
|
||||||
boundingBoxDimensions: stageBoundingBoxDimensions,
|
|
||||||
} = canvas;
|
|
||||||
|
|
||||||
const { selectedImageIndex, images, boundingBox } = layerState.stagingArea;
|
const { selectedImageIndex, images, boundingBox } = layerState.stagingArea;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
currentStagingAreaImage:
|
currentStagingAreaImage:
|
||||||
images.length > 0 && selectedImageIndex !== undefined
|
images.length > 0 && selectedImageIndex !== undefined
|
||||||
? images[selectedImageIndex]
|
? images[selectedImageIndex]
|
||||||
: undefined,
|
: undefined,
|
||||||
isOnFirstImage: selectedImageIndex === 0,
|
isOnFirstImage: selectedImageIndex === 0,
|
||||||
isOnLastImage: selectedImageIndex === images.length - 1,
|
isOnLastImage: selectedImageIndex === images.length - 1,
|
||||||
shouldShowStagingImage,
|
shouldShowStagingImage,
|
||||||
shouldShowStagingOutline,
|
shouldShowStagingOutline,
|
||||||
x: boundingBox?.x ?? stageBoundingBoxCoordinates.x,
|
x: boundingBox?.x ?? stageBoundingBoxCoordinates.x,
|
||||||
y: boundingBox?.y ?? stageBoundingBoxCoordinates.y,
|
y: boundingBox?.y ?? stageBoundingBoxCoordinates.y,
|
||||||
width: boundingBox?.width ?? stageBoundingBoxDimensions.width,
|
width: boundingBox?.width ?? stageBoundingBoxDimensions.width,
|
||||||
height: boundingBox?.height ?? stageBoundingBoxDimensions.height,
|
height: boundingBox?.height ?? stageBoundingBoxDimensions.height,
|
||||||
};
|
};
|
||||||
},
|
});
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
type Props = GroupConfig;
|
type Props = GroupConfig;
|
||||||
|
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
import { ButtonGroup, Flex } from '@chakra-ui/react';
|
import { ButtonGroup, Flex } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { skipToken } from '@reduxjs/toolkit/query';
|
||||||
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
import { stagingAreaImageSaved } from 'features/canvas/store/actions';
|
||||||
import {
|
import {
|
||||||
commitStagingAreaImage,
|
commitStagingAreaImage,
|
||||||
discardStagedImages,
|
discardStagedImages,
|
||||||
@ -11,10 +14,6 @@ import {
|
|||||||
setShouldShowStagingImage,
|
setShouldShowStagingImage,
|
||||||
setShouldShowStagingOutline,
|
setShouldShowStagingOutline,
|
||||||
} from 'features/canvas/store/canvasSlice';
|
} from 'features/canvas/store/canvasSlice';
|
||||||
|
|
||||||
import { skipToken } from '@reduxjs/toolkit/dist/query';
|
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import IAIButton from 'common/components/IAIButton';
|
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -28,30 +27,25 @@ import {
|
|||||||
FaTimes,
|
FaTimes,
|
||||||
} from 'react-icons/fa';
|
} from 'react-icons/fa';
|
||||||
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
|
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
|
||||||
import { stagingAreaImageSaved } from 'features/canvas/store/actions';
|
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector([stateSelector], ({ canvas }) => {
|
||||||
[canvasSelector],
|
const {
|
||||||
(canvas) => {
|
layerState: {
|
||||||
const {
|
stagingArea: { images, selectedImageIndex },
|
||||||
layerState: {
|
},
|
||||||
stagingArea: { images, selectedImageIndex },
|
shouldShowStagingOutline,
|
||||||
},
|
shouldShowStagingImage,
|
||||||
shouldShowStagingOutline,
|
} = canvas;
|
||||||
shouldShowStagingImage,
|
|
||||||
} = canvas;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
currentIndex: selectedImageIndex,
|
currentIndex: selectedImageIndex,
|
||||||
total: images.length,
|
total: images.length,
|
||||||
currentStagingAreaImage:
|
currentStagingAreaImage:
|
||||||
images.length > 0 ? images[selectedImageIndex] : undefined,
|
images.length > 0 ? images[selectedImageIndex] : undefined,
|
||||||
shouldShowStagingImage,
|
shouldShowStagingImage,
|
||||||
shouldShowStagingOutline,
|
shouldShowStagingOutline,
|
||||||
};
|
};
|
||||||
},
|
});
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
const IAICanvasStagingAreaToolbar = () => {
|
const IAICanvasStagingAreaToolbar = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
@ -1,74 +1,65 @@
|
|||||||
import { Box, Flex } from '@chakra-ui/react';
|
import { Box, Flex } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
|
||||||
import GenerationModeStatusText from 'features/parameters/components/Parameters/Canvas/GenerationModeStatusText';
|
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import roundToHundreth from 'features/canvas/util/roundToHundreth';
|
import roundToHundreth from 'features/canvas/util/roundToHundreth';
|
||||||
import IAICanvasStatusTextCursorPos from './IAICanvasStatusText/IAICanvasStatusTextCursorPos';
|
import GenerationModeStatusText from 'features/parameters/components/Parameters/Canvas/GenerationModeStatusText';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import IAICanvasStatusTextCursorPos from './IAICanvasStatusText/IAICanvasStatusTextCursorPos';
|
||||||
|
|
||||||
const warningColor = 'var(--invokeai-colors-warning-500)';
|
const warningColor = 'var(--invokeai-colors-warning-500)';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector([stateSelector], ({ canvas }) => {
|
||||||
[canvasSelector],
|
const {
|
||||||
(canvas) => {
|
stageDimensions: { width: stageWidth, height: stageHeight },
|
||||||
const {
|
stageCoordinates: { x: stageX, y: stageY },
|
||||||
stageDimensions: { width: stageWidth, height: stageHeight },
|
boundingBoxDimensions: { width: boxWidth, height: boxHeight },
|
||||||
stageCoordinates: { x: stageX, y: stageY },
|
scaledBoundingBoxDimensions: {
|
||||||
boundingBoxDimensions: { width: boxWidth, height: boxHeight },
|
width: scaledBoxWidth,
|
||||||
scaledBoundingBoxDimensions: {
|
height: scaledBoxHeight,
|
||||||
width: scaledBoxWidth,
|
|
||||||
height: scaledBoxHeight,
|
|
||||||
},
|
|
||||||
boundingBoxCoordinates: { x: boxX, y: boxY },
|
|
||||||
stageScale,
|
|
||||||
shouldShowCanvasDebugInfo,
|
|
||||||
layer,
|
|
||||||
boundingBoxScaleMethod,
|
|
||||||
shouldPreserveMaskedArea,
|
|
||||||
} = canvas;
|
|
||||||
|
|
||||||
let boundingBoxColor = 'inherit';
|
|
||||||
|
|
||||||
if (
|
|
||||||
(boundingBoxScaleMethod === 'none' &&
|
|
||||||
(boxWidth < 512 || boxHeight < 512)) ||
|
|
||||||
(boundingBoxScaleMethod === 'manual' &&
|
|
||||||
scaledBoxWidth * scaledBoxHeight < 512 * 512)
|
|
||||||
) {
|
|
||||||
boundingBoxColor = warningColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
const activeLayerColor = layer === 'mask' ? warningColor : 'inherit';
|
|
||||||
|
|
||||||
return {
|
|
||||||
activeLayerColor,
|
|
||||||
layer,
|
|
||||||
boundingBoxColor,
|
|
||||||
boundingBoxCoordinatesString: `(${roundToHundreth(
|
|
||||||
boxX
|
|
||||||
)}, ${roundToHundreth(boxY)})`,
|
|
||||||
boundingBoxDimensionsString: `${boxWidth}×${boxHeight}`,
|
|
||||||
scaledBoundingBoxDimensionsString: `${scaledBoxWidth}×${scaledBoxHeight}`,
|
|
||||||
canvasCoordinatesString: `${roundToHundreth(stageX)}×${roundToHundreth(
|
|
||||||
stageY
|
|
||||||
)}`,
|
|
||||||
canvasDimensionsString: `${stageWidth}×${stageHeight}`,
|
|
||||||
canvasScaleString: Math.round(stageScale * 100),
|
|
||||||
shouldShowCanvasDebugInfo,
|
|
||||||
shouldShowBoundingBox: boundingBoxScaleMethod !== 'auto',
|
|
||||||
shouldShowScaledBoundingBox: boundingBoxScaleMethod !== 'none',
|
|
||||||
shouldPreserveMaskedArea,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
},
|
||||||
|
boundingBoxCoordinates: { x: boxX, y: boxY },
|
||||||
|
stageScale,
|
||||||
|
shouldShowCanvasDebugInfo,
|
||||||
|
layer,
|
||||||
|
boundingBoxScaleMethod,
|
||||||
|
shouldPreserveMaskedArea,
|
||||||
|
} = canvas;
|
||||||
|
|
||||||
|
let boundingBoxColor = 'inherit';
|
||||||
|
|
||||||
|
if (
|
||||||
|
(boundingBoxScaleMethod === 'none' &&
|
||||||
|
(boxWidth < 512 || boxHeight < 512)) ||
|
||||||
|
(boundingBoxScaleMethod === 'manual' &&
|
||||||
|
scaledBoxWidth * scaledBoxHeight < 512 * 512)
|
||||||
|
) {
|
||||||
|
boundingBoxColor = warningColor;
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
const activeLayerColor = layer === 'mask' ? warningColor : 'inherit';
|
||||||
|
|
||||||
|
return {
|
||||||
|
activeLayerColor,
|
||||||
|
layer,
|
||||||
|
boundingBoxColor,
|
||||||
|
boundingBoxCoordinatesString: `(${roundToHundreth(boxX)}, ${roundToHundreth(
|
||||||
|
boxY
|
||||||
|
)})`,
|
||||||
|
boundingBoxDimensionsString: `${boxWidth}×${boxHeight}`,
|
||||||
|
scaledBoundingBoxDimensionsString: `${scaledBoxWidth}×${scaledBoxHeight}`,
|
||||||
|
canvasCoordinatesString: `${roundToHundreth(stageX)}×${roundToHundreth(
|
||||||
|
stageY
|
||||||
|
)}`,
|
||||||
|
canvasDimensionsString: `${stageWidth}×${stageHeight}`,
|
||||||
|
canvasScaleString: Math.round(stageScale * 100),
|
||||||
|
shouldShowCanvasDebugInfo,
|
||||||
|
shouldShowBoundingBox: boundingBoxScaleMethod !== 'auto',
|
||||||
|
shouldShowScaledBoundingBox: boundingBoxScaleMethod !== 'none',
|
||||||
|
shouldPreserveMaskedArea,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const IAICanvasStatusText = () => {
|
const IAICanvasStatusText = () => {
|
||||||
const {
|
const {
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
import { Box } from '@chakra-ui/react';
|
import { Box } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
|
||||||
import roundToHundreth from 'features/canvas/util/roundToHundreth';
|
import roundToHundreth from 'features/canvas/util/roundToHundreth';
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const cursorPositionSelector = createSelector(
|
const cursorPositionSelector = createMemoizedSelector(
|
||||||
[canvasSelector],
|
[stateSelector],
|
||||||
(canvas) => {
|
({ canvas }) => {
|
||||||
const { cursorPosition } = canvas;
|
const { cursorPosition } = canvas;
|
||||||
|
|
||||||
const { cursorX, cursorY } = cursorPosition
|
const { cursorX, cursorY } = cursorPosition
|
||||||
@ -21,11 +19,6 @@ const cursorPositionSelector = createSelector(
|
|||||||
cursorY
|
cursorY
|
||||||
)})`,
|
)})`,
|
||||||
};
|
};
|
||||||
},
|
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,20 +1,18 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
|
||||||
import { rgbaColorToString } from 'features/canvas/util/colorToString';
|
import { rgbaColorToString } from 'features/canvas/util/colorToString';
|
||||||
import { GroupConfig } from 'konva/lib/Group';
|
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
|
|
||||||
import { Circle, Group } from 'react-konva';
|
|
||||||
import {
|
import {
|
||||||
COLOR_PICKER_SIZE,
|
COLOR_PICKER_SIZE,
|
||||||
COLOR_PICKER_STROKE_RADIUS,
|
COLOR_PICKER_STROKE_RADIUS,
|
||||||
} from 'features/canvas/util/constants';
|
} from 'features/canvas/util/constants';
|
||||||
|
import { GroupConfig } from 'konva/lib/Group';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
import { Circle, Group } from 'react-konva';
|
||||||
|
|
||||||
const canvasBrushPreviewSelector = createSelector(
|
const canvasBrushPreviewSelector = createMemoizedSelector(
|
||||||
canvasSelector,
|
stateSelector,
|
||||||
(canvas) => {
|
({ canvas }) => {
|
||||||
const {
|
const {
|
||||||
cursorPosition,
|
cursorPosition,
|
||||||
brushSize,
|
brushSize,
|
||||||
@ -105,11 +103,6 @@ const canvasBrushPreviewSelector = createSelector(
|
|||||||
dotRadius: 1.5 / stageScale,
|
dotRadius: 1.5 / stageScale,
|
||||||
clip,
|
clip,
|
||||||
};
|
};
|
||||||
},
|
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import {
|
import {
|
||||||
@ -17,13 +17,11 @@ import Konva from 'konva';
|
|||||||
import { GroupConfig } from 'konva/lib/Group';
|
import { GroupConfig } from 'konva/lib/Group';
|
||||||
import { KonvaEventObject } from 'konva/lib/Node';
|
import { KonvaEventObject } from 'konva/lib/Node';
|
||||||
import { Vector2d } from 'konva/lib/types';
|
import { Vector2d } from 'konva/lib/types';
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
|
|
||||||
import { memo, useCallback, useEffect, useRef, useState } from 'react';
|
import { memo, useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { Group, Rect, Transformer } from 'react-konva';
|
import { Group, Rect, Transformer } from 'react-konva';
|
||||||
|
|
||||||
const boundingBoxPreviewSelector = createSelector(
|
const boundingBoxPreviewSelector = createMemoizedSelector(
|
||||||
[stateSelector],
|
[stateSelector],
|
||||||
({ canvas, generation }) => {
|
({ canvas, generation }) => {
|
||||||
const {
|
const {
|
||||||
@ -51,11 +49,6 @@ const boundingBoxPreviewSelector = createSelector(
|
|||||||
hitStrokeWidth: 20 / stageScale,
|
hitStrokeWidth: 20 / stageScale,
|
||||||
aspectRatio,
|
aspectRatio,
|
||||||
};
|
};
|
||||||
},
|
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Box, ButtonGroup, Flex } from '@chakra-ui/react';
|
import { Box, ButtonGroup, Flex } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import IAIColorPicker from 'common/components/IAIColorPicker';
|
import IAIColorPicker from 'common/components/IAIColorPicker';
|
||||||
@ -7,10 +8,7 @@ import IAIIconButton from 'common/components/IAIIconButton';
|
|||||||
import IAIPopover from 'common/components/IAIPopover';
|
import IAIPopover from 'common/components/IAIPopover';
|
||||||
import IAISimpleCheckbox from 'common/components/IAISimpleCheckbox';
|
import IAISimpleCheckbox from 'common/components/IAISimpleCheckbox';
|
||||||
import { canvasMaskSavedToGallery } from 'features/canvas/store/actions';
|
import { canvasMaskSavedToGallery } from 'features/canvas/store/actions';
|
||||||
import {
|
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
||||||
canvasSelector,
|
|
||||||
isStagingSelector,
|
|
||||||
} from 'features/canvas/store/canvasSelectors';
|
|
||||||
import {
|
import {
|
||||||
clearMask,
|
clearMask,
|
||||||
setIsMaskEnabled,
|
setIsMaskEnabled,
|
||||||
@ -19,17 +17,15 @@ import {
|
|||||||
setShouldPreserveMaskedArea,
|
setShouldPreserveMaskedArea,
|
||||||
} from 'features/canvas/store/canvasSlice';
|
} from 'features/canvas/store/canvasSlice';
|
||||||
import { rgbaColorToString } from 'features/canvas/util/colorToString';
|
import { rgbaColorToString } from 'features/canvas/util/colorToString';
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
import { ChangeEvent, memo, useCallback } from 'react';
|
import { ChangeEvent, memo, useCallback } from 'react';
|
||||||
import { RgbaColor } from 'react-colorful';
|
import { RgbaColor } from 'react-colorful';
|
||||||
|
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { FaMask, FaSave, FaTrash } from 'react-icons/fa';
|
import { FaMask, FaSave, FaTrash } from 'react-icons/fa';
|
||||||
|
|
||||||
export const selector = createSelector(
|
export const selector = createMemoizedSelector(
|
||||||
[canvasSelector, isStagingSelector],
|
[stateSelector, isStagingSelector],
|
||||||
(canvas, isStaging) => {
|
({ canvas }, isStaging) => {
|
||||||
const { maskColor, layer, isMaskEnabled, shouldPreserveMaskedArea } =
|
const { maskColor, layer, isMaskEnabled, shouldPreserveMaskedArea } =
|
||||||
canvas;
|
canvas;
|
||||||
|
|
||||||
@ -41,11 +37,6 @@ export const selector = createSelector(
|
|||||||
shouldPreserveMaskedArea,
|
shouldPreserveMaskedArea,
|
||||||
isStaging,
|
isStaging,
|
||||||
};
|
};
|
||||||
},
|
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const IAICanvasMaskOptions = () => {
|
const IAICanvasMaskOptions = () => {
|
||||||
|
@ -1,18 +1,15 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
|
import { redo } from 'features/canvas/store/canvasSlice';
|
||||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||||
|
import { useCallback } from 'react';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { FaRedo } from 'react-icons/fa';
|
import { FaRedo } from 'react-icons/fa';
|
||||||
|
|
||||||
import { redo } from 'features/canvas/store/canvasSlice';
|
const canvasRedoSelector = createMemoizedSelector(
|
||||||
|
|
||||||
import { stateSelector } from 'app/store/store';
|
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { useCallback } from 'react';
|
|
||||||
|
|
||||||
const canvasRedoSelector = createSelector(
|
|
||||||
[stateSelector, activeTabNameSelector],
|
[stateSelector, activeTabNameSelector],
|
||||||
({ canvas }, activeTabName) => {
|
({ canvas }, activeTabName) => {
|
||||||
const { futureLayerStates } = canvas;
|
const { futureLayerStates } = canvas;
|
||||||
@ -21,11 +18,6 @@ const canvasRedoSelector = createSelector(
|
|||||||
canRedo: futureLayerStates.length > 0,
|
canRedo: futureLayerStates.length > 0,
|
||||||
activeTabName,
|
activeTabName,
|
||||||
};
|
};
|
||||||
},
|
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import { Flex } from '@chakra-ui/react';
|
import { Flex } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAISimpleCheckbox from 'common/components/IAISimpleCheckbox';
|
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
import IAIPopover from 'common/components/IAIPopover';
|
import IAIPopover from 'common/components/IAIPopover';
|
||||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
import IAISimpleCheckbox from 'common/components/IAISimpleCheckbox';
|
||||||
|
import ClearCanvasHistoryButtonModal from 'features/canvas/components/ClearCanvasHistoryButtonModal';
|
||||||
import {
|
import {
|
||||||
setShouldAntialias,
|
setShouldAntialias,
|
||||||
setShouldAutoSave,
|
setShouldAutoSave,
|
||||||
@ -16,17 +17,14 @@ import {
|
|||||||
setShouldShowIntermediates,
|
setShouldShowIntermediates,
|
||||||
setShouldSnapToGrid,
|
setShouldSnapToGrid,
|
||||||
} from 'features/canvas/store/canvasSlice';
|
} from 'features/canvas/store/canvasSlice';
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
|
|
||||||
import { ChangeEvent, memo, useCallback } from 'react';
|
import { ChangeEvent, memo, useCallback } from 'react';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { FaWrench } from 'react-icons/fa';
|
import { FaWrench } from 'react-icons/fa';
|
||||||
import ClearCanvasHistoryButtonModal from 'features/canvas/components/ClearCanvasHistoryButtonModal';
|
|
||||||
|
|
||||||
export const canvasControlsSelector = createSelector(
|
export const canvasControlsSelector = createMemoizedSelector(
|
||||||
[canvasSelector],
|
[stateSelector],
|
||||||
(canvas) => {
|
({ canvas }) => {
|
||||||
const {
|
const {
|
||||||
shouldAutoSave,
|
shouldAutoSave,
|
||||||
shouldCropToBoundingBoxOnSave,
|
shouldCropToBoundingBoxOnSave,
|
||||||
@ -50,11 +48,6 @@ export const canvasControlsSelector = createSelector(
|
|||||||
shouldRestrictStrokesToBox,
|
shouldRestrictStrokesToBox,
|
||||||
shouldAntialias,
|
shouldAntialias,
|
||||||
};
|
};
|
||||||
},
|
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { ButtonGroup, Flex, Box } from '@chakra-ui/react';
|
import { Box, ButtonGroup, Flex } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIColorPicker from 'common/components/IAIColorPicker';
|
import IAIColorPicker from 'common/components/IAIColorPicker';
|
||||||
@ -14,10 +14,9 @@ import {
|
|||||||
setBrushSize,
|
setBrushSize,
|
||||||
setTool,
|
setTool,
|
||||||
} from 'features/canvas/store/canvasSlice';
|
} from 'features/canvas/store/canvasSlice';
|
||||||
import { clamp, isEqual } from 'lodash-es';
|
import { clamp } from 'lodash-es';
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { RgbaColor } from 'react-colorful';
|
import { RgbaColor } from 'react-colorful';
|
||||||
|
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import {
|
import {
|
||||||
@ -29,7 +28,7 @@ import {
|
|||||||
FaSlidersH,
|
FaSlidersH,
|
||||||
} from 'react-icons/fa';
|
} from 'react-icons/fa';
|
||||||
|
|
||||||
export const selector = createSelector(
|
export const selector = createMemoizedSelector(
|
||||||
[stateSelector, isStagingSelector],
|
[stateSelector, isStagingSelector],
|
||||||
({ canvas }, isStaging) => {
|
({ canvas }, isStaging) => {
|
||||||
const { tool, brushColor, brushSize } = canvas;
|
const { tool, brushColor, brushSize } = canvas;
|
||||||
@ -40,11 +39,6 @@ export const selector = createSelector(
|
|||||||
brushColor,
|
brushColor,
|
||||||
brushSize,
|
brushSize,
|
||||||
};
|
};
|
||||||
},
|
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { Box, ButtonGroup, Flex } from '@chakra-ui/react';
|
import { Box, ButtonGroup, Flex } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
import IAIMantineSelect from 'common/components/IAIMantineSelect';
|
import IAIMantineSelect from 'common/components/IAIMantineSelect';
|
||||||
|
import { useCopyImageToClipboard } from 'common/hooks/useCopyImageToClipboard';
|
||||||
import { useImageUploadButton } from 'common/hooks/useImageUploadButton';
|
import { useImageUploadButton } from 'common/hooks/useImageUploadButton';
|
||||||
import { useSingleAndDoubleClick } from 'common/hooks/useSingleAndDoubleClick';
|
import { useSingleAndDoubleClick } from 'common/hooks/useSingleAndDoubleClick';
|
||||||
import {
|
import {
|
||||||
@ -25,8 +26,6 @@ import {
|
|||||||
LAYER_NAMES_DICT,
|
LAYER_NAMES_DICT,
|
||||||
} from 'features/canvas/store/canvasTypes';
|
} from 'features/canvas/store/canvasTypes';
|
||||||
import { getCanvasBaseLayer } from 'features/canvas/util/konvaInstanceProvider';
|
import { getCanvasBaseLayer } from 'features/canvas/util/konvaInstanceProvider';
|
||||||
import { useCopyImageToClipboard } from 'common/hooks/useCopyImageToClipboard';
|
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -46,7 +45,7 @@ import IAICanvasSettingsButtonPopover from './IAICanvasSettingsButtonPopover';
|
|||||||
import IAICanvasToolChooserOptions from './IAICanvasToolChooserOptions';
|
import IAICanvasToolChooserOptions from './IAICanvasToolChooserOptions';
|
||||||
import IAICanvasUndoButton from './IAICanvasUndoButton';
|
import IAICanvasUndoButton from './IAICanvasUndoButton';
|
||||||
|
|
||||||
export const selector = createSelector(
|
export const selector = createMemoizedSelector(
|
||||||
[stateSelector, isStagingSelector],
|
[stateSelector, isStagingSelector],
|
||||||
({ canvas }, isStaging) => {
|
({ canvas }, isStaging) => {
|
||||||
const { tool, shouldCropToBoundingBoxOnSave, layer, isMaskEnabled } =
|
const { tool, shouldCropToBoundingBoxOnSave, layer, isMaskEnabled } =
|
||||||
@ -59,11 +58,6 @@ export const selector = createSelector(
|
|||||||
layer,
|
layer,
|
||||||
shouldCropToBoundingBoxOnSave,
|
shouldCropToBoundingBoxOnSave,
|
||||||
};
|
};
|
||||||
},
|
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,18 +1,15 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
|
||||||
import { FaUndo } from 'react-icons/fa';
|
|
||||||
|
|
||||||
import { undo } from 'features/canvas/store/canvasSlice';
|
import { undo } from 'features/canvas/store/canvasSlice';
|
||||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||||
|
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { stateSelector } from 'app/store/store';
|
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { FaUndo } from 'react-icons/fa';
|
||||||
|
|
||||||
const canvasUndoSelector = createSelector(
|
const canvasUndoSelector = createMemoizedSelector(
|
||||||
[stateSelector, activeTabNameSelector],
|
[stateSelector, activeTabNameSelector],
|
||||||
({ canvas }, activeTabName) => {
|
({ canvas }, activeTabName) => {
|
||||||
const { pastLayerStates } = canvas;
|
const { pastLayerStates } = canvas;
|
||||||
@ -21,11 +18,6 @@ const canvasUndoSelector = createSelector(
|
|||||||
canUndo: pastLayerStates.length > 0,
|
canUndo: pastLayerStates.length > 0,
|
||||||
activeTabName,
|
activeTabName,
|
||||||
};
|
};
|
||||||
},
|
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,21 +1,18 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import {
|
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
||||||
canvasSelector,
|
|
||||||
isStagingSelector,
|
|
||||||
} from 'features/canvas/store/canvasSelectors';
|
|
||||||
import {
|
import {
|
||||||
setIsMovingStage,
|
setIsMovingStage,
|
||||||
setStageCoordinates,
|
setStageCoordinates,
|
||||||
} from 'features/canvas/store/canvasSlice';
|
} from 'features/canvas/store/canvasSlice';
|
||||||
import { KonvaEventObject } from 'konva/lib/Node';
|
import { KonvaEventObject } from 'konva/lib/Node';
|
||||||
import { isEqual } from 'lodash-es';
|
import { isEqual } from 'lodash-es';
|
||||||
|
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(
|
||||||
[canvasSelector, isStagingSelector],
|
[stateSelector, isStagingSelector],
|
||||||
(canvas, isStaging) => {
|
({ canvas }, isStaging) => {
|
||||||
const { tool, isMovingBoundingBox } = canvas;
|
const { tool, isMovingBoundingBox } = canvas;
|
||||||
return {
|
return {
|
||||||
tool,
|
tool,
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import {
|
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
||||||
canvasSelector,
|
|
||||||
isStagingSelector,
|
|
||||||
} from 'features/canvas/store/canvasSelectors';
|
|
||||||
import {
|
import {
|
||||||
clearMask,
|
clearMask,
|
||||||
resetCanvasInteractionState,
|
resetCanvasInteractionState,
|
||||||
@ -12,17 +10,15 @@ import {
|
|||||||
setShouldSnapToGrid,
|
setShouldSnapToGrid,
|
||||||
setTool,
|
setTool,
|
||||||
} from 'features/canvas/store/canvasSlice';
|
} from 'features/canvas/store/canvasSlice';
|
||||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
|
|
||||||
import { useRef } from 'react';
|
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
|
||||||
import { CanvasTool } from 'features/canvas/store/canvasTypes';
|
import { CanvasTool } from 'features/canvas/store/canvasTypes';
|
||||||
import { getCanvasStage } from 'features/canvas/util/konvaInstanceProvider';
|
import { getCanvasStage } from 'features/canvas/util/konvaInstanceProvider';
|
||||||
|
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||||
|
import { useRef } from 'react';
|
||||||
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(
|
||||||
[canvasSelector, activeTabNameSelector, isStagingSelector],
|
[stateSelector, activeTabNameSelector, isStagingSelector],
|
||||||
(canvas, activeTabName, isStaging) => {
|
({ canvas }, activeTabName, isStaging) => {
|
||||||
const {
|
const {
|
||||||
cursorPosition,
|
cursorPosition,
|
||||||
shouldLockBoundingBox,
|
shouldLockBoundingBox,
|
||||||
@ -42,11 +38,6 @@ const selector = createSelector(
|
|||||||
isMaskEnabled,
|
isMaskEnabled,
|
||||||
shouldSnapToGrid,
|
shouldSnapToGrid,
|
||||||
};
|
};
|
||||||
},
|
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,26 +1,23 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import {
|
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
||||||
canvasSelector,
|
|
||||||
isStagingSelector,
|
|
||||||
} from 'features/canvas/store/canvasSelectors';
|
|
||||||
import {
|
import {
|
||||||
addLine,
|
addLine,
|
||||||
setIsDrawing,
|
setIsDrawing,
|
||||||
setIsMovingStage,
|
setIsMovingStage,
|
||||||
} from 'features/canvas/store/canvasSlice';
|
} from 'features/canvas/store/canvasSlice';
|
||||||
|
import getScaledCursorPosition from 'features/canvas/util/getScaledCursorPosition';
|
||||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||||
import Konva from 'konva';
|
import Konva from 'konva';
|
||||||
import { KonvaEventObject } from 'konva/lib/Node';
|
import { KonvaEventObject } from 'konva/lib/Node';
|
||||||
import { isEqual } from 'lodash-es';
|
import { isEqual } from 'lodash-es';
|
||||||
|
|
||||||
import { MutableRefObject, useCallback } from 'react';
|
import { MutableRefObject, useCallback } from 'react';
|
||||||
import getScaledCursorPosition from 'features/canvas/util/getScaledCursorPosition';
|
|
||||||
import useColorPicker from './useColorUnderCursor';
|
import useColorPicker from './useColorUnderCursor';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(
|
||||||
[activeTabNameSelector, canvasSelector, isStagingSelector],
|
[activeTabNameSelector, stateSelector, isStagingSelector],
|
||||||
(activeTabName, canvas, isStaging) => {
|
(activeTabName, { canvas }, isStaging) => {
|
||||||
const { tool } = canvas;
|
const { tool } = canvas;
|
||||||
return {
|
return {
|
||||||
tool,
|
tool,
|
||||||
|
@ -1,25 +1,22 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import {
|
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
||||||
canvasSelector,
|
|
||||||
isStagingSelector,
|
|
||||||
} from 'features/canvas/store/canvasSelectors';
|
|
||||||
import {
|
import {
|
||||||
addPointToCurrentLine,
|
addPointToCurrentLine,
|
||||||
setCursorPosition,
|
setCursorPosition,
|
||||||
} from 'features/canvas/store/canvasSlice';
|
} from 'features/canvas/store/canvasSlice';
|
||||||
|
import getScaledCursorPosition from 'features/canvas/util/getScaledCursorPosition';
|
||||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||||
import Konva from 'konva';
|
import Konva from 'konva';
|
||||||
import { Vector2d } from 'konva/lib/types';
|
import { Vector2d } from 'konva/lib/types';
|
||||||
import { isEqual } from 'lodash-es';
|
import { isEqual } from 'lodash-es';
|
||||||
|
|
||||||
import { MutableRefObject, useCallback } from 'react';
|
import { MutableRefObject, useCallback } from 'react';
|
||||||
import getScaledCursorPosition from 'features/canvas/util/getScaledCursorPosition';
|
|
||||||
import useColorPicker from './useColorUnderCursor';
|
import useColorPicker from './useColorUnderCursor';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(
|
||||||
[activeTabNameSelector, canvasSelector, isStagingSelector],
|
[activeTabNameSelector, stateSelector, isStagingSelector],
|
||||||
(activeTabName, canvas, isStaging) => {
|
(activeTabName, { canvas }, isStaging) => {
|
||||||
const { tool, isDrawing } = canvas;
|
const { tool, isDrawing } = canvas;
|
||||||
return {
|
return {
|
||||||
tool,
|
tool,
|
||||||
|
@ -1,25 +1,22 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import {
|
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
||||||
canvasSelector,
|
|
||||||
isStagingSelector,
|
|
||||||
} from 'features/canvas/store/canvasSelectors';
|
|
||||||
import {
|
import {
|
||||||
// addPointToCurrentEraserLine,
|
// addPointToCurrentEraserLine,
|
||||||
addPointToCurrentLine,
|
addPointToCurrentLine,
|
||||||
setIsDrawing,
|
setIsDrawing,
|
||||||
setIsMovingStage,
|
setIsMovingStage,
|
||||||
} from 'features/canvas/store/canvasSlice';
|
} from 'features/canvas/store/canvasSlice';
|
||||||
|
import getScaledCursorPosition from 'features/canvas/util/getScaledCursorPosition';
|
||||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||||
import Konva from 'konva';
|
import Konva from 'konva';
|
||||||
import { isEqual } from 'lodash-es';
|
import { isEqual } from 'lodash-es';
|
||||||
|
|
||||||
import { MutableRefObject, useCallback } from 'react';
|
import { MutableRefObject, useCallback } from 'react';
|
||||||
import getScaledCursorPosition from 'features/canvas/util/getScaledCursorPosition';
|
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(
|
||||||
[activeTabNameSelector, canvasSelector, isStagingSelector],
|
[activeTabNameSelector, stateSelector, isStagingSelector],
|
||||||
(activeTabName, canvas, isStaging) => {
|
(activeTabName, { canvas }, isStaging) => {
|
||||||
const { tool, isDrawing } = canvas;
|
const { tool, isDrawing } = canvas;
|
||||||
return {
|
return {
|
||||||
tool,
|
tool,
|
||||||
|
@ -1,24 +1,23 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
|
||||||
import {
|
import {
|
||||||
setStageCoordinates,
|
setStageCoordinates,
|
||||||
setStageScale,
|
setStageScale,
|
||||||
} from 'features/canvas/store/canvasSlice';
|
} from 'features/canvas/store/canvasSlice';
|
||||||
import Konva from 'konva';
|
|
||||||
import { KonvaEventObject } from 'konva/lib/Node';
|
|
||||||
import { clamp, isEqual } from 'lodash-es';
|
|
||||||
|
|
||||||
import { MutableRefObject, useCallback } from 'react';
|
|
||||||
import {
|
import {
|
||||||
CANVAS_SCALE_BY,
|
CANVAS_SCALE_BY,
|
||||||
MAX_CANVAS_SCALE,
|
MAX_CANVAS_SCALE,
|
||||||
MIN_CANVAS_SCALE,
|
MIN_CANVAS_SCALE,
|
||||||
} from 'features/canvas/util/constants';
|
} from 'features/canvas/util/constants';
|
||||||
|
import Konva from 'konva';
|
||||||
|
import { KonvaEventObject } from 'konva/lib/Node';
|
||||||
|
import { clamp, isEqual } from 'lodash-es';
|
||||||
|
import { MutableRefObject, useCallback } from 'react';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(
|
||||||
[canvasSelector],
|
[stateSelector],
|
||||||
(canvas) => {
|
({ canvas }) => {
|
||||||
const { isMoveStageKeyHeld, stageScale } = canvas;
|
const { isMoveStageKeyHeld, stageScale } = canvas;
|
||||||
return {
|
return {
|
||||||
isMoveStageKeyHeld,
|
isMoveStageKeyHeld,
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { RootState, stateSelector } from 'app/store/store';
|
import { RootState, stateSelector } from 'app/store/store';
|
||||||
import { CanvasImage, CanvasState, isCanvasBaseImage } from './canvasTypes';
|
import { CanvasImage, isCanvasBaseImage } from './canvasTypes';
|
||||||
|
|
||||||
export const canvasSelector = (state: RootState): CanvasState => state.canvas;
|
export const isStagingSelector = createMemoizedSelector(
|
||||||
|
|
||||||
export const isStagingSelector = createSelector(
|
|
||||||
[stateSelector],
|
[stateSelector],
|
||||||
({ canvas }) =>
|
({ canvas }) =>
|
||||||
canvas.batchIds.length > 0 ||
|
canvas.batchIds.length > 0 ||
|
||||||
|
@ -8,25 +8,24 @@ import {
|
|||||||
Flex,
|
Flex,
|
||||||
Text,
|
Text,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
|
import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
|
||||||
|
import {
|
||||||
|
changeBoardReset,
|
||||||
|
isModalOpenChanged,
|
||||||
|
} from 'features/changeBoardModal/store/slice';
|
||||||
import { memo, useCallback, useMemo, useRef, useState } from 'react';
|
import { memo, useCallback, useMemo, useRef, useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useListAllBoardsQuery } from 'services/api/endpoints/boards';
|
import { useListAllBoardsQuery } from 'services/api/endpoints/boards';
|
||||||
import {
|
import {
|
||||||
useAddImagesToBoardMutation,
|
useAddImagesToBoardMutation,
|
||||||
useRemoveImagesFromBoardMutation,
|
useRemoveImagesFromBoardMutation,
|
||||||
} from 'services/api/endpoints/images';
|
} from 'services/api/endpoints/images';
|
||||||
import {
|
|
||||||
changeBoardReset,
|
|
||||||
isModalOpenChanged,
|
|
||||||
} from 'features/changeBoardModal/store/slice';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(
|
||||||
[stateSelector],
|
[stateSelector],
|
||||||
({ changeBoardModal }) => {
|
({ changeBoardModal }) => {
|
||||||
const { isModalOpen, imagesToChange } = changeBoardModal;
|
const { isModalOpen, imagesToChange } = changeBoardModal;
|
||||||
@ -35,8 +34,7 @@ const selector = createSelector(
|
|||||||
isModalOpen,
|
isModalOpen,
|
||||||
imagesToChange,
|
imagesToChange,
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const ChangeBoardModal = () => {
|
const ChangeBoardModal = () => {
|
||||||
|
@ -9,7 +9,6 @@ import {
|
|||||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||||
import ParamControlAdapterModel from './parameters/ParamControlAdapterModel';
|
import ParamControlAdapterModel from './parameters/ParamControlAdapterModel';
|
||||||
import ParamControlAdapterWeight from './parameters/ParamControlAdapterWeight';
|
import ParamControlAdapterWeight from './parameters/ParamControlAdapterWeight';
|
||||||
|
|
||||||
import { ChevronUpIcon } from '@chakra-ui/icons';
|
import { ChevronUpIcon } from '@chakra-ui/icons';
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
import IAISwitch from 'common/components/IAISwitch';
|
import IAISwitch from 'common/components/IAISwitch';
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import { Box, Flex, Spinner } from '@chakra-ui/react';
|
import { Box, Flex, Spinner } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { skipToken } from '@reduxjs/toolkit/query';
|
||||||
import { skipToken } from '@reduxjs/toolkit/dist/query';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import IAIDndImage from 'common/components/IAIDndImage';
|
import IAIDndImage from 'common/components/IAIDndImage';
|
||||||
import IAIDndImageIcon from 'common/components/IAIDndImageIcon';
|
import IAIDndImageIcon from 'common/components/IAIDndImageIcon';
|
||||||
import { setBoundingBoxDimensions } from 'features/canvas/store/canvasSlice';
|
import { setBoundingBoxDimensions } from 'features/canvas/store/canvasSlice';
|
||||||
@ -33,7 +32,7 @@ type Props = {
|
|||||||
isSmall?: boolean;
|
isSmall?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(
|
||||||
stateSelector,
|
stateSelector,
|
||||||
({ controlAdapters, gallery, system }) => {
|
({ controlAdapters, gallery, system }) => {
|
||||||
const { pendingControlImages } = controlAdapters;
|
const { pendingControlImages } = controlAdapters;
|
||||||
@ -45,8 +44,7 @@ const selector = createSelector(
|
|||||||
autoAddBoardId,
|
autoAddBoardId,
|
||||||
isConnected,
|
isConnected,
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const ControlAdapterImagePreview = ({ isSmall, id }: Props) => {
|
const ControlAdapterImagePreview = ({ isSmall, id }: Props) => {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { ButtonGroup, Divider, Flex } from '@chakra-ui/react';
|
import { ButtonGroup, Divider, Flex } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import IAICollapse from 'common/components/IAICollapse';
|
import IAICollapse from 'common/components/IAICollapse';
|
||||||
import ControlAdapterConfig from 'features/controlAdapters/components/ControlAdapterConfig';
|
import ControlAdapterConfig from 'features/controlAdapters/components/ControlAdapterConfig';
|
||||||
|
import { useAddControlAdapter } from 'features/controlAdapters/hooks/useAddControlAdapter';
|
||||||
import {
|
import {
|
||||||
selectAllControlNets,
|
selectAllControlNets,
|
||||||
selectAllIPAdapters,
|
selectAllIPAdapters,
|
||||||
@ -19,9 +19,8 @@ import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
|||||||
import { Fragment, memo } from 'react';
|
import { Fragment, memo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { FaPlus } from 'react-icons/fa';
|
import { FaPlus } from 'react-icons/fa';
|
||||||
import { useAddControlAdapter } from 'features/controlAdapters/hooks/useAddControlAdapter';
|
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(
|
||||||
[stateSelector],
|
[stateSelector],
|
||||||
({ controlAdapters }) => {
|
({ controlAdapters }) => {
|
||||||
const activeLabel: string[] = [];
|
const activeLabel: string[] = [];
|
||||||
@ -68,8 +67,7 @@ const selector = createSelector(
|
|||||||
activeLabel: activeLabel.join(', '),
|
activeLabel: activeLabel.join(', '),
|
||||||
isError, // TODO: Add some visual indicator that the control adapters are in an error state
|
isError, // TODO: Add some visual indicator that the control adapters are in an error state
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const ControlAdaptersCollapse = () => {
|
const ControlAdaptersCollapse = () => {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
|
import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
|
||||||
import IAIMantineSelectItemWithTooltip from 'common/components/IAIMantineSelectItemWithTooltip';
|
import IAIMantineSelectItemWithTooltip from 'common/components/IAIMantineSelectItemWithTooltip';
|
||||||
import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
|
import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
|
||||||
@ -18,14 +17,10 @@ type ParamControlAdapterModelProps = {
|
|||||||
id: string;
|
id: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(stateSelector, ({ generation }) => {
|
||||||
stateSelector,
|
const { model } = generation;
|
||||||
({ generation }) => {
|
return { mainModel: model };
|
||||||
const { model } = generation;
|
});
|
||||||
return { mainModel: model };
|
|
||||||
},
|
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
const ParamControlAdapterModel = ({ id }: ParamControlAdapterModelProps) => {
|
const ParamControlAdapterModel = ({ id }: ParamControlAdapterModelProps) => {
|
||||||
const isEnabled = useControlAdapterIsEnabled(id);
|
const isEnabled = useControlAdapterIsEnabled(id);
|
||||||
|
@ -1,53 +1,47 @@
|
|||||||
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import IAIMantineSearchableSelect, {
|
import IAIMantineSearchableSelect, {
|
||||||
IAISelectDataType,
|
IAISelectDataType,
|
||||||
} from 'common/components/IAIMantineSearchableSelect';
|
} from 'common/components/IAIMantineSearchableSelect';
|
||||||
import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
|
import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
|
||||||
import { useControlAdapterProcessorNode } from 'features/controlAdapters/hooks/useControlAdapterProcessorNode';
|
import { useControlAdapterProcessorNode } from 'features/controlAdapters/hooks/useControlAdapterProcessorNode';
|
||||||
|
import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
|
||||||
|
import { controlAdapterProcessortTypeChanged } from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||||
|
import { ControlAdapterProcessorType } from 'features/controlAdapters/store/types';
|
||||||
import { configSelector } from 'features/system/store/configSelectors';
|
import { configSelector } from 'features/system/store/configSelectors';
|
||||||
import { map } from 'lodash-es';
|
import { map } from 'lodash-es';
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
|
|
||||||
import { controlAdapterProcessortTypeChanged } from 'features/controlAdapters/store/controlAdaptersSlice';
|
|
||||||
import { ControlAdapterProcessorType } from 'features/controlAdapters/store/types';
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
id: string;
|
id: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(configSelector, (config) => {
|
||||||
configSelector,
|
const controlNetProcessors: IAISelectDataType[] = map(
|
||||||
(config) => {
|
CONTROLNET_PROCESSORS,
|
||||||
const controlNetProcessors: IAISelectDataType[] = map(
|
(p) => ({
|
||||||
CONTROLNET_PROCESSORS,
|
value: p.type,
|
||||||
(p) => ({
|
label: p.label,
|
||||||
value: p.type,
|
})
|
||||||
label: p.label,
|
)
|
||||||
})
|
.sort((a, b) =>
|
||||||
|
// sort 'none' to the top
|
||||||
|
a.value === 'none'
|
||||||
|
? -1
|
||||||
|
: b.value === 'none'
|
||||||
|
? 1
|
||||||
|
: a.label.localeCompare(b.label)
|
||||||
)
|
)
|
||||||
.sort((a, b) =>
|
.filter(
|
||||||
// sort 'none' to the top
|
(d) =>
|
||||||
a.value === 'none'
|
!config.sd.disabledControlNetProcessors.includes(
|
||||||
? -1
|
d.value as ControlAdapterProcessorType
|
||||||
: b.value === 'none'
|
)
|
||||||
? 1
|
);
|
||||||
: a.label.localeCompare(b.label)
|
|
||||||
)
|
|
||||||
.filter(
|
|
||||||
(d) =>
|
|
||||||
!config.sd.disabledControlNetProcessors.includes(
|
|
||||||
d.value as ControlAdapterProcessorType
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
return controlNetProcessors;
|
return controlNetProcessors;
|
||||||
},
|
});
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
const ParamControlAdapterProcessorSelect = ({ id }: Props) => {
|
const ParamControlAdapterProcessorSelect = ({ id }: Props) => {
|
||||||
const isEnabled = useControlAdapterIsEnabled(id);
|
const isEnabled = useControlAdapterIsEnabled(id);
|
||||||
|
@ -1,17 +1,14 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
export const useControlAdapter = (id: string) => {
|
export const useControlAdapter = (id: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createSelector(
|
createMemoizedSelector(stateSelector, ({ controlAdapters }) =>
|
||||||
stateSelector,
|
selectControlAdapterById(controlAdapters, id)
|
||||||
({ controlAdapters }) => selectControlAdapterById(controlAdapters, id),
|
|
||||||
defaultSelectorOptions
|
|
||||||
),
|
),
|
||||||
[id]
|
[id]
|
||||||
);
|
);
|
||||||
|
@ -1,26 +1,21 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
export const useControlAdapterBeginEndStepPct = (id: string) => {
|
export const useControlAdapterBeginEndStepPct = (id: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createSelector(
|
createMemoizedSelector(stateSelector, ({ controlAdapters }) => {
|
||||||
stateSelector,
|
const cn = selectControlAdapterById(controlAdapters, id);
|
||||||
({ controlAdapters }) => {
|
return cn
|
||||||
const cn = selectControlAdapterById(controlAdapters, id);
|
? {
|
||||||
return cn
|
beginStepPct: cn.beginStepPct,
|
||||||
? {
|
endStepPct: cn.endStepPct,
|
||||||
beginStepPct: cn.beginStepPct,
|
}
|
||||||
endStepPct: cn.endStepPct,
|
: undefined;
|
||||||
}
|
}),
|
||||||
: undefined;
|
|
||||||
},
|
|
||||||
defaultSelectorOptions
|
|
||||||
),
|
|
||||||
[id]
|
[id]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
export const useControlAdapterControlImage = (id: string) => {
|
export const useControlAdapterControlImage = (id: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createSelector(
|
createMemoizedSelector(
|
||||||
stateSelector,
|
stateSelector,
|
||||||
({ controlAdapters }) =>
|
({ controlAdapters }) =>
|
||||||
selectControlAdapterById(controlAdapters, id)?.controlImage,
|
selectControlAdapterById(controlAdapters, id)?.controlImage
|
||||||
defaultSelectorOptions
|
|
||||||
),
|
),
|
||||||
[id]
|
[id]
|
||||||
);
|
);
|
||||||
|
@ -1,25 +1,20 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||||
import { isControlNet } from 'features/controlAdapters/store/types';
|
import { isControlNet } from 'features/controlAdapters/store/types';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
export const useControlAdapterControlMode = (id: string) => {
|
export const useControlAdapterControlMode = (id: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createSelector(
|
createMemoizedSelector(stateSelector, ({ controlAdapters }) => {
|
||||||
stateSelector,
|
const ca = selectControlAdapterById(controlAdapters, id);
|
||||||
({ controlAdapters }) => {
|
if (ca && isControlNet(ca)) {
|
||||||
const ca = selectControlAdapterById(controlAdapters, id);
|
return ca.controlMode;
|
||||||
if (ca && isControlNet(ca)) {
|
}
|
||||||
return ca.controlMode;
|
return undefined;
|
||||||
}
|
}),
|
||||||
return undefined;
|
|
||||||
},
|
|
||||||
defaultSelectorOptions
|
|
||||||
),
|
|
||||||
[id]
|
[id]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
export const useControlAdapterIsEnabled = (id: string) => {
|
export const useControlAdapterIsEnabled = (id: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createSelector(
|
createMemoizedSelector(
|
||||||
stateSelector,
|
stateSelector,
|
||||||
({ controlAdapters }) =>
|
({ controlAdapters }) =>
|
||||||
selectControlAdapterById(controlAdapters, id)?.isEnabled ?? false,
|
selectControlAdapterById(controlAdapters, id)?.isEnabled ?? false
|
||||||
defaultSelectorOptions
|
|
||||||
),
|
),
|
||||||
[id]
|
[id]
|
||||||
);
|
);
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
export const useControlAdapterModel = (id: string) => {
|
export const useControlAdapterModel = (id: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createSelector(
|
createMemoizedSelector(
|
||||||
stateSelector,
|
stateSelector,
|
||||||
({ controlAdapters }) =>
|
({ controlAdapters }) =>
|
||||||
selectControlAdapterById(controlAdapters, id)?.model,
|
selectControlAdapterById(controlAdapters, id)?.model
|
||||||
defaultSelectorOptions
|
|
||||||
),
|
),
|
||||||
[id]
|
[id]
|
||||||
);
|
);
|
||||||
|
@ -1,25 +1,20 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||||
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
export const useControlAdapterProcessedControlImage = (id: string) => {
|
export const useControlAdapterProcessedControlImage = (id: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createSelector(
|
createMemoizedSelector(stateSelector, ({ controlAdapters }) => {
|
||||||
stateSelector,
|
const ca = selectControlAdapterById(controlAdapters, id);
|
||||||
({ controlAdapters }) => {
|
|
||||||
const ca = selectControlAdapterById(controlAdapters, id);
|
|
||||||
|
|
||||||
return ca && isControlNetOrT2IAdapter(ca)
|
return ca && isControlNetOrT2IAdapter(ca)
|
||||||
? ca.processedControlImage
|
? ca.processedControlImage
|
||||||
: undefined;
|
: undefined;
|
||||||
},
|
}),
|
||||||
defaultSelectorOptions
|
|
||||||
),
|
|
||||||
[id]
|
[id]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,25 +1,20 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||||
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
export const useControlAdapterProcessorNode = (id: string) => {
|
export const useControlAdapterProcessorNode = (id: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createSelector(
|
createMemoizedSelector(stateSelector, ({ controlAdapters }) => {
|
||||||
stateSelector,
|
const ca = selectControlAdapterById(controlAdapters, id);
|
||||||
({ controlAdapters }) => {
|
|
||||||
const ca = selectControlAdapterById(controlAdapters, id);
|
|
||||||
|
|
||||||
return ca && isControlNetOrT2IAdapter(ca)
|
return ca && isControlNetOrT2IAdapter(ca)
|
||||||
? ca.processorNode
|
? ca.processorNode
|
||||||
: undefined;
|
: undefined;
|
||||||
},
|
}),
|
||||||
defaultSelectorOptions
|
|
||||||
),
|
|
||||||
[id]
|
[id]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,25 +1,20 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||||
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
export const useControlAdapterProcessorType = (id: string) => {
|
export const useControlAdapterProcessorType = (id: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createSelector(
|
createMemoizedSelector(stateSelector, ({ controlAdapters }) => {
|
||||||
stateSelector,
|
const ca = selectControlAdapterById(controlAdapters, id);
|
||||||
({ controlAdapters }) => {
|
|
||||||
const ca = selectControlAdapterById(controlAdapters, id);
|
|
||||||
|
|
||||||
return ca && isControlNetOrT2IAdapter(ca)
|
return ca && isControlNetOrT2IAdapter(ca)
|
||||||
? ca.processorType
|
? ca.processorType
|
||||||
: undefined;
|
: undefined;
|
||||||
},
|
}),
|
||||||
defaultSelectorOptions
|
|
||||||
),
|
|
||||||
[id]
|
[id]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,25 +1,20 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||||
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
export const useControlAdapterResizeMode = (id: string) => {
|
export const useControlAdapterResizeMode = (id: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createSelector(
|
createMemoizedSelector(stateSelector, ({ controlAdapters }) => {
|
||||||
stateSelector,
|
const ca = selectControlAdapterById(controlAdapters, id);
|
||||||
({ controlAdapters }) => {
|
if (ca && isControlNetOrT2IAdapter(ca)) {
|
||||||
const ca = selectControlAdapterById(controlAdapters, id);
|
return ca.resizeMode;
|
||||||
if (ca && isControlNetOrT2IAdapter(ca)) {
|
}
|
||||||
return ca.resizeMode;
|
return undefined;
|
||||||
}
|
}),
|
||||||
return undefined;
|
|
||||||
},
|
|
||||||
defaultSelectorOptions
|
|
||||||
),
|
|
||||||
[id]
|
[id]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,25 +1,20 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||||
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
export const useControlAdapterShouldAutoConfig = (id: string) => {
|
export const useControlAdapterShouldAutoConfig = (id: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createSelector(
|
createMemoizedSelector(stateSelector, ({ controlAdapters }) => {
|
||||||
stateSelector,
|
const ca = selectControlAdapterById(controlAdapters, id);
|
||||||
({ controlAdapters }) => {
|
if (ca && isControlNetOrT2IAdapter(ca)) {
|
||||||
const ca = selectControlAdapterById(controlAdapters, id);
|
return ca.shouldAutoConfig;
|
||||||
if (ca && isControlNetOrT2IAdapter(ca)) {
|
}
|
||||||
return ca.shouldAutoConfig;
|
return undefined;
|
||||||
}
|
}),
|
||||||
return undefined;
|
|
||||||
},
|
|
||||||
defaultSelectorOptions
|
|
||||||
),
|
|
||||||
[id]
|
[id]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
export const useControlAdapterType = (id: string) => {
|
export const useControlAdapterType = (id: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createSelector(
|
createMemoizedSelector(
|
||||||
stateSelector,
|
stateSelector,
|
||||||
({ controlAdapters }) =>
|
({ controlAdapters }) =>
|
||||||
selectControlAdapterById(controlAdapters, id)?.type,
|
selectControlAdapterById(controlAdapters, id)?.type
|
||||||
defaultSelectorOptions
|
|
||||||
),
|
),
|
||||||
[id]
|
[id]
|
||||||
);
|
);
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
export const useControlAdapterWeight = (id: string) => {
|
export const useControlAdapterWeight = (id: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createSelector(
|
createMemoizedSelector(
|
||||||
stateSelector,
|
stateSelector,
|
||||||
({ controlAdapters }) =>
|
({ controlAdapters }) =>
|
||||||
selectControlAdapterById(controlAdapters, id)?.weight,
|
selectControlAdapterById(controlAdapters, id)?.weight
|
||||||
defaultSelectorOptions
|
|
||||||
),
|
),
|
||||||
[id]
|
[id]
|
||||||
);
|
);
|
||||||
|
@ -35,7 +35,9 @@ import {
|
|||||||
isT2IAdapter,
|
isT2IAdapter,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
export const caAdapter = createEntityAdapter<ControlAdapterConfig>();
|
export const caAdapter = createEntityAdapter<ControlAdapterConfig, string>({
|
||||||
|
selectId: (ca) => ca.id,
|
||||||
|
});
|
||||||
|
|
||||||
export const {
|
export const {
|
||||||
selectById: selectControlAdapterById,
|
selectById: selectControlAdapterById,
|
||||||
@ -259,7 +261,7 @@ export const controlAdaptersSlice = createSlice({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const update: Update<ControlNetConfig | T2IAdapterConfig> = {
|
const update: Update<ControlNetConfig | T2IAdapterConfig, string> = {
|
||||||
id,
|
id,
|
||||||
changes: { model },
|
changes: { model },
|
||||||
};
|
};
|
||||||
@ -398,7 +400,7 @@ export const controlAdaptersSlice = createSlice({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const update: Update<ControlNetConfig | T2IAdapterConfig> = {
|
const update: Update<ControlNetConfig | T2IAdapterConfig, string> = {
|
||||||
id,
|
id,
|
||||||
changes: { shouldAutoConfig: !cn.shouldAutoConfig },
|
changes: { shouldAutoConfig: !cn.shouldAutoConfig },
|
||||||
};
|
};
|
||||||
|
@ -425,7 +425,7 @@ export type ControlAdapterConfig =
|
|||||||
|
|
||||||
export type ControlAdapterType = ControlAdapterConfig['type'];
|
export type ControlAdapterType = ControlAdapterConfig['type'];
|
||||||
|
|
||||||
export type ControlAdaptersState = EntityState<ControlAdapterConfig> & {
|
export type ControlAdaptersState = EntityState<ControlAdapterConfig, string> & {
|
||||||
pendingControlImages: string[];
|
pendingControlImages: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -9,16 +9,11 @@ import {
|
|||||||
Flex,
|
Flex,
|
||||||
Text,
|
Text,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import IAISwitch from 'common/components/IAISwitch';
|
import IAISwitch from 'common/components/IAISwitch';
|
||||||
import { setShouldConfirmOnDelete } from 'features/system/store/systemSlice';
|
|
||||||
import { some } from 'lodash-es';
|
|
||||||
import { ChangeEvent, memo, useCallback, useRef } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { imageDeletionConfirmed } from 'features/deleteImageModal/store/actions';
|
import { imageDeletionConfirmed } from 'features/deleteImageModal/store/actions';
|
||||||
import {
|
import {
|
||||||
getImageUsage,
|
getImageUsage,
|
||||||
@ -29,9 +24,13 @@ import {
|
|||||||
isModalOpenChanged,
|
isModalOpenChanged,
|
||||||
} from 'features/deleteImageModal/store/slice';
|
} from 'features/deleteImageModal/store/slice';
|
||||||
import { ImageUsage } from 'features/deleteImageModal/store/types';
|
import { ImageUsage } from 'features/deleteImageModal/store/types';
|
||||||
|
import { setShouldConfirmOnDelete } from 'features/system/store/systemSlice';
|
||||||
|
import { some } from 'lodash-es';
|
||||||
|
import { ChangeEvent, memo, useCallback, useRef } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import ImageUsageMessage from './ImageUsageMessage';
|
import ImageUsageMessage from './ImageUsageMessage';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(
|
||||||
[stateSelector, selectImageUsage],
|
[stateSelector, selectImageUsage],
|
||||||
(state, imagesUsage) => {
|
(state, imagesUsage) => {
|
||||||
const { system, config, deleteImageModal } = state;
|
const { system, config, deleteImageModal } = state;
|
||||||
@ -58,8 +57,7 @@ const selector = createSelector(
|
|||||||
isModalOpen,
|
isModalOpen,
|
||||||
imageUsageSummary,
|
imageUsageSummary,
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const DeleteImageModal = () => {
|
const DeleteImageModal = () => {
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { RootState } from 'app/store/store';
|
import { RootState } from 'app/store/store';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
|
||||||
import { some } from 'lodash-es';
|
|
||||||
import { ImageUsage } from './types';
|
|
||||||
import { selectControlAdapterAll } from 'features/controlAdapters/store/controlAdaptersSlice';
|
import { selectControlAdapterAll } from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||||
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
||||||
import { isImageFieldInputInstance } from 'features/nodes/types/field';
|
import { isImageFieldInputInstance } from 'features/nodes/types/field';
|
||||||
|
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||||
|
import { some } from 'lodash-es';
|
||||||
|
import { ImageUsage } from './types';
|
||||||
|
|
||||||
export const getImageUsage = (state: RootState, image_name: string) => {
|
export const getImageUsage = (state: RootState, image_name: string) => {
|
||||||
const { generation, canvas, nodes, controlAdapters } = state;
|
const { generation, canvas, nodes, controlAdapters } = state;
|
||||||
@ -41,7 +40,7 @@ export const getImageUsage = (state: RootState, image_name: string) => {
|
|||||||
return imageUsage;
|
return imageUsage;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const selectImageUsage = createSelector(
|
export const selectImageUsage = createMemoizedSelector(
|
||||||
[(state: RootState) => state],
|
[(state: RootState) => state],
|
||||||
(state) => {
|
(state) => {
|
||||||
const { imagesToDelete } = state.deleteImageModal;
|
const { imagesToDelete } = state.deleteImageModal;
|
||||||
@ -55,6 +54,5 @@ export const selectImageUsage = createSelector(
|
|||||||
);
|
);
|
||||||
|
|
||||||
return imagesUsage;
|
return imagesUsage;
|
||||||
},
|
}
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
);
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import type { Modifier } from '@dnd-kit/core';
|
import type { Modifier } from '@dnd-kit/core';
|
||||||
import { getEventCoordinates } from '@dnd-kit/utilities';
|
import { getEventCoordinates } from '@dnd-kit/utilities';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
const selectZoom = createSelector(
|
const selectZoom = createMemoizedSelector(
|
||||||
[stateSelector, activeTabNameSelector],
|
[stateSelector, activeTabNameSelector],
|
||||||
({ nodes }, activeTabName) =>
|
({ nodes }, activeTabName) =>
|
||||||
activeTabName === 'nodes' ? nodes.viewport.zoom : 1
|
activeTabName === 'nodes' ? nodes.viewport.zoom : 1
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { Flex } from '@chakra-ui/react';
|
import { Flex } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAICollapse from 'common/components/IAICollapse';
|
import IAICollapse from 'common/components/IAICollapse';
|
||||||
|
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
||||||
import { memo, useMemo } from 'react';
|
import { memo, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
|
||||||
import ParamDynamicPromptsMaxPrompts from './ParamDynamicPromptsMaxPrompts';
|
import ParamDynamicPromptsMaxPrompts from './ParamDynamicPromptsMaxPrompts';
|
||||||
import ParamDynamicPromptsPreview from './ParamDynamicPromptsPreview';
|
import ParamDynamicPromptsPreview from './ParamDynamicPromptsPreview';
|
||||||
import ParamDynamicPromptsSeedBehaviour from './ParamDynamicPromptsSeedBehaviour';
|
import ParamDynamicPromptsSeedBehaviour from './ParamDynamicPromptsSeedBehaviour';
|
||||||
@ -14,7 +14,7 @@ const ParamDynamicPromptsCollapse = () => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const selectActiveLabel = useMemo(
|
const selectActiveLabel = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createSelector(stateSelector, ({ dynamicPrompts }) => {
|
createMemoizedSelector(stateSelector, ({ dynamicPrompts }) => {
|
||||||
const count = dynamicPrompts.prompts.length;
|
const count = dynamicPrompts.prompts.length;
|
||||||
if (count > 1) {
|
if (count > 1) {
|
||||||
return t('dynamicPrompts.promptsWithCount_other', {
|
return t('dynamicPrompts.promptsWithCount_other', {
|
||||||
|
@ -1,21 +1,16 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import IAISwitch from 'common/components/IAISwitch';
|
import IAISwitch from 'common/components/IAISwitch';
|
||||||
|
import { combinatorialToggled } from 'features/dynamicPrompts/store/dynamicPromptsSlice';
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { combinatorialToggled } from 'features/dynamicPrompts/store/dynamicPromptsSlice';
|
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(stateSelector, (state) => {
|
||||||
stateSelector,
|
const { combinatorial } = state.dynamicPrompts;
|
||||||
(state) => {
|
|
||||||
const { combinatorial } = state.dynamicPrompts;
|
|
||||||
|
|
||||||
return { combinatorial };
|
return { combinatorial };
|
||||||
},
|
});
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
const ParamDynamicPromptsCombinatorial = () => {
|
const ParamDynamicPromptsCombinatorial = () => {
|
||||||
const { combinatorial } = useAppSelector(selector);
|
const { combinatorial } = useAppSelector(selector);
|
||||||
|
@ -1,33 +1,28 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import IAIInformationalPopover from 'common/components/IAIInformationalPopover/IAIInformationalPopover';
|
||||||
import IAISlider from 'common/components/IAISlider';
|
import IAISlider from 'common/components/IAISlider';
|
||||||
import { memo, useCallback } from 'react';
|
|
||||||
import {
|
import {
|
||||||
maxPromptsChanged,
|
maxPromptsChanged,
|
||||||
maxPromptsReset,
|
maxPromptsReset,
|
||||||
} from 'features/dynamicPrompts/store/dynamicPromptsSlice';
|
} from 'features/dynamicPrompts/store/dynamicPromptsSlice';
|
||||||
|
import { memo, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import IAIInformationalPopover from 'common/components/IAIInformationalPopover/IAIInformationalPopover';
|
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(stateSelector, (state) => {
|
||||||
stateSelector,
|
const { maxPrompts, combinatorial } = state.dynamicPrompts;
|
||||||
(state) => {
|
const { min, sliderMax, inputMax } =
|
||||||
const { maxPrompts, combinatorial } = state.dynamicPrompts;
|
state.config.sd.dynamicPrompts.maxPrompts;
|
||||||
const { min, sliderMax, inputMax } =
|
|
||||||
state.config.sd.dynamicPrompts.maxPrompts;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
maxPrompts,
|
maxPrompts,
|
||||||
min,
|
min,
|
||||||
sliderMax,
|
sliderMax,
|
||||||
inputMax,
|
inputMax,
|
||||||
isDisabled: !combinatorial,
|
isDisabled: !combinatorial,
|
||||||
};
|
};
|
||||||
},
|
});
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
const ParamDynamicPromptsMaxPrompts = () => {
|
const ParamDynamicPromptsMaxPrompts = () => {
|
||||||
const { maxPrompts, min, sliderMax, inputMax, isDisabled } =
|
const { maxPrompts, min, sliderMax, inputMax, isDisabled } =
|
||||||
|
@ -8,31 +8,26 @@ import {
|
|||||||
Spinner,
|
Spinner,
|
||||||
Text,
|
Text,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
||||||
import IAIInformationalPopover from 'common/components/IAIInformationalPopover/IAIInformationalPopover';
|
import IAIInformationalPopover from 'common/components/IAIInformationalPopover/IAIInformationalPopover';
|
||||||
import ScrollableContent from 'features/nodes/components/sidePanel/ScrollableContent';
|
import ScrollableContent from 'features/nodes/components/sidePanel/ScrollableContent';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import { FaCircleExclamation } from 'react-icons/fa6';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { FaCircleExclamation } from 'react-icons/fa6';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(stateSelector, (state) => {
|
||||||
stateSelector,
|
const { isLoading, isError, prompts, parsingError } = state.dynamicPrompts;
|
||||||
(state) => {
|
|
||||||
const { isLoading, isError, prompts, parsingError } = state.dynamicPrompts;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
prompts,
|
prompts,
|
||||||
parsingError,
|
parsingError,
|
||||||
isError,
|
isError,
|
||||||
isLoading,
|
isLoading,
|
||||||
};
|
};
|
||||||
},
|
});
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
const listItemStyles: ChakraProps['sx'] = {
|
const listItemStyles: ChakraProps['sx'] = {
|
||||||
'&::marker': { color: 'base.500', _dark: { color: 'base.500' } },
|
'&::marker': { color: 'base.500', _dark: { color: 'base.500' } },
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { SelectItem } from '@mantine/core';
|
import { SelectItem } from '@mantine/core';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
|
import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
|
||||||
import IAIMantineSelectItemWithTooltip from 'common/components/IAIMantineSelectItemWithTooltip';
|
import IAIMantineSelectItemWithTooltip from 'common/components/IAIMantineSelectItemWithTooltip';
|
||||||
import { autoAddBoardIdChanged } from 'features/gallery/store/gallerySlice';
|
import { autoAddBoardIdChanged } from 'features/gallery/store/gallerySlice';
|
||||||
@ -10,18 +9,14 @@ import { memo, useCallback, useRef } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useListAllBoardsQuery } from 'services/api/endpoints/boards';
|
import { useListAllBoardsQuery } from 'services/api/endpoints/boards';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector([stateSelector], ({ gallery }) => {
|
||||||
[stateSelector],
|
const { autoAddBoardId, autoAssignBoardOnClick } = gallery;
|
||||||
({ gallery }) => {
|
|
||||||
const { autoAddBoardId, autoAssignBoardOnClick } = gallery;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
autoAddBoardId,
|
autoAddBoardId,
|
||||||
autoAssignBoardOnClick,
|
autoAssignBoardOnClick,
|
||||||
};
|
};
|
||||||
},
|
});
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
const BoardAutoAddSelect = () => {
|
const BoardAutoAddSelect = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
@ -1,25 +1,24 @@
|
|||||||
import { MenuGroup, MenuItem, MenuList } from '@chakra-ui/react';
|
import { MenuGroup, MenuItem, MenuList } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import {
|
import {
|
||||||
IAIContextMenu,
|
IAIContextMenu,
|
||||||
IAIContextMenuProps,
|
IAIContextMenuProps,
|
||||||
} from 'common/components/IAIContextMenu';
|
} from 'common/components/IAIContextMenu';
|
||||||
import { autoAddBoardIdChanged } from 'features/gallery/store/gallerySlice';
|
import { autoAddBoardIdChanged } from 'features/gallery/store/gallerySlice';
|
||||||
import { BoardId } from 'features/gallery/store/types';
|
import { BoardId } from 'features/gallery/store/types';
|
||||||
|
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
||||||
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
import { MouseEvent, memo, useCallback, useMemo } from 'react';
|
import { MouseEvent, memo, useCallback, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { FaDownload, FaPlus } from 'react-icons/fa';
|
import { FaDownload, FaPlus } from 'react-icons/fa';
|
||||||
|
import { useBulkDownloadImagesMutation } from 'services/api/endpoints/images';
|
||||||
import { useBoardName } from 'services/api/hooks/useBoardName';
|
import { useBoardName } from 'services/api/hooks/useBoardName';
|
||||||
import { BoardDTO } from 'services/api/types';
|
import { BoardDTO } from 'services/api/types';
|
||||||
import { menuListMotionProps } from 'theme/components/menu';
|
import { menuListMotionProps } from 'theme/components/menu';
|
||||||
import GalleryBoardContextMenuItems from './GalleryBoardContextMenuItems';
|
import GalleryBoardContextMenuItems from './GalleryBoardContextMenuItems';
|
||||||
import NoBoardContextMenuItems from './NoBoardContextMenuItems';
|
import NoBoardContextMenuItems from './NoBoardContextMenuItems';
|
||||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
|
||||||
import { useBulkDownloadImagesMutation } from 'services/api/endpoints/images';
|
|
||||||
import { addToast } from 'features/system/store/systemSlice';
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
board?: BoardDTO;
|
board?: BoardDTO;
|
||||||
@ -39,15 +38,11 @@ const BoardContextMenu = ({
|
|||||||
|
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createSelector(
|
createMemoizedSelector(stateSelector, ({ gallery }) => {
|
||||||
stateSelector,
|
const isAutoAdd = gallery.autoAddBoardId === board_id;
|
||||||
({ gallery }) => {
|
const autoAssignBoardOnClick = gallery.autoAssignBoardOnClick;
|
||||||
const isAutoAdd = gallery.autoAddBoardId === board_id;
|
return { isAutoAdd, autoAssignBoardOnClick };
|
||||||
const autoAssignBoardOnClick = gallery.autoAssignBoardOnClick;
|
}),
|
||||||
return { isAutoAdd, autoAssignBoardOnClick };
|
|
||||||
},
|
|
||||||
defaultSelectorOptions
|
|
||||||
),
|
|
||||||
[board_id]
|
[board_id]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,26 +1,21 @@
|
|||||||
import { Collapse, Flex, Grid, GridItem } from '@chakra-ui/react';
|
import { Collapse, Flex, Grid, GridItem } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import DeleteBoardModal from 'features/gallery/components/Boards/DeleteBoardModal';
|
||||||
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
||||||
import { memo, useState } from 'react';
|
import { memo, useState } from 'react';
|
||||||
import { useListAllBoardsQuery } from 'services/api/endpoints/boards';
|
import { useListAllBoardsQuery } from 'services/api/endpoints/boards';
|
||||||
import { BoardDTO } from 'services/api/types';
|
import { BoardDTO } from 'services/api/types';
|
||||||
import DeleteBoardModal from 'features/gallery/components/Boards/DeleteBoardModal';
|
|
||||||
import AddBoardButton from './AddBoardButton';
|
import AddBoardButton from './AddBoardButton';
|
||||||
import BoardsSearch from './BoardsSearch';
|
import BoardsSearch from './BoardsSearch';
|
||||||
import GalleryBoard from './GalleryBoard';
|
import GalleryBoard from './GalleryBoard';
|
||||||
import NoBoardBoard from './NoBoardBoard';
|
import NoBoardBoard from './NoBoardBoard';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector([stateSelector], ({ gallery }) => {
|
||||||
[stateSelector],
|
const { selectedBoardId, boardSearchText } = gallery;
|
||||||
({ gallery }) => {
|
return { selectedBoardId, boardSearchText };
|
||||||
const { selectedBoardId, boardSearchText } = gallery;
|
});
|
||||||
return { selectedBoardId, boardSearchText };
|
|
||||||
},
|
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
|
@ -5,10 +5,9 @@ import {
|
|||||||
InputGroup,
|
InputGroup,
|
||||||
InputRightElement,
|
InputRightElement,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import { boardSearchTextChanged } from 'features/gallery/store/gallerySlice';
|
import { boardSearchTextChanged } from 'features/gallery/store/gallerySlice';
|
||||||
import {
|
import {
|
||||||
ChangeEvent,
|
ChangeEvent,
|
||||||
@ -20,14 +19,10 @@ import {
|
|||||||
} from 'react';
|
} from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector([stateSelector], ({ gallery }) => {
|
||||||
[stateSelector],
|
const { boardSearchText } = gallery;
|
||||||
({ gallery }) => {
|
return { boardSearchText };
|
||||||
const { boardSearchText } = gallery;
|
});
|
||||||
return { boardSearchText };
|
|
||||||
},
|
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
const BoardsSearch = () => {
|
const BoardsSearch = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
@ -9,19 +9,21 @@ import {
|
|||||||
Text,
|
Text,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { skipToken } from '@reduxjs/toolkit/query';
|
||||||
import { skipToken } from '@reduxjs/toolkit/dist/query';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import IAIDroppable from 'common/components/IAIDroppable';
|
import IAIDroppable from 'common/components/IAIDroppable';
|
||||||
import SelectionOverlay from 'common/components/SelectionOverlay';
|
import SelectionOverlay from 'common/components/SelectionOverlay';
|
||||||
import { AddToBoardDropData } from 'features/dnd/types';
|
import { AddToBoardDropData } from 'features/dnd/types';
|
||||||
|
import AutoAddIcon from 'features/gallery/components/Boards/AutoAddIcon';
|
||||||
|
import BoardContextMenu from 'features/gallery/components/Boards/BoardContextMenu';
|
||||||
import {
|
import {
|
||||||
autoAddBoardIdChanged,
|
autoAddBoardIdChanged,
|
||||||
boardIdSelected,
|
boardIdSelected,
|
||||||
} from 'features/gallery/store/gallerySlice';
|
} from 'features/gallery/store/gallerySlice';
|
||||||
import { memo, useCallback, useMemo, useState } from 'react';
|
import { memo, useCallback, useMemo, useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { FaUser } from 'react-icons/fa';
|
import { FaUser } from 'react-icons/fa';
|
||||||
import {
|
import {
|
||||||
useGetBoardAssetsTotalQuery,
|
useGetBoardAssetsTotalQuery,
|
||||||
@ -30,9 +32,6 @@ import {
|
|||||||
} from 'services/api/endpoints/boards';
|
} from 'services/api/endpoints/boards';
|
||||||
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
|
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
|
||||||
import { BoardDTO } from 'services/api/types';
|
import { BoardDTO } from 'services/api/types';
|
||||||
import AutoAddIcon from 'features/gallery/components/Boards/AutoAddIcon';
|
|
||||||
import BoardContextMenu from 'features/gallery/components/Boards/BoardContextMenu';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
interface GalleryBoardProps {
|
interface GalleryBoardProps {
|
||||||
board: BoardDTO;
|
board: BoardDTO;
|
||||||
@ -48,20 +47,15 @@ const GalleryBoard = ({
|
|||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createSelector(
|
createMemoizedSelector(stateSelector, ({ gallery }) => {
|
||||||
stateSelector,
|
const isSelectedForAutoAdd = board.board_id === gallery.autoAddBoardId;
|
||||||
({ gallery }) => {
|
const autoAssignBoardOnClick = gallery.autoAssignBoardOnClick;
|
||||||
const isSelectedForAutoAdd =
|
|
||||||
board.board_id === gallery.autoAddBoardId;
|
|
||||||
const autoAssignBoardOnClick = gallery.autoAssignBoardOnClick;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isSelectedForAutoAdd,
|
isSelectedForAutoAdd,
|
||||||
autoAssignBoardOnClick,
|
autoAssignBoardOnClick,
|
||||||
};
|
};
|
||||||
},
|
}),
|
||||||
defaultSelectorOptions
|
|
||||||
),
|
|
||||||
[board.board_id]
|
[board.board_id]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,38 +1,33 @@
|
|||||||
import { Box, Flex, Image, Text, Tooltip } from '@chakra-ui/react';
|
import { Box, Flex, Image, Text, Tooltip } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import InvokeAILogoImage from 'assets/images/logo.png';
|
import InvokeAILogoImage from 'assets/images/logo.png';
|
||||||
import IAIDroppable from 'common/components/IAIDroppable';
|
import IAIDroppable from 'common/components/IAIDroppable';
|
||||||
import SelectionOverlay from 'common/components/SelectionOverlay';
|
import SelectionOverlay from 'common/components/SelectionOverlay';
|
||||||
import { RemoveFromBoardDropData } from 'features/dnd/types';
|
import { RemoveFromBoardDropData } from 'features/dnd/types';
|
||||||
|
import AutoAddIcon from 'features/gallery/components/Boards/AutoAddIcon';
|
||||||
|
import BoardContextMenu from 'features/gallery/components/Boards/BoardContextMenu';
|
||||||
import {
|
import {
|
||||||
autoAddBoardIdChanged,
|
autoAddBoardIdChanged,
|
||||||
boardIdSelected,
|
boardIdSelected,
|
||||||
} from 'features/gallery/store/gallerySlice';
|
} from 'features/gallery/store/gallerySlice';
|
||||||
import { memo, useCallback, useMemo, useState } from 'react';
|
import { memo, useCallback, useMemo, useState } from 'react';
|
||||||
import { useBoardName } from 'services/api/hooks/useBoardName';
|
import { useTranslation } from 'react-i18next';
|
||||||
import AutoAddIcon from 'features/gallery/components/Boards/AutoAddIcon';
|
|
||||||
import BoardContextMenu from 'features/gallery/components/Boards/BoardContextMenu';
|
|
||||||
import {
|
import {
|
||||||
useGetBoardAssetsTotalQuery,
|
useGetBoardAssetsTotalQuery,
|
||||||
useGetBoardImagesTotalQuery,
|
useGetBoardImagesTotalQuery,
|
||||||
} from 'services/api/endpoints/boards';
|
} from 'services/api/endpoints/boards';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useBoardName } from 'services/api/hooks/useBoardName';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
isSelected: boolean;
|
isSelected: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(stateSelector, ({ gallery }) => {
|
||||||
stateSelector,
|
const { autoAddBoardId, autoAssignBoardOnClick } = gallery;
|
||||||
({ gallery }) => {
|
return { autoAddBoardId, autoAssignBoardOnClick };
|
||||||
const { autoAddBoardId, autoAssignBoardOnClick } = gallery;
|
});
|
||||||
return { autoAddBoardId, autoAssignBoardOnClick };
|
|
||||||
},
|
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
const NoBoardBoard = memo(({ isSelected }: Props) => {
|
const NoBoardBoard = memo(({ isSelected }: Props) => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
@ -9,8 +9,8 @@ import {
|
|||||||
Skeleton,
|
Skeleton,
|
||||||
Text,
|
Text,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { skipToken } from '@reduxjs/toolkit/query';
|
||||||
import { skipToken } from '@reduxjs/toolkit/dist/query';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
@ -43,7 +43,7 @@ const DeleteBoardModal = (props: Props) => {
|
|||||||
|
|
||||||
const selectImageUsageSummary = useMemo(
|
const selectImageUsageSummary = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createSelector([stateSelector], (state) => {
|
createMemoizedSelector([stateSelector], (state) => {
|
||||||
const allImageUsage = (boardImageNames ?? []).map((imageName) =>
|
const allImageUsage = (boardImageNames ?? []).map((imageName) =>
|
||||||
getImageUsage(state, imageName)
|
getImageUsage(state, imageName)
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ButtonGroup,
|
ButtonGroup,
|
||||||
Flex,
|
Flex,
|
||||||
@ -8,8 +5,9 @@ import {
|
|||||||
MenuButton,
|
MenuButton,
|
||||||
MenuList,
|
MenuList,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { skipToken } from '@reduxjs/toolkit/dist/query';
|
import { skipToken } from '@reduxjs/toolkit/query';
|
||||||
import { useAppToaster } from 'app/components/Toaster';
|
import { useAppToaster } from 'app/components/Toaster';
|
||||||
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { upscaleRequested } from 'app/store/middleware/listenerMiddleware/listeners/upscaleRequested';
|
import { upscaleRequested } from 'app/store/middleware/listenerMiddleware/listeners/upscaleRequested';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
@ -45,7 +43,7 @@ import { useGetImageDTOQuery } from 'services/api/endpoints/images';
|
|||||||
import { useDebouncedMetadata } from 'services/api/hooks/useDebouncedMetadata';
|
import { useDebouncedMetadata } from 'services/api/hooks/useDebouncedMetadata';
|
||||||
import { menuListMotionProps } from 'theme/components/menu';
|
import { menuListMotionProps } from 'theme/components/menu';
|
||||||
|
|
||||||
const currentImageButtonsSelector = createSelector(
|
const currentImageButtonsSelector = createMemoizedSelector(
|
||||||
[stateSelector, activeTabNameSelector],
|
[stateSelector, activeTabNameSelector],
|
||||||
({ gallery, system, ui, config }, activeTabName) => {
|
({ gallery, system, ui, config }, activeTabName) => {
|
||||||
const { isConnected, shouldConfirmOnDelete, denoiseProgress } = system;
|
const { isConnected, shouldConfirmOnDelete, denoiseProgress } = system;
|
||||||
@ -72,11 +70,6 @@ const currentImageButtonsSelector = createSelector(
|
|||||||
lastSelectedImage,
|
lastSelectedImage,
|
||||||
shouldFetchMetadataFromApi,
|
shouldFetchMetadataFromApi,
|
||||||
};
|
};
|
||||||
},
|
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Flex } from '@chakra-ui/react';
|
import { Flex } from '@chakra-ui/react';
|
||||||
|
|
||||||
import CurrentImageButtons from './CurrentImageButtons';
|
import CurrentImageButtons from './CurrentImageButtons';
|
||||||
import CurrentImagePreview from './CurrentImagePreview';
|
import CurrentImagePreview from './CurrentImagePreview';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Box, Flex, Image } from '@chakra-ui/react';
|
import { Box, Flex, Image } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { skipToken } from '@reduxjs/toolkit/query';
|
||||||
import { skipToken } from '@reduxjs/toolkit/dist/query';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIDndImage from 'common/components/IAIDndImage';
|
import IAIDndImage from 'common/components/IAIDndImage';
|
||||||
@ -9,19 +9,18 @@ import {
|
|||||||
TypesafeDraggableData,
|
TypesafeDraggableData,
|
||||||
TypesafeDroppableData,
|
TypesafeDroppableData,
|
||||||
} from 'features/dnd/types';
|
} from 'features/dnd/types';
|
||||||
|
import ImageMetadataViewer from 'features/gallery/components/ImageMetadataViewer/ImageMetadataViewer';
|
||||||
|
import NextPrevImageButtons from 'features/gallery/components/NextPrevImageButtons';
|
||||||
import { useNextPrevImage } from 'features/gallery/hooks/useNextPrevImage';
|
import { useNextPrevImage } from 'features/gallery/hooks/useNextPrevImage';
|
||||||
import { selectLastSelectedImage } from 'features/gallery/store/gallerySelectors';
|
import { selectLastSelectedImage } from 'features/gallery/store/gallerySelectors';
|
||||||
import { AnimatePresence, motion } from 'framer-motion';
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
import { memo, useCallback, useMemo, useRef, useState } from 'react';
|
import { memo, useCallback, useMemo, useRef, useState } from 'react';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { FaImage } from 'react-icons/fa';
|
import { FaImage } from 'react-icons/fa';
|
||||||
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
|
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
|
||||||
import ImageMetadataViewer from 'features/gallery/components/ImageMetadataViewer/ImageMetadataViewer';
|
|
||||||
import NextPrevImageButtons from 'features/gallery/components/NextPrevImageButtons';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
export const imagesSelector = createSelector(
|
export const imagesSelector = createMemoizedSelector(
|
||||||
[stateSelector, selectLastSelectedImage],
|
[stateSelector, selectLastSelectedImage],
|
||||||
({ ui, system }, lastSelectedImage) => {
|
({ ui, system }, lastSelectedImage) => {
|
||||||
const {
|
const {
|
||||||
@ -38,11 +37,6 @@ export const imagesSelector = createSelector(
|
|||||||
shouldShowProgressInViewer,
|
shouldShowProgressInViewer,
|
||||||
shouldAntialiasProgressImage,
|
shouldAntialiasProgressImage,
|
||||||
};
|
};
|
||||||
},
|
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,21 +1,16 @@
|
|||||||
import { ChevronUpIcon } from '@chakra-ui/icons';
|
import { ChevronUpIcon } from '@chakra-ui/icons';
|
||||||
import { Button, Flex, Text } from '@chakra-ui/react';
|
import { Button, Flex, Text } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import { memo, useMemo } from 'react';
|
import { memo, useMemo } from 'react';
|
||||||
import { useBoardName } from 'services/api/hooks/useBoardName';
|
import { useBoardName } from 'services/api/hooks/useBoardName';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector([stateSelector], (state) => {
|
||||||
[stateSelector],
|
const { selectedBoardId } = state.gallery;
|
||||||
(state) => {
|
|
||||||
const { selectedBoardId } = state.gallery;
|
|
||||||
|
|
||||||
return { selectedBoardId };
|
return { selectedBoardId };
|
||||||
},
|
});
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { Flex } from '@chakra-ui/react';
|
import { Flex } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
import IAIPopover from 'common/components/IAIPopover';
|
import IAIPopover from 'common/components/IAIPopover';
|
||||||
|
import IAISimpleCheckbox from 'common/components/IAISimpleCheckbox';
|
||||||
import IAISlider from 'common/components/IAISlider';
|
import IAISlider from 'common/components/IAISlider';
|
||||||
import IAISwitch from 'common/components/IAISwitch';
|
import IAISwitch from 'common/components/IAISwitch';
|
||||||
import {
|
import {
|
||||||
@ -16,25 +16,17 @@ import { ChangeEvent, memo, useCallback } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { FaWrench } from 'react-icons/fa';
|
import { FaWrench } from 'react-icons/fa';
|
||||||
import BoardAutoAddSelect from './Boards/BoardAutoAddSelect';
|
import BoardAutoAddSelect from './Boards/BoardAutoAddSelect';
|
||||||
import IAISimpleCheckbox from 'common/components/IAISimpleCheckbox';
|
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector([stateSelector], (state) => {
|
||||||
[stateSelector],
|
const { galleryImageMinimumWidth, shouldAutoSwitch, autoAssignBoardOnClick } =
|
||||||
(state) => {
|
state.gallery;
|
||||||
const {
|
|
||||||
galleryImageMinimumWidth,
|
|
||||||
shouldAutoSwitch,
|
|
||||||
autoAssignBoardOnClick,
|
|
||||||
} = state.gallery;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
galleryImageMinimumWidth,
|
galleryImageMinimumWidth,
|
||||||
shouldAutoSwitch,
|
shouldAutoSwitch,
|
||||||
autoAssignBoardOnClick,
|
autoAssignBoardOnClick,
|
||||||
};
|
};
|
||||||
},
|
});
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
const GallerySettingsPopover = () => {
|
const GallerySettingsPopover = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
import { MenuList } from '@chakra-ui/react';
|
import { MenuList } from '@chakra-ui/react';
|
||||||
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import {
|
import {
|
||||||
IAIContextMenu,
|
IAIContextMenu,
|
||||||
IAIContextMenuProps,
|
IAIContextMenuProps,
|
||||||
@ -6,27 +9,19 @@ import {
|
|||||||
import { MouseEvent, memo, useCallback } from 'react';
|
import { MouseEvent, memo, useCallback } from 'react';
|
||||||
import { ImageDTO } from 'services/api/types';
|
import { ImageDTO } from 'services/api/types';
|
||||||
import { menuListMotionProps } from 'theme/components/menu';
|
import { menuListMotionProps } from 'theme/components/menu';
|
||||||
import SingleSelectionMenuItems from './SingleSelectionMenuItems';
|
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
|
||||||
import { stateSelector } from 'app/store/store';
|
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import MultipleSelectionMenuItems from './MultipleSelectionMenuItems';
|
import MultipleSelectionMenuItems from './MultipleSelectionMenuItems';
|
||||||
|
import SingleSelectionMenuItems from './SingleSelectionMenuItems';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
imageDTO: ImageDTO | undefined;
|
imageDTO: ImageDTO | undefined;
|
||||||
children: IAIContextMenuProps<HTMLDivElement>['children'];
|
children: IAIContextMenuProps<HTMLDivElement>['children'];
|
||||||
};
|
};
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector([stateSelector], ({ gallery }) => {
|
||||||
[stateSelector],
|
const selectionCount = gallery.selection.length;
|
||||||
({ gallery }) => {
|
|
||||||
const selectionCount = gallery.selection.length;
|
|
||||||
|
|
||||||
return { selectionCount };
|
return { selectionCount };
|
||||||
},
|
});
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
const ImageContextMenu = ({ imageDTO, children }: Props) => {
|
const ImageContextMenu = ({ imageDTO, children }: Props) => {
|
||||||
const { selectionCount } = useAppSelector(selector);
|
const { selectionCount } = useAppSelector(selector);
|
||||||
|
@ -8,31 +8,26 @@ import {
|
|||||||
VStack,
|
VStack,
|
||||||
useDisclosure,
|
useDisclosure,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import { memo, useCallback, useRef } from 'react';
|
|
||||||
import { FaImages, FaServer } from 'react-icons/fa';
|
|
||||||
import { galleryViewChanged } from 'features/gallery/store/gallerySlice';
|
import { galleryViewChanged } from 'features/gallery/store/gallerySlice';
|
||||||
|
import { memo, useCallback, useRef } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { FaImages, FaServer } from 'react-icons/fa';
|
||||||
import BoardsList from './Boards/BoardsList/BoardsList';
|
import BoardsList from './Boards/BoardsList/BoardsList';
|
||||||
import GalleryBoardName from './GalleryBoardName';
|
import GalleryBoardName from './GalleryBoardName';
|
||||||
import GallerySettingsPopover from './GallerySettingsPopover';
|
import GallerySettingsPopover from './GallerySettingsPopover';
|
||||||
import GalleryImageGrid from './ImageGrid/GalleryImageGrid';
|
import GalleryImageGrid from './ImageGrid/GalleryImageGrid';
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector([stateSelector], (state) => {
|
||||||
[stateSelector],
|
const { galleryView } = state.gallery;
|
||||||
(state) => {
|
|
||||||
const { galleryView } = state.gallery;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
galleryView,
|
galleryView,
|
||||||
};
|
};
|
||||||
},
|
});
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
const ImageGalleryContent = () => {
|
const ImageGalleryContent = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import { selectListImagesBaseQueryArgs } from 'features/gallery/store/gallerySelectors';
|
import { selectListImagesBaseQueryArgs } from 'features/gallery/store/gallerySelectors';
|
||||||
|
import { selectionChanged } from 'features/gallery/store/gallerySlice';
|
||||||
|
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
||||||
import { MouseEvent, useCallback, useMemo } from 'react';
|
import { MouseEvent, useCallback, useMemo } from 'react';
|
||||||
import { useListImagesQuery } from 'services/api/endpoints/images';
|
import { useListImagesQuery } from 'services/api/endpoints/images';
|
||||||
import { ImageDTO } from 'services/api/types';
|
import { ImageDTO } from 'services/api/types';
|
||||||
import { imagesSelectors } from 'services/api/util';
|
import { imagesSelectors } from 'services/api/util';
|
||||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
|
||||||
import { selectionChanged } from 'features/gallery/store/gallerySlice';
|
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(
|
||||||
[stateSelector, selectListImagesBaseQueryArgs],
|
[stateSelector, selectListImagesBaseQueryArgs],
|
||||||
({ gallery }, queryArgs) => {
|
({ gallery }, queryArgs) => {
|
||||||
const selection = gallery.selection;
|
const selection = gallery.selection;
|
||||||
@ -19,8 +18,7 @@ const selector = createSelector(
|
|||||||
queryArgs,
|
queryArgs,
|
||||||
selection,
|
selection,
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
);
|
||||||
|
|
||||||
export const useMultiselect = (imageDTO?: ImageDTO) => {
|
export const useMultiselect = (imageDTO?: ImageDTO) => {
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import { selectListImagesBaseQueryArgs } from 'features/gallery/store/gallerySelectors';
|
||||||
import { imageSelected } from 'features/gallery/store/gallerySlice';
|
import { imageSelected } from 'features/gallery/store/gallerySlice';
|
||||||
import { clamp, isEqual } from 'lodash-es';
|
import { IMAGE_LIMIT } from 'features/gallery/store/types';
|
||||||
|
import { clamp } from 'lodash-es';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { boardsApi } from 'services/api/endpoints/boards';
|
import { boardsApi } from 'services/api/endpoints/boards';
|
||||||
import {
|
import {
|
||||||
imagesApi,
|
imagesApi,
|
||||||
useLazyListImagesQuery,
|
useLazyListImagesQuery,
|
||||||
} from 'services/api/endpoints/images';
|
} from 'services/api/endpoints/images';
|
||||||
import { selectListImagesBaseQueryArgs } from 'features/gallery/store/gallerySelectors';
|
|
||||||
import { IMAGE_LIMIT } from 'features/gallery/store/types';
|
|
||||||
import { ListImagesArgs } from 'services/api/types';
|
import { ListImagesArgs } from 'services/api/types';
|
||||||
import { imagesAdapter } from 'services/api/util';
|
import { imagesAdapter } from 'services/api/util';
|
||||||
|
|
||||||
export const nextPrevImageButtonsSelector = createSelector(
|
export const nextPrevImageButtonsSelector = createMemoizedSelector(
|
||||||
[stateSelector, selectListImagesBaseQueryArgs],
|
[stateSelector, selectListImagesBaseQueryArgs],
|
||||||
(state, baseQueryArgs) => {
|
(state, baseQueryArgs) => {
|
||||||
const { data, status } =
|
const { data, status } =
|
||||||
@ -80,11 +80,6 @@ export const nextPrevImageButtonsSelector = createSelector(
|
|||||||
prevImage,
|
prevImage,
|
||||||
queryArgs,
|
queryArgs,
|
||||||
};
|
};
|
||||||
},
|
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { RootState } from 'app/store/store';
|
import { RootState } from 'app/store/store';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import { ListImagesArgs } from 'services/api/types';
|
import { ListImagesArgs } from 'services/api/types';
|
||||||
import {
|
import {
|
||||||
ASSETS_CATEGORIES,
|
ASSETS_CATEGORIES,
|
||||||
@ -10,13 +9,12 @@ import {
|
|||||||
|
|
||||||
export const gallerySelector = (state: RootState) => state.gallery;
|
export const gallerySelector = (state: RootState) => state.gallery;
|
||||||
|
|
||||||
export const selectLastSelectedImage = createSelector(
|
export const selectLastSelectedImage = createMemoizedSelector(
|
||||||
(state: RootState) => state,
|
(state: RootState) => state,
|
||||||
(state) => state.gallery.selection[state.gallery.selection.length - 1],
|
(state) => state.gallery.selection[state.gallery.selection.length - 1]
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
);
|
||||||
|
|
||||||
export const selectListImagesBaseQueryArgs = createSelector(
|
export const selectListImagesBaseQueryArgs = createMemoizedSelector(
|
||||||
[(state: RootState) => state],
|
[(state: RootState) => state],
|
||||||
(state) => {
|
(state) => {
|
||||||
const { selectedBoardId, galleryView } = state.gallery;
|
const { selectedBoardId, galleryView } = state.gallery;
|
||||||
@ -32,6 +30,5 @@ export const selectListImagesBaseQueryArgs = createSelector(
|
|||||||
};
|
};
|
||||||
|
|
||||||
return listImagesBaseQueryArgs;
|
return listImagesBaseQueryArgs;
|
||||||
},
|
}
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
);
|
||||||
|
@ -1,26 +1,21 @@
|
|||||||
import { Flex } from '@chakra-ui/react';
|
import { Flex } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import IAICollapse from 'common/components/IAICollapse';
|
import IAICollapse from 'common/components/IAICollapse';
|
||||||
|
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
||||||
import { size } from 'lodash-es';
|
import { size } from 'lodash-es';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
import { useTranslation } from 'react-i18next';
|
||||||
import ParamLoraList from './ParamLoraList';
|
import ParamLoraList from './ParamLoraList';
|
||||||
import ParamLoRASelect from './ParamLoraSelect';
|
import ParamLoRASelect from './ParamLoraSelect';
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(stateSelector, (state) => {
|
||||||
stateSelector,
|
const loraCount = size(state.lora.loras);
|
||||||
(state) => {
|
return {
|
||||||
const loraCount = size(state.lora.loras);
|
activeLabel: loraCount > 0 ? `${loraCount} Active` : undefined,
|
||||||
return {
|
};
|
||||||
activeLabel: loraCount > 0 ? `${loraCount} Active` : undefined,
|
});
|
||||||
};
|
|
||||||
},
|
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
const ParamLoraCollapse = () => {
|
const ParamLoraCollapse = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -1,19 +1,14 @@
|
|||||||
import { Divider, Flex } from '@chakra-ui/react';
|
import { Divider, Flex } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import { map } from 'lodash-es';
|
import { map } from 'lodash-es';
|
||||||
import ParamLora from './ParamLora';
|
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
import ParamLora from './ParamLora';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(stateSelector, ({ lora }) => {
|
||||||
stateSelector,
|
return { lorasArray: map(lora.loras) };
|
||||||
({ lora }) => {
|
});
|
||||||
return { lorasArray: map(lora.loras) };
|
|
||||||
},
|
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
const ParamLoraList = () => {
|
const ParamLoraList = () => {
|
||||||
const { lorasArray } = useAppSelector(selector);
|
const { lorasArray } = useAppSelector(selector);
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import { Flex, Text } from '@chakra-ui/react';
|
import { Flex, Text } from '@chakra-ui/react';
|
||||||
import { SelectItem } from '@mantine/core';
|
import { SelectItem } from '@mantine/core';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { RootState, stateSelector } from 'app/store/store';
|
import { RootState, stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
|
import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
|
||||||
import IAIMantineSelectItemWithTooltip from 'common/components/IAIMantineSelectItemWithTooltip';
|
import IAIMantineSelectItemWithTooltip from 'common/components/IAIMantineSelectItemWithTooltip';
|
||||||
import { loraAdded } from 'features/lora/store/loraSlice';
|
import { loraAdded } from 'features/lora/store/loraSlice';
|
||||||
@ -13,13 +12,9 @@ import { memo, useCallback, useMemo } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useGetLoRAModelsQuery } from 'services/api/endpoints/models';
|
import { useGetLoRAModelsQuery } from 'services/api/endpoints/models';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(stateSelector, ({ lora }) => ({
|
||||||
stateSelector,
|
loras: lora.loras,
|
||||||
({ lora }) => ({
|
}));
|
||||||
loras: lora.loras,
|
|
||||||
}),
|
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
const ParamLoRASelect = () => {
|
const ParamLoRASelect = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { Flex } from '@chakra-ui/react';
|
import { Flex } from '@chakra-ui/react';
|
||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
import { useAppDispatch } from 'app/store/storeHooks';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { SelectItem } from '@mantine/core';
|
import { SelectItem } from '@mantine/core';
|
||||||
import { useForm } from '@mantine/form';
|
import { useForm } from '@mantine/form';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Flex, Text } from '@chakra-ui/react';
|
import { Flex, Text } from '@chakra-ui/react';
|
||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import {
|
import {
|
||||||
MainModelConfigEntity,
|
MainModelConfigEntity,
|
||||||
|
@ -16,7 +16,6 @@ import IAIInput from 'common/components/IAIInput';
|
|||||||
import { addToast } from 'features/system/store/systemSlice';
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
import { ChangeEvent, useCallback, useEffect, useState } from 'react';
|
import { ChangeEvent, useCallback, useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { useConvertMainModelsMutation } from 'services/api/endpoints/models';
|
import { useConvertMainModelsMutation } from 'services/api/endpoints/models';
|
||||||
import { CheckpointModelConfig } from 'services/api/types';
|
import { CheckpointModelConfig } from 'services/api/types';
|
||||||
|
|
||||||
|
@ -240,7 +240,7 @@ const modelsFilter = <
|
|||||||
| LoRAModelConfigEntity
|
| LoRAModelConfigEntity
|
||||||
| OnnxModelConfigEntity,
|
| OnnxModelConfigEntity,
|
||||||
>(
|
>(
|
||||||
data: EntityState<T> | undefined,
|
data: EntityState<T, string> | undefined,
|
||||||
model_type: ModelType,
|
model_type: ModelType,
|
||||||
model_format: ModelFormat | undefined,
|
model_format: ModelFormat | undefined,
|
||||||
nameFilter: string
|
nameFilter: string
|
||||||
|
@ -5,11 +5,10 @@ import {
|
|||||||
PopoverBody,
|
PopoverBody,
|
||||||
PopoverContent,
|
PopoverContent,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
|
||||||
import { useAppToaster } from 'app/components/Toaster';
|
import { useAppToaster } from 'app/components/Toaster';
|
||||||
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
|
import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
|
||||||
import { useBuildNode } from 'features/nodes/hooks/useBuildNode';
|
import { useBuildNode } from 'features/nodes/hooks/useBuildNode';
|
||||||
import {
|
import {
|
||||||
@ -62,58 +61,54 @@ const AddNodePopover = () => {
|
|||||||
(state) => state.nodes.connectionStartParams?.handleType
|
(state) => state.nodes.connectionStartParams?.handleType
|
||||||
);
|
);
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector([stateSelector], ({ nodes }) => {
|
||||||
[stateSelector],
|
// If we have a connection in progress, we need to filter the node choices
|
||||||
({ nodes }) => {
|
const filteredNodeTemplates = fieldFilter
|
||||||
// If we have a connection in progress, we need to filter the node choices
|
? filter(nodes.nodeTemplates, (template) => {
|
||||||
const filteredNodeTemplates = fieldFilter
|
const handles =
|
||||||
? filter(nodes.nodeTemplates, (template) => {
|
handleFilter == 'source' ? template.inputs : template.outputs;
|
||||||
const handles =
|
|
||||||
handleFilter == 'source' ? template.inputs : template.outputs;
|
|
||||||
|
|
||||||
return some(handles, (handle) => {
|
return some(handles, (handle) => {
|
||||||
const sourceType =
|
const sourceType =
|
||||||
handleFilter == 'source' ? fieldFilter : handle.type;
|
handleFilter == 'source' ? fieldFilter : handle.type;
|
||||||
const targetType =
|
const targetType =
|
||||||
handleFilter == 'target' ? fieldFilter : handle.type;
|
handleFilter == 'target' ? fieldFilter : handle.type;
|
||||||
|
|
||||||
return validateSourceAndTargetTypes(sourceType, targetType);
|
return validateSourceAndTargetTypes(sourceType, targetType);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
: map(nodes.nodeTemplates);
|
: map(nodes.nodeTemplates);
|
||||||
|
|
||||||
const data: NodeTemplate[] = map(filteredNodeTemplates, (template) => {
|
const data: NodeTemplate[] = map(filteredNodeTemplates, (template) => {
|
||||||
return {
|
return {
|
||||||
label: template.title,
|
label: template.title,
|
||||||
value: template.type,
|
value: template.type,
|
||||||
description: template.description,
|
description: template.description,
|
||||||
tags: template.tags,
|
tags: template.tags,
|
||||||
};
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
//We only want these nodes if we're not filtered
|
||||||
|
if (fieldFilter === null) {
|
||||||
|
data.push({
|
||||||
|
label: t('nodes.currentImage'),
|
||||||
|
value: 'current_image',
|
||||||
|
description: t('nodes.currentImageDescription'),
|
||||||
|
tags: ['progress'],
|
||||||
});
|
});
|
||||||
|
|
||||||
//We only want these nodes if we're not filtered
|
data.push({
|
||||||
if (fieldFilter === null) {
|
label: t('nodes.notes'),
|
||||||
data.push({
|
value: 'notes',
|
||||||
label: t('nodes.currentImage'),
|
description: t('nodes.notesDescription'),
|
||||||
value: 'current_image',
|
tags: ['notes'],
|
||||||
description: t('nodes.currentImageDescription'),
|
});
|
||||||
tags: ['progress'],
|
}
|
||||||
});
|
|
||||||
|
|
||||||
data.push({
|
data.sort((a, b) => a.label.localeCompare(b.label));
|
||||||
label: t('nodes.notes'),
|
|
||||||
value: 'notes',
|
|
||||||
description: t('nodes.notesDescription'),
|
|
||||||
tags: ['notes'],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
data.sort((a, b) => a.label.localeCompare(b.label));
|
return { data };
|
||||||
|
});
|
||||||
return { data };
|
|
||||||
},
|
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
const { data } = useAppSelector(selector);
|
const { data } = useAppSelector(selector);
|
||||||
const isOpen = useAppSelector((state) => state.nodes.isAddNodePopoverOpen);
|
const isOpen = useAppSelector((state) => state.nodes.isAddNodePopoverOpen);
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { useToken } from '@chakra-ui/react';
|
import { useToken } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import { useIsValidConnection } from 'features/nodes/hooks/useIsValidConnection';
|
import { useIsValidConnection } from 'features/nodes/hooks/useIsValidConnection';
|
||||||
import {
|
import {
|
||||||
connectionEnded,
|
connectionEnded,
|
||||||
@ -67,17 +66,13 @@ const nodeTypes = {
|
|||||||
// TODO: can we support reactflow? if not, we could style the attribution so it matches the app
|
// TODO: can we support reactflow? if not, we could style the attribution so it matches the app
|
||||||
const proOptions: ProOptions = { hideAttribution: true };
|
const proOptions: ProOptions = { hideAttribution: true };
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||||
stateSelector,
|
const { shouldSnapToGrid, selectionMode } = nodes;
|
||||||
({ nodes }) => {
|
return {
|
||||||
const { shouldSnapToGrid, selectionMode } = nodes;
|
shouldSnapToGrid,
|
||||||
return {
|
selectionMode,
|
||||||
shouldSnapToGrid,
|
};
|
||||||
selectionMode,
|
});
|
||||||
};
|
|
||||||
},
|
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
export const Flow = () => {
|
export const Flow = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { colorTokenToCssVar } from 'common/util/colorTokenToCssVar';
|
import { colorTokenToCssVar } from 'common/util/colorTokenToCssVar';
|
||||||
|
import { getFieldColor } from 'features/nodes/components/flow/edges/util/getEdgeColor';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import { ConnectionLineComponentProps, getBezierPath } from 'reactflow';
|
import { ConnectionLineComponentProps, getBezierPath } from 'reactflow';
|
||||||
import { getFieldColor } from 'features/nodes/components/flow/edges/util/getEdgeColor';
|
|
||||||
|
|
||||||
const selector = createSelector(stateSelector, ({ nodes }) => {
|
const selector = createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||||
const { shouldAnimateEdges, connectionStartFieldType, shouldColorEdges } =
|
const { shouldAnimateEdges, connectionStartFieldType, shouldColorEdges } =
|
||||||
nodes;
|
nodes;
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import { colorTokenToCssVar } from 'common/util/colorTokenToCssVar';
|
import { colorTokenToCssVar } from 'common/util/colorTokenToCssVar';
|
||||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||||
import { getFieldColor } from './getEdgeColor';
|
import { getFieldColor } from './getEdgeColor';
|
||||||
@ -12,31 +11,26 @@ export const makeEdgeSelector = (
|
|||||||
targetHandleId: string | null | undefined,
|
targetHandleId: string | null | undefined,
|
||||||
selected?: boolean
|
selected?: boolean
|
||||||
) =>
|
) =>
|
||||||
createSelector(
|
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||||
stateSelector,
|
const sourceNode = nodes.nodes.find((node) => node.id === source);
|
||||||
({ nodes }) => {
|
const targetNode = nodes.nodes.find((node) => node.id === target);
|
||||||
const sourceNode = nodes.nodes.find((node) => node.id === source);
|
|
||||||
const targetNode = nodes.nodes.find((node) => node.id === target);
|
|
||||||
|
|
||||||
const isInvocationToInvocationEdge =
|
const isInvocationToInvocationEdge =
|
||||||
isInvocationNode(sourceNode) && isInvocationNode(targetNode);
|
isInvocationNode(sourceNode) && isInvocationNode(targetNode);
|
||||||
|
|
||||||
const isSelected =
|
const isSelected = sourceNode?.selected || targetNode?.selected || selected;
|
||||||
sourceNode?.selected || targetNode?.selected || selected;
|
const sourceType = isInvocationToInvocationEdge
|
||||||
const sourceType = isInvocationToInvocationEdge
|
? sourceNode?.data?.outputs[sourceHandleId || '']?.type
|
||||||
? sourceNode?.data?.outputs[sourceHandleId || '']?.type
|
: undefined;
|
||||||
: undefined;
|
|
||||||
|
|
||||||
const stroke =
|
const stroke =
|
||||||
sourceType && nodes.shouldColorEdges
|
sourceType && nodes.shouldColorEdges
|
||||||
? getFieldColor(sourceType)
|
? getFieldColor(sourceType)
|
||||||
: colorTokenToCssVar('base.500');
|
: colorTokenToCssVar('base.500');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isSelected,
|
isSelected,
|
||||||
shouldAnimate: nodes.shouldAnimateEdges && isSelected,
|
shouldAnimate: nodes.shouldAnimateEdges && isSelected,
|
||||||
stroke,
|
stroke,
|
||||||
};
|
};
|
||||||
},
|
});
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
|
||||||
|
@ -1,25 +1,28 @@
|
|||||||
import { useState, PropsWithChildren, memo, useCallback } from 'react';
|
|
||||||
import { useSelector } from 'react-redux';
|
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
|
||||||
import { Flex, Image, Text } from '@chakra-ui/react';
|
import { Flex, Image, Text } from '@chakra-ui/react';
|
||||||
import { motion } from 'framer-motion';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { NodeProps } from 'reactflow';
|
import { stateSelector } from 'app/store/store';
|
||||||
import NodeWrapper from 'features/nodes/components/flow/nodes/common/NodeWrapper';
|
|
||||||
import NextPrevImageButtons from 'features/gallery/components/NextPrevImageButtons';
|
|
||||||
import IAIDndImage from 'common/components/IAIDndImage';
|
import IAIDndImage from 'common/components/IAIDndImage';
|
||||||
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
||||||
|
import NextPrevImageButtons from 'features/gallery/components/NextPrevImageButtons';
|
||||||
|
import NodeWrapper from 'features/nodes/components/flow/nodes/common/NodeWrapper';
|
||||||
import { DRAG_HANDLE_CLASSNAME } from 'features/nodes/types/constants';
|
import { DRAG_HANDLE_CLASSNAME } from 'features/nodes/types/constants';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { motion } from 'framer-motion';
|
||||||
|
import { PropsWithChildren, memo, useCallback, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { NodeProps } from 'reactflow';
|
||||||
|
|
||||||
const selector = createSelector(stateSelector, ({ system, gallery }) => {
|
const selector = createMemoizedSelector(
|
||||||
const imageDTO = gallery.selection[gallery.selection.length - 1];
|
stateSelector,
|
||||||
|
({ system, gallery }) => {
|
||||||
|
const imageDTO = gallery.selection[gallery.selection.length - 1];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
imageDTO,
|
imageDTO,
|
||||||
progressImage: system.denoiseProgress?.progress_image,
|
progressImage: system.denoiseProgress?.progress_image,
|
||||||
};
|
};
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const CurrentImageNode = (props: NodeProps) => {
|
const CurrentImageNode = (props: NodeProps) => {
|
||||||
const { progressImage, imageDTO } = useSelector(selector);
|
const { progressImage, imageDTO } = useSelector(selector);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user