Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Source management additional filtering #2

Merged
merged 10 commits into from
Sep 4, 2024
20 changes: 19 additions & 1 deletion src/api/agileLive/ingest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,25 @@ export async function getSourceThumbnail(
);
if (response.ok) {
const json = (await response.json()) as ResourcesThumbnailResponse;
return json?.data;
return json.data;
}
throw await response.json();
}

export async function getIngestSources(uuid: string) {
const response = await fetch(
new URL(
AGILE_BASE_API_PATH + `/ingests/${uuid}/sources?expand=true`,
process.env.AGILE_URL
),
{
headers: {
authorization: getAuthorizationHeader()
}
}
);
if (response.ok) {
return response.json();
}
throw await response.json();
}
24 changes: 24 additions & 0 deletions src/app/api/manager/sources/resources/[id]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { NextResponse, NextRequest } from 'next/server';
import { getIngestSources } from '../../../../../../api/agileLive/ingest';
import { isAuthenticated } from '../../../../../../api/manager/auth';

type Params = {
id: string;
};

export async function GET(
request: NextRequest,
{ params }: { params: Params }
): Promise<NextResponse> {
if (!(await isAuthenticated())) {
return new NextResponse(`Not Authorized!`, {
status: 403
});
}

try {
return NextResponse.json(await getIngestSources(params.id));
} catch (e) {
return new NextResponse(e?.toString(), { status: 404 });
}
}
17 changes: 17 additions & 0 deletions src/app/api/manager/sources/resources/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { NextResponse } from 'next/server';
import { isAuthenticated } from '../../../../../api/manager/auth';
import { getIngests } from '../../../../../api/agileLive/ingest';

export async function GET(): Promise<NextResponse> {
if (!(await isAuthenticated())) {
return new NextResponse(`Not Authorized!`, {
status: 403
});
}

try {
return NextResponse.json(await getIngests());
} catch (e) {
return new NextResponse(e?.toString(), { status: 404 });
}
}
80 changes: 77 additions & 3 deletions src/components/filter/FilterDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,16 @@ function FilterDropdown({
isLocationHidden,
showConfigSources,
selectedTags,
showNdiType,
showBmdType,
showSrtType,
setIsTypeHidden,
setIsLocationHidden,
setSelectedTags,
setOnlyShowActiveSources: setOnlyShowConfigSources
setOnlyShowActiveSources: setOnlyShowConfigSources,
setOnlyShowNdiSources: setOnlyShowNdiSources,
setOnlyShowBmdSources: setOnlyShowBmdSources,
setOnlyShowSrtSources: setOnlyShowSrtSources
}: {
close: () => void;
types: string[];
Expand All @@ -23,10 +29,16 @@ function FilterDropdown({
isLocationHidden: boolean;
showConfigSources: boolean;
selectedTags: Set<string>;
showNdiType: boolean;
showSrtType: boolean;
showBmdType: boolean;
setIsTypeHidden: React.Dispatch<React.SetStateAction<boolean>>;
setIsLocationHidden: React.Dispatch<React.SetStateAction<boolean>>;
setOnlyShowActiveSources: React.Dispatch<React.SetStateAction<boolean>>;
setSelectedTags: React.Dispatch<React.SetStateAction<Set<string>>>;
setOnlyShowNdiSources: React.Dispatch<React.SetStateAction<boolean>>;
setOnlyShowBmdSources: React.Dispatch<React.SetStateAction<boolean>>;
setOnlyShowSrtSources: React.Dispatch<React.SetStateAction<boolean>>;
}) {
const [searchedTypes, setSearchedTypes] = useState<string[]>([]);
const [searchedLocations, setSearchedLocations] = useState<string[]>([]);
Expand All @@ -48,6 +60,18 @@ function FilterDropdown({
setOnlyShowConfigSources(!showConfigSources);
};

const showSelectedNdiType = () => {
setOnlyShowNdiSources(!showNdiType);
};

const showSelectedSrtType = () => {
setOnlyShowSrtSources(!showSrtType);
};

const showSelectedBmdType = () => {
setOnlyShowBmdSources(!showBmdType);
};

const deleteTag = (value: string) => {
const temp = selectedTags;
temp.delete(value);
Expand Down Expand Up @@ -98,6 +122,9 @@ function FilterDropdown({
const handleClear = () => {
setSelectedTags(new Set<string>());
setOnlyShowConfigSources(false);
setOnlyShowBmdSources(false);
setOnlyShowNdiSources(false);
setOnlyShowSrtSources(false);
};

const typesSearch = (event: ChangeEvent<HTMLInputElement>) => {
Expand Down Expand Up @@ -222,17 +249,64 @@ function FilterDropdown({
<input
id="showSelectedCheckbox"
type="checkbox"
className="flex ml-2 mb-2 w-4 justify-center rounded-lg text-zinc-300"
className="flex ml-2 w-4 justify-center rounded-lg text-zinc-300"
checked={showConfigSources}
onChange={showSelectedConfigSources}
/>
<label
className="ml-2 mt-2 text-left text-zinc-300"
className="ml-2 mt-1 text-left text-zinc-300"
htmlFor="showSelectedCheckbox"
>
{t('inventory_list.active_sources')}
</label>
</div>
<div className="flex flex-row">
<input
id="showNdiCheckbox"
type="checkbox"
className="flex ml-2 w-4 justify-center rounded-lg text-zinc-300"
checked={showNdiType}
onChange={showSelectedNdiType}
/>
<label
className="ml-2 mt-1 text-left text-zinc-300"
htmlFor="showNdiCheckbox"
>
NDI
</label>
</div>
<div className="flex flex-row">
<input
id="showSrtCheckbox"
type="checkbox"
className="flex ml-2 w-4 justify-center rounded-lg text-zinc-300"
checked={showSrtType}
onChange={showSelectedSrtType}
/>
<label
className="ml-2 mt-1 text-left text-zinc-300"
htmlFor="showSrtCheckbox"
>
SRT
</label>
</div>
<div className="flex flex-row">
<input
id="showBmdCheckbox"
type="checkbox"
className="flex ml-2 w-4 justify-center rounded-lg text-zinc-300"
checked={showBmdType}
onChange={showSelectedBmdType}
/>
<label
className="ml-2 mt-1 text-left text-zinc-300"
htmlFor="showBmdCheckbox"
>
SDI/HDMI
</label>
</div>
</div>
<div className="flex self-end justify-end mt-4">
<button
onClick={handleClear}
id="dropdownCheckboxButton"
Expand Down
73 changes: 61 additions & 12 deletions src/components/filter/FilterOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,57 @@ import FilterDropdown from './FilterDropdown';
import { ClickAwayListener } from '@mui/base';
import { SourceWithId } from '../../interfaces/Source';
import { FilterContext } from '../inventory/FilterContext';
import { useResources } from '../../hooks/sources/useResources';

function FilterOptions({
onFilteredSources
}: {
type FilterOptionsProps = {
onFilteredSources: (sources: Map<string, SourceWithId>) => void;
}) {
};

function FilterOptions({ onFilteredSources }: FilterOptionsProps) {
const { locations, types, sources } = useContext(FilterContext);
const [resources] = useResources();

const [onlyShowActiveSources, setOnlyShowActiveSources] = useState(false);
const [onlyShowNdiSources, setOnlyShowNdiSources] = useState(false);
const [onlyShowBmdSources, setOnlyShowBmdSources] = useState(false);
const [onlyShowSrtSources, setOnlyShowSrtSources] = useState(false);
const [isFilterHidden, setIsFilterHidden] = useState(true);
const [isTypeHidden, setIsTypeHidden] = useState(true);
const [isLocationHidden, setIsLocationHidden] = useState(true);
const [searchString, setSearchString] = useState<string>('');
const [selectedTags, setSelectedTags] = useState<Set<string>>(
new Set<string>()
);

let tempSet = new Map<string, SourceWithId>(sources);

useEffect(() => {
if (
selectedTags.size === 0 &&
searchString.length === 0 &&
!onlyShowActiveSources
!onlyShowActiveSources &&
!onlyShowNdiSources &&
!onlyShowBmdSources &&
!onlyShowSrtSources
) {
resetFilter();
return;
}

handleSearch();
handleTags();
handleShowActiveSources();
filterSources();

onFilteredSources(tempSet);
tempSet.clear();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [searchString, selectedTags, onlyShowActiveSources]);
}, [
searchString,
selectedTags,
onlyShowActiveSources,
onlyShowNdiSources,
onlyShowBmdSources,
onlyShowSrtSources
]);

const resetFilter = () => {
tempSet = new Map<string, SourceWithId>(sources);
Expand Down Expand Up @@ -90,10 +105,38 @@ function FilterOptions({
}
};

const handleShowActiveSources = () => {
if (onlyShowActiveSources) {
for (const source of tempSet.values()) {
if (source.status === 'gone') {
const filterSources = async () => {
for (const source of tempSet.values()) {
const correspondingResource = resources.find(
(resource) => resource.name === source.ingest_source_name
);

if (correspondingResource) {
let shouldDelete = false;
const isNdiSelected =
onlyShowNdiSources &&
correspondingResource.type.toUpperCase() === 'NDI';
const isBmdSelected =
onlyShowBmdSources &&
correspondingResource.type.toUpperCase() === 'BMD';
const isSrtSelected =
onlyShowSrtSources &&
correspondingResource.type.toUpperCase() === 'SRT';

if (
(onlyShowNdiSources || onlyShowBmdSources || onlyShowSrtSources) &&
!isNdiSelected &&
!isBmdSelected &&
!isSrtSelected
) {
shouldDelete = true;
}

if (onlyShowActiveSources && source.status === 'gone') {
shouldDelete = true;
}

if (shouldDelete) {
tempSet.delete(source._id.toString());
}
}
Expand Down Expand Up @@ -127,6 +170,12 @@ function FilterOptions({
setIsLocationHidden={setIsLocationHidden}
setSelectedTags={setSelectedTags}
setOnlyShowActiveSources={setOnlyShowActiveSources}
setOnlyShowNdiSources={setOnlyShowNdiSources}
setOnlyShowBmdSources={setOnlyShowBmdSources}
setOnlyShowSrtSources={setOnlyShowSrtSources}
showBmdType={onlyShowBmdSources}
showNdiType={onlyShowNdiSources}
showSrtType={onlyShowSrtSources}
/>
</div>
</ClickAwayListener>
Expand Down
48 changes: 48 additions & 0 deletions src/hooks/sources/useResources.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import {
ResourcesSourceResponse,
ResourcesCompactIngestResponse
} from '../../../types/agile-live';
import { useState, useEffect } from 'react';

export function useResources() {
const [ingests, setIngests] = useState<ResourcesCompactIngestResponse[]>([]);
const [resources, setResources] = useState<ResourcesSourceResponse[]>([]);

useEffect(() => {
let isMounted = true;

const getIngests = async () =>
await fetch(`/api/manager/sources/resources`, {
method: 'GET',
headers: [['x-api-key', `Bearer apisecretkey`]]
}).then(async (response) => {
const ing = await response.json();
if (isMounted) {
setIngests(ing);
}
});
getIngests();
return () => {
isMounted = false;
};
}, []);

useEffect(() => {
if (ingests) {
for (let i = 0; i < ingests.length; i++) {
const id = ingests[i].uuid;
if (id) {
fetch(`/api/manager/sources/resources/${id}`, {
method: 'GET',
headers: [['x-api-key', `Bearer apisecretkey`]]
}).then(async (response) => {
const sources = await response.json();
setResources(sources);
});
}
}
}
}, [ingests]);

return [resources];
}
Loading