feat: Add internal runtime configuration

This commit is contained in:
Maksim Eltyshev
2026-01-22 18:02:42 +01:00
parent b852481850
commit 1264fd5715
79 changed files with 561 additions and 122 deletions
+17
View File
@@ -0,0 +1,17 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import ActionTypes from '../constants/ActionTypes';
const handleBootstrapUpdate = (bootstrap) => ({
type: ActionTypes.BOOTSTRAP_UPDATE_HANDLE,
payload: {
bootstrap,
},
});
export default {
handleBootstrapUpdate,
};
+2
View File
@@ -5,6 +5,7 @@
import router from './router';
import socket from './socket';
import bootstrap from './bootstrap';
import login from './login';
import core from './core';
import modals from './modals';
@@ -34,6 +35,7 @@ import notificationServices from './notification-services';
export default {
...router,
...socket,
...bootstrap,
...login,
...core,
...modals,
+8
View File
@@ -5,6 +5,13 @@
import ActionTypes from '../constants/ActionTypes';
const handleUsersReset = (users) => ({
type: ActionTypes.USERS_RESET_HANDLE,
payload: {
users,
},
});
const createUser = (data) => ({
type: ActionTypes.USER_CREATE,
payload: {
@@ -399,6 +406,7 @@ const removeUserFromBoardFilter = (id, boardId, currentListId) => ({
});
export default {
handleUsersReset,
createUser,
handleUserCreate,
clearUserCreateError,
@@ -38,8 +38,8 @@ const StepTypes = {
const ActionsStep = React.memo(({ userId, onClose }) => {
const selectUserById = useMemo(() => selectors.makeSelectUserById(), []);
const activeUserLimit = useSelector(selectors.selectActiveUserLimit);
const activeUserTotal = useSelector(selectors.selectActiveUserTotal);
const activeUsersLimit = useSelector(selectors.selectActiveUsersLimit);
const activeUsersTotal = useSelector(selectors.selectActiveUsersTotal);
const user = useSelector((state) => selectUserById(state, userId));
const isCurrentUser = useSelector((state) => user.id === selectors.selectCurrentUserId(state));
@@ -237,8 +237,8 @@ const ActionsStep = React.memo(({ userId, onClose }) => {
<Menu.Item
disabled={
user.isDeactivated &&
activeUserLimit !== null &&
activeUserTotal >= activeUserLimit
activeUsersLimit !== null &&
activeUsersTotal >= activeUsersLimit
}
className={styles.menuItem}
onClick={user.isDeactivated ? handleActivateClick : handleDeactivateClick}
@@ -17,8 +17,8 @@ import AddStep from './AddStep';
import styles from './UsersPane.module.scss';
const UsersPane = React.memo(() => {
const activeUserTotal = useSelector(selectors.selectActiveUserTotal);
const activeUserLimit = useSelector(selectors.selectActiveUserLimit);
const activeUsersLimit = useSelector(selectors.selectActiveUsersLimit);
const activeUsersTotal = useSelector(selectors.selectActiveUsersTotal);
const users = useSelector(selectors.selectUsers);
const canAdd = useSelector((state) => {
@@ -106,13 +106,13 @@ const UsersPane = React.memo(() => {
<AddPopup>
<Button
positive
disabled={activeUserLimit !== null && activeUserTotal >= activeUserLimit}
disabled={activeUsersLimit !== null && activeUsersTotal >= activeUsersLimit}
className={styles.addButton}
>
{t('action.addUser')}
{activeUserLimit !== null && (
{activeUsersLimit !== null && (
<span className={styles.addButtonCounter}>
{activeUserTotal}/{activeUserLimit}
{activeUsersTotal}/{activeUsersLimit}
</span>
)}
</Button>
@@ -64,10 +64,10 @@ const createMessage = (error) => {
type: 'error',
content: 'common.usernameAlreadyInUse',
};
case 'Active user limit reached':
case 'Active users limit reached':
return {
type: 'error',
content: 'common.activeUserLimitReached',
content: 'common.activeUsersLimitReached',
};
case 'Failed to fetch':
return {
+5
View File
@@ -16,6 +16,10 @@ export default {
SOCKET_RECONNECT_HANDLE: 'SOCKET_RECONNECT_HANDLE',
SOCKET_RECONNECT_HANDLE__CORE_FETCH: 'SOCKET_RECONNECT_HANDLE__CORE_FETCH',
/* Bootstrap */
BOOTSTRAP_UPDATE_HANDLE: 'BOOTSTRAP_UPDATE_HANDLE',
/* Login */
LOGIN_INITIALIZE: 'LOGIN_INITIALIZE',
@@ -78,6 +82,7 @@ export default {
/* Users */
USERS_RESET_HANDLE: 'USERS_RESET_HANDLE',
USER_CREATE: 'USER_CREATE',
USER_CREATE__SUCCESS: 'USER_CREATE__SUCCESS',
USER_CREATE__FAILURE: 'USER_CREATE__FAILURE',
+5
View File
@@ -13,6 +13,10 @@ export default {
SOCKET_DISCONNECT_HANDLE: `${PREFIX}/SOCKET_DISCONNECT_HANDLE`,
SOCKET_RECONNECT_HANDLE: `${PREFIX}/SOCKET_RECONNECT_HANDLE`,
/* Bootstrap */
BOOTSTRAP_UPDATE_HANDLE: `${PREFIX}/BOOTSTRAP_UPDATE_HANDLE`,
/* Login */
AUTHENTICATE: `${PREFIX}/AUTHENTICATE`,
@@ -51,6 +55,7 @@ export default {
/* Users */
USERS_RESET_HANDLE: `${PREFIX}/USERS_RESET_HANDLE`,
USER_CREATE: `${PREFIX}/USER_CREATE`,
USER_CREATE_HANDLE: `${PREFIX}/USER_CREATE_HANDLE`,
USER_CREATE_ERROR_CLEAR: `${PREFIX}/USER_CREATE_ERROR_CLEAR`,
+17
View File
@@ -0,0 +1,17 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import EntryActionTypes from '../constants/EntryActionTypes';
const handleBootstrapUpdate = (bootstrap) => ({
type: EntryActionTypes.BOOTSTRAP_UPDATE_HANDLE,
payload: {
bootstrap,
},
});
export default {
handleBootstrapUpdate,
};
+2
View File
@@ -4,6 +4,7 @@
*/
import socket from './socket';
import bootstrap from './bootstrap';
import login from './login';
import core from './core';
import modals from './modals';
@@ -32,6 +33,7 @@ import notificationServices from './notification-services';
export default {
...socket,
...bootstrap,
...login,
...core,
...modals,
+6
View File
@@ -5,6 +5,11 @@
import EntryActionTypes from '../constants/EntryActionTypes';
const handleUsersReset = () => ({
type: EntryActionTypes.USERS_RESET_HANDLE,
payload: {},
});
const createUser = (data) => ({
type: EntryActionTypes.USER_CREATE,
payload: {
@@ -246,6 +251,7 @@ const removeUserFromFilterInCurrentBoard = (id) => ({
});
export default {
handleUsersReset,
createUser,
handleUserCreate,
clearUserCreateError,
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'تم الوصول إلى حد المستخدمين النشطين',
activeUsersLimitReached: 'تم الوصول إلى حد المستخدمين النشطين',
adminLoginRequiredToInitializeInstance: 'مطلوب تسجيل دخول المدير لتهيئة المثيل',
emailAlreadyInUse: 'البريد الإلكتروني مستخدم بالفعل',
emailOrUsername: 'البريد الإلكتروني أو اسم المستخدم',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Достигнат е лимитът на активни потребители',
activeUsersLimitReached: 'Достигнат е лимитът на активни потребители',
adminLoginRequiredToInitializeInstance:
'Необходимо е влизане на администратор за инициализиране на инстанцията',
emailAlreadyInUse: 'Имейлът вече се използва',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: "S'ha assolit el límit d'usuaris actius",
activeUsersLimitReached: "S'ha assolit el límit d'usuaris actius",
adminLoginRequiredToInitializeInstance:
"Es requereix inici de sessió d'administrador per inicialitzar la instància",
emailAlreadyInUse: 'Correu electrònic ja en ús',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Dosažený limit aktivních uživatelů',
activeUsersLimitReached: 'Dosažený limit aktivních uživatelů',
adminLoginRequiredToInitializeInstance:
'K inicializaci instance je nutné přihlášení správce.',
emailAlreadyInUse: 'E-mail se již používá',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Grænsen for aktive brugere er nået',
activeUsersLimitReached: 'Grænsen for aktive brugere er nået',
adminLoginRequiredToInitializeInstance:
'Administrator login påkrævet for at initialisere instans',
emailAlreadyInUse: 'E-mail allerede i brug',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Maximale Anzahl aktiver Benutzer erreicht',
activeUsersLimitReached: 'Maximale Anzahl aktiver Benutzer erreicht',
adminLoginRequiredToInitializeInstance:
'Admin-Anmeldung erforderlich zur Initialisierung der Instanz',
emailAlreadyInUse: 'E-mail Adresse wird bereits benutzt',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Έχει επιτευχθεί το όριο ενεργών χρηστών',
activeUsersLimitReached: 'Έχει επιτευχθεί το όριο ενεργών χρηστών',
adminLoginRequiredToInitializeInstance:
'Απαιτείται σύνδεση διαχειριστή για την αρχικοποίηση της εφαρμογής',
emailAlreadyInUse: 'Το e-mail χρησιμοποιείται ήδη',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Active user limit reached',
activeUsersLimitReached: 'Active users limit reached',
adminLoginRequiredToInitializeInstance: 'Admin login required to initialize instance',
emailAlreadyInUse: 'E-mail already in use',
emailOrUsername: 'E-mail or username',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Active user limit reached',
activeUsersLimitReached: 'Active users limit reached',
adminLoginRequiredToInitializeInstance: 'Admin login required to initialize instance',
emailAlreadyInUse: 'E-mail already in use',
emailOrUsername: 'E-mail or username',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Se ha alcanzado el límite de usuarios activos',
activeUsersLimitReached: 'Se ha alcanzado el límite de usuarios activos',
adminLoginRequiredToInitializeInstance:
'Se requiere inicio de sesión de administrador para inicializar la instancia',
emailAlreadyInUse: 'Correo electrónico ya en uso',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Aktiivsete kasutajate limiit on täis',
activeUsersLimitReached: 'Aktiivsete kasutajate limiit on täis',
adminLoginRequiredToInitializeInstance:
'Administraatori sisselogimine on vajalik rakenduse käivitamiseks',
emailAlreadyInUse: 'E-post on juba kasutusel',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'حد کاربران فعال به پایان رسیده است',
activeUsersLimitReached: 'حد کاربران فعال به پایان رسیده است',
adminLoginRequiredToInitializeInstance: 'ورود مدیر برای راه‌اندازی نمونه مورد نیاز است',
emailAlreadyInUse: 'ایمیل قبلا استفاده شده است',
emailOrUsername: 'ایمیل یا نام کاربری',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Aktiivisten käyttäjien raja saavutettu',
activeUsersLimitReached: 'Aktiivisten käyttäjien raja saavutettu',
adminLoginRequiredToInitializeInstance:
'Järjestelmänvalvojan kirjautuminen vaaditaan instanssin alustamiseksi',
emailAlreadyInUse: 'Sähköposti on jo käytössä',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'La limite d’utilisateurs actifs a été atteinte',
activeUsersLimitReached: 'La limite d’utilisateurs actifs a été atteinte',
adminLoginRequiredToInitializeInstance:
"Connexion administrateur requise pour initialiser l'instance",
emailAlreadyInUse: 'E-mail déjà utilisé',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Aktív felhasználók korlátja elérve',
activeUsersLimitReached: 'Aktív felhasználók korlátja elérve',
adminLoginRequiredToInitializeInstance:
'Rendszergazdai bejelentkezés szükséges a példány inicializálásához',
emailAlreadyInUse: 'Az e-mail cím már használatban van',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Batas pengguna aktif tercapai',
activeUsersLimitReached: 'Batas pengguna aktif tercapai',
adminLoginRequiredToInitializeInstance:
'Login admin diperlukan untuk menginisialisasi instance',
emailAlreadyInUse: 'E-mail telah digunakan',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Limite utenti attivi raggiunto',
activeUsersLimitReached: 'Limite utenti attivi raggiunto',
adminLoginRequiredToInitializeInstance:
"Login amministratore richiesto per inizializzare l'istanza",
emailAlreadyInUse: 'E-mail già in uso',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'アクティブユーザーの上限に達しました',
activeUsersLimitReached: 'アクティブユーザーの上限に達しました',
adminLoginRequiredToInitializeInstance:
'インスタンスを初期化するには管理者ログインが必要です',
emailAlreadyInUse: 'Eメールは既に使われています',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: '활성 사용자 한도에 도달했습니다',
activeUsersLimitReached: '활성 사용자 한도에 도달했습니다',
adminLoginRequiredToInitializeInstance: '인스턴스 초기화를 위해 관리자 로그인이 필요합니다',
emailAlreadyInUse: '이미 사용 중인 이메일',
emailOrUsername: '이메일 또는 사용자 이름',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Limiet voor actieve gebruikers bereikt',
activeUsersLimitReached: 'Limiet voor actieve gebruikers bereikt',
adminLoginRequiredToInitializeInstance:
'Beheerder login vereist om instantie te initialiseren',
emailAlreadyInUse: 'E-mail is al in gebruik',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Osiągnięto limit aktywnych użytkowników',
activeUsersLimitReached: 'Osiągnięto limit aktywnych użytkowników',
adminLoginRequiredToInitializeInstance:
'Wymagane logowanie administratora do inicjalizacji instancji',
emailAlreadyInUse: 'E-mail jest już używany',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Limite de usuários ativos atingido',
activeUsersLimitReached: 'Limite de usuários ativos atingido',
adminLoginRequiredToInitializeInstance:
'Login de administrador necessário para inicializar a instância',
emailAlreadyInUse: 'E-mail já está em uso',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Limite de utilizadores activos atingido',
activeUsersLimitReached: 'Limite de utilizadores activos atingido',
adminLoginRequiredToInitializeInstance:
'Início de sessão de administrador necessário para inicializar a instância',
emailAlreadyInUse: 'E-mail já está em uso',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Limita utilizatorilor activi a fost atinsă',
activeUsersLimitReached: 'Limita utilizatorilor activi a fost atinsă',
adminLoginRequiredToInitializeInstance:
'Este necesară autentificarea administratorului pentru a inițializa instanța',
emailAlreadyInUse: 'E-mail deja utilizat',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Достигнут лимит активных пользователей',
activeUsersLimitReached: 'Достигнут лимит активных пользователей',
adminLoginRequiredToInitializeInstance:
'Требуется вход администратора для инициализации экземпляра',
emailAlreadyInUse: 'E-mail уже занят',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Limit aktívnych používateľov bol dosiahnutý',
activeUsersLimitReached: 'Limit aktívnych používateľov bol dosiahnutý',
adminLoginRequiredToInitializeInstance:
'Na inicializáciu inštancie je potrebné prihlásenie správcu',
emailAlreadyInUse: 'E-mail je už použitý',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Достигнут је лимит активних корисника',
activeUsersLimitReached: 'Достигнут је лимит активних корисника',
adminLoginRequiredToInitializeInstance:
'Потребна је администраторска пријава за иницијализацију инстанце',
emailAlreadyInUse: 'Е-пошта је већ у употреби',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Dostignut je limit aktivnih korisnika',
activeUsersLimitReached: 'Dostignut je limit aktivnih korisnika',
adminLoginRequiredToInitializeInstance:
'Potrebna je administratorska prijava za inicijalizaciju instance',
emailAlreadyInUse: 'E-pošta je već u upotrebi',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Gränsen för aktiva användare har nåtts',
activeUsersLimitReached: 'Gränsen för aktiva användare har nåtts',
adminLoginRequiredToInitializeInstance:
'Administratörsinloggning krävs för att initiera instansen',
emailAlreadyInUse: 'E-mail används redan',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Aktif kullanıcı sınırına ulaşıldı',
activeUsersLimitReached: 'Aktif kullanıcı sınırına ulaşıldı',
adminLoginRequiredToInitializeInstance: 'Örneği başlatmak için yönetici girişi gerekli',
emailAlreadyInUse: 'E-posta adresi zaten kullanımda',
emailOrUsername: 'E-posta adresi veya kullanıcı adı',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Досягнуто ліміту активних користувачів',
activeUsersLimitReached: 'Досягнуто ліміту активних користувачів',
adminLoginRequiredToInitializeInstance:
'Потрібен вхід адміністратора для ініціалізації екземпляра',
emailAlreadyInUse: 'Електронна пошта вже використовується',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Faol foydalanuvchilar chegarasiga yetildi',
activeUsersLimitReached: 'Faol foydalanuvchilar chegarasiga yetildi',
adminLoginRequiredToInitializeInstance:
'Tizimni ishga tushirish uchun admin kirishi talab qilinadi',
emailAlreadyInUse: 'E-mail allaqachon mavjud',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Đã đạt giới hạn người dùng hoạt động',
activeUsersLimitReached: 'Đã đạt giới hạn người dùng hoạt động',
adminLoginRequiredToInitializeInstance: 'Cần đăng nhập quản trị để khởi tạo phiên bản',
emailAlreadyInUse: 'E-mail đã được sử dụng',
emailOrUsername: 'E-mail hoặc tên đăng nhập',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: '活跃用户数已达上限',
activeUsersLimitReached: '活跃用户数已达上限',
adminLoginRequiredToInitializeInstance: '需要管理员登录以初始化实例',
emailAlreadyInUse: '邮箱已使用',
emailOrUsername: '邮箱或用户名',
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
translation: {
common: {
activeUserLimitReached: '活躍使用者數已達上限',
activeUsersLimitReached: '活躍使用者數已達上限',
adminLoginRequiredToInitializeInstance: '需要管理員登入以初始化實例',
emailAlreadyInUse: '郵箱已被使用',
emailOrUsername: '郵箱或使用者名稱',
+17 -16
View File
@@ -129,6 +129,23 @@ export default class extends BaseModel {
User.upsert(user);
});
break;
case ActionTypes.USERS_RESET_HANDLE:
case ActionTypes.PROJECT_CREATE_HANDLE:
case ActionTypes.PROJECT_MANAGER_CREATE_HANDLE:
case ActionTypes.BOARD_FETCH__SUCCESS:
case ActionTypes.CARDS_FETCH__SUCCESS:
case ActionTypes.CARD_CREATE_HANDLE:
case ActionTypes.CARD_TRANSFER__SUCCESS:
case ActionTypes.COMMENTS_FETCH__SUCCESS:
case ActionTypes.COMMENT_CREATE_HANDLE:
case ActionTypes.ACTIVITIES_IN_BOARD_FETCH__SUCCESS:
case ActionTypes.ACTIVITIES_IN_CARD_FETCH__SUCCESS:
case ActionTypes.NOTIFICATION_CREATE_HANDLE:
payload.users.forEach((user) => {
User.upsert(user);
});
break;
case ActionTypes.USER_CREATE__SUCCESS:
case ActionTypes.USER_CREATE_HANDLE:
@@ -347,22 +364,6 @@ export default class extends BaseModel {
break;
}
case ActionTypes.PROJECT_CREATE_HANDLE:
case ActionTypes.PROJECT_MANAGER_CREATE_HANDLE:
case ActionTypes.BOARD_FETCH__SUCCESS:
case ActionTypes.CARDS_FETCH__SUCCESS:
case ActionTypes.CARD_CREATE_HANDLE:
case ActionTypes.CARD_TRANSFER__SUCCESS:
case ActionTypes.COMMENTS_FETCH__SUCCESS:
case ActionTypes.COMMENT_CREATE_HANDLE:
case ActionTypes.ACTIVITIES_IN_BOARD_FETCH__SUCCESS:
case ActionTypes.ACTIVITIES_IN_CARD_FETCH__SUCCESS:
case ActionTypes.NOTIFICATION_CREATE_HANDLE:
payload.users.forEach((user) => {
User.upsert(user);
});
break;
default:
}
}
+8
View File
@@ -18,6 +18,14 @@ export default (state = initialState, { type, payload }) => {
...state,
bootstrap: payload.bootstrap,
};
case ActionTypes.BOOTSTRAP_UPDATE_HANDLE:
return {
...state,
bootstrap: {
...state.bootstrap,
...payload.bootstrap,
},
};
case ActionTypes.LOGIN_INITIALIZE:
return {
...state,
+16
View File
@@ -0,0 +1,16 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import { put } from 'redux-saga/effects';
import actions from '../../../actions';
export function* handleBootstrapUpdate(bootstrap) {
yield put(actions.handleBootstrapUpdate(bootstrap));
}
export default {
handleBootstrapUpdate,
};
+2
View File
@@ -5,6 +5,7 @@
import router from './router';
import socket from './socket';
import bootstrap from './bootstrap';
import core from './core';
import modals from './modals';
import config from './config';
@@ -33,6 +34,7 @@ import notificationServices from './notification-services';
export default {
...router,
...socket,
...bootstrap,
...core,
...modals,
...config,
+12
View File
@@ -16,6 +16,17 @@ import mergeRecords from '../../../utils/merge-records';
import { isUserAdminOrProjectOwner } from '../../../utils/record-helpers';
import { UserRoles } from '../../../constants/Enums';
export function* handleUsersReset() {
let users;
try {
({ items: users } = yield call(request, api.getUsers));
} catch {
return;
}
yield put(actions.handleUsersReset(users));
}
export function* createUser(data) {
yield put(actions.createUser(data));
@@ -491,6 +502,7 @@ export function* removeUserFromFilterInCurrentBoard(id) {
}
export default {
handleUsersReset,
createUser,
handleUserCreate,
clearUserCreateError,
+17
View File
@@ -0,0 +1,17 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import { all, takeEvery } from 'redux-saga/effects';
import services from '../services';
import EntryActionTypes from '../../../constants/EntryActionTypes';
export default function* bootstrapWatchers() {
yield all([
takeEvery(EntryActionTypes.BOOTSTRAP_UPDATE_HANDLE, ({ payload: { bootstrap } }) =>
services.handleBootstrapUpdate(bootstrap),
),
]);
}
+2
View File
@@ -5,6 +5,7 @@
import router from './router';
import socket from './socket';
import bootstrap from './bootstrap';
import core from './core';
import modals from './modals';
import config from './config';
@@ -33,6 +34,7 @@ import notificationServices from './notification-services';
export default [
router,
socket,
bootstrap,
core,
modals,
config,
+14
View File
@@ -25,6 +25,10 @@ const createSocketEventsChannel = () =>
emit(entryActions.logout(false));
};
const handleBootstrapUpdate = ({ item }) => {
emit(entryActions.handleBootstrapUpdate(item));
};
const handleConfigUpdate = ({ item }) => {
emit(entryActions.handleConfigUpdate(item));
};
@@ -41,6 +45,10 @@ const createSocketEventsChannel = () =>
emit(entryActions.handleWebhookDelete(item));
};
const handleUsersReset = () => {
emit(entryActions.handleUsersReset());
};
const handleUserCreate = ({ item }) => {
emit(entryActions.handleUserCreate(item));
};
@@ -290,12 +298,15 @@ const createSocketEventsChannel = () =>
socket.on('logout', handleLogout);
socket.on('bootstrapUpdate', handleBootstrapUpdate);
socket.on('configUpdate', handleConfigUpdate);
socket.on('webhookCreate', handleWebhookCreate);
socket.on('webhookUpdate', handleWebhookUpdate);
socket.on('webhookDelete', handleWebhookDelete);
socket.on('usersReset', handleUsersReset);
socket.on('userCreate', handleUserCreate);
socket.on('userUpdate', handleUserUpdate);
socket.on('userDelete', handleUserDelete);
@@ -384,12 +395,15 @@ const createSocketEventsChannel = () =>
socket.off('logout', handleLogout);
socket.off('bootstrapUpdate', handleBootstrapUpdate);
socket.off('configUpdate', handleConfigUpdate);
socket.off('webhookCreate', handleWebhookCreate);
socket.off('webhookUpdate', handleWebhookUpdate);
socket.off('webhookDelete', handleWebhookDelete);
socket.off('usersReset', handleUsersReset);
socket.off('userCreate', handleUserCreate);
socket.off('userUpdate', handleUserUpdate);
socket.off('userDelete', handleUserDelete);
+1
View File
@@ -10,6 +10,7 @@ import EntryActionTypes from '../../../constants/EntryActionTypes';
export default function* usersWatchers() {
yield all([
takeEvery(EntryActionTypes.USERS_RESET_HANDLE, () => services.handleUsersReset()),
takeEvery(EntryActionTypes.USER_CREATE, ({ payload: { data } }) => services.createUser(data)),
takeEvery(EntryActionTypes.USER_CREATE_HANDLE, ({ payload: { user } }) =>
services.handleUserCreate(user),
+2 -2
View File
@@ -11,7 +11,7 @@ export const selectBootstrap = ({ common: { bootstrap } }) => bootstrap;
export const selectOidcBootstrap = (state) => selectBootstrap(state).oidc;
export const selectActiveUserLimit = (state) => selectBootstrap(state).activeUserLimit;
export const selectActiveUsersLimit = (state) => selectBootstrap(state).activeUsersLimit;
export const selectAccessToken = ({ auth: { accessToken } }) => accessToken;
@@ -28,7 +28,7 @@ export default {
selectIsInitializing,
selectBootstrap,
selectOidcBootstrap,
selectActiveUserLimit,
selectActiveUsersLimit,
selectAccessToken,
selectAuthenticateForm,
selectUserCreateForm,
+2 -2
View File
@@ -51,7 +51,7 @@ export const selectActiveUsers = createSelector(orm, ({ User }) =>
User.getActiveQuerySet().toRefArray(),
);
export const selectActiveUserTotal = createSelector(orm, ({ User }) =>
export const selectActiveUsersTotal = createSelector(orm, ({ User }) =>
User.getActiveQuerySet().count(),
);
@@ -347,7 +347,7 @@ export default {
selectCurrentUserId,
selectUsers,
selectActiveUsers,
selectActiveUserTotal,
selectActiveUsersTotal,
selectActiveAdminOrProjectOwnerUsers,
selectCurrentUser,
selectProjectIdsForCurrentUser,