vue-girder-slicer-cli-ui 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +102 -0
  2. package/dist/api/girderRest.d.ts +36 -0
  3. package/dist/api/girderSlicerApi.d.ts +32 -0
  4. package/dist/components/FileBrowser/DataBrowser.tw.vue.d.ts +177 -0
  5. package/dist/components/FileBrowser/Modal.tw.vue.d.ts +27 -0
  6. package/dist/components/FileBrowser/RootSelection.tw.vue.d.ts +41 -0
  7. package/dist/components/FileBrowser/utils.d.ts +9 -0
  8. package/dist/components/GirderControlsPanel.tw.vue.d.ts +29 -0
  9. package/dist/components/GirderSlicerParameter.tw.vue.d.ts +50 -0
  10. package/dist/components/GirderSlicerTaskButton.tw.vue.d.ts +42 -0
  11. package/dist/components/GirderSlicerTaskCard.tw.vue.d.ts +44 -0
  12. package/dist/components/GirderSlicerTaskMenu.tw.vue.d.ts +49 -0
  13. package/dist/components/GlicerSlicerTaskMenuModal.tw.vue.d.ts +34 -0
  14. package/dist/components/GlicerSlicerTaskMenuModalButton.tw.vue.d.ts +38 -0
  15. package/dist/components/GriderSlicerTasksIntegrated.tw.vue.d.ts +74 -0
  16. package/dist/components/Parameters/BaseParameter.tw.vue.d.ts +21 -0
  17. package/dist/components/Parameters/BooleanParameter.tw.vue.d.ts +18 -0
  18. package/dist/components/Parameters/ColorParameter.tw.vue.d.ts +19 -0
  19. package/dist/components/Parameters/EnumerationParameters.tw.vue.d.ts +19 -0
  20. package/dist/components/Parameters/FileParameter.tw.vue.d.ts +32 -0
  21. package/dist/components/Parameters/RangeParameter.tw.vue.d.ts +19 -0
  22. package/dist/favicon.ico +0 -0
  23. package/dist/girderTypes.d.ts +21 -0
  24. package/dist/index.d.ts +11 -0
  25. package/dist/parser/constraints.d.ts +4 -0
  26. package/dist/parser/convert.d.ts +7 -0
  27. package/dist/parser/defaultValue.d.ts +12 -0
  28. package/dist/parser/group.d.ts +9 -0
  29. package/dist/parser/index.d.ts +8 -0
  30. package/dist/parser/panel.d.ts +11 -0
  31. package/dist/parser/param.d.ts +6 -0
  32. package/dist/parser/parse.d.ts +20 -0
  33. package/dist/parser/parserTypes.d.ts +58 -0
  34. package/dist/parser/widget.d.ts +6 -0
  35. package/dist/style.css +1 -0
  36. package/dist/tailwind.css +1370 -0
  37. package/dist/utils.d.ts +5 -0
  38. package/dist/vue-girder-slicer-cli-ui.js +12987 -0
  39. package/dist/vue-girder-slicer-cli-ui.umd.cjs +59 -0
  40. package/package.json +135 -0
  41. package/src/components/FileBrowser/DataBrowser.tw.vue +842 -0
  42. package/src/components/FileBrowser/Modal.tw.vue +82 -0
  43. package/src/components/FileBrowser/RootSelection.tw.vue +83 -0
  44. package/src/components/FileBrowser/utils.ts +48 -0
  45. package/src/components/GirderControlsPanel.tw.vue +94 -0
  46. package/src/components/GirderSlicerParameter.tw.vue +84 -0
  47. package/src/components/GirderSlicerTaskButton.tw.vue +208 -0
  48. package/src/components/GirderSlicerTaskCard.tw.vue +184 -0
  49. package/src/components/GirderSlicerTaskMenu.tw.vue +217 -0
  50. package/src/components/GlicerSlicerTaskMenuModal.tw.vue +77 -0
  51. package/src/components/GlicerSlicerTaskMenuModalButton.tw.vue +106 -0
  52. package/src/components/GriderSlicerTasksIntegrated.tw.vue +73 -0
  53. package/src/components/Parameters/BaseParameter.tw.vue +76 -0
  54. package/src/components/Parameters/BooleanParameter.tw.vue +54 -0
  55. package/src/components/Parameters/ColorParameter.tw.vue +58 -0
  56. package/src/components/Parameters/EnumerationParameters.tw.vue +66 -0
  57. package/src/components/Parameters/FileParameter.tw.vue +172 -0
  58. package/src/components/Parameters/RangeParameter.tw.vue +74 -0
@@ -0,0 +1,184 @@
1
+ <script lang="ts">
2
+ import { PropType, Ref, computed, defineComponent, ref, watch } from 'vue';
3
+ import parse from '../parser/parse';
4
+ import GirderControlsPanel from './GirderControlsPanel.tw.vue';
5
+ import RestClient from '../api/girderRest';
6
+ import { JobResponse, useGirderSlicerApi } from '../api/girderSlicerApi';
7
+ import type { XMLParameters, XMLSpecification } from '../parser/parserTypes';
8
+ import SvgIcon from '@jamescoyle/vue-icon';
9
+ import { mdiClose } from '@mdi/js';
10
+ export default defineComponent({
11
+ name:'GirderSlicerTaskCard',
12
+ compatConfig: { mode: 2 },
13
+ components: {
14
+ GirderControlsPanel,
15
+ SvgIcon
16
+ },
17
+ props: {
18
+ apiUrl: {
19
+ type: String,
20
+ default: 'api/v1',
21
+ },
22
+ taskId: {
23
+ type: String as PropType<string | null>,
24
+ default: '64e8aff6072d5e5fbb8719aa'
25
+ },
26
+ defaults: {
27
+ type: Function as PropType<(item: XMLParameters) => undefined | null | XMLParameters>,
28
+ default: (_item: XMLParameters) => undefined,
29
+ }
30
+ },
31
+ setup(props, { emit }) {
32
+ const girderRest = new RestClient({apiRoot: props.apiUrl});
33
+ girderRest
34
+ const loggedIn = computed(() => girderRest?.token);
35
+ const result: Ref<XMLSpecification | null> = ref(null);
36
+ const jobData: Ref<null | JobResponse> = ref(null)
37
+ const slicerApi = useGirderSlicerApi(girderRest);
38
+ const getData = async () => {
39
+ if (props.taskId) {
40
+ const response = await slicerApi.getSlicerXML(props.taskId);
41
+ const parseParams = parse(response.data);
42
+ // We need to assign default values if they exists
43
+ const updateParams: {panelIndex: number, groupIndex: number, parameterIndex: number, value: XMLParameters}[] = [];
44
+ parseParams.panels.forEach((panel, panelIndex) => {
45
+ panel.groups.forEach((group, groupIndex) => {
46
+ group.parameters.forEach((parameter, parameterIndex) => {
47
+ const paramResult = props.defaults(parameter);
48
+ if (paramResult && parseParams) {
49
+ // Reset the parameter
50
+ updateParams.push({
51
+ panelIndex,
52
+ groupIndex,
53
+ parameterIndex,
54
+ value: paramResult,
55
+ });
56
+ }
57
+ });
58
+ });
59
+ });
60
+ updateParams.forEach((item) => {
61
+ if (parseParams) {
62
+ parseParams.panels[item.panelIndex].groups[item.groupIndex].parameters[item.parameterIndex] = item.value;
63
+ }
64
+ });
65
+ result.value = parseParams;
66
+ }
67
+ }
68
+ if (props.taskId) {
69
+ getData();
70
+ }
71
+ watch(() => props.taskId, () => {
72
+ getData();
73
+ })
74
+ const updateParameters = (e: XMLParameters[], index: number) => {
75
+ if (result.value) {
76
+ result.value.panels[index].groups[0].parameters = e;
77
+ }
78
+ }
79
+ const runTask = async () => {
80
+ // First we need to validate the task has all parameters required.
81
+ if (result.value && props.taskId) {
82
+ const resp = await slicerApi.runTask(result.value, props.taskId);
83
+ if (resp) {
84
+ console.log(resp);
85
+ jobData.value = resp;
86
+ emit('run-task', jobData.value);
87
+ }
88
+ }
89
+ }
90
+ const processInput = async (name: string) => {
91
+ if (result.value) {
92
+ await slicerApi.processInput(result.value, name);
93
+ }
94
+ }
95
+
96
+ const cancel = () => {
97
+ result.value = null;
98
+ emit('cancel')
99
+ }
100
+ return {
101
+ result,
102
+ runTask,
103
+ cancel,
104
+ updateParameters,
105
+ processInput,
106
+ jobData,
107
+ loggedIn,
108
+ mdiClose,
109
+ }
110
+ }
111
+ });
112
+ </script>
113
+ <template>
114
+ <div
115
+ v-if="result"
116
+ class="gsu-card relative flex flex-col min-w-0 rounded break-words border pa-2"
117
+ >
118
+ <div class="flex-auto p-6">
119
+ <div class="grid grid-cols-12 gap-4 pb-2">
120
+ <span class="col-span-12">
121
+ <h5>
122
+ {{ result.title }}
123
+ </h5>
124
+ </span>
125
+ </div>
126
+ <div
127
+ v-if="jobData"
128
+ class="mb-3 flex flex-wrap justify-content-left g-0"
129
+ >
130
+ <div
131
+ class="relative px-3 py-3 mb-4 border rounded text-green-darker border-green-dark bg-green-lighter opacity-0 opacity-100 block"
132
+ role="alert"
133
+ >
134
+ <span>{{ jobData.title }} running</span>
135
+ <svg-icon
136
+ type="mdi"
137
+ :path="mdiClose"
138
+ :size="30"
139
+ class="pb-2 gsu-icon gsu-clickable"
140
+ data-dismiss="modal"
141
+ aria-label="Close"
142
+ style="float:right"
143
+ @click="jobData = null"
144
+ >
145
+ <span aria-hidden="true">&times;</span>
146
+ </svg-icon>
147
+ </div>
148
+ </div>
149
+ <p class="mb-0">
150
+ {{ result.description }}
151
+ </p>
152
+ <GirderControlsPanel
153
+ v-for="(panel, index) in result.panels"
154
+ :key="`panel_${index}`"
155
+ :panel="panel"
156
+ :collapse-override="!!jobData"
157
+ @change="updateParameters($event, index)"
158
+ @input-selected="processInput($event)"
159
+ />
160
+ </div>
161
+ <div class="flex-auto p-6">
162
+ <div class="grid gap-4 pb-2 justify-items-end">
163
+ <span>
164
+ <button
165
+ type="button"
166
+ class="bg-red-500 border-solid border-borderColor font-bold py-2 px-4 mx-2 rounded border-2"
167
+ @click="cancel()"
168
+ >
169
+ Cancel
170
+ </button>
171
+ <button
172
+ type="button"
173
+ class="gsu-btn-accept font-bold py-2 px-4 mx-2 rounded border-2"
174
+ @click="runTask()"
175
+ >
176
+ Run
177
+ </button>
178
+ </span>
179
+ </div>
180
+ </div>
181
+ </div>
182
+ </template>
183
+ <style scoped>
184
+ </style>
@@ -0,0 +1,217 @@
1
+ <script lang="ts">
2
+ import { Ref, computed, defineComponent, onMounted, ref } from "vue";
3
+ import { extractImageInfo } from "../utils";
4
+ import RestClient from "../api/girderRest";
5
+ import { SlicerImage, useGirderSlicerApi } from "../api/girderSlicerApi";
6
+ import { mdiAlert, mdiChevronDown, mdiChevronRight } from "@mdi/js";
7
+ import SvgIcon from "@jamescoyle/vue-icon";
8
+ import { cloneDeep } from 'lodash';
9
+ import { PropType } from "vue/types/v3-component-props";
10
+
11
+ interface TaskInfo {
12
+ tag: string;
13
+ tasks: {
14
+ imageBase: string;
15
+ imageTag: string;
16
+ _id: string;
17
+ name: string;
18
+ description: string;
19
+ }[];
20
+ }
21
+
22
+ type TaskHierarchy = Record<
23
+ string,
24
+ [TaskInfo]
25
+ >;
26
+ export default defineComponent({
27
+ components: {
28
+ SvgIcon,
29
+ },
30
+ props: {
31
+ apiUrl: {
32
+ type: String,
33
+ default: "api/v1",
34
+ },
35
+ filter: {
36
+ type: Function as PropType<(task: SlicerImage) => boolean>,
37
+ default: (_task: SlicerImage) => true,
38
+ },
39
+ },
40
+ setup(props, { emit }) {
41
+ const girderRest = new RestClient({ apiRoot: props.apiUrl });
42
+ const loggedIn = computed(() => girderRest?.token);
43
+ const slicerApi = useGirderSlicerApi(girderRest);
44
+ const results: Ref<TaskHierarchy> = ref({});
45
+ const clicked: Ref<Record<string, boolean>> = ref({})
46
+ const selected: Ref<null | string> = ref(null);
47
+ const getData = async () => {
48
+ try {
49
+ const response = await slicerApi.getSlicerList();
50
+ const filtered = response.data.filter((task) => props.filter(task));
51
+ // ground items by their image
52
+ const taskHierarchy: TaskHierarchy = {};
53
+ filtered.forEach((task) => {
54
+ // Lets get the base image name
55
+ const imageInfo = extractImageInfo(task.image);
56
+ if (imageInfo) {
57
+ // We create a root for it
58
+ if (taskHierarchy[imageInfo.baseName] === undefined) {
59
+ clicked.value[imageInfo.baseName] = false;
60
+ taskHierarchy[imageInfo.baseName] = [
61
+ { tag: imageInfo.tag, tasks: [] },
62
+ ];
63
+ }
64
+ const foundIndex = taskHierarchy[imageInfo.baseName].findIndex(
65
+ (item) => item.tag === imageInfo.tag
66
+ );
67
+ if (foundIndex !== -1) {
68
+ clicked.value[`${imageInfo.baseName}.${imageInfo.tag}`] = false;
69
+ taskHierarchy[imageInfo.baseName][foundIndex].tasks.push({
70
+ imageBase: imageInfo.baseName,
71
+ imageTag: imageInfo.tag,
72
+ _id: task._id,
73
+ name: task.name,
74
+ description: task.description,
75
+ });
76
+ } else if (foundIndex === -1) {
77
+ taskHierarchy[imageInfo.baseName].push({
78
+ tag: imageInfo.tag,
79
+ tasks: [
80
+ {
81
+ imageBase: imageInfo.baseName,
82
+ imageTag: imageInfo.tag,
83
+ _id: task._id,
84
+ name: task.name,
85
+ description: task.description,
86
+ },
87
+ ],
88
+ });
89
+ }
90
+ }
91
+ });
92
+ results.value = taskHierarchy;
93
+ } catch (err) {
94
+ console.error("Cannot communicate with server");
95
+ }
96
+ };
97
+ const select = (id: string, name: string) => {
98
+ emit("selected", {id, name});
99
+ selected.value = id;
100
+ };
101
+ onMounted(() => {
102
+ getData();
103
+ });
104
+ const selectItem = (item: string) => {
105
+ const tempClicked = cloneDeep(clicked.value);
106
+ if (tempClicked[item]) {
107
+ //Then we toggle it off and all children
108
+ tempClicked[item] = false;
109
+ } else {
110
+ Object.keys(tempClicked).forEach((key) => tempClicked[key] = false );
111
+ const splits = item.split('.');
112
+ const builtString: string[] = [];
113
+ splits.forEach((key) => {
114
+ builtString.push(key);
115
+ const testString = builtString.join('.');
116
+ if (tempClicked[testString] !== undefined) {
117
+ tempClicked[testString] = true;
118
+ }
119
+ });
120
+ }
121
+ clicked.value = tempClicked;
122
+
123
+ }
124
+ return {
125
+ results,
126
+ mdiAlert,
127
+ mdiChevronDown,
128
+ mdiChevronRight,
129
+ loggedIn,
130
+ select,
131
+ clicked,
132
+ selectItem,
133
+ selected,
134
+ };
135
+ },
136
+ });
137
+ </script>
138
+ <template>
139
+ <div>
140
+ <div v-if="loggedIn">
141
+ <ul
142
+ class="text-textColor"
143
+ >
144
+ <li
145
+ v-for="(item, key) in results"
146
+ :key="key"
147
+ >
148
+ <span class="gsu-menu-item rounded-t py-2 px-4 block whitespace-no-wrap" @click="selectItem(item.length === 1 ? `${key}.${item[0].tag}` : key )" >
149
+ <span class="pr-1 flex-1"
150
+ >{{ item.length === 1 ? `${key}:${item[0].tag}` : key }}
151
+ </span>
152
+ <span class="mr-auto">
153
+ <svg-icon type="mdi" :path="clicked[item.length === 1 ? `${key}.${item[0].tag}` : key] ? mdiChevronDown : mdiChevronRight" :size="30" class="pb-1" style="display:inline" />
154
+ </span>
155
+ </span>
156
+ <ul
157
+ v-if="item.length === 1 && clicked[`${key}.${item[0].tag}`]"
158
+ class="text-textColor"
159
+ >
160
+ <li
161
+ v-for="task in item[0].tasks"
162
+ :key="task._id"
163
+ class="gsu-menu-item py-2 px-4 block whitespace-no-wrap pl-8"
164
+ @click="select(task._id, `${key}:${item[0].tag} -> ${task.name}`)"
165
+ :class="`${task._id === selected ? 'bg-highlightedColor': ''}`"
166
+ >
167
+ {{ task.name }}
168
+ </li>
169
+ </ul>
170
+ <ul
171
+ v-else-if="clicked[key] && item.length > 1"
172
+ class="text-textColor"
173
+ >
174
+ <li
175
+ v-for="tag in item"
176
+ :key="tag.tag"
177
+ >
178
+ <span class="py-2 px-4 block whitespace-no-wrap pl-8" @click="selectItem(`${key}.${tag.tag}`)">
179
+ <span class="pr-1">{{ tag.tag }}</span>
180
+ <span class="mr-auto">
181
+ <svg-icon type="mdi" :path="clicked[`${key}.${tag.tag}`] ? mdiChevronDown : mdiChevronRight" :size="30" class="pb-1" style="display:inline" />
182
+
183
+ </span>
184
+ </span>
185
+ <ul
186
+ v-if="clicked[`${key}.${tag.tag}`]"
187
+ class="text-textColor"
188
+ >
189
+ <li
190
+ v-for="task in tag.tasks"
191
+ :key="task._id"
192
+ @click="select(task._id,`${key}:${tag.tag} -> ${task.name}` )"
193
+ class="py-2 px-4 block whitespace-no-wrap pl-12"
194
+ :class="`${task._id === selected ? 'bg-bgMutedColor': ''}`"
195
+ >
196
+ <span class=" py-2 px-4 block whitespace-no-wrap" href="#">
197
+ {{ task.name }}
198
+ </span>
199
+ </li>
200
+ </ul>
201
+ </li>
202
+ </ul>
203
+ </li>
204
+ </ul>
205
+ </div>
206
+ <div v-else class="mx-6">
207
+ <span>
208
+ Error
209
+ <svg-icon style="display:inline" type="mdi" color="orange" :path="mdiAlert" :size="30" class="pb-1" />
210
+ </span>
211
+ <div>The User is not logged in.</div>
212
+ </div>
213
+ </div>
214
+ </template>
215
+ <style scoped lang="scss">
216
+
217
+ </style>
@@ -0,0 +1,77 @@
1
+ <script lang="ts">
2
+ import { defineComponent, ref } from "vue";
3
+ import SvgIcon from "@jamescoyle/vue-icon";
4
+ import Modal from './FileBrowser/Modal.tw.vue';
5
+ import GirderSlicerTaskMenu from "./GirderSlicerTaskMenu.tw.vue";
6
+ import { SlicerImage } from "../api/girderSlicerApi";
7
+ import { PropType } from "vue/types/v3-component-props";
8
+
9
+ export default defineComponent({
10
+ components: {
11
+ SvgIcon,
12
+ Modal,
13
+ GirderSlicerTaskMenu,
14
+ },
15
+ props: {
16
+ apiUrl: {
17
+ type: String,
18
+ default: "api/v1",
19
+ },
20
+ filter: {
21
+ type: Function as PropType<(task: SlicerImage) => boolean>,
22
+ default: (_task: SlicerImage) => true,
23
+ },
24
+ },
25
+ setup(_props, { emit }) {
26
+ const accept = () => {
27
+ emit('selected', selectedId.value);
28
+ };
29
+ const selectedId = ref('');
30
+ const selectedName = ref('');
31
+ const processSelected = (data: { id: string, name: string }) => {
32
+ selectedId.value = data.id;
33
+ selectedName.value = data.name;
34
+ }
35
+ const selected = ref('');
36
+ return {
37
+ accept,
38
+ processSelected,
39
+ selected,
40
+ selectedId,
41
+ selectedName,
42
+ };
43
+ },
44
+ });
45
+ </script>
46
+ <template>
47
+ <span>
48
+ <Modal
49
+ :disabled-confirm="!selectedName"
50
+ @cancel="$emit('cancel')"
51
+ @confirm="accept()"
52
+ >
53
+ <template slot="header">
54
+ <span>Task Selection</span>
55
+ </template>
56
+ <template slot="body">
57
+ <GirderSlicerTaskMenu
58
+ :api-url="apiUrl"
59
+ :filter="filter"
60
+ @selected="processSelected($event)"
61
+ />
62
+ <div v-if="selectedName" class="flex flex-row justify-items-center">
63
+ <div class="ma-auto">
64
+ <span class="px-2">Selected:</span>
65
+ <span class="px-2" > {{ selectedName }}</span>
66
+ </div>
67
+ </div>
68
+ </template>
69
+ </Modal>
70
+ </span>
71
+ </template>
72
+ <style scoped lang="scss">
73
+ .dropdown:hover > .dropdown-content {
74
+ display: block;
75
+ }
76
+
77
+ </style>
@@ -0,0 +1,106 @@
1
+ <script lang="ts">
2
+ import { computed, defineComponent, ref } from "vue";
3
+ import SvgIcon from "@jamescoyle/vue-icon";
4
+ import Modal from './FileBrowser/Modal.tw.vue';
5
+ import GirderSlicerTaskMenu from "./GirderSlicerTaskMenu.tw.vue";
6
+ import RestClient from "../api/girderRest";
7
+ import { mdiAlert } from "@mdi/js";
8
+ import { PropType } from "vue/types/v3-component-props";
9
+ import { SlicerImage } from "../api/girderSlicerApi";
10
+ export default defineComponent({
11
+ components: {
12
+ SvgIcon,
13
+ Modal,
14
+ GirderSlicerTaskMenu,
15
+ },
16
+ props: {
17
+ apiUrl: {
18
+ type: String,
19
+ default: "api/v1",
20
+ },
21
+ filter: {
22
+ type: Function as PropType<(task: SlicerImage) => boolean>,
23
+ default: (_task: SlicerImage) => true,
24
+ },
25
+ },
26
+ setup(props, { emit }) {
27
+ const modalOpen = ref(false);
28
+ const girderRest = new RestClient({ apiRoot: props.apiUrl });
29
+ const loggedIn = computed(() => girderRest?.token);
30
+
31
+ const accept = () => {
32
+ emit('selected', selectedId.value);
33
+ modalOpen.value = false;
34
+ };
35
+ const selectedId = ref('');
36
+ const selectedName = ref('');
37
+ const processSelected = (data: { id: string, name: string }) => {
38
+ selectedId.value = data.id;
39
+ selectedName.value = data.name;
40
+ }
41
+ const selected = ref('');
42
+
43
+ const clearSelection = () => {
44
+ selectedId.value = '';
45
+ selectedName.value = '';
46
+ selected.value = '';
47
+ }
48
+ return {
49
+ modalOpen,
50
+ accept,
51
+ processSelected,
52
+ clearSelection,
53
+ selected,
54
+ selectedId,
55
+ selectedName,
56
+ loggedIn,
57
+ mdiAlert,
58
+ };
59
+ },
60
+ });
61
+ </script>
62
+ <template>
63
+ <span>
64
+ <button
65
+ class="gsu-btn font-semibold py-2 px-4 rounded inline-flex items-center
66
+ rounded-sm flex items-center min-w-32 border-2 border-solid border-borderColor"
67
+ @click="modalOpen = true"
68
+ >
69
+ <span v-if="!loggedIn" class="pr-1 font-semibold flex-1">
70
+ Log In
71
+ <svg-icon style="display:inline" type="mdi" color="orange" :path="mdiAlert" :size="30" class="pb-1" />
72
+ </span>
73
+ <span v-else-if="!selectedName" class="pr-1 font-semibold flex-1">Choose Task</span>
74
+ <span v-else-if="selectedName" class="pr-1 text-xs font-semibold flex-1">{{ selectedName }}</span>
75
+ </button>
76
+ <Modal
77
+ :isVisible="modalOpen"
78
+ :disabled-confirm="!selectedName"
79
+ @cancel="modalOpen =false; $emit('cancel')"
80
+ @confirm="accept()"
81
+ >
82
+ <template slot="header">
83
+ <span>Task Selection</span>
84
+ </template>
85
+ <template slot="body">
86
+ <GirderSlicerTaskMenu
87
+ :api-url="apiUrl"
88
+ :filter="filter"
89
+ @selected="processSelected($event)"
90
+ />
91
+ <div v-if="selectedName" class="flex flex-row justify-items-center">
92
+ <div class="ma-auto">
93
+ <span class="px-2">Selected:</span>
94
+ <span class="px-2" > {{ selectedName }}</span>
95
+ </div>
96
+ </div>
97
+ </template>
98
+ </Modal>
99
+ </span>
100
+ </template>
101
+ <style scoped lang="scss">
102
+ .dropdown:hover > .dropdown-content {
103
+ display: block;
104
+ }
105
+
106
+ </style>
@@ -0,0 +1,73 @@
1
+ <script lang="ts">
2
+ import { Ref, defineComponent, ref, PropType } from 'vue';
3
+ import GirderSlicerTaskMenuModalButton from './GlicerSlicerTaskMenuModalButton.tw.vue';
4
+ import GirderSlicerTaskCard from './GirderSlicerTaskCard.tw.vue';
5
+ import type { XMLParameters } from '../parser/parserTypes';
6
+ import { SlicerImage } from '../api/girderSlicerApi';
7
+
8
+
9
+ export default defineComponent({
10
+ name: 'GirderSlicerTasksIntegrated',
11
+ components: {
12
+ GirderSlicerTaskCard,
13
+ GirderSlicerTaskMenuModalButton,
14
+ },
15
+ props: {
16
+ apiUrl: {
17
+ type: String,
18
+ default: 'api/v1',
19
+ },
20
+ filter: {
21
+ type: Function as PropType<(task: SlicerImage) => boolean>,
22
+ default: (_task: SlicerImage) => true,
23
+ },
24
+ defaults: {
25
+ type: Function as PropType<(item: XMLParameters) => undefined | null | XMLParameters>,
26
+ default: (_item: XMLParameters) => undefined,
27
+ }
28
+ },
29
+ setup() {
30
+ const selected: Ref<string | null> = ref(null);
31
+ const menuModelButton: Ref<typeof GirderSlicerTaskMenuModalButton | null> = ref(null);
32
+ const select = (id: string) => {
33
+ selected.value = id;
34
+ }
35
+ const cancel = () => {
36
+ if (menuModelButton.value) {
37
+ menuModelButton.value.clearSelection();
38
+ }
39
+ selected.value = null;
40
+ }
41
+ return {
42
+ selected,
43
+ select,
44
+ cancel,
45
+ menuModelButton,
46
+ };
47
+
48
+ },
49
+ });
50
+ </script>
51
+
52
+ <template>
53
+ <div
54
+ class="card"
55
+ >
56
+ <div class="card-body">
57
+ <div class="card-title justify-content-center row g-20">
58
+ <div class="col">
59
+ <girder-slicer-task-menu-modal-button
60
+ ref="menuModelButton"
61
+ :filter="filter"
62
+ @selected="select($event)"
63
+ />
64
+ <girder-slicer-task-card :task-id="selected" :defaults="defaults" @cancel="cancel()" @run-task="$emit('run-task', $event)" />
65
+ </div>
66
+ </div>
67
+ </div>
68
+ </div>
69
+ </template>
70
+
71
+ <style>
72
+
73
+ </style>