Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions backend/src/services/file-query.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
private eventRepo: Repository<FileEventEntity>,
) {}

async findMany(

Check warning on line 83 in backend/src/services/file-query.service.ts

View workflow job for this annotation

GitHub Actions / eslint

Async method 'findMany' has a complexity of 53. Maximum allowed is 20
query: FileQueryDto,
userUuid: string,
apiKeyMissionUuid?: string,
Expand Down Expand Up @@ -123,7 +123,7 @@
// Apply mission filters
const missionUuids =
query.missionUuids ??
(query.missionUUID

Check warning on line 126 in backend/src/services/file-query.service.ts

View workflow job for this annotation

GitHub Actions / eslint

Do not nest ternary expressions
? [query.missionUUID]
: apiKeyMissionUuid
? [apiKeyMissionUuid]
Expand Down Expand Up @@ -257,6 +257,18 @@
}
}

if (query.includeStates && query.includeStates.length > 0) {
idQuery.andWhere('file.state IN (:...includeStates)', {
includeStates: query.includeStates,
});
}

if (query.excludeStates && query.excludeStates.length > 0) {
idQuery.andWhere('file.state NOT IN (:...excludeStates)', {
excludeStates: query.excludeStates,
});
}

const categoryUUIDs = query.categories
? query.categories.split(',')
: [];
Expand Down
2 changes: 2 additions & 0 deletions cli/kleinkram/api/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ class FileQuery:
patterns: List[str] = field(default_factory=list)
ids: List[UUID] = field(default_factory=list)
mission_query: MissionQuery = field(default_factory=MissionQuery)
include_states: List[str] = field(default_factory=list)
exclude_states: List[str] = field(default_factory=list)


@dataclass
Expand Down
6 changes: 6 additions & 0 deletions cli/kleinkram/api/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ class Params(str, Enum):
MISSION_IDS = "missionUuids"
PROJECT_PATTERNS = "projectPatterns"
PROJECT_IDS = "projectUuids"
INCLUDE_STATES = "includeStates"
EXCLUDE_STATES = "excludeStates"


def _handle_list_params(params: Dict[str, Any]) -> Dict[str, Any]:
Expand Down Expand Up @@ -151,6 +153,10 @@ def _file_query_to_params(file_query: FileQuery) -> Dict[str, List[str]]:
params[Params.FILE_PATTERNS.value] = list(file_query.patterns)
if file_query.ids:
params[Params.FILE_IDS.value] = list(map(str, file_query.ids))
if file_query.include_states:
params[Params.INCLUDE_STATES.value] = file_query.include_states
if file_query.exclude_states:
params[Params.EXCLUDE_STATES.value] = file_query.exclude_states
return params


Expand Down
28 changes: 25 additions & 3 deletions cli/kleinkram/cli/_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from kleinkram.api.routes import get_file
from kleinkram.api.routes import get_files
from kleinkram.config import get_shared_state
from kleinkram.models import FileState
from kleinkram.printing import print_file_info
from kleinkram.printing import print_files
from kleinkram.utils import split_args
Expand Down Expand Up @@ -91,8 +92,21 @@ def list_files(
None,
help="file names, ids or patterns",
),
projects: Optional[List[str]] = typer.Option(None, "--project", "-p", help="project name or id"),
missions: Optional[List[str]] = typer.Option(None, "--mission", "-m", help="mission name or id"),
projects: Optional[List[str]] = typer.Option(
None, "--project", "-p", help="project name or id. Repeat flag for multiple values"
),
missions: Optional[List[str]] = typer.Option(
None, "--mission", "-m", help="mission name or id. Repeat flag for multiple values"
),
include_canceled: bool = typer.Option(False, "--include-canceled", help="include canceled files"),
include_states: Optional[List[FileState]] = typer.Option(
None,
"--include-states",
help="file states to include. Repeat flag for multiple (e.g. --include-states OK --include-states FOUND)",
),
exclude_states: Optional[List[FileState]] = typer.Option(
None, "--exclude-states", help="file states to exclude. Repeat flag for multiple values"
),
) -> None:
file_ids, file_patterns = split_args(files or [])
mission_ids, mission_patterns = split_args(missions or [])
Expand All @@ -104,7 +118,15 @@ def list_files(
ids=mission_ids,
patterns=mission_patterns,
)
file_query = FileQuery(mission_query=mission_query, patterns=file_patterns, ids=file_ids)
file_query = FileQuery(
mission_query=mission_query,
patterns=file_patterns,
ids=file_ids,
include_states=[state.value for state in include_states] if include_states else [],
exclude_states=(
[state.value for state in exclude_states] if exclude_states else (["CANCELED"] if not include_canceled else [])
),
)

client = AuthenticatedClient()
parsed_files = list(get_files(client, file_query=file_query))
Expand Down
4 changes: 3 additions & 1 deletion cli/kleinkram/cli/_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ def files(
) -> None:
from kleinkram.cli._file import list_files

list_files(files=files, projects=projects, missions=missions)
list_files(
files=files, projects=projects, missions=missions, include_canceled=False, include_states=None, exclude_states=None
)


@list_typer.command()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@
import type { CategoryDto } from '@kleinkram/api-dto/types/category.dto';
import type { FileWithTopicDto } from '@kleinkram/api-dto/types/file/file.dto';
import type { FilesDto } from '@kleinkram/api-dto/types/file/files.dto';
import { FileType, HealthStatus } from '@kleinkram/shared';
import { FileState, FileType, HealthStatus } from '@kleinkram/shared';
import {
keepPreviousData,
useQuery,
Expand Down Expand Up @@ -381,6 +381,8 @@ const {
? h.searchParams.messageDatatypes.split(',')
: undefined,
h.searchParams.matchAllTopics === 'true',
undefined,
[FileState.CANCELED],
);
},
placeholderData: keepPreviousData,
Expand Down
19 changes: 17 additions & 2 deletions frontend/src/services/queries/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { FilesDto } from '@kleinkram/api-dto/types/file/files.dto';
import type { FoxgloveLinkResponseDto } from '@kleinkram/api-dto/types/file/foxglove-link-response.dto';
import type { IsUploadingDto } from '@kleinkram/api-dto/types/file/is-uploading.dto';
import type { StorageOverviewDto } from '@kleinkram/api-dto/types/storage-overview.dto';
import { FileType, HealthStatus } from '@kleinkram/shared';
import { FileState, FileType, HealthStatus } from '@kleinkram/shared';
import { AxiosResponse } from 'axios';
import axios from 'src/api/axios';

Expand All @@ -27,6 +27,8 @@ export interface FilteredFilesConfig {
sort?: string | undefined;
desc?: boolean | undefined;
health?: HealthStatus | undefined;
includeStates?: FileState[] | undefined;
excludeStates?: FileState[] | undefined;
}

export const fetchFilteredFiles = async (
Expand All @@ -50,6 +52,8 @@ export const fetchFilteredFiles = async (
sort,
desc,
health,
includeStates,
excludeStates,
} = config;
try {
const parameters: Record<string, string> = {};
Expand All @@ -74,8 +78,15 @@ export const fetchFilteredFiles = async (
if (desc !== undefined)
parameters.sortDirection = desc ? 'DESC' : 'ASC';
if (health) parameters.health = health;
const stateParameters = new URLSearchParams(parameters);
for (const state of includeStates ?? []) {
stateParameters.append('includeStates', state);
}
for (const state of excludeStates ?? []) {
stateParameters.append('excludeStates', state);
}

const queryParameters = new URLSearchParams(parameters).toString();
const queryParameters = stateParameters.toString();
const response: AxiosResponse<FilesDto> = await axios.get<FilesDto>(
`/files?${queryParameters}`,
);
Expand Down Expand Up @@ -131,6 +142,8 @@ export const filesOfMission = async (
topics?: string[],
messageDatatypes?: string[],
matchAllTopics = true,
includeStates?: FileState[],
excludeStates?: FileState[],
): Promise<FilesDto> => {
const tag: Record<string, unknown> = {};

Expand All @@ -150,6 +163,8 @@ export const filesOfMission = async (
endDate,
topics,
messageDatatypes,
includeStates,
excludeStates,
});
};

Expand Down
30 changes: 29 additions & 1 deletion packages/api-dto/src/types/file/file-query.dto.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { MissionQueryDto } from '@api-dto/mission/mission-query.dto';
import { HealthStatus } from '@kleinkram/shared';
import { FileState, HealthStatus } from '@kleinkram/shared';
import { ApiProperty } from '@nestjs/swagger';
import { Transform, Type } from 'class-transformer';
import {
Expand Down Expand Up @@ -176,4 +176,32 @@ export class FileQueryDto extends MissionQueryDto {
@IsString()
@ApiProperty({ required: false })
sort?: string;

@IsOptional()
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
@Transform(({ value }) => (Array.isArray(value) ? value : [value]))
@IsArray()
@ArrayNotEmpty()
@IsEnum(FileState, { each: true })
@ApiProperty({
required: false,
isArray: true,
enum: FileState,
description: 'File states to include (whitelist)',
})
includeStates?: FileState[];

@IsOptional()
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
@Transform(({ value }) => (Array.isArray(value) ? value : [value]))
@IsArray()
@ArrayNotEmpty()
@IsEnum(FileState, { each: true })
@ApiProperty({
required: false,
isArray: true,
enum: FileState,
description: 'File states to exclude (blacklist)',
})
excludeStates?: FileState[];
}
Loading