Skip to content

Commit 13979b1

Browse files
authored
dive-dsa-slicer DIVEMetadata Integrations (#225)
* add intercept run task to the girder interface * basic MVP functionality * add/update test scripts * remove logging * vue-girder-slicer defaults, styling, disabled slicer params * linting * lodash verison pinning * automatic refresh, metadataKey permissions modifications * poetry lock update
1 parent 7b5d1db commit 13979b1

43 files changed

Lines changed: 5100 additions & 3207 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

client/dive-common/components/ActionEditors/AttributeFilter.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export default defineComponent({
8585
}
8686
attributeFilters.value = { ...attributeFilters.value };
8787
creatingAttribute.value = false;
88-
emit('update', attributeFilters);
88+
emit('update', attributeFilters.value);
8989
};
9090
const trackAtrList = computed(() => {
9191
const result: {key: string; item: AttributeMatch}[] = [];

client/dive-common/components/Viewer.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,9 +665,11 @@ export default defineComponent({
665665
groupStyleManager.populateTypeStyles(meta.customGroupStyling);
666666
if (configMeta.customTypeStyling) {
667667
trackFilters.importTypes(Object.keys(configMeta.customTypeStyling), false);
668+
trackStyleManager.populateTypeStyles(configMeta.customTypeStyling);
668669
}
669670
if (configMeta.customGroupStyling) {
670671
groupFilters.importTypes(Object.keys(configMeta.customGroupStyling), false);
672+
groupStyleManager.populateTypeStyles(configMeta.customGroupStyling);
671673
}
672674
if (configMeta.attributes) {
673675
loadAttributes(configMeta.attributes);

client/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
"@types/jest": "^27.0.4",
6161
"@types/js-cookie": "^3.0.6",
6262
"@types/js-yaml": "^4.0.5",
63-
"@types/lodash": "^4.14.151",
63+
"@types/lodash": "4.17.0",
6464
"@types/mime-types": "^2.1.0",
6565
"@types/mock-fs": "^4.13.1",
6666
"@types/mousetrap": "^1.6.3",

client/platform/web-girder/api/divemetadata.service.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import girderRest from 'platform/web-girder/plugins/girder';
2+
import { JobResponse } from 'vue-girder-slicer-cli-ui/dist/api/girderSlicerApi';
23
import { GirderModelBase } from 'vue-girder-slicer-cli-ui/dist/girderTypes';
4+
import { XMLBaseValue } from 'vue-girder-slicer-cli-ui/dist/parser/parserTypes';
35
import { StringKeyObject } from 'vue-media-annotator/BaseAnnotation';
46

57
export interface MetadataFilterItem {
@@ -13,6 +15,7 @@ export interface FilterDisplayConfig {
1315
display: string[];
1416
hide: string[];
1517
categoricalLimit: number;
18+
slicerCLI: 'Disabled' | 'Owner' | 'All Users'
1619
}
1720

1821
export interface MetadataFilterKeysItem {
@@ -146,7 +149,7 @@ function setDiveDatasetMetadataKey(diveDatasetId: string, key: string, updateVal
146149

147150
async function updateDiveMetadataDisplay(folderId: string, key: string, state: 'display' | 'hidden' | 'none') {
148151
const resp = await girderRest.get<GirderModelBase>(`folder/${folderId}`);
149-
const DIVEMetadataFilter = resp.data.meta.DIVEMetadataFilter as {display: string[], hide: string[], categoricalLimit: number};
152+
const DIVEMetadataFilter = resp.data.meta.DIVEMetadataFilter as FilterDisplayConfig;
150153
if (DIVEMetadataFilter) {
151154
const { display } = DIVEMetadataFilter;
152155
const { hide } = DIVEMetadataFilter;
@@ -166,6 +169,19 @@ async function updateDiveMetadataDisplay(folderId: string, key: string, state: '
166169
}
167170
}
168171

172+
async function updateDiveMetadataSlicerConfig(folderId:string, value: 'Disabled' | 'Owner' | 'All Users') {
173+
const resp = await girderRest.get<GirderModelBase>(`folder/${folderId}`);
174+
const DIVEMetadataFilter = resp.data.meta.DIVEMetadataFilter as FilterDisplayConfig;
175+
if (DIVEMetadataFilter) {
176+
DIVEMetadataFilter.slicerCLI = value;
177+
await girderRest.put(`folder/${folderId}/metadata`, { DIVEMetadataFilter });
178+
}
179+
}
180+
181+
async function runSlicerMetadataTask(rootId: string, taskId: string, filters: DIVEMetadataFilter, params: Record<string, XMLBaseValue>) {
182+
return girderRest.post<JobResponse>(`dive_metadata/${rootId}/slicer-cli-task`, { taskId, filterParams: { filters, params } }, { params: { taskId, filterParams: { filters, params } } });
183+
}
184+
169185
export {
170186
getMetadataFilterValues,
171187
filterDiveMetadata,
@@ -177,4 +193,6 @@ export {
177193
deleteDiveDatasetMetadataKey,
178194
setDiveDatasetMetadataKey,
179195
updateDiveMetadataDisplay,
196+
updateDiveMetadataSlicerConfig,
197+
runSlicerMetadataTask,
180198
};

client/platform/web-girder/api/girder.service.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { GirderModel } from '@girder/components/src';
1+
import { GirderJob, GirderModel } from '@girder/components/src';
22
import girderRest from 'platform/web-girder/plugins/girder';
33

44
function deleteResources(resources: Array<GirderModel>) {
@@ -23,6 +23,19 @@ function getItemsInFolder(folderId: string, limit: number) {
2323
});
2424
}
2525

26+
function getRecentSlicerJobs(limit: number, offset: number, statuses?: number[]) {
27+
return girderRest.get<(GirderJob & { type: string})[]>('job', {
28+
params: {
29+
limit,
30+
offset,
31+
statuses: JSON.stringify(statuses),
32+
sort: 'created',
33+
sortdir: -1,
34+
handler: 'jobs._local',
35+
},
36+
});
37+
}
38+
2639
function getFolder(folderId: string) {
2740
return girderRest.get<GirderModel>(`folder/${folderId}`);
2841
}
@@ -56,6 +69,7 @@ function setUsePrivateQueue(userId: string, value = false) {
5669
export {
5770
deleteResources,
5871
getItemsInFolder,
72+
getRecentSlicerJobs,
5973
getFolder,
6074
setUsePrivateQueue,
6175
getFolderAccess,

client/platform/web-girder/store/User.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ const userModule: Module<UserState, RootState> = {
1414
state.user = merge(state.user, data);
1515
},
1616
},
17+
getters: {
18+
userLogin(state) {
19+
return state.user?.login;
20+
},
21+
},
1722
actions: {
1823
async loadUser({ commit }) {
1924
const data = await girderRest.fetchUser();

client/platform/web-girder/views/Admin/AdminJobs.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export default defineComponent({
5555
const initTypes = async () => {
5656
const typesAndStatus = (await getJobTypesStatus());
5757
jobTypes.value = typesAndStatus.data.types;
58-
filterTypes.value = typesAndStatus.data.types;
58+
filterTypes.value = ['convert', 'Dive Metadata Slicer CLI Batch', 'slicer_cli_web_job', 'Slicer CLI Metadata Run'];
5959
};
6060
const getData = async () => {
6161
const statusNums = filterStatus.value.map(

client/platform/web-girder/views/DIVEMetadataEdit.vue

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script lang="ts">
22
import {
33
defineComponent, onMounted, ref, Ref,
4+
watch,
45
} from 'vue';
56
import {
67
addDiveMetadataKey,
@@ -10,6 +11,7 @@ import {
1011
MetadataFilterKeysItem,
1112
modifyDiveMetadataPermission,
1213
updateDiveMetadataDisplay,
14+
updateDiveMetadataSlicerConfig,
1315
} from 'platform/web-girder/api/divemetadata.service';
1416
import { AccessType, getFolder, getFolderAccess } from 'platform/web-girder/api/girder.service';
1517
import { useGirderRest } from 'platform/web-girder/plugins/girder';
@@ -41,10 +43,14 @@ export default defineComponent({
4143
},
4244
},
4345
setup(props) {
44-
const displayConfig: Ref<FilterDisplayConfig> = ref({ display: [], hide: [], categoricalLimit: 50 });
46+
const displayConfig: Ref<FilterDisplayConfig> = ref({
47+
display: [], hide: [], categoricalLimit: 50, slicerCLI: 'Disabled',
48+
});
4549
4650
const girderRest = useGirderRest();
4751
const router = useRouter();
52+
const categoryLimit = ref(50);
53+
const slicerCLI: Ref<FilterDisplayConfig['slicerCLI']> = ref('Disabled');
4854
4955
const processing = ref(false);
5056
const deleteDialog = ref(false);
@@ -106,6 +112,8 @@ export default defineComponent({
106112
}
107113
if (folder.meta.DIVEMetadata) {
108114
displayConfig.value = folder.meta.DIVEMetadataFilter;
115+
categoryLimit.value = displayConfig.value.categoricalLimit || 50;
116+
slicerCLI.value = displayConfig.value.slicerCLI || 'Disabled';
109117
}
110118
if (folder.creatorId === girderRest.user._id || girderRest.user.admin) {
111119
isOwnerAdmin.value = true;
@@ -146,6 +154,10 @@ export default defineComponent({
146154
updateDiveMetadataDisplay(props.id, item.name, val);
147155
};
148156
157+
watch(slicerCLI, () => {
158+
updateDiveMetadataSlicerConfig(props.id, slicerCLI.value);
159+
});
160+
149161
const toggleUnlock = async (index: number) => {
150162
const item = formattedKeys.value[index];
151163
if (item) {
@@ -246,18 +258,30 @@ export default defineComponent({
246258
deleteDialog,
247259
deleteKey,
248260
prepDeleteMetadata,
261+
slicerCLI,
249262
};
250263
},
251264
});
252265
</script>
253266

254267
<template>
255268
<v-container v-if="isOwnerAdmin">
256-
<v-row dense class="pb-4">
269+
<v-row dense class="pb-4" align="center">
257270
<v-btn color="warning" @click="returnToMetadata()">
258271
Return to Metadata
259272
</v-btn>
260273
<v-spacer />
274+
<v-select
275+
v-model="slicerCLI"
276+
label="Slicer CLI:"
277+
variant="outlined"
278+
:items="['Disabled', 'Owner', 'All Users']"
279+
dense
280+
hide-details
281+
style="max-width:200px"
282+
class="mr-6"
283+
/>
284+
261285
<v-btn color="success" @click="initializeNewKey()">
262286
Add Metadata Field
263287
</v-btn>

client/platform/web-girder/views/DIVEMetadataFilter.vue

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ import { intersection } from 'lodash';
99
import { usePrompt } from 'dive-common/vue-utilities/prompt-service';
1010
import DIVEMetadataFilterItemVue from './DIVEMetadataFilterItem.vue';
1111
import DIVEMetadataCloneVue from './DIVEMetadataClone.vue';
12+
import DIVEMetadataSlicerVue from './DIVEMetadataSlicer.vue';
1213
1314
export default defineComponent({
1415
name: 'DIVEMetadataFilter',
15-
components: { DIVEMetadataFilterItemVue, DIVEMetadataCloneVue },
16+
components: { DIVEMetadataFilterItemVue, DIVEMetadataCloneVue, DIVEMetadataSlicerVue },
1617
props: {
1718
currentPage: {
1819
type: Number,
@@ -243,6 +244,10 @@ export default defineComponent({
243244
}
244245
};
245246
247+
const jobCompleted = () => {
248+
emit('updateFilters', { filter: currentFilter.value, sortVal: sortValue.value, sortDir: sortDir.value });
249+
};
250+
246251
return {
247252
248253
pageList,
@@ -255,6 +260,7 @@ export default defineComponent({
255260
categoricalLimit,
256261
changePage,
257262
updateFilter,
263+
jobCompleted,
258264
clearFilter,
259265
getDefaultValue,
260266
getRegExVal,
@@ -308,6 +314,7 @@ export default defineComponent({
308314
</v-btn>
309315

310316
<v-spacer />
317+
<DIVEMetadataSlicerVue :filters="currentFilter" :metadata-root="id" class="pr-8" @job-complete="jobCompleted()" />
311318
<v-chip><span class="pr-1">Filtered:</span>{{ filtered }} / {{ count }}</v-chip>
312319
<v-select
313320
v-model="sortValue"

client/platform/web-girder/views/DIVEMetadataSearch.vue

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,12 @@ export default defineComponent({
3434
},
3535
setup(props) {
3636
const folderList: Ref<MetadataResultItem[]> = ref([]);
37+
const timeString = ref(Date.now());
3738
const unlockedMap: Ref<Record<string, MetadataFilterKeysItem>> = ref({});
3839
const loading = ref(true);
39-
const displayConfig: Ref<FilterDisplayConfig> = ref({ display: [], hide: [], categoricalLimit: 50 });
40+
const displayConfig: Ref<FilterDisplayConfig> = ref({
41+
display: [], hide: [], categoricalLimit: 50, slicerCLI: 'Disabled',
42+
});
4043
const totalPages = ref(0);
4144
const currentPage = ref(0);
4245
const count = ref(0);
@@ -56,6 +59,7 @@ export default defineComponent({
5659
totalPages.value = data.totalPages;
5760
filtered.value = data.filtered;
5861
count.value = data.count;
62+
timeString.value = Date.now();
5963
};
6064
const getData = async () => {
6165
const { data } = await filterDiveMetadata(props.id, { ...filters.value });
@@ -179,6 +183,7 @@ export default defineComponent({
179183
locationStore,
180184
updateFilter,
181185
folderList,
186+
timeString,
182187
displayConfig,
183188
getAdvanced,
184189
filters,
@@ -206,6 +211,7 @@ export default defineComponent({
206211
:filtered="filtered"
207212
:display-config="displayConfig"
208213
:owner-admin="isOwnerAdmin"
214+
style="position: sticky; top: 0px; z-index: 10"
209215
@update:currentPage="changePage($event)"
210216
@updateFilters="updateFilter($event)"
211217
@filter-data="setFilterData($event)"
@@ -231,7 +237,7 @@ export default defineComponent({
231237
</template>
232238
</DIVEMetadataFilterVue>
233239
<span v-if="!openClone">
234-
<v-card v-for="(item, key) in folderList" :key="key" class="my-2 pa-2">
240+
<v-card v-for="(item, key) in folderList" :key="`${key}_${timeString}`" class="my-2 pa-2">
235241
<v-row class="ma-4">
236242
<div>{{ item.filename }}</div>
237243
<div>
@@ -246,7 +252,7 @@ export default defineComponent({
246252
</v-btn>
247253
</div>
248254
</v-row>
249-
<v-row v-for="display in displayConfig['display']" :key="display" class="ma-4" align="center">
255+
<v-row v-for="display in displayConfig['display']" :key="`${display}_${timeString}`" class="ma-4" align="center">
250256
<b>{{ display }}:</b>
251257
<div v-if="unlockedMap[display] !== undefined">
252258
<DIVEMetadataEditKey
@@ -265,7 +271,7 @@ export default defineComponent({
265271
<v-expansion-panel class="border">
266272
<v-expansion-panel-header>Advanced</v-expansion-panel-header>
267273
<v-expansion-panel-content>
268-
<v-row v-for="(data, dataKey) in getAdvanced(item)" :key="dataKey" class="border" dense>
274+
<v-row v-for="(data, dataKey) in getAdvanced(item)" :key="`${dataKey}_${timeString}`" class="border" dense>
269275
<v-col cols="2" class="border">
270276
<b>{{ dataKey }}:</b>
271277
</v-col>

0 commit comments

Comments
 (0)