diff --git a/client-app/src/App.tsx b/client-app/src/App.tsx index 8346ae3..bfdff1e 100644 --- a/client-app/src/App.tsx +++ b/client-app/src/App.tsx @@ -11,6 +11,7 @@ import UserEditPage from "./pages/UserEditPage/UserEditPage"; import ScriptListPage from "./pages/ScriptListPage/ScriptListPage"; import ScriptEditPage from "./pages/ScriptEditPage/ScriptEditPage"; import ObjectEditPage from "./pages/ObjectEditPage/ObjectEditPage"; +import ExtensionListPage from "./pages/ExtensionListPage/ExtensionListPage"; const App: React.FC = () => { @@ -35,6 +36,7 @@ const App: React.FC = () => { } /> } /> } /> + } /> } /> } /> diff --git a/client-app/src/components/AdminLayout/.module.css b/client-app/src/components/AdminLayout/.module.css index bcdd280..455ffa1 100644 --- a/client-app/src/components/AdminLayout/.module.css +++ b/client-app/src/components/AdminLayout/.module.css @@ -6,7 +6,6 @@ bottom: 0; display: grid; grid-template-columns: 73px 1fr; - transition: 0.5s; } .log_out_panel { @@ -168,10 +167,14 @@ height: 70px; } -.page:hover { +.page:not(.current_page):hover { background-color: rgb(0, 51, 255); } +.current_page { + background-color: rgb(162, 32, 255); +} + .page_img { position: absolute; left: 16px; diff --git a/client-app/src/components/AdminLayout/AdminLayout.tsx b/client-app/src/components/AdminLayout/AdminLayout.tsx index 322b6e3..b4c6f41 100644 --- a/client-app/src/components/AdminLayout/AdminLayout.tsx +++ b/client-app/src/components/AdminLayout/AdminLayout.tsx @@ -1,24 +1,13 @@ import React from "react"; import { Outlet, useNavigate } from "react-router-dom"; -import { ApiExtensions } from "../../services/api/extensions"; import { ApiAuth } from "../../services/api/auth"; import cl from './.module.css'; import Space from "../Space/Space"; import ModalWindow from "../ModalWindow/ModalWindow"; -type ShortExtensionInfo = { - id: string, - name: string, - url: string -} - const AdminLayout = () => { - - const [chosenMenu, openMenu] = React.useState(undefined); - const [isInstalledExtMenuOpened, installedExtMenuState] = React.useState(false); const [isNavMenuOpened, setNavMenuState] = React.useState(false); const [isModWinVisible, setModWinVisibility] = React.useState(false); - const [extensionList, setExtensionList] = React.useState>([]); const navigate = useNavigate(); @@ -28,11 +17,6 @@ const AdminLayout = () => { }); } - function MoveTo(path: string) { - openMenu(undefined); - navigate(path); - } - function GetTitle() { var path = window.location.pathname; @@ -64,6 +48,10 @@ const AdminLayout = () => { } } + if (path === "/admin/extensions") { + return "Extensions"; + } + if (path === "/admin/users") { return "Users"; } @@ -79,26 +67,6 @@ const AdminLayout = () => { return "UNDEFINED LOCATION"; } - function RenderInstalledExtensions() { - var result: Array = []; - - extensionList.map((el) => { - result.push( -
-

{ if (el.url) { window.location.href = el.url } }}>{el.name}

-
- ); - }); - - return result; - } - - React.useEffect(() => { - ApiExtensions.getExtensions().then((res) => { - setExtensionList([...res]); - }); - }); - return (
@@ -115,7 +83,8 @@ const AdminLayout = () => { System
-
MoveTo('/admin')} title="System info"> +
navigate('/admin')} title="System info"> system info System info
@@ -125,15 +94,15 @@ const AdminLayout = () => { Object
-
MoveTo('/admin/objects')} title="Objects"> +
navigate('/admin/objects')} title="Objects"> objects Objects
-
+
devices Devices
-
+
rooms Rooms
@@ -143,15 +112,15 @@ const AdminLayout = () => { Automation
-
+
schedules Schedules
-
MoveTo('/admin/scripts')} title="Scripts"> +
navigate('/admin/scripts')} title="Scripts"> scripts Scripts
-
+
triggers Triggers
@@ -161,7 +130,7 @@ const AdminLayout = () => { Extensions
-
+
navigate('/admin/extensions')} title="Extensions"> extensions Extensions
@@ -171,7 +140,7 @@ const AdminLayout = () => { Users
-
MoveTo('/admin/users')} title="Users"> +
navigate('/admin/users')} title="Users"> users Users
diff --git a/client-app/src/pages/ExtensionListPage/.module.css b/client-app/src/pages/ExtensionListPage/.module.css new file mode 100644 index 0000000..0014799 --- /dev/null +++ b/client-app/src/pages/ExtensionListPage/.module.css @@ -0,0 +1,246 @@ +.list_control_panel { + position: relative; + display: flex; + padding-left: 10px; +} + +.search_type_panel { + position: relative; + display: flex; + flex-wrap: wrap; + background-color: rgb(228, 255, 250); + border: 2px solid blue; + border-radius: 5px; +} + +.search_type_option_cont { + padding: 5px; +} + +.search_type_option { + cursor: pointer; + width: 100px; + background-color: #2828ff; + color: white; + padding-block: 5px; + border-radius: 5px; +} + +.search_type_option:not(.search_type_option_current):hover { + background-color: rgb(48, 145, 255); +} + +.search_type_option_current { + background-color: rgb(136, 0, 255); +} + +.search_type_option_text { + text-align: center; + font-size: 20px; +} + +.search_type_option_browse { + left: 1vw; +} + +.search_type_option_installed { + left: calc(100px + 2vw); +} + +.search_type_option_updates { + left: calc(200px + 3vw); +} + +.extension_record { + position: relative; + display: grid; + grid-template-columns: 80% 20%; + border: 3px solid rgb(0, 0, 178); + background-color: white; + width: calc(100% - 20px); + border-radius: 15px; + height: fit-content; + padding: 7px; +} + +@media (max-width: 385px) { + .extension_record { + display: block; + } +} + +@media (max-device-width: 385px) { + .extension_record { + display: block; + } +} + +.extension_info_part { + position: relative; +} + +.extension_main_info_cont { + display: flex; + flex-wrap: wrap; + width: 100%; +} + +.extension_img { + background-color: grey; + border: 1px solid black; + width: 60px; + height: 60px; +} + +.extension_name_and_author_cont { + display: grid; + grid-template-rows: 1.3fr 1fr; + padding-left: 7px; + width: fit-content; +} + +.extension_author { + font-size: 19px; +} + +.active_text_link:hover { + cursor: pointer; + color: blue; +} + +.extension_description_cont { + padding-top: 10px; + width: 100%; +} + +.extension_description { + text-align: justify; + white-space: normal; +} + +.tag_cont { + display: flex; + flex-wrap: wrap; +} + +.tag { + padding-top: 13px; +} + +.tag:not(:last-child) { + padding-right: 7px; +} + +.tag>span { + cursor: pointer; + border-radius: 8px; + background-color: #517fff; + color: white; + padding: 5px; +} + +.tag>span:hover { + background-color: rgb(54, 228, 255); +} + +.stat_cont { + position: relative; + display: flex; + flex-wrap: wrap; + width: 100%; +} + +.installed_count_cont { + display: flex; + flex-wrap: nowrap; + align-items: center; + justify-content: center; + width: fit-content; + margin-right: 30px; + margin-top: 10px; +} + +.installed_count_text { + font-weight: bold; +} + +.installed_count_img { + content: url(./img/installed.png); + width: 20px; + margin-left: 5px; +} + +.last_update_cont { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: center; + width: fit-content; + margin-top: 10px; +} + +.last_update_text { + font-weight: bold; +} + +.extension_version_control_part { + position: relative; +} + +@media (max-width: 385px) { + .extension_version_control_part { + padding-top: 10px; + } +} + +@media (max-device-width: 385px) { + .extension_version_control_part { + padding-top: 10px; + } +} + +.extension_version_cont { + width: 100%; +} + +.extension_current_version { + text-align: right; + font-weight: bold; +} + +.extension_new_version { + text-align: right; + font-weight: bold; + color: goldenrod; + margin-top: 10px; +} + +.extension_actions { + position: relative; + width: 100%; + margin-top: 10px; +} + +.extension_install_button_cont { + display: flex; + justify-content: flex-end; + width: 100%; +} + +.extension_install_button { + cursor: pointer; + background-color: rgb(61, 74, 255); + width: fit-content; + padding: 5px; + border-radius: 5px; +} + +.extension_install_button:hover { + background-color: rgb(0, 208, 255); +} + +.extension_install_button_text { + color: white; + font-size: 20px; + font-weight: bold; +} \ No newline at end of file diff --git a/client-app/src/pages/ExtensionListPage/ExtensionListPage.tsx b/client-app/src/pages/ExtensionListPage/ExtensionListPage.tsx new file mode 100644 index 0000000..5bafff7 --- /dev/null +++ b/client-app/src/pages/ExtensionListPage/ExtensionListPage.tsx @@ -0,0 +1,179 @@ +import React from "react"; +import cl from "./.module.css"; +import { ApiExtensions } from "../../services/api/extensions"; +import Space from "../../components/Space/Space"; +import LoadingAnimation from "../../components/LoadingAnimation/LoadingAnimation"; +import CustomTextarea from "../../components/CustomTextarea/CustomTextarea"; + +type ExtensionData = { + id: string, + name: string, + author: string, + version: string, + description?: string, + url?: string, + authorUrl?: string +} + +enum ExtensionFilter { + Browse = 0, + Installed = 1, + Updates = 2 +} + +const ExtensionListPage = () => { + + const [isLoading, setLoadingState] = React.useState(false); + const [extensions, setExtensions] = React.useState>([]); + const [extensionFilter, setExtensionFilter] = React.useState(ExtensionFilter.Browse); + const [search, setSearch] = React.useState(''); + + async function UpdateExtensions() { + setLoadingState(true); + + await ApiExtensions.getExtensions().then(data => { + setExtensions(data); + }); + + setLoadingState(false); + } + + function RenderExtensions() { + if (isLoading) { + return ( +
+ + +
+ ); + } + + var result: Array = []; + var sortedExtensions: Array = [...extensions]; + + sortedExtensions.sort((a, b) => { + if (a.name.toLowerCase() < b.name.toLowerCase()) { + return -1; + } + if (a.name.toLowerCase() > b.name.toLowerCase()) { + return 1; + } + return 0; + }); + + sortedExtensions.map((extension) => { + if (search !== '' && + !extension.name.toLowerCase().includes(search.toLowerCase()) && + !extension.author.toLowerCase().includes(search.toLowerCase()) && + !extension.description?.toLowerCase().includes(search.toLowerCase())) { + return; + } + + result.push( +
+ +
+
+
+ +
+

{ + if (extension.url) { + window.location.href = (extension.url ?? ""); + } + }}>{extension.name}

+

{ + if (extension.authorUrl) { + window.location.href = (extension.authorUrl ?? ""); + } + }}>by {extension.author}

+
+
+
+

{extension.description}

+
+
+
logs
+
logs
+
logs
+
logs
+
logs
+
logs
+
logs
+
logs
+
+
+
+ 659.4k + +
+
+ Last update 2 days ago +
+
+
+
+
+

{extension.version}

+

1.0.1

+
+
+
+
+ Install +
+
+
+
+
+
+ ); + }); + + return result; + } + + React.useEffect(() => { + document.body.style.backgroundColor = 'whitesmoke'; + UpdateExtensions(); + }, []); + + return ( +
+ +
+ ) => setSearch(e.target.value)} /> +
+ +
+
+
+
+
setExtensionFilter(ExtensionFilter.Browse)}> +

Browse

+
+
+
+
setExtensionFilter(ExtensionFilter.Installed)}> +

Installed

+
+
+
+
setExtensionFilter(ExtensionFilter.Updates)}> +

Updates

+
+
+
+ {RenderExtensions()} + +
+
+
+ ); +} + +export default ExtensionListPage; \ No newline at end of file diff --git a/client-app/src/pages/ExtensionListPage/img/installed.png b/client-app/src/pages/ExtensionListPage/img/installed.png new file mode 100644 index 0000000..e8b06ab Binary files /dev/null and b/client-app/src/pages/ExtensionListPage/img/installed.png differ diff --git a/client-app/src/pages/ScriptListPage/.module.css b/client-app/src/pages/ScriptListPage/.module.css index f8b7a81..0ddd06c 100644 --- a/client-app/src/pages/ScriptListPage/.module.css +++ b/client-app/src/pages/ScriptListPage/.module.css @@ -106,7 +106,7 @@ .list_control_panel { position: relative; display: flex; - padding-left: 2%; + padding-left: 10px; } .add_script_button { @@ -128,7 +128,7 @@ .script_record { border: 3px solid rgb(0, 0, 178); - width: 100%; + width: calc(100% - 6px); background-color: white; color: rgb(57, 75, 108); padding-block: 15px; diff --git a/client-app/src/pages/ScriptListPage/ScriptListPage.tsx b/client-app/src/pages/ScriptListPage/ScriptListPage.tsx index 9cbbd5a..913e69d 100644 --- a/client-app/src/pages/ScriptListPage/ScriptListPage.tsx +++ b/client-app/src/pages/ScriptListPage/ScriptListPage.tsx @@ -117,13 +117,14 @@ const ScriptListPage = () => { } function RenderScriptList() { - if (!isListLoaded) + if (!isListLoaded) { return (
); + } var res = []; var fixedScripts: Array = [...scripts]; @@ -217,7 +218,7 @@ const ScriptListPage = () => {
-
+
{ } function RenderUserList() { - if (!isListLoaded) + if (!isListLoaded) { return (
); + } var res = []; var fixedUsers: Array = [...users]; @@ -228,7 +229,7 @@ const UserListPage = () => {
-
+