Skip to content

Commit 32420b5

Browse files
committed
Merge branch 'release26.3-SNAPSHOT' into 26.3_fb_issue_936
2 parents cc65c08 + 54fb550 commit 32420b5

56 files changed

Lines changed: 2611 additions & 371 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/pull_request_template.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@
1010
<!-- list of standard tasks (remove this comment to enable)
1111
#### Tasks 📍
1212
- [ ] Manual Testing
13-
- [ ] Needs Automation
13+
- [ ] Test Automation
1414
- [ ] Verify Fix
15-
-->
15+
-->

‎announcements/src/org/labkey/announcements/announcementThread.jsp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ if (!announcementModel.getAttachments().isEmpty())
127127
{
128128
ActionURL downloadURL = AnnouncementsController.getDownloadURL(announcementModel, d.getName());
129129
%>
130-
<a href="<%=h(downloadURL)%>"><img alt="" src="<%=getWebappURL(d.getFileIcon())%>">&nbsp;<%=h(d.getName())%></a>&nbsp;<%
130+
<%=d.renderDownloadLink(downloadURL)%>&nbsp;<%
131131
} %>
132132
</div></td>
133133
</tr><%
@@ -210,7 +210,7 @@ if (!announcementModel.getResponses().isEmpty())
210210
{
211211
ActionURL downloadURL = AnnouncementsController.getDownloadURL(r, rd.getName());
212212
%>
213-
<a href="<%=h(downloadURL)%>"><img alt="" src="<%=getWebappURL(rd.getFileIcon())%>">&nbsp;<%=h(rd.getName())%></a>&nbsp;<%
213+
<%=rd.renderDownloadLink(downloadURL)%>&nbsp;<%
214214
}
215215
%>
216216
</div></td>

‎announcements/src/org/labkey/announcements/announcementWebPartSimple.jsp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ for (AnnouncementModel a : bean.announcementModels)
195195
for (Attachment d : a.getAttachments())
196196
{
197197
ActionURL downloadURL = AnnouncementsController.getDownloadURL(a, d.getName());
198-
%><a href="<%=h(downloadURL)%>"><img src="<%=getWebappURL(d.getFileIcon())%>">&nbsp;<%=h(d.getName())%></a>&nbsp;<%
198+
%><%=d.renderDownloadLink(downloadURL)%>&nbsp;<%
199199
}
200200
%></td></tr><%
201201
}

‎announcements/src/org/labkey/announcements/announcementWebPartWithExpandos.jsp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ for (AnnouncementModel a : bean.announcementModels)
217217
for (Attachment d : a.getAttachments())
218218
{
219219
ActionURL downloadURL = AnnouncementsController.getDownloadURL(a, d.getName());
220-
%><a href="<%=h(downloadURL)%>"><img src="<%=getWebappURL(d.getFileIcon())%>">&nbsp;<%=h(d.getName())%></a>&nbsp;<%
220+
%><%=d.renderDownloadLink(downloadURL)%>&nbsp;<%
221221
}
222222
%></td></tr><%
223223
}

‎announcements/src/org/labkey/announcements/update.jsp‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,6 @@ if (settings.hasExpires())
140140
<tbody>
141141
<%
142142
int x = -1;
143-
String id;
144143
for (Attachment att : ann.getAttachments())
145144
{
146145
x++;

‎api/src/org/labkey/api/assay/AbstractAssayProvider.java‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@
124124
import javax.script.ScriptEngine;
125125
import java.io.File;
126126
import java.io.IOException;
127+
import java.io.InputStream;
127128
import java.net.URI;
128129
import java.net.URL;
129130
import java.sql.ResultSet;
@@ -1274,9 +1275,9 @@ public Pair<ValidationException, Pair<String, String>> setValidationAndAnalysisS
12741275
if (!(engine instanceof ExternalScriptEngine && ((ExternalScriptEngine) engine).isBinary(scriptFile)))
12751276
{
12761277
String scriptText;
1277-
try
1278+
try (InputStream is = scriptFile.openInputStream())
12781279
{
1279-
scriptText = IOUtils.toString(scriptFile.openInputStream(), StringUtilsLabKey.DEFAULT_CHARSET);
1280+
scriptText = IOUtils.toString(is, StringUtilsLabKey.DEFAULT_CHARSET);
12801281
}
12811282
catch (IOException e)
12821283
{

‎api/src/org/labkey/api/attachments/Attachment.java‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,13 @@
2121
import org.labkey.api.security.User;
2222
import org.labkey.api.security.UserManager;
2323
import org.labkey.api.services.ServiceRegistry;
24+
import org.labkey.api.util.DOM;
25+
import org.labkey.api.util.HtmlString;
2426
import org.labkey.api.util.MemTracker;
2527
import org.labkey.api.util.MimeMap;
28+
import org.labkey.api.util.PageFlowUtil;
2629
import org.labkey.api.util.Path;
30+
import org.labkey.api.view.ActionURL;
2731
import org.labkey.api.view.ViewServlet;
2832
import org.labkey.api.webdav.WebdavResolver;
2933

@@ -350,4 +354,29 @@ public void setDocumentSize(int documentSize)
350354
{
351355
_documentSize = documentSize;
352356
}
357+
358+
/**
359+
* Returns an HtmlString rendering a download link: an anchor containing a file type icon and the filename.
360+
* The icon is marked aria-hidden since it is decorative; the link text serves as the accessible name.
361+
*/
362+
public HtmlString renderDownloadLink(ActionURL downloadURL)
363+
{
364+
return renderDownloadLink(downloadURL, getName());
365+
}
366+
367+
/**
368+
* Returns an HtmlString rendering a download link: an anchor containing a file type icon and custom link text.
369+
* Use this overload when the visible link label differs from the filename (e.g. "Study Protocol Document").
370+
* The icon is marked aria-hidden since it is decorative; linkText serves as the accessible name.
371+
*/
372+
public HtmlString renderDownloadLink(ActionURL downloadURL, String linkText)
373+
{
374+
return DOM.createHtmlFragment(
375+
DOM.A(DOM.at(DOM.Attribute.href, downloadURL.toString()),
376+
DOM.IMG(DOM.at(DOM.Attribute.alt, "").at(DOM.Attribute.src, PageFlowUtil.staticResourceUrl(getFileIcon()))),
377+
HtmlString.NBSP,
378+
linkText
379+
)
380+
);
381+
}
353382
}

‎api/src/org/labkey/api/exp/list/ListService.java‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ static void setInstance(ListService ls)
5151
boolean hasLists(Container container, boolean includeProjectAndShared);
5252
ListDefinition createList(Container container, String name, ListDefinition.KeyType keyType);
5353
ListDefinition createList(Container container, String name, ListDefinition.KeyType keyType, @Nullable TemplateInfo templateInfo, @Nullable ListDefinition.Category category);
54+
void deleteLists(Container container, User user, @Nullable String auditUserComment);
5455
@Nullable ListDefinition getList(Container container, int listId);
5556
@Nullable ListDefinition getList(Container container, String name);
5657
@Nullable ListDefinition getList(Container container, String name, boolean includeProjectAndShared);

‎api/src/org/labkey/api/inventory/InventoryService.java‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ enum InventoryStatusColumn
5252
StorageColSort,
5353
StorageComment,
5454
StorageLocation,
55+
StorageTerminalLocation,
5556
StorageRow,
5657
StorageRowSort,
5758
StoragePositionNumber,

‎api/src/org/labkey/api/mcp/McpService.java‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@
2929
/// ### MCP Development Guide
3030
/// `McpService` lets you expose functionality over the MCP protocol (only simple http for now). This allows external
3131
/// chat sessions to pull information from LabKey Server. Exposed functionality is also made available to chat sessions
32-
/// hosted by LabKey (see `AbstractAgentAction``).
32+
/// hosted by LabKey (see `AbstractAgentAction`).
3333
///
3434
/// ### Adding a new MCP class
3535
/// 1. Create a new class that implements `McpImpl` (see below) in the appropriate module
36-
/// 2. Register that class in your module `init()` method: `McpService.get().register(new MyMcp())`
36+
/// 2. Register that class in your module's `startup()` method: `McpService.get().register(new MyMcp())`
3737
/// 3. Add tools and resources
3838
///
3939
/// ### Adding a new MCP tool
@@ -44,13 +44,13 @@
4444
/// permission annotation is required, otherwise your tool will not be registered.**
4545
/// 4. Add `ToolContext` as the first parameter to the method
4646
/// 5. Add additional required or optional parameters to the method signature, as needed. Note that "required" is the
47-
/// default. Again here, the parameter descriptions are very important. Provide examples.
47+
/// default. Again here, the parameter descriptions are very important. Provide examples of parameter values.
4848
/// 6. Use the helper method `getContext(ToolContext)` to retrieve the current `Container` and `User`
4949
/// 7. Use the helper method `getUser(ToolContext)` in the rare cases where you need just a `User`
5050
/// 8. Perform additional permissions checking (beyond what the annotations offer), where appropriate
5151
/// 9. Filter all results to the current container, of course
5252
/// 10. For any error conditions, throw exceptions with detailed information. These will get translated into appropriate
53-
/// failure responses and the LLM client will attempt to correct the problem.
53+
/// failure responses and the LLM client will attempt to correct any problems (hopefully).
5454
/// 11. For success cases, return a String with a message or JSON content, for example, `JSONObject.toString()`. Spring
5555
/// has some limited ability to convert other objects into JSON strings, but we haven't experimented with that. See
5656
/// `DefaultToolCallResultConverter` and the ability to provide a custom result converter via the `@Tool` annotation.
@@ -126,6 +126,7 @@ static void setInstance(McpService service)
126126

127127
boolean isReady();
128128

129+
// Register MCPs in Module.startup()
129130
default void register(McpImpl mcp)
130131
{
131132
try

0 commit comments

Comments
 (0)