Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
8aabbc0
feat: comment out condition for new action docker hub namespace to st…
lbarberi1927 Oct 7, 2025
f5d73ca
bump version to 0.51.0
wp99cp Oct 10, 2025
973e5e2
feat: missions get command returns files count and files size
lbarberi1927 Oct 10, 2025
1928ecb
fix: run and fix eslint checks
lbarberi1927 Oct 10, 2025
ad2778d
docs: Add MCAP compression best practices guide
Idate96 Oct 13, 2025
2b66742
Merge pull request #1811 from leggedrobotics/feat/1790_show_n_files_l…
wp99cp Oct 13, 2025
1bd80a8
feat: define environment variable for docker hub namespace restrictions
lbarberi1927 Oct 13, 2025
fa31d10
fix: update documentation
lbarberi1927 Oct 13, 2025
6f505c9
fix: get_project has exact_match param set to True where needed
lbarberi1927 Oct 13, 2025
e9059af
chore(deps-dev): bump vue-tsc from 3.0.8 to 3.1.1 in /frontend
dependabot[bot] Oct 13, 2025
6e9ebf5
chore(deps): bump @nestjs/bull from 11.0.3 to 11.0.4 in /queueConsumer
dependabot[bot] Oct 13, 2025
752584c
chore(deps-dev): bump @types/node in /queueConsumer
dependabot[bot] Oct 13, 2025
6b96760
chore(deps): bump googleapis from 161.0.0 to 162.0.0 in /queueConsumer
dependabot[bot] Oct 13, 2025
b343c11
chore(deps-dev): bump @types/node from 24.7.1 to 24.7.2 in /common
dependabot[bot] Oct 13, 2025
2600f34
chore(deps): bump @tanstack/vue-query from 5.90.2 to 5.90.3 in /frontend
dependabot[bot] Oct 13, 2025
aaa69aa
chore(deps): bump systeminformation in /queueConsumer
dependabot[bot] Oct 13, 2025
f53dce3
chore(deps-dev): bump @types/node from 24.7.0 to 24.7.2 in /frontend
dependabot[bot] Oct 13, 2025
c795aee
chore(deps): bump vue from 3.5.21 to 3.5.22 in /frontend
dependabot[bot] Oct 13, 2025
6994538
chore(deps): bump @swc/core from 1.13.3 to 1.13.5 in /backend
dependabot[bot] Oct 13, 2025
61d5c32
chore(deps-dev): bump eslint from 9.36.0 to 9.37.0 in /backend
dependabot[bot] Oct 13, 2025
81d7943
chore(deps): bump @nestjs/common from 10.4.17 to 10.4.20 in /backend
dependabot[bot] Oct 13, 2025
f6970ec
fix: tailing spaces on project names raises informative error
lbarberi1927 Oct 14, 2025
d6a74eb
Merge remote-tracking branch 'origin/dependabot/npm_and_yarn/backend/…
wp99cp Oct 15, 2025
81d4e8a
Merge remote-tracking branch 'origin/dependabot/npm_and_yarn/backend/…
wp99cp Oct 15, 2025
a695c2f
Merge remote-tracking branch 'origin/dependabot/npm_and_yarn/frontend…
wp99cp Oct 15, 2025
8fda4da
Merge remote-tracking branch 'origin/dependabot/npm_and_yarn/frontend…
wp99cp Oct 15, 2025
a5d5d08
Merge remote-tracking branch 'origin/dependabot/npm_and_yarn/frontend…
wp99cp Oct 15, 2025
8eac9f7
Merge remote-tracking branch 'origin/dependabot/npm_and_yarn/queueCon…
wp99cp Oct 15, 2025
17386e3
Merge remote-tracking branch 'origin/dependabot/npm_and_yarn/common/s…
wp99cp Oct 15, 2025
c34b287
Merge remote-tracking branch 'origin/dependabot/npm_and_yarn/queueCon…
wp99cp Oct 15, 2025
531f41c
Merge remote-tracking branch 'origin/dependabot/npm_and_yarn/queueCon…
wp99cp Oct 15, 2025
5190862
Merge remote-tracking branch 'origin/dependabot/npm_and_yarn/queueCon…
wp99cp Oct 15, 2025
b960a9e
Merge remote-tracking branch 'origin/dependabot/npm_and_yarn/frontend…
wp99cp Oct 15, 2025
de98235
Merge branch 'dev' of https://github.com/leggedrobotics/kleinkram int…
wp99cp Oct 15, 2025
bcde474
Merge remote-tracking branch 'origin/fix/1786_ignore_tailing_spaces' …
wp99cp Oct 15, 2025
bea569d
Merge remote-tracking branch 'origin/fix/1787_duplicate_project_name_…
wp99cp Oct 15, 2025
6ea42bd
Merge remote-tracking branch 'origin/feat/1757_actions_arbitrary_name…
wp99cp Oct 15, 2025
ad21ca3
Merge remote-tracking branch 'origin/docs/mcap-compression-guide' int…
wp99cp Oct 15, 2025
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
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,6 @@ GOOGLE_ARTIFACT_UPLOADER_KEY_FILE=anymal-grand-tour-3b7a5d0c8ef4.json
# can be left empty if you don't want to use docker hub
DOCKER_HUB_USERNAME=
DOCKER_HUB_PASSWORD=
VITE_DOCKER_HUB_NAMESPACE=

ARTIFACTS_UPLOADER_IMAGE=rslethz/grandtour-datasets:artifact-uploader-latest
8 changes: 4 additions & 4 deletions backend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "kleinkram-backend",
"version": "0.51.0",
"version": "0.52.0",
"description": "",
"author": "",
"private": true,
Expand All @@ -20,7 +20,7 @@
"dependencies": {
"@aws-sdk/client-sts": "3.726.1",
"@google-cloud/local-auth": "^3.0.1",
"@nestjs/common": "^10.4.7",
"@nestjs/common": "^10.4.20",
"@nestjs/config": "^4.0.2",
"@nestjs/core": "^10.4.5",
"@nestjs/jwt": "^11.0.0",
Expand All @@ -41,7 +41,7 @@
"@opentelemetry/instrumentation-winston": "^0.51.0",
"@opentelemetry/sdk-node": "^0.206.0",
"@opentelemetry/sdk-trace-base": "^2.0.0",
"@swc/core": "^1.13.3",
"@swc/core": "^1.13.5",
"@swc/jest": "^0.2.39",
"@willsoto/nestjs-prometheus": "^6.0.1",
"aws4": "^1.13.2",
Expand Down Expand Up @@ -89,7 +89,7 @@
"@types/passport-google-oauth20": "^2.0.16",
"@typescript-eslint/eslint-plugin": "^8.32.1",
"@typescript-eslint/parser": "^8.25.0",
"eslint": "^9.36.0",
"eslint": "^9.37.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.4",
"jest": "^29.7.0",
Expand Down
8 changes: 2 additions & 6 deletions backend/src/serialization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,8 @@ export const missionEntityToDtoWithCreator = (
export const missionEntityToFlatDto = (mission: Mission): FlatMissionDto => {
return {
...missionEntityToDtoWithCreator(mission),
filesCount: mission.files?.length || 0,
size:
mission.files?.reduce(
(accumulator, file) => accumulator + (file.size ?? 0),
0,
) || 0,
filesCount: mission.fileCount ?? 0,
size: mission.size ?? 0,
};
};

Expand Down
19 changes: 12 additions & 7 deletions backend/src/services/action.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,14 @@ export class ActionService {
data: CreateTemplateDto,
auth: AuthHeader,
): Promise<ActionTemplateDto> {
if (!data.dockerImage.startsWith('rslethz/')) {
const dockerhub_namespace = process.env['VITE_DOCKER_HUB_NAMESPACE'];
// assert that we only run images from a specified namespace
if (
dockerhub_namespace !== undefined &&
!data.dockerImage.startsWith(dockerhub_namespace)
) {
throw new ConflictException(
'Only images from the rslethz namespace are allowed',
`Only images from the ${dockerhub_namespace} namespace are allowed`,
);
}
const exists = await this.actionTemplateRepository.exists({
Expand Down Expand Up @@ -140,11 +145,11 @@ export class ActionService {
data: UpdateTemplateDto,
auth: AuthHeader,
): Promise<ActionTemplateDto> {
if (!data.dockerImage.startsWith('rslethz/')) {
throw new ConflictException(
'Only images from the rslethz namespace are allowed',
);
}
//if (!data.dockerImage.startsWith('rslethz/')) {
// throw new ConflictException(
// 'Only images from the rslethz namespace are allowed',
// );
//}
const template = await this.actionTemplateRepository.findOneOrFail({
where: { uuid: data.uuid },
});
Expand Down
101 changes: 87 additions & 14 deletions backend/src/services/mission.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,12 @@ import {
} from '../serialization';
import { TagService } from './tag.service';
import { UserService } from './user.service';
import { addMissionFilters, addProjectFilters, addSort } from './utilities';
import {
addFileStats,
addMissionFilters,
addProjectFilters,
addSort,
} from './utilities';

import { SortOrder } from '@common/api/types/pagination';

Expand Down Expand Up @@ -162,36 +167,104 @@ export class MissionService {
take: number,
userUuid: string,
): Promise<MissionsDto> {
let query = this.missionRepository
let idQuery = this.missionRepository
.createQueryBuilder('mission')
.leftJoinAndSelect('mission.project', 'project')
.leftJoinAndSelect('mission.creator', 'creator')
.leftJoinAndSelect('mission.tags', 'tag')
.leftJoinAndSelect('tag.tagType', 'tagType');
.select('mission.uuid')
.leftJoin('mission.project', 'project')
.leftJoin('mission.creator', 'creator')
.leftJoin('mission.tags', 'tag')
.leftJoin('tag.tagType', 'tagType');

query = addAccessConstraintsToMissionQuery(query, userUuid);
idQuery = addAccessConstraintsToMissionQuery(idQuery, userUuid);

query = addProjectFilters(
query,
idQuery = addProjectFilters(
idQuery,
this.projectRepository,
projectUuids,
projectPatterns,
);

query = addMissionFilters(
query,
idQuery = addMissionFilters(
idQuery,
this.missionRepository,
missionUuids,
missionPatterns,
missionMetadata,
);

if (sortBy !== undefined) {
query = addSort(query, FIND_MANY_SORT_KEYS, sortBy, sortOrder);
idQuery = addSort(idQuery, FIND_MANY_SORT_KEYS, sortBy, sortOrder);
}

query.take(take).skip(skip);
const [missions, count] = await query.getManyAndCount();
// Get distinct mission UUIDs
idQuery.groupBy('mission.uuid');

// Get count before pagination
const count = await idQuery.getCount();
idQuery.take(take).skip(skip);

const missionIds = await idQuery.getRawMany();

if (missionIds.length === 0) {
return {
data: [],
count,
skip,
take,
};
}

let dataQuery = this.missionRepository
.createQueryBuilder('mission')
.leftJoinAndSelect('mission.project', 'project')
.leftJoinAndSelect('mission.creator', 'creator')
.leftJoinAndSelect('mission.tags', 'tag')
.leftJoinAndSelect('tag.tagType', 'tagType')
.where('mission.uuid IN (:...missionIds)', {
missionIds: missionIds.map((m) => m.mission_uuid),
});

if (sortBy !== undefined) {
dataQuery = addSort(
dataQuery,
FIND_MANY_SORT_KEYS,
sortBy,
sortOrder,
);
}

dataQuery = addFileStats(dataQuery);

const result = await dataQuery.getRawAndEntities();
const missions = result.entities;
const rawResults = result.raw;

// Create a map for quick lookup of file stats by mission UUID
const statsMap = new Map<
string,
{ fileCount: number; fileSize: number }
>();
for (const raw of rawResults) {
const missionUuid = raw.mission_uuid;
if (!statsMap.has(missionUuid)) {
statsMap.set(missionUuid, {
fileCount: Number.parseInt(raw.fileCount) || 0,
fileSize: Number.parseInt(raw.fileSize) || 0,
});
}
}

// Assign file stats to missions
for (const mission of missions) {
const stats = statsMap.get(mission.uuid);
if (stats) {
mission.fileCount = stats.fileCount;
mission.size = stats.fileSize;
} else {
mission.fileCount = 0;
mission.size = 0;
}
}

return {
data: missions.map((element) => missionEntityToFlatDto(element)),
Expand Down
20 changes: 20 additions & 0 deletions backend/src/services/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,26 @@ export const addMissionCount = (
return query;
};

export const addFileStats = (
query: SelectQueryBuilder<Mission>,
): SelectQueryBuilder<Mission> => {
query
.addSelect((subQuery) => {
return subQuery
.select('COUNT(file.uuid)', 'count')
.from('file_entity', 'file')
.where('file."missionUuid" = mission.uuid');
}, 'fileCount')
.addSelect((subQuery) => {
return subQuery
.select('COALESCE(SUM(file.size), 0)', 'sum')
.from('file_entity', 'file')
.where('file."missionUuid" = mission.uuid');
}, 'fileSize');

return query;
};

export const addProjectCreatorFilter = (
query: SelectQueryBuilder<any>,
creatorUuid: string | undefined,
Expand Down
Loading
Loading