MoveTo('/admin/users')} title="Users">
+
navigate('/admin/users')} title="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
+
+
+
+
+
+ );
+ });
+
+ 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 = () => {