From 362eeab9ce96d3c4d3b04c598e02bea620b72625 Mon Sep 17 00:00:00 2001 From: vasya Date: Sat, 14 Mar 2026 20:08:21 +0300 Subject: [PATCH 01/11] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D1=8E=20=D1=80=D0=BE=D1=83=D1=82=20=D0=B2=D1=8B=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=20=D0=BC=D0=B5=D0=BD=D1=8E=20=D1=81=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B8=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D0=B8=D1=8F=D0=BC?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- routes/web.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/routes/web.php b/routes/web.php index 86a06c5..995738a 100644 --- a/routes/web.php +++ b/routes/web.php @@ -5,3 +5,6 @@ use Illuminate\Support\Facades\Route; Route::get('/', function () { return view('welcome'); }); +Route::get('/menu', function () { + return view('menu_start'); +})->name('magic_menu'); -- 2.52.0 From 659bcb88f6d9670123f18948042a58bc61aa9eec Mon Sep 17 00:00:00 2001 From: vasya Date: Sat, 14 Mar 2026 20:37:08 +0300 Subject: [PATCH 02/11] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D1=8E=20=D0=BF=D1=83=D1=81=D1=82=D0=BE=D0=B9=20=D1=84?= =?UTF-8?q?=D0=B0=D0=B9=D0=BB=20=D1=81=20api=20=D0=B5=D0=BD=D0=B4=D0=BF?= =?UTF-8?q?=D0=BE=D0=B8=D0=BD=D1=82=D0=B0=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- routes/api.php | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 routes/api.php diff --git a/routes/api.php b/routes/api.php new file mode 100644 index 0000000..e69de29 -- 2.52.0 From 2baec23c1e5f365daa3c99f17d2f71df1c22dc7b Mon Sep 17 00:00:00 2001 From: vasya Date: Sat, 14 Mar 2026 20:38:54 +0300 Subject: [PATCH 03/11] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D1=8E=20api=20=D0=B5=D0=BD=D0=B4=D0=BF=D0=BE=D0=B8=D0=BD?= =?UTF-8?q?=D1=82=D1=8B=20=D0=B4=D0=BB=D1=8F=20=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D1=8B=20=D1=81=20=D0=BC=D0=B5=D0=BD=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- routes/api.php | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/routes/api.php b/routes/api.php index e69de29..7edc9b0 100644 --- a/routes/api.php +++ b/routes/api.php @@ -0,0 +1,23 @@ + Date: Sat, 21 Mar 2026 19:45:52 +0300 Subject: [PATCH 04/11] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D1=8E=20=D0=BA=D0=BE=D0=BD=D1=82=D1=80=D0=BE=D0=BB=D0=BB?= =?UTF-8?q?=D0=B5=D1=80=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=8B=20=D1=81=20?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D1=8E=20=D0=BF=D1=80=D0=B8=D0=BB=D0=BE=D0=B6?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Http/Controllers/MenuController.php | 133 ++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 app/Http/Controllers/MenuController.php diff --git a/app/Http/Controllers/MenuController.php b/app/Http/Controllers/MenuController.php new file mode 100644 index 0000000..a70a8b3 --- /dev/null +++ b/app/Http/Controllers/MenuController.php @@ -0,0 +1,133 @@ +userLogin = 'dgavrilov'; + } + + + /** + * Получение всех записей из таблицы с приложениями для меню + * TODO + * передавай флаг isActive и используй его для получения записей с приложениями меню архивных и не архивных + * + * @return mixed + */ + public function getApps() + { + //Приложения старого мэджик из скрипта Config_AD + $oldApps = $this->getOldApps(); + #Гаврилов + //НОВЫЕ ПРИЛОЖЕНИЯ НЕ ИСПОЛЬЗУЕШЬ + //Приложения нового мэджик из базы данных + #Гаврилов + //отрисовывать только то, что может видеть пользователь + $newApps = Models\MagicApps::get()->toArray(); + + return response()->json($oldApps); + } + + + /** + * Метод получает конфиг со старыми приложениями Magic + * + * @return string + */ + public function getOldApps() + { + $oldAppConf = json_decode(file_get_contents('http://cs/magic/return_config.AD.php')); + + return $oldAppConf; + } + + + /** + * Метод должен проверить есть ли избранные приложения у пользователя. Если есть, их необходимо обновить либо добавив, либо убрав то приложение, по которому кликнул пользователь. Если избранных приложений нет - вставить новую запись + * + * @return boolean + */ + public function updateUserFavApp(Request $rqst) + { + #Гаврилов + //ВНИЗУ ИСПОЛЬЗУЕТСЯ ЛОГИН DGAVRILOV, ПЕРЕПИШИ НА ЛОГИН ПОЛЬЗОВАТЕЛЯ MAGIC + $userFavApp = $this->getUserFavApp('dgavrilov'); + $appName = $rqst->all()['appName']; + $newFavAppList = null; + //Если массив с избранными приложениями пустой - пользователь не добавил ни 1 приложения мэджик в избранное + if (!$userFavApp) { + $newFavAppList = $appName; + } else { + $currentFavApp = $userFavApp; + if (in_array($appName, $currentFavApp) !== false) { + $newFavAppList = implode(';', array_filter($currentFavApp, function($el) use($appName) {return $el !== $appName;})); + } else { + $newFavAppList = implode(';', array_merge($currentFavApp, [$appName])); + } + } + + if ($newFavAppList) { + #Гаврилов + //ПРИ ВЫЗОВЕ ИЗ REACT НЕ ОБНОВЛЯЕТСЯ ПОЛЕ UPDATE_AT + $this->insertFavApp($newFavAppList); + //Если список приложений пуст - просто удаляем запись с избранными приложениями пользователя + } else { + $this->delAllUserFavApp('dgavrilov'); + } + return $this->getUserFavApp('dgavrilov'); + } + + #Гаврилов + //try catch для отслеживания ошибок вставки записей в БД? + + /** + * Метод вставки новой записи с избранными приложениями + * + * @return boolean + */ + public function insertFavApp($appName) + { + Models\UserFavApp::updateOrCreate( + ['user_login' => $this->userLogin], + ['fav_apps' => $appName] + ); + + return true; + } + + + /** + * Метод удаляет запись с избранными приложениями пользователя + * + * @param string $userLogin логин пользователя + * @return boolean + */ + public function delAllUserFavApp($userLogin) + { + Models\UserFavApp::where('user_login', $userLogin)->delete(); + + return true; + } + + + /** + * Метод получает избранные приложения пользователя + * + * @param string $userLogin логин пользователя + * @return array + */ + public function getUserFavApp(string $userLogin): array + { + #Гаврилов + //ЗДЕСЬ ВМЕСТО DGAVRILOV ДОЛЖНО БЫТЬ ОБРАЩЕНИЕ К КУКАСАМ, ЧТОБЫ БРАТЬ ЛОГИН ОТТУДА + $userFavApp = Models\UserFavApp::where('user_login', $userLogin)->first(); + + return $userFavApp ? explode(';', $userFavApp['fav_apps']) : []; + } +} -- 2.52.0 From 123fc969f060a6c8ad094adf8484429c04a94c81 Mon Sep 17 00:00:00 2001 From: vasya Date: Sat, 21 Mar 2026 19:48:37 +0300 Subject: [PATCH 05/11] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D1=8E=20=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB=D1=8C=20=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82=D1=8B=20=D1=81=20=D0=B8=D0=B7=D0=B1?= =?UTF-8?q?=D1=80=D0=B0=D0=BD=D0=BD=D1=8B=D0=BC=D0=BC=D0=B8=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D0=B8=D1=8F=D0=BC=D0=B8=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5?= =?UTF-8?q?=D0=BB=D1=8F=20=D0=B8=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86?= =?UTF-8?q?=D1=8B=20=D0=91=D0=94,=20=D0=B3=D0=B4=D0=B5=20=D1=85=D1=80?= =?UTF-8?q?=D0=B0=D0=BD=D1=8F=D1=82=D1=81=D1=8F=20=D0=BF=D0=BE=D0=BB=D1=8C?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D1=8C=D1=81=D0=BA?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=B8=D0=B7=D0=B1=D1=80=D0=B0=D0=BD=D0=BD=D1=8B?= =?UTF-8?q?=D0=B5=20=D0=BF=D1=80=D0=B8=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Models/UserFavApp.php | 17 +++++++++++++++++ database/tables_for_magic2.0/user_fav_app.sql | 10 ++++++++++ .../user_fav_app_202602271736.sql | 2 ++ 3 files changed, 29 insertions(+) create mode 100644 app/Models/UserFavApp.php create mode 100644 database/tables_for_magic2.0/user_fav_app.sql create mode 100644 database/tables_for_magic2.0/user_fav_app_202602271736.sql diff --git a/app/Models/UserFavApp.php b/app/Models/UserFavApp.php new file mode 100644 index 0000000..04740af --- /dev/null +++ b/app/Models/UserFavApp.php @@ -0,0 +1,17 @@ + Date: Sat, 21 Mar 2026 19:51:37 +0300 Subject: [PATCH 06/11] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D1=8E=20=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB=D1=8C=20=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82=D1=8B=20=D1=81=D0=BE=20=D0=B2=D1=81?= =?UTF-8?q?=D0=B5=D0=BC=D0=B8=20=D0=BF=D1=80=D0=B8=D0=BB=D0=BE=D0=B6=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=D0=BC=D0=B8=20magic=202.0=20=D0=B8=20=D1=82?= =?UTF-8?q?=D0=B0=D0=B1=D0=BB=D0=B8=D1=86=D1=8B=20=D0=91=D0=94,=20=D0=B3?= =?UTF-8?q?=D0=B4=D0=B5=20=D1=85=D1=80=D0=B0=D0=BD=D1=8F=D1=82=D1=81=D1=8F?= =?UTF-8?q?=20=D0=BF=D1=80=D0=B8=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D0=B8=D1=8F?= =?UTF-8?q?=20magic=202.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Models/MagicApps.php | 19 +++++++++++++++++++ database/tables_for_magic2.0/magic_apps.sql | 13 +++++++++++++ .../magic_apps_202602271731.sql | 5 +++++ 3 files changed, 37 insertions(+) create mode 100644 app/Models/MagicApps.php create mode 100644 database/tables_for_magic2.0/magic_apps.sql create mode 100644 database/tables_for_magic2.0/magic_apps_202602271731.sql diff --git a/app/Models/MagicApps.php b/app/Models/MagicApps.php new file mode 100644 index 0000000..6497177 --- /dev/null +++ b/app/Models/MagicApps.php @@ -0,0 +1,19 @@ +hasMany(AppRoles::class, 'app_id', 'id') + ->orderBy('role_priority', 'asc'); + } +} diff --git a/database/tables_for_magic2.0/magic_apps.sql b/database/tables_for_magic2.0/magic_apps.sql new file mode 100644 index 0000000..af435d4 --- /dev/null +++ b/database/tables_for_magic2.0/magic_apps.sql @@ -0,0 +1,13 @@ +-- custom.magic_apps definition + +CREATE TABLE `magic_apps` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `app_name` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'Имя приложения', + `app_title` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'Название приложения на русском', + `app_link` varchar(150) COLLATE utf8mb4_unicode_ci NOT NULL, + `role_driver` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'Драйвер определения ролей: по группам AD, по почтовым рассылкам, по логинам. NULL, если ролевая модель не предусмотрена', + `access_groups_email` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'Доступ к приложениям по почтовым рассылкам', + `access_groups_ad` text COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'Доступ к приложениям по группам AD', + `is_active` tinyint(4) NOT NULL DEFAULT 1 COMMENT 'Активно ли приложение', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; \ No newline at end of file diff --git a/database/tables_for_magic2.0/magic_apps_202602271731.sql b/database/tables_for_magic2.0/magic_apps_202602271731.sql new file mode 100644 index 0000000..066da21 --- /dev/null +++ b/database/tables_for_magic2.0/magic_apps_202602271731.sql @@ -0,0 +1,5 @@ +INSERT INTO custom.magic_apps (app_name,app_title,app_link,role_driver,access_groups_email,access_groups_ad,is_active) VALUES + ('Test','','test.index',NULL,NULL,'CTXAL.CryptoPRO',1), + ('About','','about',NULL,NULL,'CTXAL.CryptoPRO',1), + ('Test create','','test.create',NULL,NULL,'CTXAL.CryptoPRO',1), + ('taxi','Реестр заказа такси','test','email','# Magic_admins',NULL,1); -- 2.52.0 From a5151145ec7bb0e9ae6bfb9c2687d0a1ef85721b Mon Sep 17 00:00:00 2001 From: vasya Date: Sat, 21 Mar 2026 19:56:39 +0300 Subject: [PATCH 07/11] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D1=8E=20blade=20=D1=88=D0=B0=D0=B1=D0=BB=D0=BE=D0=BD=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=BE=D1=82=D1=80=D0=B8=D1=81=D0=BE=D0=B2?= =?UTF-8?q?=D0=BA=D0=B8=20=D0=B2=20=D0=BD=D0=B5=D0=BC=20=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D1=8E=20magic=202.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resources/views/menu_start.blade.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 resources/views/menu_start.blade.php diff --git a/resources/views/menu_start.blade.php b/resources/views/menu_start.blade.php new file mode 100644 index 0000000..b6ccd81 --- /dev/null +++ b/resources/views/menu_start.blade.php @@ -0,0 +1,17 @@ + + + + + + Laravel + React + + + @viteReactRefresh + @vite(['resources/css/app.css', 'resources/js/app.jsx']) + + + + +
+ + \ No newline at end of file -- 2.52.0 From 2097d3487cb9d86c2ae86d720ab05d13b8084c87 Mon Sep 17 00:00:00 2001 From: vasya Date: Sat, 21 Mar 2026 20:02:25 +0300 Subject: [PATCH 08/11] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D1=8E=20react=20=D0=BA=D0=BE=D0=BC=D0=BF=D0=BE=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D1=82=20=D0=BC=D0=B5=D0=BD=D1=8E=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D0=B8=D0=B9=20magic=202.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resources/js/components/MenuApp.tsx | 231 ++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) create mode 100644 resources/js/components/MenuApp.tsx diff --git a/resources/js/components/MenuApp.tsx b/resources/js/components/MenuApp.tsx new file mode 100644 index 0000000..16e61b1 --- /dev/null +++ b/resources/js/components/MenuApp.tsx @@ -0,0 +1,231 @@ +import { Button } from '@SharePoint/rencredit_uikit'; +import React, { useEffect, useState } from "react"; + +function MenuApp () +{ + //Приложения и процессы Magic для отображения в меню + const [menuApps, setMenuApps] = useState<{ + 'proccesses': object, + 'scripts': object + }>({ + 'proccesses': {}, + 'scripts': {} + }); + //TODO + //ВНЕДРИ В КОНТРОЛЛЕРЕ ПРОВЕРКУ ДОСТУПОВ, А НЕ ВОЗВРАЩАЙ ВСЕ ПОДРЯД ПРИЛОЖЕНИЯ + //Избранные приложения пользователя + const [favApps, setFavApps] = useState([]); + //Массив избраннных процессов, в приложениях которых есть хотя бы одно избранное + const [favProcs, setFavProcs] = useState([]); + //Состояния видимости скрипта + const [hideScriptClass, setHideScriptClass] = useState(''); + //const [sanctumToken, setSanctumToken] = useState(''); + + const sanctumToken = () => { + const metaTag = document.getElementById('sanctum_token_block') as HTMLMetaElement; + return metaTag.dataset.token; + } + + //Получаем при рендере страницы все приложения Magic и все избранные приложения пользователя + useEffect( () => { + Promise.all( + [ + fetch('api/magic_apps').then(menuAppsRes => menuAppsRes.json()), + //TODO + //СЮДА ПОТЯГИВАЙ ЛОГИН ПОЛЬЗОВАТЕЛЯ, А НЕ DGAVRILOV + fetch('api/user_fav_app/dgavrilov').then(favAppsRes => favAppsRes.json()) + ] + ).then( + ([ + responseMenuApp, + responseFavApp + ]) => { + setMenuApps(responseMenuApp); + setFavApps(responseFavApp); + } + ) + }, []); + + + //Обновление видимости процесса (собрания приложений) в зависимости от того находится ли в избранном хотя бы одно приложение + useEffect( () => { + if (menuApps === null) { return } + //Массив с процессами, в которых есть хотя бы одно избранное приложение + const favProcsArr:string[] = []; + //Мы собираем все избранные приложения в массив-состояние, чтобы при изменении состояния каждого приложения (например при переключении switcher) проверять входит ли это приложение в избранные. Если входит - его родительский процесс не прячем, так как в его дочерних приложениях есть избранные + Object.entries(menuApps.proccesses).forEach( (procData) => { + //Флаг - есть ли в приложениях процесса хотя бы 1 избранное + const hasFavorite: boolean = procData[1].tabs.split(';').some( (tab: string) => { + return favApps.includes(tab); + }) + if (hideScriptClass !== 'script-hide' || hasFavorite) { + favProcsArr.push(procData[0]); + } + }) + setFavProcs(favProcsArr); + }, [hideScriptClass, menuApps, favApps]); + + //console.log(sanctumToken()) + + //ГАВРИЛОВ + //ПОЧЕМУ КОД НИЖЕ ИСПОЛНЯЕТСЯ ПОСТОЯННО ПОКА НЕ БУДЕТ ПОЛУЧЕН КОНТЕНТ ДЛЯ СТРАНИЦЫ ИЗ ПРОМИСОВ ВЫШЕ, А НЕ ОТРАБАТЫВАЕТ ТОЛЬКО ПРИ РЕНДЕРИНГЕ СТРАНИЦЫ + //Уместно ли отслеживать состояние до получения запросов fetch в подобном виде? + if (menuApps === null || favApps === null) { + return прелоадер + } else { + return ( + + ) + } +} + + +//Гаврилов +//ПЕРЕПИСАТЬ АРГУМЕНТЫ ПОД ОБЪЕКТ СО СВОЙСТВАМИ, ИСПОЛЬЗОВАТЬ ...obj +/** + * + * @param {int} appIndex ключ для экземлпяра компонента + * @param {string} appName уникальное имя скрипта + * @param {string} appTitle название скрипта в меню + * @param {string} favIconClassName класс для иконки избранного + * @param {string} hideAppClass класс для видимости приложения + * @param {string} setUpdateFavApps функция для обновления состояния избранны приложений (при снятия, установки признака избранности) + * @returns + */ +function AppElem({ + appIndex, + appName, + appTitle, + appUrl, + favIconClassName, + hideAppClass, + setUpdateFavApps +} : { + appIndex: string, + appName: string, + appTitle: string, + appUrl: string, + favIconClassName: string, + hideAppClass: string, + setUpdateFavApps: string +}) { + const [appElemClass, changeFav] = useState(favIconClassName); + const callChangeFav = ( changeAppName: string ) => { + fetch('api/user_fav_app', { + method: 'post', + body: JSON.stringify({ appName: changeAppName }), + headers: { + 'content-type': 'application/json' + } + } + ) + .then( (response) => response.json() ) + .then( (response) => { + //Если скрипт был избранным - удаляем из избранного и наоборот + appElemClass == 'favorite' ? changeFav('not_favorite') : changeFav('favorite'); + //Возвращаем обновленный список избранных приложений пользователя + setUpdateFavApps(response?.fav_apps?.split( ';' ) || []) + } ) + } + + return ( + //Если приложение в избранном - оно всегда должно быть "видимо", даже если переключатель в положении Скрыть неизбранные приложения +
+ + {/* Анонимная функция нужна для создания функции смены состояния для каждого компонента в отдельности, в противном случае вызов функции в одном экземпляре компонента вызывает функцию изменения для каждого экземпляра компонента */} + callChangeFav(appName) }> +
+ ) +} + + +//TODO +//ВЫНЕСИ В ПАПКУ COMPONENTS/MAIN +/** + * Компонент переключателя В ДАННОМ СЛУЧАЕ видимости скриптов (видны только избранные или все) + * @param {string} switcherId идентификатор переключателя (для стилей css), так как в будущем, на странице можно будет размещать несколько переключателей + * @param {function} toggleAppsVisible функция обновления состояния hideScriptClass + * @returns + */ +function Switcher({ switcherId, toggleAppsVisible }) { + const [favSwitcherClass, setFavSwitcherClass] = useState('showAll'); + + //Переключение состояния переключателя после рендеринга страницы + useEffect( () => { + //Получаем из локал сторадж состояние переключателя + const savedState = localStorage.getItem('magicMenuFavSwitcher'); + if (savedState) { + setFavSwitcherClass(savedState); + } + }, []); + + //При изменении состояния Переключателя изменяется состояние всех приложени (переключается их видимость в зависимости от состояния переключателя - только избранные или все) + useEffect( () => { + //Синхронизируем зависимые компоненты + toggleAppsVisible(favSwitcherClass === 'showFav' ? 'script-hide' : ''); + }, [favSwitcherClass] ); + + const callToggleFavSwitcher = () => { + let switcherState = (favSwitcherClass === 'showFav' ? 'showAll' : 'showFav'); + //favSwitcherClass => favSwitcherClass = ... - функциональное обновление. Здесь оно не особо нужно, но чтобы не забыть + //Меняем класс switcher, а также меняем состояние видимости всех приложений (в зависимости от того избранные они или нет) + setFavSwitcherClass( favSwitcherClass => { + if (favSwitcherClass === 'showFav') { + toggleAppsVisible('script-hide') + } else { + toggleAppsVisible('') + } + localStorage.setItem('magicMenuFavSwitcher', switcherState) + + return switcherState; + } ) + } + + return ( +
+ +
+ ) +} + +export default MenuApp; -- 2.52.0 From 52920040a1a8331e4b4b41d7e066145d611056ea Mon Sep 17 00:00:00 2001 From: vasya Date: Sat, 21 Mar 2026 20:03:39 +0300 Subject: [PATCH 09/11] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D1=8E=20css=20=D1=81=D1=82=D0=B8=D0=BB=D0=B8=20=D1=81?= =?UTF-8?q?=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=86=D1=8B=20=D1=81=20=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D1=8E=20=D0=BF=D1=80=D0=B8=D0=BB=D0=BE=D0=B6=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B9=20Magic=202.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resources/css/app.css | 196 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 187 insertions(+), 9 deletions(-) diff --git a/resources/css/app.css b/resources/css/app.css index 3e6abea..ff2d0ca 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -1,11 +1,189 @@ -@import 'tailwindcss'; +/* ГАВРИЛОВ. ВЫЯСНИТЬ, ГДЕ ИСПОЛЬЗУЮТСЯ */ -@source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php'; -@source '../../storage/framework/views/*.php'; -@source '../**/*.blade.php'; -@source '../**/*.js'; - -@theme { - --font-sans: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', - 'Segoe UI Symbol', 'Noto Color Emoji'; +html { + overflow-y: scroll; +} + +#root{ + --color_ruby: #ff0078; +} + +.container { + background-color: lightblue; + padding: 20px; +} + +#menu-container{ + display: flex; + + &>#menu__left-block{ + flex-basis: 15%; + + &>.menu__left-block__call-app{ + display: flex; + + &>.fa{ + flex-basis: 20%; + } + } + } +} + +.switcher-container{ + position: fixed; + top: 0; + right: 0; + display: flex; + justify-content: flex-end; + align-items: center; + + &>.switch { + position: relative; + display: inline-block; + width: 60px; + height: 34px; + margin: 9px; + + &>.switcher__favorite-app { + opacity: 0; + width: 0; + height: 0; + + &.showFav + .slider{ + background-color: var(--color_ruby); + + &:before{ + transform: translateX(26px); + color: var(--color_ruby); + padding: 2px 0 0 0; + align-content: baseline; + } + } + } + + &>.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc; + -webkit-transition: .4s; + transition: .4s cubic-bezier(0,1,0.5,1); + border-radius: 4px; + + @import url('https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css'); + &:before { + position: absolute; + content: "\f006"; + font-family: FontAwesome; + text-align: center; + font-size: 1.2rem; + height: 26px; + width: 26px; + left: 4px; + bottom: 4px; + background-color: white; + -webkit-transition: .4s; + transition: .4s cubic-bezier(0,1,0.5,1); + border-radius: 3px; + } + + &.round { + border-radius: 34px; + + &:before { + border-radius: 50%; + } + } + } + } +} + + + + +.switcher__favorite-app.showFav + .slider { + background-color: var(--color_ruby); +} +.switcher__favorite-app.showFav + .slider:before { + transform: translateX(26px); +} +/* Rounded sliders */ +/* .slider.round { + border-radius: 34px; + + &:before { + border-radius: 50%; + } +} */ + +#round { + border-radius: 34px; + + &:before { + border-radius: 50%; + } +} + +#menu__app-container__app-block{ + /* display: grid; + grid-template-columns: 50% 50%; */ + column-count: 2; + + >.apps-block__proc{ + margin-bottom: 20px; + + >.proc__title{ + font-size: 1.1rem; + padding: 10px 0; + font-weight: 600; + } + + >.proc__title.proc-hide{ + display: none; + } + } + + .script-list__el{ + display: flex; + + >.script-list__el__script-name{ + margin-bottom: 5px; + transition: 0.2s; + &:hover{ + transform: translateY(-1px); + } + + >a{ + text-decoration: none; + color: black; + + &:hover{ + color: var(--color_ruby); + } + } + } + + >.fa-star{ + margin-left: 5px; + cursor: pointer; + opacity: 0.2; + transition: 0.3s; + } + + >.fa-star:hover{ + opacity: 1; + } + + >.fa-star.favorite{ + opacity: 1; + color: var(--color_ruby); + } + } + + .script-list__el.script-hide{ + display: none; + } } -- 2.52.0 From 738c4535dc769cebfc7b30dd29bdf580efeeba8d Mon Sep 17 00:00:00 2001 From: vasya Date: Sat, 21 Mar 2026 20:37:16 +0300 Subject: [PATCH 10/11] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D1=8E=20=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB=D1=8C=20=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82=D1=8B=20=D1=81=20=D1=80=D0=BE=D0=BB?= =?UTF-8?q?=D1=8F=D0=BC=D0=B8=20=D0=BF=D0=BE=20=D0=BF=D1=80=D0=B8=D0=BB?= =?UTF-8?q?=D0=BE=D0=B6=D0=B5=D0=BD=D1=8F=D0=BC=D0=B8=20magic=202.0=20?= =?UTF-8?q?=D0=B8=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86=D1=8B=20=D0=91?= =?UTF-8?q?=D0=94,=20=D0=B3=D0=B4=D0=B5=20=D1=85=D1=80=D0=B0=D0=BD=D1=8F?= =?UTF-8?q?=D1=82=D1=81=D1=8F=20=D1=80=D0=BE=D0=BB=D0=B8=20=D0=BF=D0=BE=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B8=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D1=8F=D0=BC=20?= =?UTF-8?q?magic=202.0.=20=D0=A1=D0=B5=D0=B9=D1=87=D0=B0=D1=81=20=D1=80?= =?UTF-8?q?=D0=BE=D0=BB=D0=B8=20=D1=80=D0=B0=D1=81=D0=BF=D1=80=D0=B5=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D1=8F=D1=82=D1=81=D1=8F=20=D0=BF=D0=BE=20=D0=BB?= =?UTF-8?q?=D0=BE=D0=B3=D0=B8=D0=BD=D0=B0=D0=BC,=20=D0=BD=D0=B5=D0=BE?= =?UTF-8?q?=D0=B1=D1=85=D0=BE=D0=B4=D0=B8=D0=BC=D0=BE=20=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D0=BF=D0=B8=D1=81=D0=B0=D1=82=D1=8C=20=D0=BF=D0=BE=D0=B4?= =?UTF-8?q?=20=D0=B2=D1=8B=D0=B4=D0=B0=D1=87=D1=83=20=D1=80=D0=BE=D0=BB?= =?UTF-8?q?=D0=B5=D0=B9=20=D0=BF=D0=BE=20=D0=B3=D1=80=D1=83=D0=BF=D0=BF?= =?UTF-8?q?=D0=B0=D0=BC=20=D0=B4=D0=BE=D1=81=D1=82=D1=83=D0=BF=D0=B0.=20?= =?UTF-8?q?=D0=AF=20=D0=BD=D0=B5=20=D1=83=D1=81=D0=BF=D0=B5=D0=BB=20=D0=BF?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D0=B4=D0=B5=D0=BB=D0=B0=D1=82=D1=8C=20=D0=BB?= =?UTF-8?q?=D0=BE=D0=B3=D0=B8=D0=BA=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Models/AppRoles.php | 18 ++++++++++++++++++ database/tables_for_magic2.0/app_roles.sql | 13 +++++++++++++ .../app_roles_202602271730.sql | 3 +++ 3 files changed, 34 insertions(+) create mode 100644 app/Models/AppRoles.php create mode 100644 database/tables_for_magic2.0/app_roles.sql create mode 100644 database/tables_for_magic2.0/app_roles_202602271730.sql diff --git a/app/Models/AppRoles.php b/app/Models/AppRoles.php new file mode 100644 index 0000000..4f8bd18 --- /dev/null +++ b/app/Models/AppRoles.php @@ -0,0 +1,18 @@ +belongsTo(MagicApps::class, 'app_id', 'id'); + } +} diff --git a/database/tables_for_magic2.0/app_roles.sql b/database/tables_for_magic2.0/app_roles.sql new file mode 100644 index 0000000..16fd62c --- /dev/null +++ b/database/tables_for_magic2.0/app_roles.sql @@ -0,0 +1,13 @@ +-- custom.app_roles definition + +CREATE TABLE `app_roles` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `app_id` bigint(20) unsigned NOT NULL COMMENT 'id приложения (связь с таблицей magic_apps)', + `app_role` text COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'Роль в приложении', + `app_title` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'Название роли на русском', + `role_priority` smallint(6) NOT NULL COMMENT 'Приоритет роли', + `role_access` text COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'Кому доступна роль (зависит от драйвера в magic_apps)', + PRIMARY KEY (`id`), + KEY `app_roles_app_id_foreign` (`app_id`), + CONSTRAINT `app_roles_app_id_foreign` FOREIGN KEY (`app_id`) REFERENCES `magic_apps` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Ролевая модель приложений'; \ No newline at end of file diff --git a/database/tables_for_magic2.0/app_roles_202602271730.sql b/database/tables_for_magic2.0/app_roles_202602271730.sql new file mode 100644 index 0000000..e8bf79e --- /dev/null +++ b/database/tables_for_magic2.0/app_roles_202602271730.sql @@ -0,0 +1,3 @@ +INSERT INTO custom.app_roles (app_id,app_role,app_title,role_priority,role_access) VALUES + (4,'admin','Администратор',1,'# Magic_admins'), + (4,'user','Пользователь',2,'# Test'); -- 2.52.0 From cda29ccaf9eaac67db9765cd5c98cdd5e629b572 Mon Sep 17 00:00:00 2001 From: vasya Date: Sat, 21 Mar 2026 20:51:03 +0300 Subject: [PATCH 11/11] =?UTF-8?q?=D0=B2=D1=85=D0=BE=D0=B4=D0=BD=D0=BE?= =?UTF-8?q?=D0=B9=20typescript=20=D0=B4=D0=BB=D1=8F=20=D1=84=D1=80=D0=BE?= =?UTF-8?q?=D0=BD=D1=82=D0=B0=20=D1=81=20=D0=BC=D0=B5=D0=BD=D1=8E=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B8=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D0=B8=D0=B9=20magic?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resources/js/app.tsx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 resources/js/app.tsx diff --git a/resources/js/app.tsx b/resources/js/app.tsx new file mode 100644 index 0000000..5b23c21 --- /dev/null +++ b/resources/js/app.tsx @@ -0,0 +1,14 @@ +import { createRoot } from 'react-dom/client'; +import '@SharePoint/rencredit_uikit/dist/static/fonts/mont/Mont.css'; +import '@fortawesome/fontawesome-free/css/all.css'; +import { UIKitThemeProvider } from '@SharePoint/rencredit_uikit'; +import MenuApp from './components/MenuApp.tsx'; // Создайте этот файл, если используете React +import React from 'react'; + +const container:HTMLElement = document.getElementById('root')!; +const root = createRoot(container); +root.render( + + + +); -- 2.52.0