Skip to content

Commit 9d0cbe8

Browse files
committed
Merge remote-tracking branch 'origin/develop' into fb_workflowStorageActions
2 parents 3441f90 + 5727364 commit 9d0cbe8

27 files changed

Lines changed: 1128 additions & 173 deletions

File tree

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/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

api/src/org/labkey/api/module/ModuleLoader.java

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -580,19 +580,6 @@ private void doInit(Execution execution) throws ServletException
580580
throw new IllegalStateException("Core module was not first or could not find the Core module. Ensure that Tomcat user can create directories under the <LABKEY_HOME>/modules directory.");
581581
setProjectRoot(coreModule);
582582

583-
for (Module module : modules)
584-
{
585-
module.registerFilters(_servletContext);
586-
}
587-
for (Module module : modules)
588-
{
589-
module.registerServlets(_servletContext);
590-
}
591-
for (Module module : modules)
592-
{
593-
module.registerFinalServlets(_servletContext);
594-
}
595-
596583
// Do this after we've checked to see if we can find the core module. See issue 22797.
597584
verifyProductionModeMatchesBuild();
598585

@@ -790,12 +777,34 @@ public void addStaticWarnings(@NotNull Warnings warnings, boolean showAllWarning
790777
if (!modulesRequiringUpgrade.isEmpty() || !additionalSchemasRequiringUpgrade.isEmpty())
791778
setUpgradeState(UpgradeState.UpgradeRequired);
792779

793-
// Don't accept any requests if we're bootstrapping empty schemas or migrating from SQL Server
780+
// Don't accept any requests if we're bootstrapping empty schemas or doing a database migration
794781
if (!shouldInsertData())
795782
execution = Execution.Synchronous;
796783

797784
startNonCoreUpgradeAndStartup(execution, lockFile);
798785

786+
// Register filters and servlets at the last minute, just before Tomcat starts. At this point, the list of
787+
// modules is final. We've had one case where the CSP filter was getting initialized before the core module
788+
// was initialized, GitHub Issue 1008. We have no idea how that happened, but registering late won't hurt.
789+
790+
_log.info("Registering filters");
791+
792+
for (Module module : _modules)
793+
{
794+
module.registerFilters(_servletContext);
795+
}
796+
797+
_log.info("Registering servlets");
798+
799+
for (Module module : _modules)
800+
{
801+
module.registerServlets(_servletContext);
802+
}
803+
for (Module module : _modules)
804+
{
805+
module.registerFinalServlets(_servletContext);
806+
}
807+
799808
_log.info("LabKey Server startup is complete; {}", execution.getLogMessage());
800809
}
801810

api/src/org/labkey/api/util/DOM.java

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,54 @@ public enum Attribute
362362
action,
363363
align,
364364
alt,
365+
aria_activedescendant,
366+
aria_atomic,
367+
aria_autocomplete,
368+
aria_busy,
369+
aria_checked,
370+
aria_colcount,
371+
aria_colindex,
372+
aria_colspan,
373+
aria_controls,
374+
aria_current,
375+
aria_describedby,
376+
aria_details,
377+
aria_disabled,
378+
aria_dropeffect,
379+
aria_errormessage,
380+
aria_expanded,
381+
aria_flowto,
382+
aria_grabbed,
383+
aria_haspopup,
384+
aria_hidden,
385+
aria_invalid,
386+
aria_keyshortcuts,
387+
aria_label,
388+
aria_labelledby,
389+
aria_level,
390+
aria_live,
391+
aria_modal,
392+
aria_multiline,
393+
aria_multiselectable,
394+
aria_orientation,
395+
aria_owns,
396+
aria_placeholder,
397+
aria_posinset,
398+
aria_pressed,
399+
aria_readonly,
400+
aria_relevant,
401+
aria_required,
402+
aria_roledescription,
403+
aria_rowcount,
404+
aria_rowindex,
405+
aria_rowspan,
406+
aria_selected,
407+
aria_setsize,
408+
aria_sort,
409+
aria_valuemax,
410+
aria_valuemin,
411+
aria_valuenow,
412+
aria_valuetext,
365413
async,
366414
autocomplete,
367415
autofocus,
@@ -579,7 +627,6 @@ public _Attributes data(boolean condition, String datakey, Object value)
579627
}
580628
return this;
581629
}
582-
583630
public _Attributes cl(String...names)
584631
{
585632
if (null != names)
@@ -900,7 +947,7 @@ private static Appendable appendAttribute(Appendable html, Attribute key, Object
900947
if (null==value)
901948
return html;
902949
html.append(" ");
903-
html.append(key.name());
950+
html.append(key.name().replace('_', '-'));
904951
html.append("=\"");
905952
// NOTE it is somewhat unusual to pass in a Renderable, but it is possible that we
906953
// want to render HTML into an attribute. We still need to re-encode the value before trying to wrap with "".

0 commit comments

Comments
 (0)