Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
852e45a
Use card layout for credentials tables
timja Dec 19, 2025
b633bf9
Refine card UI
janfaracik Dec 20, 2025
27276a3
Adjust colors + padding
janfaracik Dec 20, 2025
10b4636
Update domain items
janfaracik Dec 20, 2025
8d9e091
Add Configure button
janfaracik Dec 20, 2025
9302a64
Add credential count
janfaracik Dec 20, 2025
2f8f1dd
Start migrating home page
janfaracik Dec 20, 2025
e30d6ed
WIP homepage cards
janfaracik Dec 20, 2025
a06256d
Update credentials.css
janfaracik Dec 20, 2025
08fd291
Fixes
janfaracik Dec 20, 2025
600c93d
Refine further
janfaracik Dec 20, 2025
1a1805b
Update credentials.css
janfaracik Dec 20, 2025
4a94613
Add missing check
timja Dec 20, 2025
4bcb15b
Remove no longer needed brackets
timja Dec 20, 2025
b6353cd
Fix non editable stores showing actions
timja Dec 20, 2025
850049f
Add empty state support
timja Dec 20, 2025
2947831
Remove unneeded brackets around description
timja Dec 20, 2025
ce2e83f
Drop the .
janfaracik Dec 21, 2025
a5ed6be
Switch to adjunct for settings-subpage compat
timja Dec 21, 2025
4d4c975
Initial credentials implementation of experimental views
timja Dec 14, 2025
9b78fe1
Add to system store
timja Dec 15, 2025
a13bf61
More
timja Dec 15, 2025
e8b22c4
More progress
timja Dec 15, 2025
4e0655f
Should be all the system pages
timja Dec 16, 2025
37bd9b2
Mostly fix it up
timja Dec 19, 2025
9297ea1
Drop job page rework change
timja Dec 21, 2025
6ded96c
Address Jan feedback
timja Dec 21, 2025
df4a321
Update incremental
timja Dec 21, 2025
b9347b6
Update bom
timja Dec 21, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,9 @@
<changelist>999999-SNAPSHOT</changelist>
<gitHubRepo>jenkinsci/${project.artifactId}-plugin</gitHubRepo>
<!-- https://www.jenkins.io/doc/developer/plugin-development/choosing-jenkins-baseline/ -->
<jenkins.baseline>2.479</jenkins.baseline>
<jenkins.version>${jenkins.baseline}.1</jenkins.version>
<jenkins.baseline>2.528</jenkins.baseline>
<!-- TODO https://github.com/jenkinsci/jenkins/pull/25959 -->
<jenkins.version>2.543-rc37824.9e78b_3809343</jenkins.version>
<hpi.compatibleSinceVersion>1372</hpi.compatibleSinceVersion>
</properties>

Expand All @@ -91,7 +92,7 @@
<dependency>
<groupId>io.jenkins.tools.bom</groupId>
<artifactId>bom-${jenkins.baseline}.x</artifactId>
<version>3482.vc10d4f6da_28a_</version>
<version>5804.v80587a_38d937</version>
<scope>import</scope>
<type>pom</type>
</dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@
import com.cloudbees.plugins.credentials.domains.Domain;
import com.cloudbees.plugins.credentials.domains.DomainSpecification;
import com.cloudbees.plugins.credentials.impl.BaseStandardCredentials;
import com.cloudbees.plugins.credentials.links.DeleteCredentialsLink;
import com.cloudbees.plugins.credentials.links.DeleteDomainLink;
import com.cloudbees.plugins.credentials.links.MoveCredentialsLink;
import com.cloudbees.plugins.credentials.links.NewCredentialsLink;
import com.cloudbees.plugins.credentials.links.NewDomainLink;
import com.cloudbees.plugins.credentials.links.UpdateCredentialsLink;
import com.cloudbees.plugins.credentials.links.UpdateDomainLink;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
Expand Down Expand Up @@ -86,6 +93,7 @@
import org.apache.commons.lang3.StringUtils;
import org.jenkins.ui.icon.IconSpec;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.DoNotUse;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.HttpResponse;
Expand Down Expand Up @@ -575,77 +583,97 @@
getACL().checkPermission(permission);
}

@Restricted(DoNotUse.class) // jelly
public NewDomainLink getNewDomainLink() {
return new NewDomainLink();
}

/**
* {@inheritDoc}
*/
@Override
public boolean hasPermission(@NonNull Permission permission) {
return getACL().hasPermission(permission);
}

/**
* A wrapper object to bind and expose {@link Domain} instances into the web UI.
*/
@ExportedBean
public static class DomainWrapper extends AbstractDescribableImpl<DomainWrapper> implements
ModelObjectWithContextMenu, ModelObjectWithChildren, AccessControlled {

/**
* The {@link CredentialsStoreAction} that we belong to.
*/
private final CredentialsStoreAction parent;
/**
* The {@link Domain} that we are exposing.
*/
private final Domain domain;

/**
* Our constructor.
*
* @param parent our parent action.
* @param domain the domain we are wrapping.
*/
public DomainWrapper(CredentialsStoreAction parent, Domain domain) {
this.parent = parent;
this.domain = domain;
}

/**
* Expose a Jenkins {@link Api}.
*
* @return the {@link Api}.
*/
public Api getApi() {
return new Api(this);
}

/**
* Expose the backing {@link CredentialsStore}.
*
* @return the backing {@link CredentialsStore}.
*/
public CredentialsStore getStore() {
return getParent().getStore();
}

/**
* Expose the backing {@link Domain}.
*
* @return the backing {@link Domain}.
*/
public Domain getDomain() {
return domain;
}

/**
* Expose the parent {@link CredentialsStoreAction}.
*
* @return the parent {@link CredentialsStoreAction}.
*/
public CredentialsStoreAction getParent() {
return parent;
}

@Restricted(DoNotUse.class) // jelly
public UpdateDomainLink getUpdateDomainLink() {
return new UpdateDomainLink();
}

@Restricted(DoNotUse.class) // jelly
public DeleteDomainLink getDeleteDomainLink() {
return new DeleteDomainLink();

Check warning on line 669 in src/main/java/com/cloudbees/plugins/credentials/CredentialsStoreAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 588-669 are not covered by tests
}

@Restricted(DoNotUse.class) // jelly
public NewCredentialsLink getNewCredentialsLink() {
return new NewCredentialsLink();
}

/**
* Return the URL name.
*
Expand Down Expand Up @@ -1158,6 +1186,22 @@
return new Api(this);
}

@Restricted(DoNotUse.class) // jelly
public UpdateCredentialsLink getUpdateLink() {
return new UpdateCredentialsLink();
}

@Restricted(DoNotUse.class) // jelly
public DeleteCredentialsLink getDeleteLink() {
return new DeleteCredentialsLink();
}

@Restricted(DoNotUse.class) // jelly
public MoveCredentialsLink getMoveLink() {
return new MoveCredentialsLink();

Check warning on line 1201 in src/main/java/com/cloudbees/plugins/credentials/CredentialsStoreAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 1196-1201 are not covered by tests
}


/**
* Gets the display name of the {@link Credentials}.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
@Restricted(NoExternalUse.class)
public class ManageCredentialsConfiguration extends ManagementLink {

public String getCategoryName() {
return "SECURITY";
@NonNull
@Override
public Category getCategory() {
return Category.SECURITY;

Check warning on line 22 in src/main/java/com/cloudbees/plugins/credentials/ManageCredentialsConfiguration.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 22 is not covered by tests
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@
import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.Extension;
import hudson.ExtensionList;
import hudson.model.Action;
import hudson.model.Api;
import hudson.model.Item;
import hudson.model.ItemGroup;
import hudson.model.ManagementLink;
import hudson.model.ModelObject;
import hudson.model.RootAction;
import hudson.model.TopLevelItem;
Expand All @@ -59,6 +61,7 @@
import jenkins.model.TransientActionFactory;
import org.jenkins.ui.icon.IconSpec;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.DoNotUse;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.StaplerRequest2;
import org.kohsuke.stapler.StaplerResponse2;
Expand Down Expand Up @@ -239,280 +242,290 @@
return false;
}

@Restricted(DoNotUse.class) // for jelly
public ManagementLink getManagementLink() {
return ExtensionList.lookupSingleton(ManageCredentialsConfiguration.class);
}

/**
* Administrator's view credentials from 'Manage Jenkins'.
* @param accessControlled an access controlled object.
* @return whether the action should be visible or not if the user is an administrator.
*/
private boolean isVisibleForAdministrator(AccessControlled accessControlled) {
return accessControlled instanceof Jenkins && accessControlled.hasPermission(Jenkins.ADMINISTER);
}

/**
* Expose a Jenkins {@link Api}.
*
* @return the {@link Api}.
*/
public Api getApi() {
return new Api(this);
}

/**
* Returns the credential entries.
*
* @return the credential entries.
*/
public List<TableEntry> getTableEntries() {
List<TableEntry> result = new ArrayList<>();
Set<String> ids = new HashSet<>();
for (CredentialsStore p : CredentialsProvider.lookupStores(context)) {
if (p.hasPermission(CredentialsProvider.VIEW)) {
for (Domain domain : p.getDomains()) {
for (Credentials c : p.getCredentials(domain)) {
CredentialsScope scope = c.getScope();
if (scope != null && !scope.isVisible(context)) {
continue;
}
boolean masked;
if (c instanceof IdCredentials) {
String id = ((IdCredentials) c).getId();
masked = ids.contains(id);
ids.add(id);
} else {
masked = false;
}
result.add(new TableEntry(p.getProvider(), p, domain, c, masked));
}
}
}
}
return result;
}

/**
* {@inheritDoc}
*/
@Override
public String getIconClassName() {
return isVisible()
? "symbol-credentials plugin-credentials"
: null;
}

/**
* Returns the full name of this action.
*
* @return the full name of this action.
*/
public final String getFullName() {
String n = getContextFullName();
if (n.length() == 0) {
return getUrlName();
} else {
return n + '/' + getUrlName();
}
}

/**
* Returns the full name of the {@link #getContext()}.
*
* @return the full name of the {@link #getContext()}.
*/
public String getContextFullName() {
String n;
if (context instanceof Item) {
n = ((Item) context).getFullName();
} else if (context instanceof ItemGroup) {
n = ((ItemGroup) context).getFullName();
} else if (context instanceof User) {
n = "user/" + ((User) context).getId();
} else {
n = "";
}
return n;
}

/**
* Returns the full display name of this action.
*
* @return the full display name of this action.
*/
public final String getFullDisplayName() {
String n = getContextFullDisplayName();
if (n.length() == 0) {
return getDisplayName();
} else {
return n + " \u00BB " + getDisplayName();
}
}

/**
* Returns the full display name of the {@link #getContext()}.
*
* @return the full display name of the {@link #getContext()}.
*/
public String getContextFullDisplayName() {
String n;
if (context instanceof Item) {
n = ((Item) context).getFullDisplayName();
} else if (context instanceof Jenkins) {
n = context.getDisplayName();
} else if (context instanceof ItemGroup) {
n = ((ItemGroup) context).getFullDisplayName();
} else if (context instanceof User) {
n = Messages.CredentialsStoreAction_UserDisplayName(((User) context).getDisplayName());
} else {
n = Jenkins.get().getFullDisplayName();
}
return n;
}

/**
* {@inheritDoc}
*/
@NonNull
@Override
public ACL getACL() {
final AccessControlled accessControlled =
context instanceof AccessControlled ? (AccessControlled) context : Jenkins.get();
return new ACL() {
@Override
public boolean hasPermission2(@NonNull Authentication a, @NonNull Permission permission) {
if (accessControlled.hasPermission2(a, permission)) {
for (CredentialsStore s : getLocalStores()) {
if (s.hasPermission2(a, permission)) {
return true;
}
}
}
return false;
}
};
}

/**
* {@inheritDoc}
*/
// In the general case we would implement ModelObjectWithChildren as the child actions could be viewed as children
// but in this case we expose them in the sidebar, so they are more correctly part of the context menu.
@Override
public ContextMenu doContextMenu(StaplerRequest2 request, StaplerResponse2 response) {
ContextMenu menu = new ContextMenu();
for (CredentialsStoreAction action : getStoreActions()) {
ContextMenuIconUtils.addMenuItem(
menu,
"store",
action,
action.getContextMenu(ContextMenuIconUtils.buildUrl("store", action.getUrlName()))
);
}
return menu;
}

/**
* Add the {@link ViewCredentialsAction} to all {@link TopLevelItem} instances.
*/
@Extension(ordinal = -1000)
public static class TransientTopLevelItemActionFactoryImpl extends TransientActionFactory<TopLevelItem> {

/**
* {@inheritDoc}
*/
@Override
public Class<TopLevelItem> type() {
return TopLevelItem.class;
}

/**
* {@inheritDoc}
*/
@NonNull
@Override
public Collection<? extends Action> createFor(@NonNull TopLevelItem target) {
return Collections.singleton(new ViewCredentialsAction(target));
}
}

/**
* Add the {@link ViewCredentialsAction} to all {@link User} instances.
*/
@Extension(ordinal = -1000)
public static class TransientUserActionFactoryImpl extends TransientUserActionFactory {
/**
* {@inheritDoc}
*/
@Override
public Collection<? extends Action> createFor(User target) {
return Collections.singleton(new ViewCredentialsAction(target));
}
}

/**
* Add the {@link ViewCredentialsAction} to the {@link Jenkins} root.
*/
@Extension(ordinal = -1000)
public static class RootActionImpl extends ViewCredentialsAction implements RootAction {

/**
* Our constructor.
*/
public RootActionImpl() {
super(Jenkins.get());
}
}

/**
* Value class to simplify creating the table.
*/
public static class TableEntry implements IconSpec {
/**
* The backing {@link Credentials}.
*/
private final Credentials credentials;
/**
* The backing {@link CredentialsProvider}.
*/
private final CredentialsProvider provider;
/**
* The backing {@link CredentialsStore}.
*/
private final CredentialsStore store;
/**
* The backing {@link Domain}.
*/
private final Domain domain;
/**
* Whether this entry's ID is being masked by another entry.
*/
private final boolean masked;

/**
* Constructor.
*
* @param provider the backing {@link CredentialsProvider}.
* @param store the backing {@link CredentialsStore}.
* @param domain the backing {@link Domain}.
* @param credentials the backing {@link Credentials}.
* @param masked whether this entry is masked or not.
*/
public TableEntry(CredentialsProvider provider, CredentialsStore store,
Domain domain, Credentials credentials, boolean masked) {
this.provider = provider;
this.store = store;
this.domain = domain;
this.credentials = credentials;
this.masked = masked;
}

/**
* Returns the {@link IdCredentials#getId()} of the {@link #credentials}.
*
* @return the {@link IdCredentials#getId()} of the {@link #credentials}.
*/
public String getId() {
return credentials instanceof IdCredentials ? ((IdCredentials) credentials).getId() : null;
}

@SuppressWarnings("unused") // jelly
public boolean isEditable() {
return store.hasPermission(CredentialsProvider.UPDATE);

Check warning on line 526 in src/main/java/com/cloudbees/plugins/credentials/ViewCredentialsAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 247-526 are not covered by tests
}

/**
* Returns the {@link Credentials#getScope()} of the {@link #credentials}.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.cloudbees.plugins.credentials.links;

public class DeleteCredentialsLink {
public String getDisplayName() {
return Messages.DeleteCredentialsLink_displayName();

Check warning on line 5 in src/main/java/com/cloudbees/plugins/credentials/links/DeleteCredentialsLink.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 3-5 are not covered by tests
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.cloudbees.plugins.credentials.links;

public class DeleteDomainLink {
public String getDisplayName() {
return Messages.DeleteDomainLink_displayName();

Check warning on line 5 in src/main/java/com/cloudbees/plugins/credentials/links/DeleteDomainLink.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 3-5 are not covered by tests
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.cloudbees.plugins.credentials.links;

public class MoveCredentialsLink {
public String getDisplayName() {
return Messages.MoveCredentialsLink_displayName();

Check warning on line 5 in src/main/java/com/cloudbees/plugins/credentials/links/MoveCredentialsLink.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 3-5 are not covered by tests
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.cloudbees.plugins.credentials.links;

public class NewCredentialsLink {
public String getDisplayName() {
return Messages.NewCredentialsLink_displayName();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.cloudbees.plugins.credentials.links;

public class NewDomainLink {
public String getDisplayName() {
return Messages.NewDomainLink_displayName();

Check warning on line 5 in src/main/java/com/cloudbees/plugins/credentials/links/NewDomainLink.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 3-5 are not covered by tests
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.cloudbees.plugins.credentials.links;

public class UpdateCredentialsLink {
public String getDisplayName() {
return Messages.UpdateCredentialsLink_displayName();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.cloudbees.plugins.credentials.links;

public class UpdateDomainLink {
public String getDisplayName() {
return Messages.UpdateDomainLink_displayName();

Check warning on line 5 in src/main/java/com/cloudbees/plugins/credentials/links/UpdateDomainLink.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 3-5 are not covered by tests
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,33 @@
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt">
<l:layout title="${%Delete credentials}" permission="${it.domain.parent.DELETE}">
<st:include page="sidepanel.jelly" />
<l:main-panel>
<h1>${%Delete credentials}</h1>
<form method="post" action="doDelete">
<p>${%confirm(it.displayName,it.typeName)}</p>
<div>
<f:submit value="${%Yes}"/>
</div>
</form>
</l:main-panel>
</l:layout>
<j:jelly xmlns:j="jelly:core" xmlns:d="jelly:define" xmlns:local="local" xmlns:l="/lib/layout"
xmlns:f="/lib/form">

<d:taglib uri="local">
<d:tag name="contents">
<form method="post" action="doDelete">
<p>${%confirm(it.displayName,it.typeName)}</p>
<div>
<f:submit value="${%Yes}" clazz="jenkins-!-destructive-color"/>
</div>
</form>
</d:tag>
</d:taglib>

<j:choose>
<j:when test="${it.store.context == app}">
<l:settings-subpage managementLink="${it.deleteLink}" includeBreadcrumb="true"
noDefer="true" permission="${it.domain.parent.DELETE}">

<local:contents/>
</l:settings-subpage>
</j:when>
<j:otherwise>
<l:layout type="one-column" title="${it.displayName}" permission="${it.domain.parent.DELETE}">
<l:main-panel>
<l:app-bar title="${it.deleteLink.displayName}"/>
<local:contents/>
</l:main-panel>
</l:layout>
</j:otherwise>
</j:choose>
</j:jelly>
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,17 @@
Index page
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:l="/lib/layout" xmlns:t="/lib/hudson">
<l:layout title="${it.fullDisplayName}" permission="${it.domain.parent.VIEW}">
<st:include page="sidepanel.jelly"/>
<l:main-panel>
<h1>${it.displayName}</h1>
<div>
<j:out value="${it.description!=null ? app.markupFormatter.translate(it.description) : ''}" />
</div>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:l="/lib/layout" xmlns:t="/lib/hudson"
xmlns:d="jelly:define" xmlns:local="local">

<d:taglib uri="local">
<d:tag name="contents">
<j:if test="${it.description != null}">
<div class="jenkins-page-description">
<j:out value="${app.markupFormatter.translate(it.description)}"/>
</div>
</j:if>

<h2 id="usage">${%Usage}</h2>
<j:choose>
<j:when test="${it.isFingerprintEnabled()}">
Expand All @@ -45,14 +48,18 @@
<p id="usage-missing">
${%This credential has not been recorded as used anywhere.}
<br/>
<small><em>${%usageTrackingImperfect}</em></small>
<small>
<em>${%usageTrackingImperfect}</em>
</small>
</p>
</j:when>
<j:otherwise>
<p id="usage-present">
${%This credential has been recorded as used in the following places}:
<br/>
<small><em>${%usageTrackingImperfect}</em></small>
<small>
<em>${%usageTrackingImperfect}</em>
</small>
</p>
<table class="fingerprint-summary">
<j:forEach var="j" items="${jobs}">
Expand Down Expand Up @@ -85,6 +92,41 @@
<p class="warning">${%fingerprintDisabledWarning(app.rootUrl)}</p>
</j:otherwise>
</j:choose>
</l:main-panel>
</l:layout>

</d:tag>
</d:taglib>

<j:set var="header">
<l:view>
<l:app-bar title="${it.displayName}">
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not the best for long display names with sidepanel:

image

It just gets truncated with no way to view the full name

cc @janfaracik

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assume that would be a core fix, but I can get a temp fix in this plugin if wanted?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better to fix in core as its just using standard controls.

We can possibly also fix by not using the display name on that page and using the ID or description.
The display name field contains duplicated information for a lot of credential types e.g. description...

<l:hasPermission permission="${it.domain.parent.UPDATE}">
<a class="jenkins-button jenkins-button--primary" href="update">${%Update}</a>
</l:hasPermission>
<l:hasPermission permission="${it.domain.parent.DELETE}">
<a class="jenkins-button jenkins-!-destructive-color" href="delete">${%Delete}</a>
</l:hasPermission>
<l:hasPermission permission="${it.domain.parent.DELETE}">
<a class="jenkins-button" href="move">${%Move}</a>
</l:hasPermission>
</l:app-bar>
</l:view>
</j:set>

<j:choose>
<j:when test="${it.store.context == app}">
<l:settings-subpage header="${header}"
noDefer="true" permission="${it.domain.parent.VIEW}">

<local:contents/>
</l:settings-subpage>
</j:when>
<j:otherwise>
<l:layout type="one-column" title="${it.fullDisplayName}" permission="${it.domain.parent.VIEW}">
<l:main-panel>
<j:out value="${header}"/>
<local:contents/>
</l:main-panel>
</l:layout>
</j:otherwise>
</j:choose>
</j:jelly>
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt">
<l:layout title="${%Move credentials}" permission="${it.domain.parent.DELETE}">
<st:include page="sidepanel.jelly" />
<l:main-panel>
<h1>${%Move credentials}</h1>
<j:jelly xmlns:j="jelly:core" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:local="local"
xmlns:f="/lib/form">
<d:taglib uri="local">
<d:tag name="contents">
<form method="post" action="doMove">
<p>${%blurb(it.displayName,it.typeName)}</p>
<div class="jenkins-select form-group">
Expand All @@ -26,6 +25,24 @@
</div>
<f:submit value="${%Move}"/>
</form>
</l:main-panel>
</l:layout>

</d:tag>
</d:taglib>

<j:choose>
<j:when test="${it.store.context == app}">
<l:settings-subpage managementLink="${it.moveLink}" includeBreadcrumb="true"
noDefer="true" permission="${it.domain.parent.DELETE}">
<local:contents/>
</l:settings-subpage>
</j:when>
<j:otherwise>
<l:layout type="one-column" title="${it.moveLink.displayName}" permission="${it.domain.parent.DELETE}">
<l:main-panel>
<l:app-bar title="${it.moveLink.displayName}" />
<local:contents/>
</l:main-panel>
</l:layout>
</j:otherwise>
</j:choose>
</j:jelly>
Loading
Loading