WIP 4
This commit is contained in:
parent
f62c9f064d
commit
b8c6e893ff
43 changed files with 4721 additions and 1807 deletions
|
|
@ -1,6 +1,11 @@
|
|||
"use client";
|
||||
|
||||
import { FC } from "react";
|
||||
import { ZammadWrapper } from "./ZammadWrapper";
|
||||
import { OpenSearchWrapper } from "leafcutter-common";
|
||||
|
||||
export const Home: FC = () => <ZammadWrapper path="#dashboard" hideSidebar />;
|
||||
export const Home: FC = () => (
|
||||
<OpenSearchWrapper
|
||||
url="/app/dashboards#/view/c39012d0-eb7a-11ed-8e00-17d7d50cd7b2?embed=true&tenant=global"
|
||||
marginTop="0"
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -6,10 +6,5 @@ export const metadata: Metadata = {
|
|||
};
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<iframe src="/opensearch/app/dashboards?security_tenant=global#/view/722b74f0-b882-11e8-a6d9-e546fe2bba5f?embed=true&_g=(filters%3A!()%2CrefreshInterval%3A(pause%3A!f%2Cvalue%3A900000)%2Ctime%3A(from%3Anow-7d%2Cto%3Anow))&hide-filter-bar=true"
|
||||
height="1000"
|
||||
width="1200"
|
||||
></iframe>
|
||||
);
|
||||
return <Home />;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,32 +29,16 @@ const checkRewrites = async (request: NextRequestWithAuth) => {
|
|||
const labelStudioURL = process.env.LABEL_STUDIO_URL ?? "http://label-studio:8080";
|
||||
const { token } = request.nextauth;
|
||||
const headers = { 'X-Forwarded-User': token?.email?.toLowerCase() };
|
||||
console.log ({ pathname: request.nextUrl.pathname});
|
||||
console.log({ pathname: request.nextUrl.pathname });
|
||||
|
||||
if (request.nextUrl.pathname.startsWith('/api/v1/configuration/account') ||
|
||||
request.nextUrl.pathname.startsWith('/api/v1/restapiinfo') ||
|
||||
request.nextUrl.pathname.startsWith('/api/v1/auth') ||
|
||||
request.nextUrl.pathname.startsWith('/api/core') ||
|
||||
request.nextUrl.pathname.startsWith('/api/dataconnections') ||
|
||||
request.nextUrl.pathname.startsWith('/api/v1/multitenancy') ||
|
||||
request.nextUrl.pathname.startsWith('/api/ism') ||
|
||||
request.nextUrl.pathname.startsWith('/node_modules') ||
|
||||
request.nextUrl.pathname.startsWith('/translations') || request.nextUrl.pathname.startsWith('/6867') || request.nextUrl.pathname.startsWith('/ui') || request.nextUrl.pathname.startsWith('/bootstrap')) {
|
||||
const headers = {
|
||||
'x-proxy-user': "admin",
|
||||
'x-proxy-roles': "all_access",
|
||||
// 'X-Forwarded-For': "link"
|
||||
};
|
||||
return rewriteURL(request, `${linkBaseURL}`, opensearchURL, headers);
|
||||
}
|
||||
else if (request.nextUrl.pathname.startsWith('/opensearch')) {
|
||||
if (request.nextUrl.pathname.startsWith('/opensearch')) {
|
||||
const headers = {
|
||||
'x-proxy-user': "admin",
|
||||
'x-proxy-roles': "all_access",
|
||||
// 'X-Forwarded-For': "link"
|
||||
};
|
||||
return rewriteURL(request, `${linkBaseURL}/opensearch`, opensearchURL, headers);
|
||||
}else if (request.nextUrl.pathname.startsWith('/metamigo')) {
|
||||
} else if (request.nextUrl.pathname.startsWith('/metamigo')) {
|
||||
return rewriteURL(request, `${linkBaseURL}/metamigo`, metamigoURL);
|
||||
} else if (request.nextUrl.pathname.startsWith('/label-studio')) {
|
||||
return rewriteURL(request, `${linkBaseURL}/label-studio`, labelStudioURL);
|
||||
|
|
|
|||
|
|
@ -39,7 +39,8 @@
|
|||
"sharp": "^0.33.2",
|
||||
"swr": "^2.2.5",
|
||||
"tss-react": "^4.9.4",
|
||||
"twilio-client": "^1.15.1"
|
||||
"twilio-client": "^1.15.1",
|
||||
"ui": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.24.0",
|
||||
|
|
|
|||
14
apps/metamigo-frontend/app/_lib/authentication.ts
Normal file
14
apps/metamigo-frontend/app/_lib/authentication.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import NextAuth from "next-auth"
|
||||
import GoogleProvider from "next-auth/providers/google"
|
||||
import { KyselyAdapter } from "@auth/kysely-adapter"
|
||||
import { db } from "./database";
|
||||
|
||||
export const authOptions = NextAuth({
|
||||
adapter: KyselyAdapter(db),
|
||||
providers: [
|
||||
GoogleProvider({
|
||||
clientId: process.env.GOOGLE_CLIENT_ID!,
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
import { PostgresDialect } from "kysely";
|
||||
import { Pool } from "pg";
|
||||
import { KyselyAuth } from "@auth/kysely-adapter";
|
||||
import { CamelCasePlugin } from "kysely";
|
||||
import type { GeneratedAlways } from "kysely";
|
||||
|
||||
interface Database {
|
||||
User: {
|
||||
id: GeneratedAlways<string>;
|
||||
name: string | null;
|
||||
email: string;
|
||||
emailVerified: Date | null;
|
||||
image: string | null;
|
||||
};
|
||||
|
||||
Account: {
|
||||
id: GeneratedAlways<string>;
|
||||
userId: string;
|
||||
type: string;
|
||||
provider: string;
|
||||
providerAccountId: string;
|
||||
refresh_token: string | null;
|
||||
access_token: string | null;
|
||||
expires_at: number | null;
|
||||
token_type: string | null;
|
||||
scope: string | null;
|
||||
id_token: string | null;
|
||||
session_state: string | null;
|
||||
};
|
||||
|
||||
Session: {
|
||||
id: GeneratedAlways<string>;
|
||||
userId: string;
|
||||
sessionToken: string;
|
||||
expires: Date;
|
||||
};
|
||||
|
||||
VerificationToken: {
|
||||
identifier: string;
|
||||
token: string;
|
||||
expires: Date;
|
||||
};
|
||||
|
||||
WhatsAppBot: {
|
||||
id: GeneratedAlways<string>;
|
||||
userId: string;
|
||||
phone: string;
|
||||
password: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const db = new KyselyAuth<Database>({
|
||||
dialect: new PostgresDialect({
|
||||
pool: new Pool({
|
||||
host: process.env.DATABASE_HOST,
|
||||
database: process.env.DATABASE_NAME,
|
||||
user: process.env.DATABASE_USER,
|
||||
password: process.env.DATABASE_PASSWORD,
|
||||
}),
|
||||
}),
|
||||
plugins: [new CamelCasePlugin()],
|
||||
});
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
import NextAuth from "next-auth";
|
||||
import { authOptions } from "@/app/_lib/authentication";
|
||||
|
||||
const handler = NextAuth(authOptions);
|
||||
|
||||
export { handler as GET, handler as POST };
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
"use client";
|
||||
|
||||
import { GridColDef } from "@mui/x-data-grid-pro";
|
||||
import { List } from "@/app/_components/List";
|
||||
import { List } from "ui";
|
||||
|
||||
export default function Page() {
|
||||
const columns: GridColDef[] = [
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"use client";
|
||||
|
||||
import { GridColDef } from "@mui/x-data-grid-pro";
|
||||
import { List } from "@/app/_components/List";
|
||||
import { List } from "ui";
|
||||
|
||||
export default function Page() {
|
||||
const columns: GridColDef[] = [
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"use client";
|
||||
|
||||
import { GridColDef } from "@mui/x-data-grid-pro";
|
||||
import { List } from "@/app/_components/List";
|
||||
import { List } from "ui";
|
||||
|
||||
export default function Page() {
|
||||
const columns: GridColDef[] = [
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"use client";
|
||||
|
||||
import { GridColDef } from "@mui/x-data-grid-pro";
|
||||
import { List } from "@/app/_components/List";
|
||||
import { List } from "ui";
|
||||
|
||||
export default function Page() {
|
||||
const columns: GridColDef[] = [
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"use client";
|
||||
|
||||
import { GridColDef } from "@mui/x-data-grid-pro";
|
||||
import { List } from "@/app/_components/List";
|
||||
import { List } from "ui";
|
||||
|
||||
export default function Page() {
|
||||
const columns: GridColDef[] = [
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {};
|
||||
const nextConfig = {
|
||||
transpilePackages: ["ui"]
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
|
|
|||
|
|
@ -9,37 +9,40 @@
|
|||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@auth/kysely-adapter": "^0.6.0",
|
||||
"@emotion/cache": "^11.11.0",
|
||||
"@emotion/react": "^11.11.4",
|
||||
"@emotion/server": "^11.11.0",
|
||||
"@emotion/styled": "^11.11.0",
|
||||
"@mui/icons-material": "^5",
|
||||
"@mui/lab": "^5.0.0-alpha.168",
|
||||
"@mui/material": "^5",
|
||||
"@mui/material-nextjs": "^5.15.11",
|
||||
"@mui/x-data-grid-pro": "^6.19.6",
|
||||
"@mui/x-date-pickers-pro": "^6.19.7",
|
||||
"date-fns": "^3.5.0",
|
||||
"kysely": "^0.27.3",
|
||||
"leafcutter-common": "*",
|
||||
"kysely": "^0.26.1",
|
||||
"material-ui-popup-state": "^5.0.10",
|
||||
"mui-chips-input": "^2.1.4",
|
||||
"next": "14.1.3",
|
||||
"next-auth": "^4.24.7",
|
||||
"pg": "^8.11.3",
|
||||
"react": "18.2.0",
|
||||
"react-cookie": "^7.1.0",
|
||||
"react-digit-input": "^2.1.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-polyglot": "^0.7.2",
|
||||
"react-qr-code": "^2.0.12",
|
||||
"react-timer-hook": "^3.0.7",
|
||||
"tss-react": "^4.9.4"
|
||||
"tss-react": "^4.9.4",
|
||||
"ui": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20",
|
||||
"@types/pg": "^8.11.2",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "14.1.3",
|
||||
"typescript": "^5"
|
||||
"typescript": "^5",
|
||||
"ts-config": "*"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
"author": "Abel Luck <abel@guardianproject.info>",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"graphile-worker": "^0.13.0",
|
||||
"graphile-worker": "^0.16.4",
|
||||
"html-to-text": "^9.0.5",
|
||||
"node-fetch": "^3",
|
||||
"pg-promise": "^11.5.4",
|
||||
|
|
@ -14,6 +14,7 @@
|
|||
"twilio": "^5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ts-config": "*",
|
||||
"@babel/core": "7.24.0",
|
||||
"@babel/preset-env": "7.24.0",
|
||||
"@babel/preset-typescript": "7.23.3",
|
||||
|
|
|
|||
|
|
@ -1,8 +1,24 @@
|
|||
version: "3.4"
|
||||
|
||||
x-metamigo-vars:
|
||||
&common-metamigo-variables
|
||||
DATABASE_HOST: "metamigo-postgresql"
|
||||
x-global-vars: &common-global-variables
|
||||
TZ: Etc/UTC
|
||||
|
||||
x-zammad-vars: &common-zammad-variables
|
||||
MEMCACHE_SERVERS: "zammad-memcached:11211"
|
||||
REDIS_URL: "redis://zammad-redis:6379"
|
||||
POSTGRESQL_HOST: "postgresql"
|
||||
POSTGRESQL_PORT: "5432"
|
||||
POSTGRESQL_USER: "zammad"
|
||||
POSTGRESQL_PASS: ${ZAMMAD_DATABASE_PASSWORD}
|
||||
POSTGRESQL_DB: "zammad_production"
|
||||
ELASTICSEARCH_HOST: ${OPENSEARCH_HOST}
|
||||
ELASTICSEARCH_USER: ${OPENSEARCH_USER}
|
||||
ELASTICSEARCH_PASS: ${OPENSEARCH_PASS}
|
||||
ELASTICSEARCH_SSL_VERIFY: false # this doesn't set es_ssl_verify as expected, but ideally it would
|
||||
ELASTICSEARCH_SCHEMA: "https"
|
||||
|
||||
x-metamigo-vars: &common-metamigo-variables
|
||||
DATABASE_HOST: "postgresql"
|
||||
DATABASE_NAME: "metamigo"
|
||||
DATABASE_ROOT_OWNER: "root"
|
||||
DATABASE_ROOT_PASSWORD: ${METAMIGO_DATABASE_ROOT_PASSWORD}
|
||||
|
|
@ -32,22 +48,34 @@ x-metamigo-vars:
|
|||
SIGNALD_SOCKET: /signald/signald.sock
|
||||
|
||||
services:
|
||||
metamigo-postgresql:
|
||||
postgresql:
|
||||
container_name: postgresql
|
||||
environment:
|
||||
<<:
|
||||
[
|
||||
*common-global-variables,
|
||||
*common-zammad-variables,
|
||||
*common-metamigo-variables,
|
||||
]
|
||||
POSTGRES_USER: zammad
|
||||
POSTGRES_PASSWORD: ${ZAMMAD_DATABASE_PASSWORD}
|
||||
build: ../postgresql
|
||||
image: registry.gitlab.com/digiresilience/link/link-stack/postgresql:${LINK_STACK_VERSION}
|
||||
container_name: metamigo-postgresql
|
||||
restart: ${RESTART}
|
||||
volumes:
|
||||
- metamigo-data:/var/lib/postgresql/data
|
||||
- ./scripts/bootstrap-metamigo.sh:/docker-entrypoint-initdb.d/bootstrap-metamigo.sh
|
||||
environment:
|
||||
<<: *common-metamigo-variables
|
||||
POSTGRES_PASSWORD: ${METAMIGO_DATABASE_ROOT_PASSWORD}
|
||||
POSTGRES_USER: "root"
|
||||
POSTGRES_DB: "metamigo"
|
||||
ports:
|
||||
- 127.0.0.1:5433:5432
|
||||
- 5432:5432
|
||||
volumes:
|
||||
- postgresql-data:/var/lib/postgresql/data
|
||||
|
||||
# volumes:
|
||||
# - metamigo-data:/var/lib/postgresql/data
|
||||
# - ./scripts/bootstrap-metamigo.sh:/docker-entrypoint-initdb.d/bootstrap-metamigo.sh
|
||||
#environment:
|
||||
# <<: *common-metamigo-variables
|
||||
# POSTGRES_PASSWORD: ${METAMIGO_DATABASE_ROOT_PASSWORD}
|
||||
# POSTGRES_USER: "root"
|
||||
# POSTGRES_DB: "metamigo"
|
||||
|
||||
volumes:
|
||||
metamigo-data:
|
||||
postgresql-data:
|
||||
driver: local
|
||||
|
|
|
|||
|
|
@ -1,21 +1,19 @@
|
|||
version: "3.4"
|
||||
|
||||
x-global-vars:
|
||||
&common-global-variables
|
||||
x-global-vars: &common-global-variables
|
||||
TZ: Etc/UTC
|
||||
|
||||
x-zammad-vars:
|
||||
&common-zammad-variables
|
||||
x-zammad-vars: &common-zammad-variables
|
||||
MEMCACHE_SERVERS: "zammad-memcached:11211"
|
||||
REDIS_URL: "redis://zammad-redis:6379"
|
||||
POSTGRESQL_HOST: "zammad-postgresql"
|
||||
POSTGRESQL_HOST: "postgresql"
|
||||
POSTGRESQL_PORT: "5432"
|
||||
POSTGRESQL_USER: "zammad"
|
||||
POSTGRESQL_PASS: ${ZAMMAD_DATABASE_PASSWORD}
|
||||
POSTGRESQL_DB: "zammad_production"
|
||||
ELASTICSEARCH_HOST: ${OPENSEARCH_HOST}
|
||||
ELASTICSEARCH_USER: ${OPENSEARCH_USER}
|
||||
ELASTICSEARCH_PASS: ${OPENSEARCH_PASS}
|
||||
ELASTICSEARCH_PASS: ${OPENSEARCH_ADMIN_PASSWORD}
|
||||
ELASTICSEARCH_SSL_VERIFY: false # this doesn't set es_ssl_verify as expected, but ideally it would
|
||||
ELASTICSEARCH_SCHEMA: "https"
|
||||
|
||||
|
|
@ -23,11 +21,11 @@ services:
|
|||
zammad-init:
|
||||
platform: linux/x86_64
|
||||
container_name: zammad-init
|
||||
command: [ "zammad-init" ]
|
||||
command: ["zammad-init"]
|
||||
depends_on:
|
||||
- zammad-postgresql
|
||||
- postgresql
|
||||
environment:
|
||||
<<: [ *common-zammad-variables, *common-global-variables ]
|
||||
<<: [*common-zammad-variables, *common-global-variables]
|
||||
POSTGRESQL_USER: zammad
|
||||
POSTGRESQL_PASS: ${ZAMMAD_DATABASE_PASSWORD}
|
||||
build:
|
||||
|
|
@ -53,7 +51,7 @@ services:
|
|||
zammad-nginx:
|
||||
platform: linux/x86_64
|
||||
container_name: zammad-nginx
|
||||
command: [ "zammad-nginx" ]
|
||||
command: ["zammad-nginx"]
|
||||
expose:
|
||||
- "8080"
|
||||
ports:
|
||||
|
|
@ -75,30 +73,16 @@ services:
|
|||
- zammad-config-nginx:/etc/nginx/sites-enabled:ro
|
||||
- zammad-var:/opt/zammad/var:ro
|
||||
|
||||
zammad-postgresql:
|
||||
container_name: zammad-postgresql
|
||||
environment:
|
||||
<<: [ *common-global-variables, *common-zammad-variables ]
|
||||
POSTGRES_USER: zammad
|
||||
POSTGRES_PASSWORD: ${ZAMMAD_DATABASE_PASSWORD}
|
||||
build: ../postgresql
|
||||
image: registry.gitlab.com/digiresilience/link/link-stack/postgresql:${LINK_STACK_VERSION}
|
||||
restart: ${RESTART}
|
||||
ports:
|
||||
- 5432:5432
|
||||
volumes:
|
||||
- postgresql-data:/var/lib/postgresql/data
|
||||
|
||||
zammad-railsserver:
|
||||
platform: linux/x86_64
|
||||
container_name: zammad-railsserver
|
||||
command: [ "zammad-railsserver" ]
|
||||
command: ["zammad-railsserver"]
|
||||
depends_on:
|
||||
- zammad-memcached
|
||||
- zammad-postgresql
|
||||
- zammad-redis
|
||||
- postgresql
|
||||
environment:
|
||||
<<: [ *common-global-variables, *common-zammad-variables ]
|
||||
<<: [*common-global-variables, *common-zammad-variables]
|
||||
RAILS_RELATIVE_URL_ROOT: /zammad
|
||||
build:
|
||||
context: ../zammad
|
||||
|
|
@ -123,13 +107,13 @@ services:
|
|||
zammad-scheduler:
|
||||
platform: linux/x86_64
|
||||
container_name: zammad-scheduler
|
||||
command: [ "zammad-scheduler" ]
|
||||
command: ["zammad-scheduler"]
|
||||
depends_on:
|
||||
- zammad-memcached
|
||||
- zammad-railsserver
|
||||
- zammad-redis
|
||||
environment:
|
||||
<<: [ *common-global-variables, *common-zammad-variables ]
|
||||
<<: [*common-global-variables, *common-zammad-variables]
|
||||
build:
|
||||
context: ../zammad
|
||||
args:
|
||||
|
|
@ -143,13 +127,13 @@ services:
|
|||
zammad-websocket:
|
||||
platform: linux/x86_64
|
||||
container_name: zammad-websocket
|
||||
command: [ "zammad-websocket" ]
|
||||
command: ["zammad-websocket"]
|
||||
depends_on:
|
||||
- zammad-memcached
|
||||
- zammad-railsserver
|
||||
- zammad-redis
|
||||
environment:
|
||||
<<: [ *common-global-variables, *common-zammad-variables ]
|
||||
<<: [*common-global-variables, *common-zammad-variables]
|
||||
build:
|
||||
context: ../zammad
|
||||
args:
|
||||
|
|
@ -161,10 +145,6 @@ services:
|
|||
- zammad-storage:/opt/zammad/storage
|
||||
|
||||
volumes:
|
||||
opensearch-data:
|
||||
driver: local
|
||||
postgresql-data:
|
||||
driver: local
|
||||
redis-data:
|
||||
driver: local
|
||||
zammad-config-nginx:
|
||||
|
|
|
|||
|
|
@ -2,14 +2,22 @@ opensearch.hosts: [https://opensearch:9200]
|
|||
opensearch.ssl.verificationMode: none
|
||||
opensearch.username: kibanaserver
|
||||
opensearch.password: kibanaserver
|
||||
opensearch.requestHeadersAllowlist: ["securitytenant","Authorization","x-forwarded-for","x-proxy-user","x-proxy-roles"]
|
||||
opensearch_security.auth.type: "proxy"
|
||||
opensearch_security.proxycache.user_header: "x-proxy-user"
|
||||
opensearch_security.proxycache.roles_header: "x-proxy-roles"
|
||||
opensearch.requestHeadersAllowlist:
|
||||
[
|
||||
"securitytenant",
|
||||
"Authorization",
|
||||
"x-forwarded-for",
|
||||
"x-proxy-user",
|
||||
"x-proxy-roles",
|
||||
]
|
||||
# opensearch_security.auth.type: "proxy"
|
||||
# opensearch_security.proxycache.user_header: "x-proxy-user"
|
||||
# opensearch_security.proxycache.roles_header: "x-proxy-roles"
|
||||
|
||||
opensearch_security.multitenancy.enabled: true
|
||||
opensearch_security.multitenancy.tenants.preferred: [Private, Global]
|
||||
opensearch_security.readonly_mode.roles: [kibana_read_only]
|
||||
# Use this setting if you are running opensearch-dashboards without https
|
||||
opensearch_security.cookie.secure: false
|
||||
server.host: '0.0.0.0'
|
||||
server.host: "0.0.0.0"
|
||||
server.basePath: "/opensearch"
|
||||
server.rewriteBasePath: false
|
||||
|
|
|
|||
|
|
@ -15,17 +15,17 @@ config:
|
|||
description: "Authenticate via HTTP Basic against internal users database"
|
||||
http_enabled: true
|
||||
transport_enabled: true
|
||||
order: 4
|
||||
order: 0
|
||||
http_authenticator:
|
||||
type: basic
|
||||
challenge: true
|
||||
challenge: false
|
||||
authentication_backend:
|
||||
type: intern
|
||||
proxy_auth_domain:
|
||||
description: "Authenticate via proxy"
|
||||
http_enabled: true
|
||||
transport_enabled: true
|
||||
order: 0
|
||||
order: 1
|
||||
http_authenticator:
|
||||
type: proxy
|
||||
challenge: false
|
||||
|
|
|
|||
|
|
@ -22,5 +22,9 @@ const finalCommand = command === "up" ? ["up", "-d"] : [command];
|
|||
const dockerCompose = spawn('docker', ['compose', '--env-file', '.env', ...finalFiles, ...finalCommand]);
|
||||
|
||||
dockerCompose.stdout.on('data', (data) => {
|
||||
console.log(`stdout: ${data}`);
|
||||
console.log(`${data}`);
|
||||
});
|
||||
|
||||
dockerCompose.stderr.on('data', (data) => {
|
||||
console.log(`${data}`);
|
||||
});
|
||||
5328
package-lock.json
generated
5328
package-lock.json
generated
File diff suppressed because it is too large
Load diff
64
package.json
64
package.json
|
|
@ -1,41 +1,40 @@
|
|||
{
|
||||
"name": "link-stack",
|
||||
"version": "2.1.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"version": "2.2.0",
|
||||
"description": "Link from the Center for Digital Resilience",
|
||||
"scripts": {
|
||||
"dev": "dotenv -- turbo run dev --concurrency 30",
|
||||
"build": "turbo build --concurrency 30",
|
||||
"dev": "dotenv -- turbo run dev",
|
||||
"build": "turbo build",
|
||||
"migrate": "dotenv -- npm run migrate --workspace=database",
|
||||
"fmt": "turbo run fmt",
|
||||
"docker:all:up": "node scripts/docker.js all up",
|
||||
"docker:all:down": "node scripts/docker.js all down",
|
||||
"docker:all:build": "node scripts/docker.js all build",
|
||||
"docker:link:dev:up": "node scripts/docker.js linkDev up",
|
||||
"docker:link:dev:down": "node scripts/docker.js linkDev down",
|
||||
"docker:link:up": "node scripts/docker.js link up",
|
||||
"docker:link:down": "node scripts/docker.js link down",
|
||||
"docker:link:build": "node scripts/docker.js link build",
|
||||
"docker:opensearch:up": "node scripts/docker.js opensearch up",
|
||||
"docker:opensearch:down": "node scripts/docker.js opensearch down",
|
||||
"docker:opensearch:build": "node scripts/docker.js opensearch build",
|
||||
"docker:leafcutter:dev:up": "node scripts/docker.js leafcutterDev up",
|
||||
"docker:leafcutter:dev:down": "node scripts/docker.js leafcutterDev down",
|
||||
"docker:leafcutter:up": "node scripts/docker.js leafcutter up",
|
||||
"docker:leafcutter:down": "node scripts/docker.js leafcutter down",
|
||||
"docker:leafcutter:build": "node scripts/docker.js leafcutter build",
|
||||
"docker:zammad:up": "node scripts/docker.js zammad up",
|
||||
"docker:zammad:down": "node scripts/docker.js zammad down",
|
||||
"docker:zammad:build": "node scripts/docker.js zammad build",
|
||||
"docker:metamigo:dev:up": "node scripts/docker.js metamigoDev up",
|
||||
"docker:metamigo:dev:down": "node scripts/docker.js metamigoDev down",
|
||||
"docker:metamigo:up": "node scripts/docker.js metamigo up",
|
||||
"docker:metamigo:down": "node scripts/docker.js metamigo down",
|
||||
"docker:metamigo:build": "node scripts/docker.js metamigo build",
|
||||
"upgrade:setup": "npm i -g npm-check-updates",
|
||||
"upgrade:check": "ncu && ncu -ws",
|
||||
"upgrade:all": "ncu -u && ncu -ws -u && npm i",
|
||||
"clean": "rm -f package-lock.json && rm -rf node_modules && rm -rf apps/*/node_modules && rm -rf packages/*/node_modules && rm -rf apps/*/.next && rm -rf packages/*/.turbo && rm -rf apps/*/.turbo && rm -rf docker/zammad/addons/*"
|
||||
"clean": "rm -f package-lock.json && rm -rf node_modules && rm -rf apps/*/node_modules && rm -rf packages/*/node_modules && rm -rf apps/*/.next && rm -rf packages/*/.turbo && rm -rf apps/*/.turbo && rm -rf docker/zammad/addons/*",
|
||||
"docker:all:up": "node docker/scripts/docker.js all up",
|
||||
"docker:all:down": "node docker/scripts/docker.js all down",
|
||||
"docker:all:build": "node docker/scripts/docker.js all build",
|
||||
"docker:link:dev:up": "node docker/scripts/docker.js linkDev up",
|
||||
"docker:link:dev:down": "node docker/scripts/docker.js linkDev down",
|
||||
"docker:link:up": "node docker/scripts/docker.js link up",
|
||||
"docker:link:down": "node docker/scripts/docker.js link down",
|
||||
"docker:link:build": "node docker/scripts/docker.js link build",
|
||||
"docker:opensearch:up": "node docker/scripts/docker.js opensearch up",
|
||||
"docker:opensearch:down": "node docker/scripts/docker.js opensearch down",
|
||||
"docker:opensearch:build": "node docker/scripts/docker.js opensearch build",
|
||||
"docker:leafcutter:dev:up": "node docker/scripts/docker.js leafcutterDev up",
|
||||
"docker:leafcutter:dev:down": "node docker/scripts/docker.js leafcutterDev down",
|
||||
"docker:leafcutter:up": "node docker/scripts/docker.js leafcutter up",
|
||||
"docker:leafcutter:down": "node docker/scripts/docker.js leafcutter down",
|
||||
"docker:leafcutter:build": "node docker/scripts/docker.js leafcutter build",
|
||||
"docker:zammad:up": "node docker/scripts/docker.js zammad up",
|
||||
"docker:zammad:down": "node docker/scripts/docker.js zammad down",
|
||||
"docker:zammad:build": "node docker/scripts/docker.js zammad build",
|
||||
"docker:metamigo:dev:up": "node docker/scripts/docker.js metamigoDev up",
|
||||
"docker:metamigo:dev:down": "node docker/scripts/docker.js metamigoDev down",
|
||||
"docker:metamigo:up": "node docker/scripts/docker.js metamigo up",
|
||||
"docker:metamigo:down": "node docker/scripts/docker.js metamigo down",
|
||||
"docker:metamigo:build": "node docker/scripts/docker.js metamigo build"
|
||||
},
|
||||
"workspaces": [
|
||||
"apps/*",
|
||||
|
|
@ -50,11 +49,10 @@
|
|||
"author": "Darren Clarke",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"devDependencies": {
|
||||
"dotenv-cli": "latest",
|
||||
"prettier": "^3.2.5"
|
||||
"dotenv-cli": "latest"
|
||||
},
|
||||
"engines": {
|
||||
"npm": ">=9.6.7",
|
||||
"npm": ">=10",
|
||||
"node": ">=20"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ export const OpenSearchWrapper: FC<OpenSearchWrapperProps> = ({
|
|||
>
|
||||
<Iframe
|
||||
id="opensearch"
|
||||
url={`${process.env.NEXT_PUBLIC_NEXTAUTH_URL}${url}&_g=(filters%3A!()%2CrefreshInterval%3A(pause%3A!t%2Cvalue%3A0)%2Ctime%3A(from%3Anow-3y%2Cto%3Anow))`}
|
||||
url={`/opensearch/${url}&_g=(filters%3A!()%2CrefreshInterval%3A(pause%3A!t%2Cvalue%3A0)%2Ctime%3A(from%3Anow-3y%2Cto%3Anow))`}
|
||||
width="100%"
|
||||
height="100%"
|
||||
frameBorder={0}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ export { Tooltip } from "./components/Tooltip";
|
|||
export { Preview } from "./components/Preview";
|
||||
export { GettingStartedDialog } from "./components/GettingStartedDialog";
|
||||
export { VisualizationDetail } from "./components/VisualizationDetail";
|
||||
export { OpenSearchWrapper } from "./components/OpenSearchWrapper";
|
||||
export const locales = {
|
||||
en,
|
||||
fr,
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1,9 +1,8 @@
|
|||
{
|
||||
"name": "tsconfig",
|
||||
"name": "ts-config",
|
||||
"version": "0.1.4",
|
||||
"description": "Shared TypeScript config",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"repository": "https://gitlab.com/digiresilience.org/link/tsconfig-amigo",
|
||||
"author": "Abel Luck <abel@guardianproject.info>",
|
||||
"main": "tsconfig.json",
|
||||
"engines": {
|
||||
26
packages/ui/components/Detail.tsx
Normal file
26
packages/ui/components/Detail.tsx
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
"use client";
|
||||
|
||||
import { FC } from "react";
|
||||
import { Grid, Box } from "@mui/material";
|
||||
import { typography } from "../styles/theme";
|
||||
|
||||
interface DetailProps {
|
||||
title: string;
|
||||
entity: string;
|
||||
children: any;
|
||||
}
|
||||
|
||||
export const Detail: FC<DetailProps> = ({ title, entity, children }) => {
|
||||
const { h3 } = typography;
|
||||
|
||||
return (
|
||||
<Box sx={{ height: "100vh", backgroundColor: "#ddd", p: 3 }}>
|
||||
<Grid container direction="column">
|
||||
<Grid item>
|
||||
<Box sx={h3}>{title}</Box>
|
||||
</Grid>
|
||||
<Grid item>{children}</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
67
packages/ui/components/Dialog.tsx
Normal file
67
packages/ui/components/Dialog.tsx
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
"use client";
|
||||
|
||||
import { FC } from "react";
|
||||
import {
|
||||
Grid,
|
||||
Button,
|
||||
Dialog as MUIDialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
TextField,
|
||||
Autocomplete,
|
||||
} from "@mui/material";
|
||||
import { typography } from "../styles/theme";
|
||||
|
||||
interface DialogProps {
|
||||
title: string;
|
||||
open: boolean;
|
||||
closeDialog: () => void;
|
||||
children?: any;
|
||||
}
|
||||
|
||||
export const Dialog: FC<DialogProps> = ({
|
||||
title,
|
||||
open,
|
||||
closeDialog,
|
||||
children,
|
||||
}) => {
|
||||
return (
|
||||
<MUIDialog open={open} maxWidth="md" fullWidth>
|
||||
<DialogContent>{children}</DialogContent>
|
||||
<DialogActions sx={{ px: 3, pt: 0, pb: 3 }}>
|
||||
<Grid container justifyContent="space-between">
|
||||
<Grid item>
|
||||
<Button
|
||||
sx={{
|
||||
backgroundColor: "white",
|
||||
color: "#666",
|
||||
fontFamily: "Poppins, sans-serif",
|
||||
fontWeight: 700,
|
||||
borderRadius: 2,
|
||||
textTransform: "none",
|
||||
}}
|
||||
onClick={() => {
|
||||
closeDialog();
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Button
|
||||
sx={{
|
||||
fontFamily: "Poppins, sans-serif",
|
||||
fontWeight: 700,
|
||||
borderRadius: 2,
|
||||
textTransform: "none",
|
||||
px: 3,
|
||||
}}
|
||||
>
|
||||
Create Ticket
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DialogActions>
|
||||
</MUIDialog>
|
||||
);
|
||||
};
|
||||
86
packages/ui/components/List.tsx
Normal file
86
packages/ui/components/List.tsx
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
"use client";
|
||||
|
||||
import { FC } from "react";
|
||||
import { Grid, Box } from "@mui/material";
|
||||
import { DataGridPro, GridColDef } from "@mui/x-data-grid-pro";
|
||||
import { typography } from "../styles/theme";
|
||||
|
||||
interface ListProps {
|
||||
title: string;
|
||||
rows: any;
|
||||
columns: GridColDef<any>[];
|
||||
onRowClick: (id: string) => void;
|
||||
buttons?: React.ReactNode;
|
||||
}
|
||||
|
||||
export const List: FC<ListProps> = ({ title, rows, columns, onRowClick, buttons }) => {
|
||||
const { h3 } = typography;
|
||||
|
||||
return (
|
||||
<Box sx={{ height: "100vh", backgroundColor: "#ddd", p: 3 }}>
|
||||
<Grid container direction="column">
|
||||
<Grid item container direction="row" justifyContent="space-between">
|
||||
<Grid item>
|
||||
<Box sx={h3}>{title}</Box>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
{buttons}
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Box
|
||||
sx={{
|
||||
backgroundColor: "#ddd",
|
||||
border: 0,
|
||||
width: "100%",
|
||||
height: "100vh",
|
||||
".MuiDataGrid-row": {
|
||||
cursor: "pointer",
|
||||
"&:hover": {
|
||||
backgroundColor: "#1982fc33 !important",
|
||||
fontWeight: "bold",
|
||||
},
|
||||
},
|
||||
".MuiDataGrid-row:nth-of-type(1n)": {
|
||||
backgroundColor: "#f3f3f3",
|
||||
},
|
||||
".MuiDataGrid-row:nth-of-type(2n)": {
|
||||
backgroundColor: "#fff",
|
||||
},
|
||||
".MuiDataGrid-columnHeaderTitle": {
|
||||
color: "#333",
|
||||
fontWeight: "bold",
|
||||
fontSize: 11,
|
||||
margin: "0 auto",
|
||||
},
|
||||
".MuiDataGrid-columnHeader": {
|
||||
backgroundColor: "#ccc",
|
||||
border: 0,
|
||||
borderBottom: "3px solid #ddd",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<DataGridPro
|
||||
rows={rows}
|
||||
columns={columns}
|
||||
density="compact"
|
||||
pagination
|
||||
initialState={{
|
||||
pagination: { paginationModel: { pageSize: 25 } },
|
||||
}}
|
||||
pageSizeOptions={[5, 10, 25]}
|
||||
paginationMode="client"
|
||||
sx={{ height: "100vh" }}
|
||||
rowBuffer={30}
|
||||
rowHeight={46}
|
||||
scrollbarSize={0}
|
||||
disableVirtualization
|
||||
disableColumnMenu
|
||||
onRowClick={(row: any) => onRowClick(row.id)}
|
||||
/>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
350
packages/ui/components/Sidebar.tsx
Normal file
350
packages/ui/components/Sidebar.tsx
Normal file
|
|
@ -0,0 +1,350 @@
|
|||
"use client";
|
||||
|
||||
import { FC } from "react";
|
||||
import {
|
||||
Box,
|
||||
Grid,
|
||||
Typography,
|
||||
List,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
ListItemSecondaryAction,
|
||||
Drawer,
|
||||
} from "@mui/material";
|
||||
import {
|
||||
ExpandCircleDown as ExpandCircleDownIcon,
|
||||
AccountCircle as AccountCircleIcon,
|
||||
Chat as ChatIcon,
|
||||
PermPhoneMsg as PhoneIcon,
|
||||
WhatsApp as WhatsAppIcon,
|
||||
Facebook as FacebookIcon,
|
||||
} from "@mui/icons-material";
|
||||
import { usePathname } from "next/navigation";
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { fonts } from "../styles/theme";
|
||||
// import LinkLogo from "@/public/link-logo-small.png";
|
||||
// import { useSession, signOut } from "next-auth/react";
|
||||
|
||||
const openWidth = 270;
|
||||
const closedWidth = 100;
|
||||
|
||||
const MenuItem = ({
|
||||
name,
|
||||
href,
|
||||
Icon,
|
||||
iconSize,
|
||||
inset = false,
|
||||
selected = false,
|
||||
open = true,
|
||||
badge,
|
||||
target = "_self",
|
||||
}: any) => (
|
||||
<Link href={href} target={target}>
|
||||
<ListItemButton
|
||||
sx={{
|
||||
p: 0,
|
||||
mb: 1,
|
||||
bl: iconSize === 0 ? "1px solid white" : "inherit",
|
||||
}}
|
||||
selected={selected}
|
||||
>
|
||||
{iconSize > 0 ? (
|
||||
<ListItemIcon
|
||||
sx={{
|
||||
color: `white`,
|
||||
minWidth: 0,
|
||||
mr: 2,
|
||||
textAlign: "center",
|
||||
margin: open ? "0 8 0 0" : "0 auto",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: iconSize,
|
||||
height: iconSize,
|
||||
mr: 0.5,
|
||||
mt: "-4px",
|
||||
}}
|
||||
>
|
||||
<Icon />
|
||||
</Box>
|
||||
</ListItemIcon>
|
||||
) : (
|
||||
<Box
|
||||
sx={{
|
||||
width: 30,
|
||||
height: "28px",
|
||||
position: "relative",
|
||||
ml: "9px",
|
||||
mr: "1px",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: "1px",
|
||||
height: "56px",
|
||||
backgroundColor: "white",
|
||||
position: "absolute",
|
||||
left: "3px",
|
||||
top: "-10px",
|
||||
}}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
width: "42px",
|
||||
height: "42px",
|
||||
position: "absolute",
|
||||
top: "-27px",
|
||||
left: "3px",
|
||||
border: "solid 1px #fff",
|
||||
borderColor: "transparent transparent transparent #fff",
|
||||
borderRadius: "60px",
|
||||
rotate: "-35deg",
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
{open && (
|
||||
<ListItemText
|
||||
inset={inset}
|
||||
primary={
|
||||
<Typography
|
||||
variant="body1"
|
||||
sx={{
|
||||
fontSize: 16,
|
||||
fontWeight: "bold",
|
||||
border: 0,
|
||||
textAlign: "left",
|
||||
color: "white",
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{badge && badge > 0 ? (
|
||||
<ListItemSecondaryAction>
|
||||
<Typography
|
||||
color="textSecondary"
|
||||
variant="body1"
|
||||
className="badge"
|
||||
sx={{
|
||||
backgroundColor: "#FFB620",
|
||||
color: "black !important",
|
||||
borderRadius: 10,
|
||||
px: 1,
|
||||
fontSize: 12,
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
>
|
||||
{badge}
|
||||
</Typography>
|
||||
</ListItemSecondaryAction>
|
||||
) : null}
|
||||
</ListItemButton>
|
||||
</Link>
|
||||
);
|
||||
|
||||
interface SidebarProps {
|
||||
open: boolean;
|
||||
setOpen: (open: boolean) => void;
|
||||
}
|
||||
|
||||
export const Sidebar: FC<SidebarProps> = ({ open, setOpen }) => {
|
||||
const pathname = usePathname();
|
||||
const { poppins } = fonts;
|
||||
// const { data: session } = useSession();
|
||||
// const username = session?.user?.name || "User";
|
||||
|
||||
// const logout = () => {
|
||||
// signOut({ callbackUrl: "/login" });
|
||||
// };
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
sx={{ width: open ? openWidth : closedWidth, flexShrink: 0 }}
|
||||
variant="permanent"
|
||||
anchor="left"
|
||||
open={open}
|
||||
PaperProps={{
|
||||
sx: {
|
||||
width: open ? openWidth : closedWidth,
|
||||
border: 0,
|
||||
overflow: "visible",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
position: "absolute",
|
||||
top: 20,
|
||||
right: open ? -8 : -16,
|
||||
color: "#1C75FD",
|
||||
rotate: open ? "90deg" : "-90deg",
|
||||
}}
|
||||
onClick={() => {
|
||||
setOpen!(!open);
|
||||
}}
|
||||
>
|
||||
<ExpandCircleDownIcon
|
||||
sx={{
|
||||
width: 30,
|
||||
height: 30,
|
||||
background: "white",
|
||||
borderRadius: 500,
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<Grid
|
||||
container
|
||||
direction="column"
|
||||
justifyContent="space-between"
|
||||
wrap="nowrap"
|
||||
spacing={0}
|
||||
sx={{ backgroundColor: "#25272A", height: "100%", p: 2 }}
|
||||
>
|
||||
<Grid item container>
|
||||
<Grid item sx={{ width: open ? "40px" : "100%" }}>
|
||||
<Box
|
||||
sx={{
|
||||
width: "40px",
|
||||
height: "40px",
|
||||
margin: open ? "0" : "0 auto",
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
src={"" /* LinkLogo */}
|
||||
alt="Link logo"
|
||||
width={40}
|
||||
height={40}
|
||||
style={{
|
||||
objectFit: "cover",
|
||||
filter: "grayscale(100) brightness(100)",
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
.
|
||||
</Grid>
|
||||
{open && (
|
||||
<Grid item>
|
||||
<Typography
|
||||
variant="h2"
|
||||
sx={{
|
||||
fontSize: 26,
|
||||
color: "white",
|
||||
fontWeight: 700,
|
||||
mt: 1,
|
||||
ml: 0.5,
|
||||
fontFamily: poppins.style.fontFamily,
|
||||
}}
|
||||
>
|
||||
Metamigo
|
||||
</Typography>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Box
|
||||
sx={{
|
||||
height: "0.5px",
|
||||
width: "100%",
|
||||
backgroundColor: "#666",
|
||||
mb: 1,
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid
|
||||
item
|
||||
container
|
||||
direction="column"
|
||||
sx={{
|
||||
mt: "6px",
|
||||
overflow: "scroll",
|
||||
scrollbarWidth: "none",
|
||||
msOverflowStyle: "none",
|
||||
"&::-webkit-scrollbar": { display: "none" },
|
||||
}}
|
||||
flexGrow={1}
|
||||
>
|
||||
<List
|
||||
component="nav"
|
||||
sx={{
|
||||
a: {
|
||||
textDecoration: "none",
|
||||
|
||||
".MuiListItemButton-root": {
|
||||
p: 1,
|
||||
borderRadius: 2,
|
||||
"&:hover": {
|
||||
background: "#555",
|
||||
},
|
||||
".MuiTypography-root": {
|
||||
p: {
|
||||
color: "#999 !important",
|
||||
fontSize: 16,
|
||||
},
|
||||
},
|
||||
".badge": {
|
||||
p: { fontSize: 12, color: "black !important" },
|
||||
},
|
||||
},
|
||||
".Mui-selected": {
|
||||
background: "#444",
|
||||
color: "#fff !important",
|
||||
".MuiTypography-root": {
|
||||
p: {
|
||||
color: "#fff !important",
|
||||
fontSize: 16,
|
||||
},
|
||||
},
|
||||
".badge": {
|
||||
p: { fontSize: 12, color: "black !important" },
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<MenuItem
|
||||
name="Whatsapp"
|
||||
href="/whatsapp"
|
||||
selected={pathname.endsWith("/whatsapp")}
|
||||
Icon={WhatsAppIcon}
|
||||
iconSize={20}
|
||||
/>
|
||||
<MenuItem
|
||||
name="Signal"
|
||||
href="/signal"
|
||||
selected={pathname.startsWith("/signal")}
|
||||
Icon={ChatIcon}
|
||||
iconSize={20}
|
||||
/>
|
||||
<MenuItem
|
||||
name="Facebook"
|
||||
href="/facebook"
|
||||
selected={pathname.startsWith("/facebook")}
|
||||
Icon={FacebookIcon}
|
||||
iconSize={20}
|
||||
/>
|
||||
<MenuItem
|
||||
name="Voice"
|
||||
href="/voice"
|
||||
selected={pathname.startsWith("/voice")}
|
||||
Icon={PhoneIcon}
|
||||
iconSize={20}
|
||||
/>
|
||||
<MenuItem
|
||||
name="Users"
|
||||
href="/users"
|
||||
selected={pathname.startsWith("/users")}
|
||||
Icon={AccountCircleIcon}
|
||||
iconSize={20}
|
||||
/>
|
||||
</List>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
135
packages/ui/components/SidebarItem.tsx
Normal file
135
packages/ui/components/SidebarItem.tsx
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
"use client";
|
||||
|
||||
import { FC } from "react";
|
||||
import {
|
||||
Box,
|
||||
Typography,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
ListItemSecondaryAction,
|
||||
} from "@mui/material";
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { fonts } from "../styles/theme";
|
||||
|
||||
const openWidth = 270;
|
||||
const closedWidth = 100;
|
||||
|
||||
export const SidebarItem: FC = ({
|
||||
name,
|
||||
href,
|
||||
Icon,
|
||||
iconSize,
|
||||
inset = false,
|
||||
selected = false,
|
||||
open = true,
|
||||
badge,
|
||||
target = "_self",
|
||||
}: any) => (
|
||||
<Link href={href} target={target}>
|
||||
<ListItemButton
|
||||
sx={{
|
||||
p: 0,
|
||||
mb: 1,
|
||||
bl: iconSize === 0 ? "1px solid white" : "inherit",
|
||||
}}
|
||||
selected={selected}
|
||||
>
|
||||
{iconSize > 0 ? (
|
||||
<ListItemIcon
|
||||
sx={{
|
||||
color: `white`,
|
||||
minWidth: 0,
|
||||
mr: 2,
|
||||
textAlign: "center",
|
||||
margin: open ? "0 8 0 0" : "0 auto",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: iconSize,
|
||||
height: iconSize,
|
||||
mr: 0.5,
|
||||
mt: "-4px",
|
||||
}}
|
||||
>
|
||||
<Icon />
|
||||
</Box>
|
||||
</ListItemIcon>
|
||||
) : (
|
||||
<Box
|
||||
sx={{
|
||||
width: 30,
|
||||
height: "28px",
|
||||
position: "relative",
|
||||
ml: "9px",
|
||||
mr: "1px",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: "1px",
|
||||
height: "56px",
|
||||
backgroundColor: "white",
|
||||
position: "absolute",
|
||||
left: "3px",
|
||||
top: "-10px",
|
||||
}}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
width: "42px",
|
||||
height: "42px",
|
||||
position: "absolute",
|
||||
top: "-27px",
|
||||
left: "3px",
|
||||
border: "solid 1px #fff",
|
||||
borderColor: "transparent transparent transparent #fff",
|
||||
borderRadius: "60px",
|
||||
rotate: "-35deg",
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
{open && (
|
||||
<ListItemText
|
||||
inset={inset}
|
||||
primary={
|
||||
<Typography
|
||||
variant="body1"
|
||||
sx={{
|
||||
fontSize: 16,
|
||||
fontWeight: "bold",
|
||||
border: 0,
|
||||
textAlign: "left",
|
||||
color: "white",
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{badge && badge > 0 ? (
|
||||
<ListItemSecondaryAction>
|
||||
<Typography
|
||||
color="textSecondary"
|
||||
variant="body1"
|
||||
className="badge"
|
||||
sx={{
|
||||
backgroundColor: "#FFB620",
|
||||
color: "black !important",
|
||||
borderRadius: 10,
|
||||
px: 1,
|
||||
fontSize: 12,
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
>
|
||||
{badge}
|
||||
</Typography>
|
||||
</ListItemSecondaryAction>
|
||||
) : null}
|
||||
</ListItemButton>
|
||||
</Link>
|
||||
);
|
||||
2
packages/ui/index.ts
Normal file
2
packages/ui/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export { List } from "./components/List";
|
||||
export { fonts, typography, colors } from "./styles/theme";
|
||||
25
packages/ui/package.json
Normal file
25
packages/ui/package.json
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"name": "ui",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"build": "tsc -p tsconfig.json"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@mui/icons-material": "^5",
|
||||
"@mui/lab": "^5.0.0-alpha.168",
|
||||
"@mui/material": "^5",
|
||||
"@mui/x-data-grid-pro": "^6.19.6",
|
||||
"@mui/x-date-pickers-pro": "^6.19.7",
|
||||
"next": "14.1.3",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.11.28",
|
||||
"@types/react": "18.2.66",
|
||||
"typescript": "^5.4.2"
|
||||
}
|
||||
}
|
||||
112
packages/ui/styles/theme.ts
Normal file
112
packages/ui/styles/theme.ts
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
import { Roboto, Playfair_Display, Poppins } from "next/font/google";
|
||||
|
||||
const roboto = Roboto({
|
||||
weight: ["400"],
|
||||
subsets: ["latin"],
|
||||
display: "swap",
|
||||
});
|
||||
|
||||
const playfair = Playfair_Display({
|
||||
weight: ["900"],
|
||||
subsets: ["latin"],
|
||||
display: "swap",
|
||||
});
|
||||
|
||||
const poppins = Poppins({
|
||||
weight: ["400", "700"],
|
||||
subsets: ["latin"],
|
||||
display: "swap",
|
||||
});
|
||||
|
||||
export const fonts = {
|
||||
roboto,
|
||||
playfair,
|
||||
poppins,
|
||||
};
|
||||
|
||||
export const colors: any = {
|
||||
lightGray: "#ededf0",
|
||||
mediumGray: "#e3e5e5",
|
||||
darkGray: "#33302f",
|
||||
mediumBlue: "#4285f4",
|
||||
green: "#349d7b",
|
||||
lavender: "#a5a6f6",
|
||||
darkLavender: "#5d5fef",
|
||||
pink: "#fcddec",
|
||||
cdrLinkOrange: "#ff7115",
|
||||
coreYellow: "#fac942",
|
||||
helpYellow: "#fff4d5",
|
||||
dwcDarkBlue: "#191847",
|
||||
hazyMint: "#ecf7f8",
|
||||
leafcutterElectricBlue: "#4d6aff",
|
||||
leafcutterLightBlue: "#fafbfd",
|
||||
waterbearElectricPurple: "#332c83",
|
||||
waterbearLightSmokePurple: "#eff3f8",
|
||||
bumpedPurple: "#212058",
|
||||
mutedPurple: "#373669",
|
||||
warningPink: "#ef5da8",
|
||||
lightPink: "#fff0f7",
|
||||
lightGreen: "#f0fff3",
|
||||
lightOrange: "#fff5f0",
|
||||
beige: "#f6f2f1",
|
||||
almostBlack: "#33302f",
|
||||
white: "#ffffff",
|
||||
};
|
||||
|
||||
export const typography: any = {
|
||||
h1: {
|
||||
fontFamily: playfair.style.fontFamily,
|
||||
fontSize: 45,
|
||||
fontWeight: 700,
|
||||
lineHeight: 1.1,
|
||||
margin: 0,
|
||||
},
|
||||
h2: {
|
||||
fontFamily: poppins.style.fontFamily,
|
||||
fontSize: 35,
|
||||
fontWeight: 700,
|
||||
lineHeight: 1.1,
|
||||
margin: 0,
|
||||
},
|
||||
h3: {
|
||||
fontFamily: poppins.style.fontFamily,
|
||||
fontWeight: 400,
|
||||
fontSize: 27,
|
||||
lineHeight: 1.1,
|
||||
margin: 0,
|
||||
},
|
||||
h4: {
|
||||
fontFamily: poppins.style.fontFamily,
|
||||
fontWeight: 700,
|
||||
fontSize: 18,
|
||||
},
|
||||
h5: {
|
||||
fontFamily: roboto.style.fontFamily,
|
||||
fontWeight: 700,
|
||||
fontSize: 16,
|
||||
lineHeight: "24px",
|
||||
textTransform: "uppercase",
|
||||
textAlign: "center",
|
||||
margin: 1,
|
||||
},
|
||||
h6: {
|
||||
fontFamily: roboto.style.fontFamily,
|
||||
fontWeight: 400,
|
||||
fontSize: 14,
|
||||
textAlign: "center",
|
||||
},
|
||||
p: {
|
||||
fontFamily: roboto.style.fontFamily,
|
||||
fontSize: 17,
|
||||
lineHeight: "26.35px",
|
||||
fontWeight: 400,
|
||||
margin: 0,
|
||||
},
|
||||
small: {
|
||||
fontFamily: roboto.style.fontFamily,
|
||||
fontSize: 13,
|
||||
lineHeight: "18px",
|
||||
fontWeight: 400,
|
||||
margin: 0,
|
||||
},
|
||||
};
|
||||
29
packages/ui/tsconfig.json
Normal file
29
packages/ui/tsconfig.json
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./*", "../../node_modules/*"]
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
]
|
||||
},
|
||||
"include": ["**.d.ts", "**/*.ts", "**/*.tsx", "**/*.png, **/*.svg"],
|
||||
"exclude": ["node_modules", "babel__core"]
|
||||
}
|
||||
1
packages/ui/tsconfig.tsbuildinfo
Normal file
1
packages/ui/tsconfig.tsbuildinfo
Normal file
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue