Loading client/src/components/Collections/common/CollectionEditView.vue +2 −14 Original line number Diff line number Diff line Loading @@ -11,8 +11,8 @@ import { GalaxyApi } from "@/api"; import { updateContentFields } from "@/components/History/model/queries"; import { DatatypesProvider, DbKeyProvider, SuitableConvertersProvider } from "@/components/providers"; import { useConfig } from "@/composables/config"; import { useDetailedCollection } from "@/composables/datasetCollections"; import { useCollectionAttributesStore } from "@/stores/collectionAttributesStore"; import { useCollectionElementsStore } from "@/stores/collectionElementsStore"; import { useHistoryStore } from "@/stores/historyStore"; import localize from "@/utils/localization"; import { prependPath } from "@/utils/redirect"; Loading Loading @@ -40,7 +40,7 @@ const collectionAttributesStore = useCollectionAttributesStore(); const historyStore = useHistoryStore(); const { currentHistoryId } = storeToRefs(historyStore); const collectionStore = useCollectionElementsStore(); const { collection, collectionLoadError } = useDetailedCollection(props); const jobError = ref(null); const errorMessage = ref(""); Loading @@ -63,18 +63,6 @@ const attributesLoadError = computed(() => { return undefined; }); const collection = computed(() => { return collectionStore.getCollectionById(props.collectionId); }); const collectionLoadError = computed(() => { if (collection.value) { const collectionElementLoadError = collectionStore.getLoadingCollectionElementsError(collection.value); if (collectionElementLoadError) { return errorMessageAsString(collectionElementLoadError); } } return undefined; }); watch([attributesLoadError, collectionLoadError], () => { if (attributesLoadError.value) { errorMessage.value = attributesLoadError.value; Loading client/src/components/Collections/common/DisplayCollectionAsSheet.vue 0 → 100644 +113 −0 Original line number Diff line number Diff line <script setup lang="ts"> import type { ColDef } from "ag-grid-community"; import { BAlert } from "bootstrap-vue"; import { computed, ref, watch } from "vue"; import type { SampleSheetColumnDefinitions } from "@/api"; import { type AgRowData, buildsSampleSheetGrid, toAgGridColumnDefinition, } from "@/components/Collections/sheet/useSampleSheetGrid"; import { useDetailedCollection } from "@/composables/datasetCollections"; import { useAgGrid } from "@/composables/useAgGrid"; import LoadingSpan from "@/components/LoadingSpan.vue"; interface Props { collectionId: string; } const props = defineProps<Props>(); const { collection, collectionLoadError } = useDetailedCollection(props); function initializeRowData(rowData: AgRowData[]) { const collectionDetailed = collection.value; if (collectionDetailed) { for (const element of collectionDetailed.elements) { const row: AgRowData = { __model_object: element }; (collectionDetailed.column_definitions || []).forEach((colDef) => { // TODO: row[colDef.name] = "foobar"; }); rowData.push(row); } } return []; } const { rowData, initialize, sampleSheetStyle } = buildsSampleSheetGrid(initializeRowData); const { gridApi, AgGridVue, onGridReady, theme } = useAgGrid(resize); function resize() { if (gridApi.value) { gridApi.value.sizeColumnsToFit(); } } // Generate Column Definitions from Schema function generateGridColumnDefs(columnDefinitions: SampleSheetColumnDefinitions): ColDef[] { const columns: ColDef[] = []; columns.push({ headerName: "Identifier", field: "__model_object", editable: false, cellEditorParams: {}, valueFormatter: (params) => { return params.data.__model_object.element_identifier; }, }); (columnDefinitions || []).forEach((colDef) => { const baseDef = toAgGridColumnDefinition(colDef); columns.push(baseDef); }); return columns; } // Column Definitions const columnDefs = computed(() => { if (!collection.value || !collection.value.column_definitions) { return []; } return generateGridColumnDefs(collection.value.column_definitions as SampleSheetColumnDefinitions); }); watch( () => collection.value, () => { initialize(); resize(); }, { immediate: true }, ); // Default Column Properties const defaultColDef = ref<ColDef>({ editable: false, sortable: false, filter: true, resizable: true, }); </script> <template> <div> <LoadingSpan v-if="!collection" /> <BAlert v-else-if="collectionLoadError" variant="danger" show dismissible> {{ collectionLoadError }} </BAlert> <div v-else> <div :class="theme"> <AgGridVue :row-data="rowData" :column-defs="columnDefs" :default-col-def="defaultColDef" :style="sampleSheetStyle" @gridReady="onGridReady" /> </div> </div> </div> </template> client/src/components/Collections/sheet/SampleSheetGrid.vue +9 −31 Original line number Diff line number Diff line Loading @@ -36,11 +36,11 @@ import { useUploadConfigurations } from "@/composables/uploadConfigurations"; import { useAgGrid } from "@/composables/useAgGrid"; import localize from "@/utils/localization"; import { type AgRowData, buildsSampleSheetGrid, toAgGridColumnDefinition } from "./useSampleSheetGrid"; import UploadSelect from "@/components/Upload//UploadSelect.vue"; import UploadSelectExtension from "@/components/Upload/UploadSelectExtension.vue"; type AgRowData = Record<string, unknown>; interface Props { currentHistoryId: string; collectionType: SampleSheetCollectionType; Loading Loading @@ -120,14 +120,7 @@ function initializeRowData(rowData: AgRowData[]) { } } // Example Row Data // const rowData = ref([{ "replicate number": 1, treatment: "treatment1", "is control?": true }]); const rowData = ref<AgRowData[]>([]); function initialize() { rowData.value.splice(0, rowData.value.length); initializeRowData(rowData.value); } const { rowData, initialize, sampleSheetStyle } = buildsSampleSheetGrid(initializeRowData); const { gridApi, AgGridVue, onGridReady, theme } = useAgGrid(resize); Loading Loading @@ -232,22 +225,10 @@ function generateGridColumnDefs(columnDefinitions: SampleSheetColumnDefinitions) } } (columnDefinitions || []).forEach((colDef) => { const headerDescription = colDef.description || colDef.name; const hasCustomHeaderDescription = headerDescription != colDef.name; let headerClass = ""; if (hasCustomHeaderDescription) { headerClass = "ag-grid-column-has-custom-header-description"; } const baseDef: ColDef = { headerName: colDef.name, headerTooltip: colDef.description || colDef.name, headerClass, field: colDef.name, editable: true, cellEditorParams: {}, valueSetter: (params) => { const baseDef = toAgGridColumnDefinition(colDef); baseDef.editable = true; baseDef.valueSetter = (params) => { return valueSetter(params, colDef); }, }; // Restrictions: Add dropdown editor for string type with restrictions Loading Loading @@ -344,10 +325,6 @@ const defaultColDef = ref<ColDef>({ resizable: true, }); const style = computed(() => { return { width: "100%", height: "500px" }; }); const emit = defineEmits<{ (e: "workbook-contents", base64Content: string): void; (e: "on-fetch-target", target: HdcaUploadTarget): void; Loading Loading @@ -573,6 +550,7 @@ async function attemptCreateViaExistingObjects() { rows[elementIdentifierFromRow(row)] = elementRow; } payload.rows = rows; payload.column_definitions = props.columnDefinitions; emit("on-collection-create-payload", payload); } Loading Loading @@ -615,7 +593,7 @@ defineExpose({ attemptCreate }); :row-data="rowData" :column-defs="columnDefs" :default-col-def="defaultColDef" :style="style" :style="sampleSheetStyle" @gridReady="onGridReady" /> <BRow align-h="center" style="margin-top: 10px"> <BCol v-if="showExtension" cols="4"> Loading client/src/components/Collections/sheet/useSampleSheetGrid.ts 0 → 100644 +44 −0 Original line number Diff line number Diff line import type { ColDef } from "ag-grid-community"; import { computed, ref } from "vue"; import type { SampleSheetColumnDefinition } from "@/api"; // Example Row Data // const rowData = ref([{ "replicate number": 1, treatment: "treatment1", "is control?": true }]); export type AgRowData = Record<string, unknown>; export function buildsSampleSheetGrid(initializeRowData: (rowData: AgRowData[]) => void) { const rowData = ref<AgRowData[]>([]); const sampleSheetStyle = computed(() => { return { width: "100%", height: "500px" }; }); function initialize() { rowData.value.splice(0, rowData.value.length); initializeRowData(rowData.value); } return { initialize, rowData, sampleSheetStyle, }; } export function toAgGridColumnDefinition(colDef: SampleSheetColumnDefinition): ColDef { const headerDescription = colDef.description || colDef.name; const hasCustomHeaderDescription = headerDescription != colDef.name; let headerClass = ""; if (hasCustomHeaderDescription) { headerClass = "ag-grid-column-has-custom-header-description"; } const baseDef: ColDef = { headerName: colDef.name, headerTooltip: colDef.description || colDef.name, headerClass, field: colDef.name, cellEditorParams: {}, }; return baseDef; } client/src/components/History/CurrentCollection/CollectionOperations.vue +15 −1 Original line number Diff line number Diff line <script setup lang="ts"> import { faDownload, faInfoCircle, faRedo } from "@fortawesome/free-solid-svg-icons"; import { faDownload, faInfoCircle, faRedo, faTable } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; import { computed } from "vue"; import { useRouter } from "vue-router/composables"; Loading @@ -22,6 +22,10 @@ const showCollectionDetailsUrl = computed(() => ); const disableDownload = props.dsc.populated_state !== "ok"; const sheetUrl = computed(() => { return `${getAppRoot()}collection/${props.dsc.id}/sheet`; }); function onDownload() { window.location.href = downloadUrl.value; } Loading Loading @@ -63,6 +67,16 @@ function onDownload() { <FontAwesomeIcon class="mr-1" :icon="faRedo" /> <span>Run Job Again</span> </b-button> <b-button v-if="sheetUrl" class="rounded-0 text-decoration-none" size="sm" variant="link" :href="sheetUrl" @click.prevent.stop="router.push(sheetUrl)"> <FontAwesomeIcon class="mr-1" :icon="faTable" /> <span>View Sheet</span> </b-button> </b-button-group> </nav> </section> Loading Loading
client/src/components/Collections/common/CollectionEditView.vue +2 −14 Original line number Diff line number Diff line Loading @@ -11,8 +11,8 @@ import { GalaxyApi } from "@/api"; import { updateContentFields } from "@/components/History/model/queries"; import { DatatypesProvider, DbKeyProvider, SuitableConvertersProvider } from "@/components/providers"; import { useConfig } from "@/composables/config"; import { useDetailedCollection } from "@/composables/datasetCollections"; import { useCollectionAttributesStore } from "@/stores/collectionAttributesStore"; import { useCollectionElementsStore } from "@/stores/collectionElementsStore"; import { useHistoryStore } from "@/stores/historyStore"; import localize from "@/utils/localization"; import { prependPath } from "@/utils/redirect"; Loading Loading @@ -40,7 +40,7 @@ const collectionAttributesStore = useCollectionAttributesStore(); const historyStore = useHistoryStore(); const { currentHistoryId } = storeToRefs(historyStore); const collectionStore = useCollectionElementsStore(); const { collection, collectionLoadError } = useDetailedCollection(props); const jobError = ref(null); const errorMessage = ref(""); Loading @@ -63,18 +63,6 @@ const attributesLoadError = computed(() => { return undefined; }); const collection = computed(() => { return collectionStore.getCollectionById(props.collectionId); }); const collectionLoadError = computed(() => { if (collection.value) { const collectionElementLoadError = collectionStore.getLoadingCollectionElementsError(collection.value); if (collectionElementLoadError) { return errorMessageAsString(collectionElementLoadError); } } return undefined; }); watch([attributesLoadError, collectionLoadError], () => { if (attributesLoadError.value) { errorMessage.value = attributesLoadError.value; Loading
client/src/components/Collections/common/DisplayCollectionAsSheet.vue 0 → 100644 +113 −0 Original line number Diff line number Diff line <script setup lang="ts"> import type { ColDef } from "ag-grid-community"; import { BAlert } from "bootstrap-vue"; import { computed, ref, watch } from "vue"; import type { SampleSheetColumnDefinitions } from "@/api"; import { type AgRowData, buildsSampleSheetGrid, toAgGridColumnDefinition, } from "@/components/Collections/sheet/useSampleSheetGrid"; import { useDetailedCollection } from "@/composables/datasetCollections"; import { useAgGrid } from "@/composables/useAgGrid"; import LoadingSpan from "@/components/LoadingSpan.vue"; interface Props { collectionId: string; } const props = defineProps<Props>(); const { collection, collectionLoadError } = useDetailedCollection(props); function initializeRowData(rowData: AgRowData[]) { const collectionDetailed = collection.value; if (collectionDetailed) { for (const element of collectionDetailed.elements) { const row: AgRowData = { __model_object: element }; (collectionDetailed.column_definitions || []).forEach((colDef) => { // TODO: row[colDef.name] = "foobar"; }); rowData.push(row); } } return []; } const { rowData, initialize, sampleSheetStyle } = buildsSampleSheetGrid(initializeRowData); const { gridApi, AgGridVue, onGridReady, theme } = useAgGrid(resize); function resize() { if (gridApi.value) { gridApi.value.sizeColumnsToFit(); } } // Generate Column Definitions from Schema function generateGridColumnDefs(columnDefinitions: SampleSheetColumnDefinitions): ColDef[] { const columns: ColDef[] = []; columns.push({ headerName: "Identifier", field: "__model_object", editable: false, cellEditorParams: {}, valueFormatter: (params) => { return params.data.__model_object.element_identifier; }, }); (columnDefinitions || []).forEach((colDef) => { const baseDef = toAgGridColumnDefinition(colDef); columns.push(baseDef); }); return columns; } // Column Definitions const columnDefs = computed(() => { if (!collection.value || !collection.value.column_definitions) { return []; } return generateGridColumnDefs(collection.value.column_definitions as SampleSheetColumnDefinitions); }); watch( () => collection.value, () => { initialize(); resize(); }, { immediate: true }, ); // Default Column Properties const defaultColDef = ref<ColDef>({ editable: false, sortable: false, filter: true, resizable: true, }); </script> <template> <div> <LoadingSpan v-if="!collection" /> <BAlert v-else-if="collectionLoadError" variant="danger" show dismissible> {{ collectionLoadError }} </BAlert> <div v-else> <div :class="theme"> <AgGridVue :row-data="rowData" :column-defs="columnDefs" :default-col-def="defaultColDef" :style="sampleSheetStyle" @gridReady="onGridReady" /> </div> </div> </div> </template>
client/src/components/Collections/sheet/SampleSheetGrid.vue +9 −31 Original line number Diff line number Diff line Loading @@ -36,11 +36,11 @@ import { useUploadConfigurations } from "@/composables/uploadConfigurations"; import { useAgGrid } from "@/composables/useAgGrid"; import localize from "@/utils/localization"; import { type AgRowData, buildsSampleSheetGrid, toAgGridColumnDefinition } from "./useSampleSheetGrid"; import UploadSelect from "@/components/Upload//UploadSelect.vue"; import UploadSelectExtension from "@/components/Upload/UploadSelectExtension.vue"; type AgRowData = Record<string, unknown>; interface Props { currentHistoryId: string; collectionType: SampleSheetCollectionType; Loading Loading @@ -120,14 +120,7 @@ function initializeRowData(rowData: AgRowData[]) { } } // Example Row Data // const rowData = ref([{ "replicate number": 1, treatment: "treatment1", "is control?": true }]); const rowData = ref<AgRowData[]>([]); function initialize() { rowData.value.splice(0, rowData.value.length); initializeRowData(rowData.value); } const { rowData, initialize, sampleSheetStyle } = buildsSampleSheetGrid(initializeRowData); const { gridApi, AgGridVue, onGridReady, theme } = useAgGrid(resize); Loading Loading @@ -232,22 +225,10 @@ function generateGridColumnDefs(columnDefinitions: SampleSheetColumnDefinitions) } } (columnDefinitions || []).forEach((colDef) => { const headerDescription = colDef.description || colDef.name; const hasCustomHeaderDescription = headerDescription != colDef.name; let headerClass = ""; if (hasCustomHeaderDescription) { headerClass = "ag-grid-column-has-custom-header-description"; } const baseDef: ColDef = { headerName: colDef.name, headerTooltip: colDef.description || colDef.name, headerClass, field: colDef.name, editable: true, cellEditorParams: {}, valueSetter: (params) => { const baseDef = toAgGridColumnDefinition(colDef); baseDef.editable = true; baseDef.valueSetter = (params) => { return valueSetter(params, colDef); }, }; // Restrictions: Add dropdown editor for string type with restrictions Loading Loading @@ -344,10 +325,6 @@ const defaultColDef = ref<ColDef>({ resizable: true, }); const style = computed(() => { return { width: "100%", height: "500px" }; }); const emit = defineEmits<{ (e: "workbook-contents", base64Content: string): void; (e: "on-fetch-target", target: HdcaUploadTarget): void; Loading Loading @@ -573,6 +550,7 @@ async function attemptCreateViaExistingObjects() { rows[elementIdentifierFromRow(row)] = elementRow; } payload.rows = rows; payload.column_definitions = props.columnDefinitions; emit("on-collection-create-payload", payload); } Loading Loading @@ -615,7 +593,7 @@ defineExpose({ attemptCreate }); :row-data="rowData" :column-defs="columnDefs" :default-col-def="defaultColDef" :style="style" :style="sampleSheetStyle" @gridReady="onGridReady" /> <BRow align-h="center" style="margin-top: 10px"> <BCol v-if="showExtension" cols="4"> Loading
client/src/components/Collections/sheet/useSampleSheetGrid.ts 0 → 100644 +44 −0 Original line number Diff line number Diff line import type { ColDef } from "ag-grid-community"; import { computed, ref } from "vue"; import type { SampleSheetColumnDefinition } from "@/api"; // Example Row Data // const rowData = ref([{ "replicate number": 1, treatment: "treatment1", "is control?": true }]); export type AgRowData = Record<string, unknown>; export function buildsSampleSheetGrid(initializeRowData: (rowData: AgRowData[]) => void) { const rowData = ref<AgRowData[]>([]); const sampleSheetStyle = computed(() => { return { width: "100%", height: "500px" }; }); function initialize() { rowData.value.splice(0, rowData.value.length); initializeRowData(rowData.value); } return { initialize, rowData, sampleSheetStyle, }; } export function toAgGridColumnDefinition(colDef: SampleSheetColumnDefinition): ColDef { const headerDescription = colDef.description || colDef.name; const hasCustomHeaderDescription = headerDescription != colDef.name; let headerClass = ""; if (hasCustomHeaderDescription) { headerClass = "ag-grid-column-has-custom-header-description"; } const baseDef: ColDef = { headerName: colDef.name, headerTooltip: colDef.description || colDef.name, headerClass, field: colDef.name, cellEditorParams: {}, }; return baseDef; }
client/src/components/History/CurrentCollection/CollectionOperations.vue +15 −1 Original line number Diff line number Diff line <script setup lang="ts"> import { faDownload, faInfoCircle, faRedo } from "@fortawesome/free-solid-svg-icons"; import { faDownload, faInfoCircle, faRedo, faTable } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; import { computed } from "vue"; import { useRouter } from "vue-router/composables"; Loading @@ -22,6 +22,10 @@ const showCollectionDetailsUrl = computed(() => ); const disableDownload = props.dsc.populated_state !== "ok"; const sheetUrl = computed(() => { return `${getAppRoot()}collection/${props.dsc.id}/sheet`; }); function onDownload() { window.location.href = downloadUrl.value; } Loading Loading @@ -63,6 +67,16 @@ function onDownload() { <FontAwesomeIcon class="mr-1" :icon="faRedo" /> <span>Run Job Again</span> </b-button> <b-button v-if="sheetUrl" class="rounded-0 text-decoration-none" size="sm" variant="link" :href="sheetUrl" @click.prevent.stop="router.push(sheetUrl)"> <FontAwesomeIcon class="mr-1" :icon="faTable" /> <span>View Sheet</span> </b-button> </b-button-group> </nav> </section> Loading