Skip to content

Commit b66ae39

Browse files
authored
Sample type color field and color configuration (#7866)
1 parent 319316a commit b66ae39

23 files changed

Lines changed: 1345 additions & 46 deletions

api/src/org/labkey/api/audit/SampleTimelineAuditEvent.java

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.jetbrains.annotations.Nullable;
2121
import org.labkey.api.collections.CaseInsensitiveHashMap;
2222
import org.labkey.api.data.Container;
23+
import org.labkey.api.exp.api.ExperimentService;
2324
import org.labkey.api.qc.DataState;
2425
import org.labkey.api.qc.SampleStatusService;
2526
import org.labkey.api.query.QueryService;
@@ -224,46 +225,42 @@ public Map<String, Object> getAuditLogMessageElements()
224225
return elements;
225226
}
226227

227-
/**
228-
* If the sample state changed, explicitly add in the Status Label value to the map so that it will render in the
229-
* audit log timeline event even if the DataState row is later deleted. Also, remove the aliquot rollup calculated
230-
* fields from the data.
231-
*/
232228
@Override
233229
public void setOldRecordMap(String oldRecordMap, Container container)
234230
{
235-
if (oldRecordMap != null)
236-
{
237-
Map<String, String> row = new CaseInsensitiveHashMap<>(AbstractAuditTypeProvider.decodeFromDataMap(oldRecordMap));
238-
EXCLUDED_DETAIL_FIELDS.forEach(row::remove);
239-
String label = getStatusLabel(row, container);
240-
if (label != null)
241-
{
242-
row.put("samplestatelabel", label);
243-
oldRecordMap = AbstractAuditTypeProvider.encodeForDataMap(row);
244-
}
245-
}
246-
super.setOldRecordMap(oldRecordMap);
231+
super.setOldRecordMap(withResolvedLabels(oldRecordMap, container));
247232
}
248233

249-
/**
250-
* If the sample state changed, explicitly add in the Status Label value to the map so that it will render in the
251-
* audit log timeline event even if the DataState row is later deleted. Also, remove the aliquot rollup calculated
252-
* fields from the data.
253-
*/
254234
@Override
255235
public void setNewRecordMap(String newRecordMap, Container container)
256236
{
257-
if (newRecordMap != null)
237+
super.setNewRecordMap(withResolvedLabels(newRecordMap, container), container);
238+
}
239+
240+
/**
241+
* If the sample state or color changed, explicitly add the resolved Status/Color label to the map so it renders in
242+
* the audit log timeline event even if the DataState/DataColor row is later deleted. Also removes the aliquot rollup
243+
* calculated fields from the data.
244+
*/
245+
private String withResolvedLabels(String recordMap, Container container)
246+
{
247+
if (recordMap == null)
248+
return null;
249+
250+
Map<String, String> row = new CaseInsensitiveHashMap<>(AbstractAuditTypeProvider.decodeFromDataMap(recordMap));
251+
EXCLUDED_DETAIL_FIELDS.forEach(row::remove);
252+
253+
String statusLabel = getStatusLabel(row, container);
254+
if (row.containsKey("samplestate"))
255+
row.put("samplestatelabel", statusLabel);
256+
257+
if (row.containsKey(ExpMaterialColor.name()))
258258
{
259-
Map<String, String> row = new CaseInsensitiveHashMap<>(AbstractAuditTypeProvider.decodeFromDataMap(newRecordMap));
260-
EXCLUDED_DETAIL_FIELDS.forEach(row::remove);
261-
String label = getStatusLabel(row, container);
262-
if (label != null)
263-
row.put("samplestatelabel", label);
264-
newRecordMap = AbstractAuditTypeProvider.encodeForDataMap(row);
259+
String colorLabel = getColorLabel(row, container);
260+
row.put("expmaterialcolorlabel", colorLabel);
265261
}
266-
super.setNewRecordMap(newRecordMap, container);
262+
263+
return AbstractAuditTypeProvider.encodeForDataMap(row);
267264
}
268265

269266
private String getStatusLabel(Map<String, String> row, Container container)
@@ -276,4 +273,12 @@ private String getStatusLabel(Map<String, String> row, Container container)
276273
}
277274
return null;
278275
}
276+
277+
private String getColorLabel(Map<String, String> row, Container container)
278+
{
279+
String value = row.get(ExpMaterialColor.name());
280+
if (!StringUtils.isBlank(value))
281+
return ExperimentService.get().getDataColorLabel(container, Long.parseLong(value));
282+
return null;
283+
}
279284
}

api/src/org/labkey/api/data/ContainerManager.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1951,10 +1951,6 @@ private static boolean delete(final Container c, User user, @Nullable String com
19511951
// and delete all container-based sequences
19521952
DbSequenceManager.deleteAll(c);
19531953

1954-
ExperimentService experimentService = ExperimentService.get();
1955-
if (experimentService != null)
1956-
experimentService.removeContainerDataTypeExclusions(c.getId());
1957-
19581954
// Issue 17015: After we've committed the transaction, be sure that we remove this container from the cache
19591955
tx.addCommitTask(() ->
19601956
{

api/src/org/labkey/api/exp/api/ExpMaterial.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ public interface ExpMaterial extends ExpRunItem
8585

8686
void setSampleStateId(Long stateId);
8787

88+
Long getSampleColorId();
89+
90+
void setSampleColorId(Long colorId);
91+
8892
Date getMaterialExpDate();
8993

9094
ActionURL detailsURL(Container container, boolean checkForOverride);

api/src/org/labkey/api/exp/api/ExperimentService.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ public interface ExperimentService extends ExperimentRunTypeSource
134134

135135
String EXPERIMENTAL_FEATURE_ALLOW_ROW_ID_MERGE = "org.labkey.experiment.api.SampleTypeUpdateServiceDI#ALLOW_ROW_ID_SAMPLE_MERGE";
136136

137+
String EXPERIMENTAL_SAMPLE_COLORS = "org.labkey.api.exp.api.ExperimentService#SAMPLE_COLORS";
138+
137139
int SIMPLE_PROTOCOL_FIRST_STEP_SEQUENCE = 1;
138140
int SIMPLE_PROTOCOL_CORE_STEP_SEQUENCE = 10;
139141
int SIMPLE_PROTOCOL_EXTRA_STEP_SEQUENCE = 15;
@@ -710,6 +712,8 @@ static void validateParentAlias(Map<String, String> aliasMap, Set<String> reserv
710712

711713
SampleStatusTable createSampleStatusTable(ExpSchema expSchema, ContainerFilter cf);
712714

715+
TableInfo createDataColorTable(ExpSchema expSchema, ContainerFilter cf);
716+
713717
ExpUnreferencedSampleFilesTable createUnreferencedSampleFilesTable(ExpSchema expSchema, ContainerFilter cf);
714718

715719
FilteredTable<ExpSchema> createFieldsTable(ExpSchema expSchema, ContainerFilter cf);
@@ -1139,6 +1143,25 @@ List<? extends ExpProtocol> getExpProtocolsWithParameterValue(
11391143

11401144
String getDisabledDataTypeAuditMsg(DataTypeForExclusion type, List<Long> ids, boolean isUpdate);
11411145

1146+
@NotNull Set<Long> getDataTypeExcludedColors(DataTypeForExclusion dataType, long dataTypeId);
1147+
1148+
/** The data type rowIds (e.g. sample type rowIds) that currently exclude the given color. Inverse of {@link #getDataTypeExcludedColors}. */
1149+
@NotNull Set<Long> getDataTypesExcludingColor(DataTypeForExclusion dataType, long colorRowId);
1150+
1151+
@NotNull Set<Long> getActiveDataTypeColors(@NotNull Container container, DataTypeForExclusion dataType, long dataTypeId);
1152+
1153+
@Nullable String getDataColorLabel(@NotNull Container container, long colorRowId);
1154+
1155+
boolean ensureDataColorExclusions(long dataTypeId, DataTypeForExclusion dataType, @Nullable Collection<Long> disabledColorRowIds, @NotNull Container container, User user);
1156+
1157+
@NotNull Set<Long> updateColorDataTypeExclusions(long colorRowId, DataTypeForExclusion dataType, @Nullable Collection<Long> newlyDisabledDataTypeIds, @Nullable Collection<Long> newlyEnabledDataTypeIds, @NotNull Container container, User user);
1158+
1159+
void removeDataColorExclusionsForColor(long colorRowId);
1160+
1161+
void removeDataColorExclusionsForDataType(long dataTypeId, DataTypeForExclusion dataType);
1162+
1163+
void removeContainerDataColors(String containerId);
1164+
11421165
void registerRunInputsViewProvider(QueryViewProvider<ExpRun> provider);
11431166

11441167
void registerRunOutputsViewProvider(QueryViewProvider<ExpRun> providers);

api/src/org/labkey/api/exp/api/SampleTypeDomainKind.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,8 @@ public Domain createDomain(GWTDomain<GWTPropertyDescriptor> domain, @Nullable Sa
535535
Map<String, Map<String, Object>> aliases = null;
536536
List<String> excludedContainerIds = null;
537537
List<String> excludedDashboardContainerIds = null;
538+
List<Integer> excludedSampleColorIds = null;
539+
538540

539541
if (arguments != null)
540542
{
@@ -556,12 +558,13 @@ public Domain createDomain(GWTDomain<GWTPropertyDescriptor> domain, @Nullable Sa
556558
aliases = arguments.getImportAliases();
557559
excludedContainerIds = arguments.getExcludedContainerIds();
558560
excludedDashboardContainerIds = arguments.getExcludedDashboardContainerIds();
561+
excludedSampleColorIds = arguments.getDisabledSampleColorRowIds();
559562
}
560563
ExpSampleType st;
561564
try
562565
{
563566
st = SampleTypeService.get().createSampleType(container, user, name, description, properties, indices, idCol1, idCol2, idCol3, parentCol, nameExpression, aliquotNameExpression,
564-
templateInfo, aliases, labelColor, metricUnit, autoLinkTargetContainer, autoLinkCategory, category, domain.getDisabledSystemFields(), excludedContainerIds, excludedDashboardContainerIds, arguments != null ? arguments.getAuditRecordMap() : null);
567+
templateInfo, aliases, labelColor, metricUnit, autoLinkTargetContainer, autoLinkCategory, category, domain.getDisabledSystemFields(), excludedContainerIds, excludedDashboardContainerIds, excludedSampleColorIds, arguments != null ? arguments.getAuditRecordMap() : null);
565568
}
566569
catch (ExperimentException e)
567570
{

api/src/org/labkey/api/exp/api/SampleTypeDomainKindProperties.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ public SampleTypeDomainKindProperties(ExpSampleType st)
8787
private String category;
8888
private List<String> excludedContainerIds;
8989
private List<String> excludedDashboardContainerIds;
90+
private List<Integer> disabledSampleColorRowIds;
9091

9192
//Ignored on import/save, use Domain.name & Domain.description instead
9293
private String name;
@@ -285,6 +286,16 @@ public List<String> getExcludedDashboardContainerIds()
285286
return excludedDashboardContainerIds;
286287
}
287288

289+
public List<Integer> getDisabledSampleColorRowIds()
290+
{
291+
return disabledSampleColorRowIds;
292+
}
293+
294+
public void setDisabledSampleColorRowIds(List<Integer> disabledSampleColorRowIds)
295+
{
296+
this.disabledSampleColorRowIds = disabledSampleColorRowIds;
297+
}
298+
288299
public void setExcludedDashboardContainerIds(List<String> excludedDashboardContainerIds)
289300
{
290301
this.excludedDashboardContainerIds = excludedDashboardContainerIds;

api/src/org/labkey/api/exp/api/SampleTypeService.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ static void setInstance(SampleTypeService impl)
123123

124124
Map<String, ExpSampleType> getSampleTypesForRoles(Container container, ContainerFilter filter, ExpProtocol.ApplicationType type);
125125

126+
void auditSampleColorExclusion(Container container, long sampleTypeRowId, @Nullable String auditUserComment, User user);
127+
126128
/**
127129
* Create a new SampleType with the provided properties.
128130
* If a 'Name' property exists in the list, it will be used as the 'id' property of the SampleType.
@@ -150,7 +152,7 @@ ExpSampleType createSampleType(Container container, User user, String name, Stri
150152
ExpSampleType createSampleType(Container c, User u, String name, String description, List<GWTPropertyDescriptor> properties, List<GWTIndex> indices, int idCol1, int idCol2, int idCol3, int parentCol,
151153
String nameExpression, String aliquotNameExpression, @Nullable TemplateInfo templateInfo, @Nullable Map<String, Map<String, Object>> importAliases, @Nullable String labelColor, @Nullable String metricUnit,
152154
@Nullable Container autoLinkTargetContainer, @Nullable String autoLinkCategory, @Nullable String category, @Nullable List<String> disabledSystemField,
153-
@Nullable List<String> excludedContainerIds, @Nullable List<String> excludedDashboardContainerIds, @Nullable Map<String, Object> changeDetails)
155+
@Nullable List<String> excludedContainerIds, @Nullable List<String> excludedDashboardContainerIds, @Nullable List<Integer> excludedSampleColorIds, @Nullable Map<String, Object> changeDetails)
154156
throws ExperimentException;
155157

156158
@NotNull

api/src/org/labkey/api/exp/query/ExpMaterialTable.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ enum Column
6666
RunId, // database table only
6767
RunApplication,
6868
RunApplicationOutput,
69+
ExpMaterialColor,
6970
SampleSet,
7071
SampleState,
7172
SourceApplicationId, // database table only

api/src/org/labkey/api/exp/query/ExpSchema.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,14 @@ public TableInfo createTable(ExpSchema expSchema, String queryName, ContainerFil
245245
return ExperimentService.get().createSampleStatusTable(expSchema, cf);
246246
}
247247
},
248+
DataColors
249+
{
250+
@Override
251+
public TableInfo createTable(ExpSchema expSchema, String queryName, ContainerFilter cf)
252+
{
253+
return ExperimentService.get().createDataColorTable(expSchema, cf);
254+
}
255+
},
248256
Fields
249257
{
250258
@Override

api/src/org/labkey/api/query/AbstractQueryUpdateService.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,8 @@ protected DataIteratorBuilder _toDataIteratorBuilder(String debugName, List<Map<
596596

597597
/** @deprecated switch to using DIB based method */
598598
@Deprecated
599-
protected List<Map<String, Object>> _insertRowsUsingInsertRow(User user, Container container, List<Map<String, Object>> rows, BatchValidationException errors, Map<String, Object> extraScriptContext)
599+
protected List<Map<String, Object>> _insertRowsUsingInsertRow(User user, Container container, List<Map<String, Object>> rows, BatchValidationException errors,
600+
@Nullable Map<Enum, Object> configParameters, Map<String, Object> extraScriptContext)
600601
throws DuplicateKeyException, BatchValidationException, QueryUpdateServiceException, SQLException
601602
{
602603
if (!hasInsertRowsPermission(user))
@@ -664,7 +665,7 @@ else if (SqlDialect.isTransactionException(sqlx) && errors.hasErrors())
664665
if (hasTableScript)
665666
getQueryTable().fireBatchTrigger(container, user, TableInfo.TriggerType.INSERT, null, false, errors, extraScriptContext);
666667

667-
addAuditEvent(user, container, QueryService.AuditAction.INSERT, null, result, null, providedValues);
668+
addAuditEvent(user, container, QueryService.AuditAction.INSERT, configParameters, result, null, providedValues);
668669

669670
return result;
670671
}
@@ -715,7 +716,7 @@ public List<Map<String, Object>> insertRows(User user, Container container, List
715716
{
716717
try
717718
{
718-
List<Map<String,Object>> ret = _insertRowsUsingInsertRow(user, container, rows, errors, extraScriptContext);
719+
List<Map<String,Object>> ret = _insertRowsUsingInsertRow(user, container, rows, errors, configParameters, extraScriptContext);
719720
afterInsertUpdate(null==ret?0:ret.size(), errors);
720721
if (errors.hasErrors())
721722
return null;

0 commit comments

Comments
 (0)