Skip to content

Commit

Permalink
work on bridged instances
Browse files Browse the repository at this point in the history
  • Loading branch information
targoninc-alex committed May 31, 2024
1 parent e97d589 commit 24aec89
Show file tree
Hide file tree
Showing 8 changed files with 291 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions ui/api/Api.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,10 @@ export class Api extends ApiBase {
static async search(query = null) {
return await this.get("/api/users/search", {query});
}
static async getInstances() {
return await this.get("/api/bridging/getInstances", {});
}
static async addInstance(url = null, useAllowlist = null, enabled = null) {
return await this.post("/api/bridging/addInstance", {url, useAllowlist, enabled});
}
}
6 changes: 3 additions & 3 deletions ui/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,15 @@ h1 {
}

h2 {
font-size: 2rem;
font-size: 1.75rem;
}

h3 {
font-size: 1.75rem;
font-size: 1.5rem;
}

h4 {
font-size: 1.5rem;
font-size: 1.2rem;
}

span {
Expand Down
19 changes: 19 additions & 0 deletions ui/classes.css
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,21 @@
font-size: 0.8em;
}

.pill {
padding: 0.5em 1em;
border-radius: 9999px;
background: var(--text-3);
color: var(--bg);
font-size: 0.8em;
}

.circle {
border-radius: 50%;
width: 0.8em;
height: 0.8em;
background: var(--bg-3);
}

.align-center {
align-items: center;
}
Expand Down Expand Up @@ -299,4 +314,8 @@
--size: 38px;
width: var(--size);
height: var(--size);
}

.max800 {
max-width: 800px;
}
41 changes: 40 additions & 1 deletion ui/components/common.mjs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import {create, FjsObservable, ifjs, signal, signalFromProperty} from "https://fjs.targoninc.com/f.js";
import {computedSignal, create, FjsObservable, ifjs, signal, signalFromProperty} from "https://fjs.targoninc.com/f.js";
import {popup, removePopups, toast} from "../actions.mjs";
import {PopupComponents} from "./popup.mjs";
import {Api} from "../api/Api.mjs";
import {Live} from "../live/Live.mjs";
import {Popups} from "../api/Popups.mjs";
import {Store} from "../api/Store.mjs";

export class CommonTemplates {
static icon(icon, classes = [], tag = "span") {
Expand Down Expand Up @@ -83,6 +84,8 @@ export class CommonTemplates {
const activeIfActive = page => {
return (currentRoute && currentRoute.path === page) ? "active" : "_";
};
const user = Store.get('user');
const hasAnyRole = computedSignal(user, user => user && user.roles && user.roles.length > 0);

return create("div")
.classes("flex", "align-center", "full-width", "space-between", "padded")
Expand All @@ -93,6 +96,11 @@ export class CommonTemplates {
CommonTemplates.buttonWithIcon("chat", "Chat", () => window.router.navigate('chat'), [activeIfActive("chat")]),
CommonTemplates.buttonWithIcon("person_add", "New DM", () => Popups.newDm()),
).build(),
ifjs(hasAnyRole, create("div")
.classes("flex", "align-center")
.children(
CommonTemplates.buttonWithIcon("admin_panel_settings", "Administration", () => window.router.navigate('admin'), [activeIfActive("admin")]),
).build()),
create("div")
.classes("flex", "align-center")
.children(
Expand All @@ -102,6 +110,20 @@ export class CommonTemplates {
).build();
}

static circleIndicator(text, color = "var(--blue)") {
return create("div")
.classes("flex", "align-center")
.children(
create("span")
.classes("circle")
.styles("background-color", color)
.build(),
create("span")
.text(text)
.build()
).build();
}

static userInList(image, name, text, onclick) {
return create("button")
.classes("flex")
Expand Down Expand Up @@ -269,4 +291,21 @@ export class CommonTemplates {
.build()
).build();
}

static checkbox(id, label, value, onchange) {
return create("div")
.classes("flex", "small-gap")
.children(
create("input")
.type("checkbox")
.id(id)
.checked(value)
.onchange(onchange)
.build(),
create("label")
.for(id)
.text(label)
.build()
).build();
}
}
212 changes: 212 additions & 0 deletions ui/components/pages/admin.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
import {LayoutTemplates} from "../layout.mjs";
import {create, ifjs, signal, signalFromProperty, signalMap} from "https://fjs.targoninc.com/f.js";
import {CommonTemplates} from "../common.mjs";
import {Store} from "../../api/Store.mjs";
import {Api} from "../../api/Api.mjs";
import {popup, removePopups, toast} from "../../actions.mjs";
import {PopupComponents} from "../popup.mjs";

export class AdminComponent {
static render() {
return LayoutTemplates.pageFull(AdminComponent.content());
}

static content() {
const user = Store.get('user');

return create("div")
.classes("panes-v", "full-width", "full-height")
.children(
CommonTemplates.actions(),
create("div")
.classes("panes", "full-width", "flex-grow")
.children(
LayoutTemplates.pane(LayoutTemplates.centeredContent(
create("div")
.classes("flex-v", "padded")
.children(
create("h1")
.text("Administration")
.build(),
AdminComponent.roleList(user),
AdminComponent.permissionList(user),
AdminComponent.bridgeInstanceSettings()
).build()
), "100%", "500px", "100%")
).build()
).build();
}

static roleList(user) {
const roles = signalFromProperty(user, 'roles');

return create("div")
.classes("flex-v", "card")
.children(
create("h2")
.text("Your Roles")
.build(),
signalMap(roles,
create("div")
.classes("flex", "max800"),
role => AdminComponent.role(role)),
).build();
}

static role(role) {
return create("span")
.classes("pill")
.text(role.name)
.title(role.description)
.build();
}

static permissionList(user) {
const permissions = signalFromProperty(user, 'permissions');

return create("div")
.classes("flex-v", "card")
.children(
create("h2")
.text("Your Permissions")
.build(),
signalMap(permissions,
create("div")
.classes("flex", "max800"),
permission => AdminComponent.permission(permission)),
).build();
}

static permission(permission) {
return create("span")
.classes("pill")
.text(permission.name)
.title(permission.description)
.build();
}

static bridgeInstanceSettings() {
const bridgedInstances = signal([]);
const loading = signal(true);
Api.getInstances().then(res => {
loading.value = false;
if (res.status === 200) {
bridgedInstances.value = res.data;
} else {
toast("Failed to fetch bridged instances", "negative");
}
});

return create("div")
.classes("flex-v", "card")
.children(
create("h2")
.text("Bridged Instances")
.build(),
AdminComponent.bridgeInstanceActions(bridgedInstances),
ifjs(loading, CommonTemplates.spinner()),
signalMap(bridgedInstances,
create("div")
.classes("flex-v", "max800"),
instance => AdminComponent.bridgeInstance(instance)),
).build();
}

static bridgeInstanceActions(bridgedInstances) {
return create("div")
.classes("flex-v")
.children(
create("p")
.text("Bridged instances allow you to connect to other instances of Venel.")
.build(),
create("div")
.classes("flex", "max800")
.children(
CommonTemplates.buttonWithIcon("add_link", "Add Bridged Instance", () => {
popup(AdminComponent.addBridgedInstancePopup(() => {
removePopups();
}, bridgedInstances));
}),
).build(),
).build();
}

static addBridgedInstancePopup(onclose, bridgedInstances) {
const instanceInfo = signal({
url: "",
useAllowlist: false,
enabled: true
});
const url = signalFromProperty(instanceInfo, 'url');
const useAllowlist = signalFromProperty(instanceInfo, 'useAllowlist');
const enabled = signalFromProperty(instanceInfo, 'enabled');

return create("div")
.classes("flex-v", "card")
.children(
create("div")
.classes("flex", "space-between")
.children(
create("h3").text("Add instance").build(),
PopupComponents.closeButton(onclose),
).build(),
create("div")
.classes("flex-v", "max800")
.children(
CommonTemplates.input("url", "url", "URL", "URL of the instance", url, (e) => {
instanceInfo.value = {
...instanceInfo.value,
url: e.target.value
};
}, true),
CommonTemplates.checkbox("useAllowlist", "Use Allowlist", useAllowlist, (e) => {
instanceInfo.value = {
...instanceInfo.value,
useAllowlist: e.target.checked
};
}),
CommonTemplates.checkbox("enabled", "Enabled", enabled, (e) => {
instanceInfo.value = {
...instanceInfo.value,
enabled: e.target.checked
};
}),
).build(),
create("div")
.classes("flex", "space-between")
.children(
CommonTemplates.buttonWithIcon("close", "Cancel" , onclose),
CommonTemplates.buttonWithIcon("add_link", "Add", () => {
if (!url.value) {
toast("URL is required", "negative");
return;
}

Api.addInstance(url.value, useAllowlist.value, enabled.value).then(res => {
if (res.status === 200) {
toast("Bridged instance added", "positive");
bridgedInstances.value.push(res.data);
onclose();
} else {
toast("Failed to add bridged instance", "negative");
}
});
}),
).build(),
).build();
}

static bridgeInstance(instance) {
return create("div")
.classes("flex", "max800")
.children(
create("span")
.classes("instance")
.text(instance.url)
.build(),
ifjs(instance.useAllowlist, CommonTemplates.circleIndicator("Only allowed users", "var(--green)")),
ifjs(instance.enabled, CommonTemplates.circleIndicator("Enabled", "var(--green)")),
ifjs(instance.enabled, CommonTemplates.circleIndicator("Disabled", "var(--red)"), true),
).build();
}
}
4 changes: 4 additions & 0 deletions ui/routing/Page.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ export class Page {
"profile": {
path: "profile",
component: "ProfileComponent"
},
"admin": {
path: "admin",
component: "AdminComponent"
}
};
}
6 changes: 6 additions & 0 deletions ui/routing/Routes.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,11 @@ export const routes = [
path: "profile",
title: "Profile",
noUser: "login"
},
{
path: "admin",
title: "Administration",
noUser: "login",
noAdmin: "chat"
}
];

0 comments on commit 24aec89

Please sign in to comment.