Skip to content

Commit 84db9dc

Browse files
Merge 26.3 to develop
2 parents b1719f2 + 49c3073 commit 84db9dc

14 files changed

Lines changed: 190 additions & 134 deletions

File tree

api/src/org/labkey/api/reports/report/ScriptEngineReport.java

Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,7 @@
6060
import org.labkey.api.reports.report.r.view.TsvOutput;
6161
import org.labkey.api.thumbnail.Thumbnail;
6262
import org.labkey.api.util.FileUtil;
63-
import org.labkey.api.util.Path;
64-
import org.labkey.api.util.UnexpectedException;
63+
import org.labkey.api.util.UnexpectedException;
6564
import org.labkey.api.view.HttpView;
6665
import org.labkey.api.view.VBox;
6766
import org.labkey.api.view.ViewContext;
@@ -71,8 +70,7 @@
7170

7271
import javax.script.ScriptEngine;
7372
import javax.script.ScriptException;
74-
import java.io.File;
75-
import java.io.IOException;
73+
import java.io.IOException;
7674
import java.io.PrintWriter;
7775
import java.sql.ResultSetMetaData;
7876
import java.sql.SQLException;
@@ -212,36 +210,41 @@ public FileLike createInputDataFile(@NotNull ViewContext context) throws SQLExce
212210
* Note: This method used to stash results in members (_tempFolder and _tempFolderPipeline), but that no longer works
213211
* now that we cache reports between threads (e.g., Thread.currentThread().getId() is part of the path).
214212
*/
215-
public FileLike getReportDirFileLike(@NotNull String executingContainerId)
216-
{
217-
boolean isPipeline = BooleanUtils.toBoolean(getDescriptor().getProperty(ScriptReportDescriptor.Prop.runInBackground));
218-
return getReportDirFileLike(executingContainerId, isPipeline);
219-
}
220-
221-
protected FileLike getReportDirFileLike(@NotNull String executingContainerId, boolean isPipeline)
222-
{
223-
FileLike tempRoot = getTempRootFileLike(getDescriptor());
224-
String reportId = FileUtil.makeLegalName(String.valueOf(getDescriptor().getReportId())).replaceAll(" ", "_");
225-
FileLike tempFolder;
226-
227-
try
228-
{
229-
if (isPipeline)
230-
{
231-
String identifier = RReportJob.getJobIdentifier();
232-
if (identifier != null)
233-
tempFolder = FileUtil.appendPath(tempRoot,
234-
Path.parse(executingContainerId + File.separator + "Report_" + reportId + File.separator + identifier));
235-
else
236-
tempFolder = FileUtil.appendPath(tempRoot,
237-
Path.parse(executingContainerId + File.separator + "Report_" + reportId));
238-
}
239-
else
240-
tempFolder = FileUtil.appendPath(tempRoot,
241-
Path.parse(executingContainerId + File.separator + "Report_" + reportId + File.separator + Thread.currentThread().getId()));
242-
243-
FileUtil.mkdirs(tempFolder);
244-
return tempFolder;
213+
public FileLike getReportDirFileLike(@NotNull String executingContainerId)
214+
{
215+
boolean isPipeline = BooleanUtils.toBoolean(getDescriptor().getProperty(ScriptReportDescriptor.Prop.runInBackground));
216+
return getReportDirFileLike(executingContainerId, isPipeline);
217+
}
218+
219+
protected FileLike getBackgroundOutputDirFileLike(@NotNull String executingContainerId)
220+
{
221+
FileLike tempRoot = getTempRootFileLike(getDescriptor());
222+
String reportId = FileUtil.makeLegalName(String.valueOf(getDescriptor().getReportId())).replaceAll(" ", "_");
223+
224+
// Build FileLike paths from VFS path segments instead of File.separator so Windows
225+
// backslashes do not get folded into a single org.labkey.api.util.Path segment.
226+
return tempRoot.resolveChild(executingContainerId).resolveChild("Report_" + reportId);
227+
}
228+
229+
protected FileLike getReportDirFileLike(@NotNull String executingContainerId, boolean isPipeline)
230+
{
231+
FileLike tempFolder;
232+
233+
try
234+
{
235+
tempFolder = getBackgroundOutputDirFileLike(executingContainerId);
236+
237+
if (isPipeline)
238+
{
239+
String identifier = RReportJob.getJobIdentifier();
240+
if (identifier != null)
241+
tempFolder = tempFolder.resolveChild(identifier);
242+
}
243+
else
244+
tempFolder = tempFolder.resolveChild(String.valueOf(Thread.currentThread().getId()));
245+
246+
FileUtil.mkdirs(tempFolder);
247+
return tempFolder;
245248
}
246249
catch (IOException e)
247250
{

api/src/org/labkey/api/reports/report/r/RReport.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,20 @@ public FileLike getReportDirFileLike(@NotNull String executingContainerId)
696696
return super.getReportDirFileLike(executingContainerId);
697697
}
698698

699+
@Override
700+
protected FileLike getBackgroundOutputDirFileLike(@NotNull String executingContainerId)
701+
{
702+
FileLike reportDir = null;
703+
704+
if (getKnitrFormat() != RReportDescriptor.KnitrFormat.None)
705+
reportDir = getCacheDir(executingContainerId);
706+
707+
if (reportDir != null)
708+
return reportDir;
709+
710+
return super.getBackgroundOutputDirFileLike(executingContainerId);
711+
}
712+
699713
@Override
700714
public void clearCache()
701715
{

api/src/org/labkey/api/reports/report/r/RReportJob.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242

4343
import java.io.File;
4444
import java.io.Serializable;
45-
import java.nio.file.CopyOption;
4645
import java.nio.file.StandardCopyOption;
4746
import java.util.ArrayList;
4847
import java.util.HashMap;
@@ -275,16 +274,22 @@ protected void processOutputs(RReport report, List<ParamReplacement> outputSubst
275274
{
276275
// write the output substitution map to disk so we can render the view later
277276
FileLike reportDir = report.getReportDirFileLike(getJob().getContainerId());
277+
FileLike parentDir = report.getBackgroundOutputDirFileLike(getJob().getContainerId());
278278
FileLike substitutionMap;
279279

280-
if (reportDir.getName().equals(getJobIdentifier()))
280+
// ScriptEngineReport#getReportDirFileLike() appends the ThreadLocal job identifier only
281+
// when background execution needs a per-job child directory under parentDir.
282+
boolean hasJobSpecificReportDir = !reportDir.equals(parentDir);
283+
if (hasJobSpecificReportDir)
281284
{
282-
FileLike parentDir = reportDir.getParent();
283285
// clean up the destination folder
284286
for (FileLike file : parentDir.getChildren())
285287
{
286-
if (!file.isDirectory() && !"log".equalsIgnoreCase(FileUtil.getExtension(file)))
288+
if (file.isFile() && !"log".equalsIgnoreCase(FileUtil.getExtension(file)))
289+
{
290+
getJob().debug("deleting parent file=" + file);
287291
file.delete();
292+
}
288293
}
289294

290295
// rewrite the parameter replacement files to point to the destination folder
@@ -294,6 +299,7 @@ protected void processOutputs(RReport report, List<ParamReplacement> outputSubst
294299
for (FileLike file : replacement.getFiles())
295300
{
296301
FileLike newFile = parentDir.resolveChild(file.getName());
302+
getJob().debug("move replacement file =" + replacement.getName() + " from=" + file + " to=" + newFile);
297303
file.move(newFile);
298304
newFiles.add(newFile);
299305
}
@@ -317,6 +323,7 @@ protected void processOutputs(RReport report, List<ParamReplacement> outputSubst
317323
{
318324
newFile = FileUtil.createTempFile(LOG_FILE_PREFIX, ".log", parentDir);
319325
getJob().setLogFile(newFile);
326+
getJob().debug("copy log file from=" + file + " to=" + newFile);
320327
FileUtil.copyFile(file, newFile, StandardCopyOption.REPLACE_EXISTING);
321328
}
322329
// report.log != getLogFile(), just regular file
@@ -325,16 +332,19 @@ protected void processOutputs(RReport report, List<ParamReplacement> outputSubst
325332
String logFileContent = PageFlowUtil.getStreamContentsAsString(file.openInputStream());
326333
if (!StringUtils.isEmpty(logFileContent))
327334
getJob().info("REPORT.LOG CONTENTS:\n" + logFileContent);
335+
getJob().debug("move log file from=" + file + " to=" + newFile);
328336
file.move(newFile);
329337
}
330338
}
331339
else
332340
{
341+
getJob().debug("move file from=" + file + " to=" + newFile);
333342
file.move(newFile);
334343
}
335344
}
345+
getJob().debug("delete reportDir=" + reportDir);
336346
FileUtil.deleteDir(reportDir);
337-
substitutionMap = reportDir.getParent().resolveChild(RReport.SUBSTITUTION_MAP);
347+
substitutionMap = parentDir.resolveChild(RReport.SUBSTITUTION_MAP);
338348
}
339349
else
340350
substitutionMap = reportDir.resolveChild(RReport.SUBSTITUTION_MAP);

core/src/org/labkey/core/query/DocumentsTable.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import org.jetbrains.annotations.NotNull;
44
import org.labkey.api.attachments.AttachmentService;
5+
import org.labkey.api.collections.CsvSet;
56
import org.labkey.api.collections.LabKeyCollectors;
67
import org.labkey.api.data.BaseColumnInfo;
78
import org.labkey.api.data.ContainerFilter;
@@ -11,6 +12,7 @@
1112
import org.labkey.api.data.SQLFragment;
1213
import org.labkey.api.data.dialect.SqlDialect;
1314
import org.labkey.api.query.AliasManager;
15+
import org.labkey.api.query.FieldKey;
1416
import org.labkey.api.query.FilteredTable;
1517
import org.labkey.api.query.UserIdQueryForeignKey;
1618

@@ -26,16 +28,21 @@ public DocumentsTable(@NotNull CoreQuerySchema userSchema, ContainerFilter cf)
2628
getMutableColumnOrThrow("ModifiedBy").setHidden(true);
2729
getMutableColumnOrThrow("Modified").setHidden(true);
2830
MutableColumnInfo owner = getMutableColumnOrThrow("Owner");
29-
owner.setHidden(true);
3031
owner.setFk(new UserIdQueryForeignKey(_userSchema));
3132
getMutableColumnOrThrow("Parent").setHidden(true);
3233
getMutableColumnOrThrow("DocumentSize").setFormat("#,##0");
3334
getMutableColumnOrThrow("Document").setHidden(true);
3435
getMutableColumnOrThrow("LastIndexed").setHidden(true);
3536
addColumn(new BaseColumnInfo("ParentDescription", this, JdbcType.VARCHAR));
3637
BaseColumnInfo orphaned = new BaseColumnInfo("Orphaned", this, JdbcType.BOOLEAN);
37-
orphaned.setHidden(true);
3838
addColumn(orphaned);
39+
40+
setDefaultVisibleColumns(
41+
new CsvSet("CreatedBy, Created, Container, DocumentName, DocumentSize, DocumentType, ParentType, ParentDescription")
42+
.stream()
43+
.map(FieldKey::fromParts)
44+
.toList()
45+
);
3946
}
4047

4148
@Override

core/src/org/labkey/core/view/template/bootstrap/header.jsp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,12 @@
143143
{
144144
%>
145145
<li class="navbar-search hidden-xs">
146-
<a class="fa fa-search" id="global-search-trigger" aria-label="<%=h(SearchUtils.getPlaceholder(c))%>"></a>
146+
<a class="fa fa-search" id="global-search-trigger" aria-label="<%=h(SearchUtils.getPlaceholder(c))%>" role="button"></a>
147147
<div id="global-search" class="global-search">
148148
<labkey:form id="global-search-form" action="<%=urlProvider(SearchUrls.class).getSearchURL(c, null)%>" method="GET">
149149
<input type="text" class="search-box" name="q" placeholder="<%=h(SearchUtils.getPlaceholder(c))%>" value="">
150150
<input type="submit" hidden>
151-
<a id="a_header_search" href="#" class="btn-search fa fa-search"></a>
151+
<a id="a_header_search" href="#" class="btn-search fa fa-search" aria-label="Search" role="button"></a>
152152
</labkey:form>
153153
<% pageConfig.addHandler("a_header_search","click","document.getElementById('global-search-form').submit(); return false;"); %>
154154
</div>

core/webapp/internal/tippy.lib.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<libraries xmlns="http://labkey.org/clientLibrary/xml/">
22
<library compileInProductionMode="false">
3+
<script path="internal/tippy/popper.min.js"/>
34
<script path="internal/tippy/tippy-bundle.umd.js" mode="dev"/>
4-
<script path="internal/tippy/popper.min.js" mode="dev"/>
5+
<script path="internal/tippy/tippy-bundle.umd.min.js" mode="production"/>
56
</library>
67
</libraries>

core/webapp/internal/tippy/tippy-bundle.umd.min.js

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

list/src/org/labkey/list/model/ListDefinitionImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -576,10 +576,10 @@ public void delete(User user, @Nullable String auditUserComment) throws DomainNo
576576
try (DbScope.Transaction transaction = (table != null) ? table.getSchema().getScope().ensureTransaction() :
577577
ExperimentService.get().ensureTransaction())
578578
{
579-
// remove related attachments, discussions, and indices
579+
// remove related full-text search docs and attachments
580580
ListManager.get().deleteIndexedList(this);
581581
if (qus instanceof ListQueryUpdateService listQus)
582-
listQus.deleteRelatedListData(user, getContainer());
582+
listQus.deleteRelatedListData(null);
583583

584584
// then delete the list itself
585585
ListManager.get().deleteListDef(getContainer(), getListId());

list/src/org/labkey/list/model/ListQueryUpdateService.java

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.labkey.api.audit.AuditLogService;
2727
import org.labkey.api.audit.TransactionAuditProvider;
2828
import org.labkey.api.collections.CaseInsensitiveHashMap;
29+
import org.labkey.api.collections.CsvSet;
2930
import org.labkey.api.data.ColumnInfo;
3031
import org.labkey.api.data.CompareType;
3132
import org.labkey.api.data.Container;
@@ -90,6 +91,7 @@
9091
import java.util.HashMap;
9192
import java.util.List;
9293
import java.util.Map;
94+
import java.util.stream.Collectors;
9395

9496
import static org.labkey.api.util.IntegerUtils.isIntegral;
9597

@@ -759,45 +761,39 @@ protected Map<String, Object> deleteRow(User user, Container container, Map<Stri
759761
return result;
760762
}
761763

764+
record ListRow(Container container, String entityId){}
762765

763-
// Deletes attachments & discussions, and removes list documents from full-text search index.
764-
public void deleteRelatedListData(final User user, final Container container)
766+
// Delete attachments and remove documents from the full-text search index. If Container is non-null, delete only
767+
// from that container (truncate case). If container is null, delete from all containers (delete list case).
768+
public void deleteRelatedListData(final @Nullable Container container)
765769
{
766770
// Unindex all item docs and the entire list doc
767771
ListManager.get().deleteIndexedList(_list);
768772

769-
// Delete attachments and discussions associated with a list in batches of 1,000
770-
new TableSelector(getDbTable(), Collections.singleton("entityId"), SimpleFilter.createContainerFilter(container), null).forEachBatch(String.class, 1000, new ForEachBatchBlock<>()
773+
if (hasAttachmentProperties())
771774
{
772-
@Override
773-
public boolean accept(String entityId)
774-
{
775-
return null != entityId;
776-
}
775+
SimpleFilter filter = null != container ? SimpleFilter.createContainerFilter(container) : null;
777776

778-
@Override
779-
public void exec(List<String> entityIds)
777+
// Delete attachments associated with a list in batches of 1,000
778+
new TableSelector(getDbTable(), new CsvSet("Container, EntityId"), filter, null).forEachBatch(ListRow.class, 1000, new ForEachBatchBlock<>()
780779
{
781-
// delete the related list data for this block
782-
deleteRelatedListData(user, container, entityIds);
783-
}
784-
});
785-
}
786-
787-
// delete the related list data for this block of entityIds
788-
private void deleteRelatedListData(User user, Container container, List<String> entityIds)
789-
{
790-
// Build up set of entityIds and AttachmentParents
791-
List<AttachmentParent> attachmentParents = new ArrayList<>();
780+
@Override
781+
public boolean accept(ListRow row)
782+
{
783+
return null != row.entityId();
784+
}
792785

793-
// Delete Attachments
794-
if (hasAttachmentProperties())
795-
{
796-
for (String entityId : entityIds)
797-
{
798-
attachmentParents.add(new ListItemAttachmentParent(entityId, container));
799-
}
800-
AttachmentService.get().deleteAttachments(attachmentParents);
786+
@Override
787+
public void exec(List<ListRow> rows)
788+
{
789+
// delete the related attachments for this block
790+
AttachmentService.get().deleteAttachments(
791+
rows.stream()
792+
.map(row -> new ListItemAttachmentParent(row.entityId(), row.container()))
793+
.collect(Collectors.toList())
794+
);
795+
}
796+
});
801797
}
802798
}
803799

@@ -807,7 +803,7 @@ protected int truncateRows(User user, Container container) throws QueryUpdateSer
807803
int result;
808804
try (DbScope.Transaction transaction = getDbTable().getSchema().getScope().ensureTransaction())
809805
{
810-
deleteRelatedListData(user, container);
806+
deleteRelatedListData(container);
811807
result = super.truncateRows(getListUser(user, container), container);
812808
transaction.addCommitTask(() -> ListManager.get().addAuditEvent(_list, user, "Deleted " + result + " rows from list."), DbScope.CommitTaskOption.POSTCOMMIT);
813809
transaction.commit();

0 commit comments

Comments
 (0)