Unverified Commit c0e686af authored by Marius van den Beek's avatar Marius van den Beek Committed by GitHub
Browse files

Merge pull request #20798 from jmchilton/sample_sheet_history

Implement bare-bones view of sample sheet collections as sheet.
parents 7a0bb123 8077b899
Loading
Loading
Loading
Loading
+2 −14
Original line number Diff line number Diff line
@@ -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";
@@ -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("");
@@ -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;
+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>
+9 −31
Original line number Diff line number Diff line
@@ -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;
@@ -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);

@@ -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
@@ -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;
@@ -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);
}

@@ -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">
+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;
}
+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";
@@ -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;
}
@@ -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