Skip to content
Merged
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
17 changes: 17 additions & 0 deletions client/dive-common/apispec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,10 @@ interface FrameImage {
}

export interface MultiCamImportFolderArgs {
datasetName?: string; // Girder parent folder name (required on web)
defaultDisplay: string; // In multicam the default camera to display
/** Display order for cameras (matches sourceList / UI order). */
cameraOrder?: string[];
sourceList: Record<string, {
sourcePath: string;
trackFile: string;
Expand Down Expand Up @@ -154,6 +157,8 @@ interface MultiCamMedia {
videoUrl: string;
}>;
defaultDisplay: string; // Default camera for displaying the MultiCamMedia
/** Camera names in display order (import / UI order). */
cameraOrder?: string[];
}

interface MediaImportResponse {
Expand Down Expand Up @@ -223,6 +228,18 @@ interface Api {
// Non-Endpoint shared functions
openFromDisk(datasetType: DatasetType | 'bulk' | 'calibration' | 'annotation' | 'text' | 'zip', directory?: boolean):
Promise<{canceled?: boolean; filePaths: string[]; fileList?: File[]; root?: string}>;
/** Desktop: immediate child directory names under a parent folder (multicam subfolder import). */
listImmediateSubfolders?(parentPath: string): Promise<string[]>;
/** Desktop: subfolders or root-level video files under a parent folder (multicam import). */
listParentFolderCameras?(
parentPath: string,
mediaType: 'image-sequence' | 'video',
): Promise<{ name: string; sourcePath: string }[]>;
/** Desktop: folder path for image-sequence, or first video file inside the folder for video. */
resolveMulticamCameraSourcePath?(
subfolderPath: string,
mediaType: 'image-sequence' | 'video',
): Promise<string>;
getTiles?(itemId: string, projection?: string): Promise<StringKeyObject>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
getTileURL?(itemId: string, x: number, y: number, level: number, query: Record<string, any>):
Expand Down
82 changes: 2 additions & 80 deletions client/dive-common/components/ImportMultiCamAddType.vue
Original file line number Diff line number Diff line change
@@ -1,83 +1,5 @@
<script lang="ts">
import { defineComponent, ref } from 'vue';
import ImportMultiCamAddType from 'dive-common/components/ImportMultiCamDialog/ImportMultiCamAddType.vue';

export default defineComponent({
name: 'ImportMultiCamAddType',
props: {
nameList: {
type: Array,
required: true,
},
},
setup(props, { emit }) {
const newSetName = ref('');
const alphaNumeric = /^[a-zA-Z0-9]*$/;
const enabled = ref(false);

const addNewSet = () => {
emit('add-new', newSetName.value);
newSetName.value = '';
enabled.value = false;
};
return {
enabled,
newSetName,
alphaNumeric,
/* methods */
addNewSet,
};
},
});
export default ImportMultiCamAddType;
</script>

<template>
<v-row
class="align-start"
no-gutters
style="height: 48px;"
>
<v-btn
color="primary"
class="mr-3"
:disabled="enabled"
@click="enabled = true"
>
Add Camera
<v-icon class="ml-1">
mdi-camera
</v-icon>
</v-btn>
<template v-if="enabled">
<v-text-field
v-model="newSetName"
:rules="[
v => !!v || 'Name is required',
v => alphaNumeric.test(v) || 'Letters and Numbers only',
v => !v.includes(' ') || 'No spaces',
v => !nameList.includes(v) || 'No duplicate Names']"
label="name"
placeholder="Choose a Camera Name"
outlined
persistent-hint
dense
hide-details="auto"
/>
<v-btn
color="error"
class="mx-3"
@click="newSetName = ''; enabled = false;"
>
Cancel
</v-btn>
<v-btn
color="success"
@click="addNewSet"
>
Create
</v-btn>
</template>
</v-row>
</template>

<style scoped lang="scss">
</style>
37 changes: 2 additions & 35 deletions client/dive-common/components/ImportMultiCamCameraGroup.vue
Original file line number Diff line number Diff line change
@@ -1,38 +1,5 @@
<script lang="ts">
import { defineComponent } from 'vue';
import ImportMultiCamCameraGroup from 'dive-common/components/ImportMultiCamDialog/ImportMultiCamCameraGroup.vue';

export default defineComponent({
props: {
cameraName: String,
showDelete: Boolean,
},
});
export default ImportMultiCamCameraGroup;
</script>

<template>
<v-card
class="camera-group px-3 py-2"
flat
style="background-color: #2b2b2b;"
>
<v-row
no-gutters
class="align-center mb-2"
>
<h3>
Camera {{ cameraName }}
</h3>
<v-btn
v-if="showDelete"
class="mx-3"
icon
small
color="error"
@click="$emit('delete')"
>
<v-icon>mdi-delete</v-icon>
</v-btn>
</v-row>
<slot />
</v-card>
</template>
37 changes: 2 additions & 35 deletions client/dive-common/components/ImportMultiCamChooseAnnotation.vue
Original file line number Diff line number Diff line change
@@ -1,38 +1,5 @@
<script lang="ts">
import { defineComponent } from 'vue';
import ImportMultiCamChooseAnnotation from 'dive-common/components/ImportMultiCamDialog/ImportMultiCamChooseAnnotation.vue';

export default defineComponent({
props: {
trackFile: String,
cameraName: String,
},
});
export default ImportMultiCamChooseAnnotation;
</script>

<template>
<v-row
class="align-center"
no-gutters
>
<v-text-field
label="Annotation File"
:placeholder="`Annotation File (${cameraName})`"
outlined
dense
hide-details
clearable
:value="trackFile"
class="mr-3"
@click:clear="$emit('clear')"
/>
<v-btn
color="primary"
@click="$emit('open')"
>
Open
<v-icon class="ml-2">
mdi-file-table
</v-icon>
</v-btn>
</v-row>
</template>
63 changes: 2 additions & 61 deletions client/dive-common/components/ImportMultiCamChooseSource.vue
Original file line number Diff line number Diff line change
@@ -1,64 +1,5 @@
<script lang="ts">
import { defineComponent, PropType } from 'vue';
import { DatasetType } from 'dive-common/apispec';
import ImportMultiCamChooseSource from 'dive-common/components/ImportMultiCamDialog/ImportMultiCamChooseSource.vue';

export default defineComponent({
props: {
cameraName: {
type: String,
required: true,
},
dataType: {
type: String as PropType<DatasetType>,
required: true,
},
value: {
type: String,
required: true,
},
showDelete: {
type: Boolean,
default: false,
},
},
});
export default ImportMultiCamChooseSource;
</script>

<template>
<v-row
no-gutters
class="align-center"
>
<v-text-field
:placeholder="dataType === 'image-sequence'
? 'Choose folder or image list' : 'Choose Video'
"
disabled
outlined
dense
hide-details
class="mr-3"
:value="value"
/>
<v-btn
color="primary"
class="mr-3"
@click="$emit('open')"
>
{{ dataType === 'image-sequence' ? 'Folder' : 'Open Video' }}
<v-icon class="ml-2">
{{ dataType === 'image-sequence' ? 'mdi-folder-open' : 'mdi-file-video' }}
</v-icon>
</v-btn>
<v-btn
v-if="dataType === 'image-sequence'"
color="primary"
@click="$emit('open-text')"
>
List File
<v-icon class="ml-2">
mdi-view-list-outline
</v-icon>
</v-btn>
</v-row>
</template>
Loading
Loading