Skip to content

Commit

Permalink
Merge branch 'dev' into 35416-Add-Quality-Contol-table-to-MolecularAn…
Browse files Browse the repository at this point in the history
…alysisRun-view
  • Loading branch information
brandonandre authored Dec 18, 2024
2 parents 7e3f031 + 52968b0 commit 7e566a3
Show file tree
Hide file tree
Showing 14 changed files with 415 additions and 127 deletions.
71 changes: 42 additions & 29 deletions packages/common-ui/lib/list-page/useElasticSearchDistinctTerm.tsx
Original file line number Diff line number Diff line change
@@ -1,50 +1,57 @@
import Bodybuilder from "bodybuilder";
import { castArray } from "lodash";
import { castArray, pick } from "lodash";
import { useEffect, useState } from "react";
import { useApiClient, useQueryBuilderContext } from "..";

const TOTAL_SUGGESTIONS: number = 100;
const FILTER_AGGREGATION_NAME: string = "included_type_filter";
const AGGREGATION_NAME: string = "term_aggregation";
const NEST_AGGREGATION_NAME: string = "included_aggregation";

interface QuerySuggestionFieldProps {
/** The string you want elastic search to use. */
fieldName?: string;

/** If the field is a relationship, we need to know the type to filter it. */
relationshipType?: string;

/** The index you want elastic search to perform the search on */
indexName: string;

/** Used to determine if ".keyword" should be appended to the field name. */
keywordMultiFieldSupport: boolean;
}

/** Used to determine if field is an array in the back end. */
isFieldArray?: boolean;

/** User input used to query against */
inputValue?: string;

/** Group to be queried to only show the users most used values. */
groupNames?: string[];

/** Number of suggestions */
size?: number;
}
export function useElasticSearchDistinctTerm({
fieldName,
relationshipType,
indexName,
keywordMultiFieldSupport
keywordMultiFieldSupport,
isFieldArray = false,
inputValue,
groupNames,
size
}: QuerySuggestionFieldProps) {
const { apiClient } = useApiClient();

const [suggestions, setSuggestions] = useState<string[]>([]);

const { groups } = useQueryBuilderContext();

const { groups } = groupNames
? { groups: groupNames }
: useQueryBuilderContext();
// Every time the textEntered has changed, perform a new request for new suggestions.
useEffect(() => {
if (!fieldName) return;
queryElasticSearchForSuggestions();
}, [fieldName, relationshipType, groups]);

}, [fieldName, relationshipType, groups, inputValue]);
async function queryElasticSearchForSuggestions() {
// Use bodybuilder to generate the query to send to elastic search.
const builder = Bodybuilder();
builder.size(0);

// Group needs to be queried to only show the users most used values.
if (groups && groups.length !== 0) {
// terms is used to be able to support multiple groups.
Expand All @@ -54,7 +61,6 @@ export function useElasticSearchDistinctTerm({
castArray(groups)
);
}

// If the field has a relationship type, we need to do a nested query to filter it.
if (relationshipType) {
builder.aggregation(
Expand Down Expand Up @@ -83,16 +89,27 @@ export function useElasticSearchDistinctTerm({
);
} else {
// If it's an attribute, no need to use nested filters.
builder.aggregation(
"terms",
fieldName + (keywordMultiFieldSupport ? ".keyword" : ""),
{
size: TOTAL_SUGGESTIONS
},
AGGREGATION_NAME
);
if (isFieldArray) {
builder.aggregation(
"terms",
fieldName + (keywordMultiFieldSupport ? ".keyword" : ""),
{
size: size ?? TOTAL_SUGGESTIONS,
include: `.*${inputValue}.*`
},
AGGREGATION_NAME
);
} else {
builder.aggregation(
"terms",
fieldName + (keywordMultiFieldSupport ? ".keyword" : ""),
{
size: TOTAL_SUGGESTIONS
},
AGGREGATION_NAME
);
}
}

await apiClient.axios
.post(`search-api/search-ws/search`, builder.build(), {
params: {
Expand All @@ -115,9 +132,7 @@ export function useElasticSearchDistinctTerm({
}
return undefined;
};

let suggestionArray: string[] | undefined;

// The path to the results in the response changes if it contains the nested aggregation.
if (relationshipType) {
suggestionArray = findTermAggregationKey(
Expand All @@ -136,7 +151,6 @@ export function useElasticSearchDistinctTerm({
AGGREGATION_NAME
)?.buckets?.map((bucket) => bucket.key);
}

if (suggestionArray !== undefined) {
setSuggestions(suggestionArray);
} else {
Expand All @@ -149,6 +163,5 @@ export function useElasticSearchDistinctTerm({
setSuggestions([]);
});
}

return suggestions;
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
StringArrayField,
TextField,
TextFieldWithCoordButtons,
Tooltip,
filterBy,
useDinaFormContext,
useInstanceContext
Expand All @@ -32,7 +33,8 @@ import {
NotPubliclyReleasableWarning,
ParseVerbatimToRangeButton,
PersonSelectField,
TagsAndRestrictionsSection
TagsAndRestrictionsSection,
TagSelectReadOnly
} from "../..";
import { ManagedAttributesEditor } from "../../";
import { DinaMessage, useDinaIntl } from "../../../intl/dina-ui-intl";
Expand Down Expand Up @@ -602,7 +604,20 @@ export function CollectingEventFormLayout({
sectionName="general-section"
>
<NotPubliclyReleasableWarning />
<TagsAndRestrictionsSection resourcePath="collection-api/collecting-event" />
{readOnly ? (
<TagSelectReadOnly />
) : (
<Tooltip
id="collecting_event_tag_info"
disableSpanMargin={true}
visibleElement={
<TagsAndRestrictionsSection
resourcePath="collection-api/collecting-event"
indexName="dina_material_sample_index"
/>
}
/>
)}
</DinaFormSection>
<div className="row mb-3">
<div className="col-md-12">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,10 @@ export function MaterialSampleForm({
<CollectionSelectSection resourcePath="collection-api/collection" />
<ProjectSelectSection resourcePath="collection-api/project" />
<AssemblageSelectSection resourcePath="collection-api/assemblage" />
<TagsAndRestrictionsSection resourcePath="collection-api/material-sample" />
<TagsAndRestrictionsSection
resourcePath="collection-api/material-sample"
indexName="dina_material_sample_index"
/>
</div>
<div className="col-md-4">
<NotPubliclyReleasableSection />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,14 @@ export function useMetagenomicsWorkflowMolecularAnalysisRun({
const { bulkGet, save } = useApiClient();
const { formatMessage } = useDinaIntl();
const { compareByStringAndNumber } = useStringComparator();
// Map of MolecularAnalysisRunItem {id:name}
const [molecularAnalysisRunItemNames, setMolecularAnalysisRunItemNames] =
useState<Record<string, string>>({});
const columns = getMolecularAnalysisRunColumns(
compareByStringAndNumber,
"metagenomics-batch-item"
"metagenomics-batch-item",
setMolecularAnalysisRunItemNames,
!editMode
);

// Used to display if the network calls are still in progress.
Expand All @@ -253,8 +258,13 @@ export function useMetagenomicsWorkflowMolecularAnalysisRun({
const [sequencingRunItems, setSequencingRunItems] =
useState<SequencingRunItem[]>();

// Used to determine if the resource needs to be reloaded.
const [reloadResource, setReloadResource] = useState<number>(Date.now());

// Network Requests, starting with the SeqReaction
useQuery<MetagenomicsBatchItem[]>(
const { loading: loadingMetagenomicsBatchItems } = useQuery<
MetagenomicsBatchItem[]
>(
{
filter: filterBy([], {
extraFilters: [
Expand All @@ -271,6 +281,7 @@ export function useMetagenomicsWorkflowMolecularAnalysisRun({
"indexI5,indexI7,pcrBatchItem,molecularAnalysisRunItem,molecularAnalysisRunItem.run"
},
{
deps: [reloadResource],
onSuccess: async ({ data: metagenomicsBatchItems }) => {
/**
* Go through each of the MetagenomicsBatchItems and retrieve the Molecular Analysis Run. There
Expand Down Expand Up @@ -390,21 +401,29 @@ export function useMetagenomicsWorkflowMolecularAnalysisRun({

// Create a MolecularAnalysisRunitem for each MetagenomicsBatchItem.
const molecularAnalysisRunItemSaveArgs: SaveArgs<MolecularAnalysisRunItem>[] =
sequencingRunItems.map(() => ({
type: "molecular-analysis-run-item",
resource: {
sequencingRunItems.map((item) => {
const molecularAnalysisRunItemName = item.materialSampleSummary?.id
? molecularAnalysisRunItemNames[item.materialSampleSummary?.id]
: undefined;
return {
type: "molecular-analysis-run-item",
usageType: "metagenomics-batch-item",
relationships: {
run: {
data: {
id: savedMolecularAnalysisRun[0].id,
type: "molecular-analysis-run"
resource: {
type: "molecular-analysis-run-item",
usageType: "metagenomics-batch-item",
...(molecularAnalysisRunItemName && {
name: molecularAnalysisRunItemName
}),
relationships: {
run: {
data: {
id: savedMolecularAnalysisRun[0].id,
type: "molecular-analysis-run"
}
}
}
}
} as any
}));
} as any
};
});
const savedMolecularAnalysisRunItem = await save(
molecularAnalysisRunItemSaveArgs,
{ apiBaseUrl: "/seqdb-api" }
Expand Down Expand Up @@ -481,10 +500,37 @@ export function useMetagenomicsWorkflowMolecularAnalysisRun({
apiBaseUrl: "/seqdb-api"
});

// Update existing MolecularAnalysisRunItem names
if (sequencingRunItems) {
const molecularAnalysisRunItemSaveArgs: SaveArgs<MolecularAnalysisRunItem>[] =
[];
sequencingRunItems.forEach((item) => {
const molecularAnalysisRunItemName = item.materialSampleSummary?.id
? molecularAnalysisRunItemNames[item.materialSampleSummary?.id]
: undefined;
if (molecularAnalysisRunItemName) {
molecularAnalysisRunItemSaveArgs.push({
type: "molecular-analysis-run-item",
resource: {
id: item.molecularAnalysisRunItemId,
type: "molecular-analysis-run-item",
name: molecularAnalysisRunItemName
}
});
}
});
if (molecularAnalysisRunItemSaveArgs.length) {
await save(molecularAnalysisRunItemSaveArgs, {
apiBaseUrl: "/seqdb-api"
});
}
}

// Go back to view mode once completed.
setPerformSave(false);
setEditMode(false);
setLoading(false);
setReloadResource(Date.now());
} catch (error) {
console.error("Error updating sequencing run: ", error);
setPerformSave(false);
Expand Down Expand Up @@ -527,7 +573,7 @@ export function useMetagenomicsWorkflowMolecularAnalysisRun({
}, [performSave, loading]);

return {
loading,
loading: loading || loadingMetagenomicsBatchItems,
errorMessage,
multipleRunWarning,
sequencingRunName,
Expand Down
Loading

0 comments on commit 7e566a3

Please sign in to comment.