diff --git a/index.html b/index.html
index e624e358..a54377b3 100644
--- a/index.html
+++ b/index.html
@@ -2,11 +2,11 @@
-
-
-
-
-
+
+
+
+
+
@@ -19,6 +19,6 @@
-
+
diff --git a/public/site.webmanifest b/public/site.webmanifest
index 408e7998..4e0d1684 100644
--- a/public/site.webmanifest
+++ b/public/site.webmanifest
@@ -3,12 +3,12 @@
"short_name": "OpenTAKServer",
"icons": [
{
- "src": "/android-chrome-192x192.png",
+ "src": "android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
- "src": "/android-chrome-512x512.png",
+ "src": "android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
@@ -16,4 +16,4 @@
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
-}
+}
\ No newline at end of file
diff --git a/src/App.tsx b/src/App.tsx
index d132fcad..3470af90 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,7 +1,7 @@
import '@mantine/core/styles.css';
import { MantineProvider } from '@mantine/core';
import { Notifications } from '@mantine/notifications';
-import { BrowserRouter, Route, Routes } from 'react-router';
+import { HashRouter, Route, Routes } from 'react-router';
import React from 'react';
import { theme } from './theme';
import '@mantine/notifications/styles.css';
@@ -11,7 +11,7 @@ import 'react-resizable/css/styles.css'
import '@mantine/dates/styles.css';
import 'mantine-datatable/styles.css';
import './i18n';
-import {I18nextProvider, useTranslation} from "react-i18next";
+import { I18nextProvider, useTranslation } from "react-i18next";
const Login = React.lazy(() => import('./pages/Login/Login'));
const Error404 = React.lazy(() => import('./pages/Errors/Error404'));
@@ -19,23 +19,23 @@ const DefaultLayout = React.lazy(() => import('./DefaultLayout'));
const PasswordReset = React.lazy(() => import('./pages/PasswordReset'));
export default function App() {
- const { t, i18n } = useTranslation();
+ const { t, i18n } = useTranslation();
return (
-
-
-
-
- } />
- } />
- } />
- {/*} />
+
+
+
+
+ } />
+ } />
+ } />
+ {/*} />
} />*/}
- } />
-
-
-
+ } />
+
+
+
);
}
diff --git a/src/DefaultLayout.tsx b/src/DefaultLayout.tsx
index 45e3ccc7..5b5014df 100644
--- a/src/DefaultLayout.tsx
+++ b/src/DefaultLayout.tsx
@@ -24,7 +24,7 @@ import axios from './axios_config';
import { apiRoutes } from './apiRoutes';
import Navbar from './components/Navbar/Navbar';
import { socket } from './socketio';
-import {t} from "i18next";
+import { t } from "i18next";
export function DefaultLayout() {
const [mobileOpened, { toggle: toggleMobile }] = useDisclosure();
@@ -44,11 +44,11 @@ export function DefaultLayout() {
setSocketConnected(false);
}
- function onAlert(alert:any) {
+ function onAlert(alert: any) {
let message = `${alert.alert_type} from ${alert.callsign}`;
let color = 'red';
let icon = ;
- const alert_sound = new Audio('/alert.mp3');
+ const alert_sound = new Audio('alert.mp3');
alert_sound.play();
if (alert.cancel_time !== null) {
@@ -93,13 +93,13 @@ export function DefaultLayout() {
return (
@@ -120,13 +120,13 @@ export function DefaultLayout() {
OpenTAKServer
} onClick={() => {navigate('/profile')}}>
+ leftSection={} onClick={() => { navigate('/profile') }}>
{t("Profile")}
}
- onClick={() => {
+ disabled={localStorage.getItem('loggedIn') !== 'true'}
+ leftSection={}
+ onClick={() => {
logout();
}}
>
diff --git a/src/apiRoutes.tsx b/src/apiRoutes.tsx
index 91fd93a9..e6065b8d 100644
--- a/src/apiRoutes.tsx
+++ b/src/apiRoutes.tsx
@@ -1,69 +1,69 @@
export const apiRoutes = {
- login: '/api/login?include_auth_token',
- logout: '/api/logout',
- eud: '/api/eud',
- users: '/api/users',
- alerts: '/api/alerts',
- me: '/api/me',
- create_user: '/api/user/create',
- video_streams: '/api/video_streams',
- generate_certificate: '/api/certificate',
- data_packages: '/api/data_packages',
- download_data_packages: '/api/data_packages/download',
- assign_eud_to_user: '/api/user/assign_eud',
- status: '/api/status',
- casevac: '/api/casevac',
- deleteDataPackage: '/api/data_packages',
- addVideoStream: '/api/mediamtx/stream/add',
- deleteVideoStream: '/api/mediamtx/stream/delete',
- updateVideoStream: '/api/mediamtx/stream/update',
- addUser: '/api/user/add',
- changeRole: '/api/user/role',
- deactivateUser: '/api/user/deactivate',
- activateUser: '/api/user/activate',
- deleteUser: '/api/user/delete',
- adminResetPassword: '/api/user/password/reset', //Allows admins to change any user's password
- register: '/api/register',
- tfValidate: '/api/tf-validate',
- tfSetup: '/api/tf-setup',
- resetPassword: '/api/password/reset', //Allows users to reset their own password if they forgot it
- mapState: '/api/map_state',
- getScheduledJobs: '/api/scheduler/jobs',
- runJob: '/api/scheduler/job/run',
- resumeJob: '/api/scheduler/job/resume',
- pauseJob: '/api/scheduler/job/pause',
- getRecording: '/api/videos/recording',
- getRecordings: '/api/videos/recordings',
- deleteRecording: '/api/videos/recording',
- adminSettings: '/api/config',
- modifyJob: '/api/scheduler/job/modify',
- startSSL: '/api/ssl/start',
- stopSSL: '/api/ssl/stop',
- startTCP: '/api/tcp/start',
- stopTCP: '/api/tcp/stop',
- itakQrString: '/api/itak_qr_string',
- meshtasticChannels: '/api/meshtastic/channel',
- generateMeshtasticPsk: '/api/meshtastic/generate_psk',
- pluginPackage: '/api/packages',
- deviceProfiles: '/api/profiles',
- truststore: '/api/truststore',
- missions: '/api/missions',
- groups: '/api/groups',
- mission_invite: '/api/missions/invite',
- eud_stats: '/api/eud_stats',
- plugins: '/api/plugins',
- atakQrString: '/api/atak_qr_string',
- pluginRepo: '/api/plugins/repo',
- ldapLogin: '/api/ldap_login',
- allGroups: '/api/groups/all',
- allUsers: '/api/users/all',
- groupMembers: '/api/groups/members',
- userGroups: '/api/users/groups',
- takgov: '/api/takgov',
- takgovLink: '/api/takgov/link',
- takgovToken: '/api/takgov/token',
- takgovPlugins: '/api/takgov/plugins',
- takgovIcon: '/api/takgov/icon',
- takgovPlugin: '/api/takgov/plugin',
- language: '/api/language',
+ login: 'api/login?include_auth_token',
+ logout: 'api/logout',
+ eud: 'api/eud',
+ users: 'api/users',
+ alerts: 'api/alerts',
+ me: 'api/me',
+ create_user: 'api/user/create',
+ video_streams: 'api/video_streams',
+ generate_certificate: 'api/certificate',
+ data_packages: 'api/data_packages',
+ download_data_packages: 'api/data_packages/download',
+ assign_eud_to_user: 'api/user/assign_eud',
+ status: 'api/status',
+ casevac: 'api/casevac',
+ deleteDataPackage: 'api/data_packages',
+ addVideoStream: 'api/mediamtx/stream/add',
+ deleteVideoStream: 'api/mediamtx/stream/delete',
+ updateVideoStream: 'api/mediamtx/stream/update',
+ addUser: 'api/user/add',
+ changeRole: 'api/user/role',
+ deactivateUser: 'api/user/deactivate',
+ activateUser: 'api/user/activate',
+ deleteUser: 'api/user/delete',
+ adminResetPassword: 'api/user/password/reset', //Allows admins to change any user's password
+ register: 'api/register',
+ tfValidate: 'api/tf-validate',
+ tfSetup: 'api/tf-setup',
+ resetPassword: 'api/password/reset', //Allows users to reset their own password if they forgot it
+ mapState: 'api/map_state',
+ getScheduledJobs: 'api/scheduler/jobs',
+ runJob: 'api/scheduler/job/run',
+ resumeJob: 'api/scheduler/job/resume',
+ pauseJob: 'api/scheduler/job/pause',
+ getRecording: 'api/videos/recording',
+ getRecordings: 'api/videos/recordings',
+ deleteRecording: 'api/videos/recording',
+ adminSettings: 'api/config',
+ modifyJob: 'api/scheduler/job/modify',
+ startSSL: 'api/ssl/start',
+ stopSSL: 'api/ssl/stop',
+ startTCP: 'api/tcp/start',
+ stopTCP: 'api/tcp/stop',
+ itakQrString: 'api/itak_qr_string',
+ meshtasticChannels: 'api/meshtastic/channel',
+ generateMeshtasticPsk: 'api/meshtastic/generate_psk',
+ pluginPackage: 'api/packages',
+ deviceProfiles: 'api/profiles',
+ truststore: 'api/truststore',
+ missions: 'api/missions',
+ groups: 'api/groups',
+ mission_invite: 'api/missions/invite',
+ eud_stats: 'api/eud_stats',
+ plugins: 'api/plugins',
+ atakQrString: 'api/atak_qr_string',
+ pluginRepo: 'api/plugins/repo',
+ ldapLogin: 'api/ldap_login',
+ allGroups: 'api/groups/all',
+ allUsers: 'api/users/all',
+ groupMembers: 'api/groups/members',
+ userGroups: 'api/users/groups',
+ takgov: 'api/takgov',
+ takgovLink: 'api/takgov/link',
+ takgovToken: 'api/takgov/token',
+ takgovPlugins: 'api/takgov/plugins',
+ takgovIcon: 'api/takgov/icon',
+ takgovPlugin: 'api/takgov/plugin',
+ language: 'api/language',
};
diff --git a/src/i18n.js b/src/i18n.js
index befad660..0a7a3b3e 100644
--- a/src/i18n.js
+++ b/src/i18n.js
@@ -1,5 +1,5 @@
import i18n from "i18next";
-import {initReactI18next} from "react-i18next";
+import { initReactI18next } from "react-i18next";
import HttpApi from "i18next-http-backend";
import LanguageDetector from "i18next-browser-languagedetector";
@@ -13,7 +13,7 @@ i18n
returnEmptyString: false,
debug: false,
backend: {
- loadPath: "/locales/{{lng}}/{{ns}}.json",
+ loadPath: "locales/{{lng}}/{{ns}}.json",
}
});
diff --git a/src/pages/Map/Map.tsx b/src/pages/Map/Map.tsx
index 2ebced20..09c074b8 100644
--- a/src/pages/Map/Map.tsx
+++ b/src/pages/Map/Map.tsx
@@ -38,9 +38,9 @@ export default function Map() {
const markersLayer = new L.LayerGroup();
const fovsLayer = new L.LayerGroup();
- function formatDrawer(eud:any, point:any) {
- const detail_rows:ReactElement[] = [];
- const position_rows:ReactElement[] = [];
+ function formatDrawer(eud: any, point: any) {
+ const detail_rows: ReactElement[] = [];
+ const position_rows: ReactElement[] = [];
if (eud !== null) {
Object.keys(eud).map((key, index) => {
@@ -109,7 +109,7 @@ export default function Map() {
return null;
}
- function handleFov(point:any) {
+ function handleFov(point: any) {
if (!point) return;
const uid = point.device_uid;
@@ -139,12 +139,12 @@ export default function Map() {
setFovs(fovs);
} else {
fovs[uid].setLatLngs([[point.latitude, point.longitude],
- [p1.LAT, p1.LON], [p2.LAT, p2.LON]]);
+ [p1.LAT, p1.LON], [p2.LAT, p2.LON]]);
}
}
}
- function addEud(eud:any) {
+ function addEud(eud: any) {
let className = classes.disconnected;
if (eud.last_status === 'Connected') {
className = classes.connected;
@@ -309,26 +309,26 @@ export default function Map() {
if (Object.hasOwn(value, 'iconset_path') &&
value.iconset_path !== null &&
value.iconset_path.includes('COT_MAPPING_SPOTMAP')) {
- if (Object.hasOwn(circles, uid)) {
- map.removeLayer(circles[uid]);
- }
- const circle = L.circle(
- [value.point.latitude, value.point.longitude],
- { radius: 5, color: `#${value.color_hex.slice(2)}` }
- );
- circle.bindTooltip(value.callsign, {
- opacity: 0.7,
- permanent: true,
- direction: 'bottom',
- });
- circle.on('click', (e) => {
- setDrawerTitle(value.callsign);
- formatDrawer(value, null);
- open();
- });
- circles[uid] = circle;
- setCircles(circles);
- circle.addTo(map);
+ if (Object.hasOwn(circles, uid)) {
+ map.removeLayer(circles[uid]);
+ }
+ const circle = L.circle(
+ [value.point.latitude, value.point.longitude],
+ { radius: 5, color: `#${value.color_hex.slice(2)}` }
+ );
+ circle.bindTooltip(value.callsign, {
+ opacity: 0.7,
+ permanent: true,
+ direction: 'bottom',
+ });
+ circle.on('click', (e) => {
+ setDrawerTitle(value.callsign);
+ formatDrawer(value, null);
+ open();
+ });
+ circles[uid] = circle;
+ setCircles(circles);
+ circle.addTo(map);
} else {
let marker = L.marker([value.point.latitude, value.point.longitude]);
if (Object.hasOwn(markers, uid)) {
@@ -372,8 +372,8 @@ export default function Map() {
}));
} else {
marker.setIcon(L.icon({
- iconUrl: '/map_icons/marker-icon.png',
- shadowUrl: '/map_icons/marker-shadow.png',
+ iconUrl: 'map_icons/marker-icon.png',
+ shadowUrl: 'map_icons/marker-shadow.png',
iconAnchor: [12, 24],
popupAnchor: [7, -20],
tooltipAnchor: [-4, -10],
@@ -457,13 +457,13 @@ export default function Map() {
return (
<>
@@ -476,21 +476,21 @@ export default function Map() {
@@ -512,19 +512,20 @@ export default function Map() {
diff --git a/vite.config.mjs b/vite.config.mjs
index 8c572128..48998370 100644
--- a/vite.config.mjs
+++ b/vite.config.mjs
@@ -3,6 +3,7 @@ import react from '@vitejs/plugin-react';
import tsconfigPaths from 'vite-tsconfig-paths';
export default defineConfig({
+ base: './',
plugins: [react(), tsconfigPaths()],
test: {
globals: true,