diff --git a/web/liveman/components/login.tsx b/web/liveman/components/login.tsx
index e152738..cf4c032 100644
--- a/web/liveman/components/login.tsx
+++ b/web/liveman/components/login.tsx
@@ -26,7 +26,7 @@ function useInput(label: string, type = 'text') {
export interface LoginProps {
show: boolean;
- onSuccess?: (token: string) => void;
+ onSuccess?: (tokenType: string, tokenValue: string) => void;
}
export function Login({ show, onSuccess }: LoginProps) {
@@ -76,7 +76,7 @@ export function Login({ show, onSuccess }: LoginProps) {
const tk = `${tokenType} ${tokenValue}`;
livemanApi.setAuthToken(tk);
sharedApi.setAuthToken(tk);
- onSuccess?.(tokenValue);
+ onSuccess?.(tokenType, tokenValue);
} catch (e) {
livemanApi.setAuthToken('');
sharedApi.setAuthToken('');
diff --git a/web/liveman/components/nodes-table.tsx b/web/liveman/components/nodes-table.tsx
index 9a985fb..8356603 100644
--- a/web/liveman/components/nodes-table.tsx
+++ b/web/liveman/components/nodes-table.tsx
@@ -18,9 +18,7 @@ export function NodesTable() {
const tokenContext = useContext(TokenContext);
useEffect(() => {
- if (tokenContext.token.length > 0) {
- nodes.updateData();
- }
+ nodes.updateData();
}, [tokenContext.token]);
return (
@@ -57,7 +55,7 @@ export function NodesTable() {
{n.status}
{n.duration}
- {location.href + '?nodes=' + n.alias}
+
) :
N/A |
}
@@ -76,7 +74,6 @@ function NodeStrategyLabel({ strategy }: NodeStrategyLabelProps) {
return (
- {/* */}
{entries[0].join(' = ')}
@@ -95,3 +92,12 @@ function NodeStrategyLabel({ strategy }: NodeStrategyLabelProps) {
);
}
+
+function NodeLink({ node }: { node: Node }) {
+ const urlObject = new URL(location.href);
+ urlObject.searchParams.set('nodes', node.alias);
+ const url = urlObject.toString();
+ return (
+ {url}
+ );
+}
diff --git a/web/liveman/liveman.tsx b/web/liveman/liveman.tsx
index 7cc4731..157bf59 100644
--- a/web/liveman/liveman.tsx
+++ b/web/liveman/liveman.tsx
@@ -1,25 +1,33 @@
import { useCallback, useEffect, useRef, useState } from 'preact/hooks';
import { Button } from 'react-daisyui';
-import { type Stream } from '@/shared/api';
import { useNeedAuthorization } from '@/shared/hooks/use-need-authorization';
import { StreamsTable } from '@/shared/components/streams-table';
import { PageLayout } from '@/shared/components/page-layout';
import * as api from './api';
-import { Login } from './components/login';
+import { type LoginProps, Login } from './components/login';
import { NodesTable } from './components/nodes-table';
import { type IStreamTokenDialog, StreamTokenDialog } from './components/dialog-token';
+const TOKEN_KEY = 'liveman_auth_token';
+const initialToken = localStorage.getItem(TOKEN_KEY) ?? '';
+if (initialToken) {
+ api.setAuthToken(initialToken);
+}
+
+const initialNodes = new URLSearchParams(location.search).getAll('nodes');
+
export function Liveman() {
- const [token, setToken] = useState('');
+ const [token, setToken] = useState(initialToken);
const [needsAuthorizaiton, setNeedsAuthorization] = useNeedAuthorization(api);
- const onLoginSuccess = (t: string) => {
- setToken(t);
+ const onLoginSuccess: LoginProps['onSuccess'] = (tokenType, tokenValue) => {
+ setToken(tokenValue);
setNeedsAuthorization(false);
+ localStorage.setItem(TOKEN_KEY, `${tokenType} ${tokenValue}`);
};
- const [filterNodes, setFilterNodes] = useState();
+ const [filterNodes, setFilterNodes] = useState(initialNodes);
useEffect(() => {
const params = new URLSearchParams(location.search);
setFilterNodes(params.getAll('nodes'));
@@ -27,10 +35,10 @@ export function Liveman() {
const getStreams = useCallback(async () => {
const streams = await api.getStreams(filterNodes);
return streams.sort((a, b) => a.createdAt - b.createdAt);
- }, [filterNodes]);
+ }, filterNodes);
const getWhxpUrl = (whxp: 'whep' | 'whip', streamId: string) => {
let url = `/${whxp}/${streamId}`;
- if (filterNodes && filterNodes.length > 0) {
+ if (filterNodes.length > 0) {
const params = new URLSearchParams();
filterNodes?.forEach(v => params.append('nodes', v));
url += `?${params.toString()}`;
@@ -39,21 +47,18 @@ export function Liveman() {
};
const refStreamTokenDialog = useRef(null);
- const renderCreateToken = useCallback((stream: Stream) => {
- return (
-
- );
- }, []);
return (
<>
- {filterNodes && filterNodes.length > 0 ? null : }
+ {filterNodes.length > 0 ? null : }
getWhxpUrl('whep', streamId)}
getWhipUrl={streamId => getWhxpUrl('whip', streamId)}
- renderExtraActions={renderCreateToken}
+ renderExtraActions={stream => (
+
+ )}
/>
diff --git a/web/shared/components/streams-table.tsx b/web/shared/components/streams-table.tsx
index ea971f6..40e95b6 100644
--- a/web/shared/components/streams-table.tsx
+++ b/web/shared/components/streams-table.tsx
@@ -44,9 +44,7 @@ export function StreamsTable(props: StreamTableProps) {
const tokenContext = useContext(TokenContext);
useEffect(() => {
- if (tokenContext.token.length > 0) {
- streams.updateData();
- }
+ streams.updateData();
}, [tokenContext.token]);
const handleViewClients = (id: string) => {
diff --git a/web/shared/hooks/use-refresh-timer.ts b/web/shared/hooks/use-refresh-timer.ts
index e3518bd..9ce1f0a 100644
--- a/web/shared/hooks/use-refresh-timer.ts
+++ b/web/shared/hooks/use-refresh-timer.ts
@@ -1,16 +1,12 @@
import { useCallback, useEffect, useState } from 'preact/hooks';
-export function useRefreshTimer(initial: T, fetchData: () => Promise, timeout = 3000, immediate = true) {
+export function useRefreshTimer(initial: T, fetchData: () => Promise, timeout = 3000) {
const [data, setData] = useState(initial);
- const [isImmediate, _setIsImmediate] = useState(immediate);
const [refreshTimer, setRefreshTimer] = useState(-1);
const isRefreshing = refreshTimer > 0;
+
const updateData = useCallback(async () => setData(await fetchData()), [fetchData]);
- useEffect(() => {
- if (isImmediate) {
- updateData();
- }
- }, []);
+
useEffect(() => {
if (isRefreshing) {
window.clearInterval(refreshTimer);
@@ -20,6 +16,7 @@ export function useRefreshTimer(initial: T, fetchData: () => Promise, time
window.clearInterval(refreshTimer);
};
}, [updateData, timeout]);
+
const toggleTimer = () => {
if (isRefreshing) {
clearInterval(refreshTimer);
@@ -29,6 +26,7 @@ export function useRefreshTimer(initial: T, fetchData: () => Promise, time
setRefreshTimer(window.setInterval(updateData, timeout));
}
};
+
return {
data,
isRefreshing,