Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
94 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
a41d5cf
Fix text wrap, fix icon shrinking + alignment
janfaracik Dec 22, 2025
3b0cb04
Fix description wrap
janfaracik Dec 22, 2025
02d734e
Pull out Stores into own Jelly file
janfaracik Dec 22, 2025
0123378
Use symbol-business-outline plugin-ionicons-api
janfaracik Dec 22, 2025
f9b420a
Fix page description spacing
janfaracik Dec 22, 2025
18109b0
Use dialog for deleting domains
janfaracik Dec 26, 2025
8df7aa8
Use dialog for deleting credentials
janfaracik Dec 26, 2025
21f5196
Update index.jelly
janfaracik Dec 26, 2025
b8944f9
Fix ATH
timja Dec 27, 2025
4645df8
Basic new credentials dialog
timja Dec 27, 2025
0ccee24
Working
timja Dec 27, 2025
d3a89e3
Init
janfaracik Dec 29, 2025
04ff0d9
Almost working
janfaracik Dec 29, 2025
245d836
Push
janfaracik Dec 29, 2025
a44f0f3
Improve info
janfaracik Dec 29, 2025
e1858f3
Move apply sub tree
timja Dec 29, 2025
c89f3bd
Add non functional back button
janfaracik Dec 29, 2025
84650ef
Fix back button, reduce padding
janfaracik Dec 29, 2025
afdf656
Fix behavior loading
janfaracik Dec 29, 2025
fba7ea0
Ensure only writable stores are used
timja Dec 29, 2025
c642caa
Fix not all stores showing
janfaracik Dec 29, 2025
56fc28e
Fixups
timja Dec 29, 2025
38491b1
Merge branch 'new-credentials-wizard' into new-credentials-dialog
timja Dec 29, 2025
26bee01
Hide empty descriptions
timja Dec 29, 2025
17775bf
Don't repeat Add to as its in the button label
timja Dec 29, 2025
8db3ac8
Add description to overflow
timja Dec 29, 2025
b2e16f1
Remove unneeded adjunct
timja Dec 29, 2025
0fcbe92
Fix dialogs since credentials added
timja Dec 29, 2025
f2ad90f
Use dialog for domains
janfaracik Dec 30, 2025
3ef9688
Hacky sticky bottom bar
janfaracik Dec 30, 2025
04dad00
Merge branch 'master' into new-credentials-dialog
timja Dec 30, 2025
8482a8c
Fix merge
timja Dec 30, 2025
3587fb2
Fix merge 2
timja Dec 30, 2025
662de8e
Discard changes to src/main/resources/lib/credentials/store.jelly
timja Dec 30, 2025
a7c87bf
Update dialog.jelly
janfaracik Dec 31, 2025
2db0e2d
Remove unused newCredentials
timja Dec 31, 2025
2cbd2b6
Better param name
timja Dec 31, 2025
d7c1500
Update card.css
janfaracik Dec 31, 2025
eb8ec31
Return to correct view
timja Jan 1, 2026
f9f5d5d
Fix title on c:select
timja Jan 1, 2026
1336234
Mostly implement c:select
timja Jan 1, 2026
6a068f6
Mostly there with c:select
timja Jan 2, 2026
bc6cea6
Refine, fix sticky bottom app bar
janfaracik Jan 2, 2026
02ba7e3
Rename classes based on my taste in music, disable next button if no …
janfaracik Jan 2, 2026
6737634
Make c:select refill only
timja Jan 2, 2026
6608c61
WIP HtmlUnit
timja Jan 3, 2026
e6908be
Update select.js
janfaracik Jan 3, 2026
7c86666
Test now working a little more - failing on action
janfaracik Jan 3, 2026
8498ed0
Further
timja Jan 4, 2026
951099e
Some progress...
timja Jan 4, 2026
88156c8
Fix first test
timja Jan 4, 2026
e75bf3e
Simplify
timja Jan 4, 2026
763ccf2
Progress
timja Jan 4, 2026
81a7f5b
Getting there
timja Jan 4, 2026
c93c995
Update index.jelly
janfaracik Jan 4, 2026
c1510d4
Fix tests
timja Jan 4, 2026
9a64610
Tidy up notice link, add permission check for add credentials
janfaracik Jan 4, 2026
ce76505
Merge branch 'master' into new-credentials-dialog
timja Jan 4, 2026
d4fc4d8
Add empty state add for main page
timja Jan 4, 2026
658fbbf
Fix appearance of dropdowns
janfaracik Jan 5, 2026
0474461
Use jenkins-button for notice
janfaracik Jan 5, 2026
fff6ff2
Fix description wrap
janfaracik Jan 5, 2026
b126aa8
Adjust content, simplify domains
janfaracik Jan 5, 2026
28c48d6
Fix tests
janfaracik Jan 5, 2026
4352625
Fix name tests
janfaracik Jan 5, 2026
b9065c9
Remove getModifiableStoreActions
janfaracik Jan 5, 2026
14d1765
Make store icon non clickable / focusable
timja Jan 5, 2026
d409620
Fix folder credentials provider
timja Jan 5, 2026
2b9f561
Fix c:select
timja Jan 5, 2026
e33fa7b
Fix c:select overflow menu
timja Jan 5, 2026
c07aa45
Merge branch 'master' into pr/992
janfaracik Jan 7, 2026
179773d
Merge branch 'master' into new-credentials-dialog
timja Jan 10, 2026
997bfa0
Revert baseline change
timja Jan 11, 2026
4fe9e4e
Tests pass on this baseline
timja Jan 11, 2026
172b32e
Improve Behaviour handling
timja Jan 11, 2026
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
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
<changelist>999999-SNAPSHOT</changelist>
<gitHubRepo>jenkinsci/${project.artifactId}-plugin</gitHubRepo>
<!-- https://www.jenkins.io/doc/developer/plugin-development/choosing-jenkins-baseline/ -->
<jenkins.baseline>2.504</jenkins.baseline>
<jenkins.baseline>2.516</jenkins.baseline>
<jenkins.version>${jenkins.baseline}.3</jenkins.version>
<ban-junit4-imports.skip>false</ban-junit4-imports.skip>
<hpi.compatibleSinceVersion>1372</hpi.compatibleSinceVersion>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -605,4 +605,10 @@ public String toCheckUrl() {
}
}

/**
* @return the description of this credential descriptor.
*/
public String getDescription() {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,17 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import jakarta.servlet.ServletException;
import jenkins.model.Jenkins;
Expand Down Expand Up @@ -121,6 +125,26 @@
return context instanceof ModelObject mo ? mo : CredentialsDescriptor.findContextInPath(ModelObject.class);
}

/**
* @return modifiable store actions for the context provided.
*/
@Restricted(NoExternalUse.class)
public Map<String, List<CredentialsStoreAction.DomainWrapper>> getModifiableStoreActions(ModelObject context) {
return StreamSupport.stream(CredentialsProvider.lookupStores(context).spliterator(), false)
Copy link
Member Author

Choose a reason for hiding this comment

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

Something isn't right here with nested folders.

It's showing 2 global domains:

image

.filter(s -> s.hasPermission(CredentialsProvider.CREATE))
.map(CredentialsStore::getStoreAction)
.filter(Objects::nonNull)
.collect(Collectors.toMap(
CredentialsStoreAction::getDisplayName,
store -> new ArrayList<>(store.getDomains().values()),
(left, right) -> {
left.addAll(right);
return left;

Check warning on line 142 in src/main/java/com/cloudbees/plugins/credentials/CredentialsSelectHelper.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 141-142 are not covered by tests
},
LinkedHashMap::new
));
}

/**
* Returns the {@link StoreItem} instances for the current Stapler request.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -730,9 +730,12 @@
public HttpResponse doCreateCredentials(StaplerRequest2 req) throws ServletException, IOException {
getStore().checkPermission(CREATE);
String requestContentType = req.getContentType();

String acceptHeader = req.getHeader("Accept");
if (requestContentType == null) {
throw new Failure("No Content-Type header set");
}
boolean jsonResponse = acceptHeader != null && acceptHeader.contains("application/json");

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

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 738 is only partially covered, one branch is missing

if (requestContentType.startsWith("application/xml") || requestContentType.startsWith("text/xml")) {
final StringWriter out = new StringWriter();
Expand All @@ -753,7 +756,20 @@
} else {
JSONObject data = req.getSubmittedForm();
Credentials credentials = Descriptor.bindJSON(req, Credentials.class, data.getJSONObject("credentials"));
getStore().addCredentials(domain, credentials);
boolean credentialsWereAdded = getStore().addCredentials(domain, credentials);

if (jsonResponse) {

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

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 761 is only partially covered, one branch is missing
if (credentialsWereAdded) {

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

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 762 is only partially covered, one branch is missing
return HttpResponses.okJSON(new JSONObject()
.element("message", "Credentials created")
.element("notificationType", "SUCCESS"));
} else {
return HttpResponses.okJSON(new JSONObject()
.element("message", "Credentials with specified ID already exist")
// TODO: or domain does not exist at all?

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

View check run for this annotation

ci.jenkins.io / Open Tasks Scanner

TODO

NORMAL: or domain does not exist at all?
.element("notificationType", "ERROR"));

Check warning on line 770 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 767-770 are not covered by tests
}
}
return HttpResponses.redirectTo("../../domain/" + getUrlName());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,12 @@
return Messages.CertificateCredentialsImpl_DisplayName();
}

@Override
public String getDescription() {
// TODO - this is ChatGPT content

Check warning on line 237 in src/main/java/com/cloudbees/plugins/credentials/impl/CertificateCredentialsImpl.java

View check run for this annotation

ci.jenkins.io / Open Tasks Scanner

TODO

NORMAL: - this is ChatGPT content
return "Upload a file and store it securely (for example, a key file, config file, or license file).";
}

/**
* {@inheritDoc}
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,12 @@
return Messages.UsernamePasswordCredentialsImpl_DisplayName();
}

@Override
public String getDescription() {
// TODO - this is ChatGPT content

Check warning on line 139 in src/main/java/com/cloudbees/plugins/credentials/impl/UsernamePasswordCredentialsImpl.java

View check run for this annotation

ci.jenkins.io / Open Tasks Scanner

TODO

NORMAL: - this is ChatGPT content
return "Use for basic auth (username and password) to services like Git, APIs, or registries.";
}

/**
* {@inheritDoc}
*/
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ The MIT License
~
~ Copyright (c) 2011-2016, CloudBees, Inc., Stephen Connolly.
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy
~ of this software and associated documentation files (the "Software"), to deal
~ in the Software without restriction, including without limitation the rights
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ copies of the Software, and to permit persons to whom the Software is
~ furnished to do so, subject to the following conditions:
~
~ The above copyright notice and this permission notice shall be included in
~ all copies or substantial portions of the Software.
~
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
~ THE SOFTWARE.
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:l="/lib/layout" xmlns:f="/lib/form">
<st:setHeader name="X-Wizard-Title" value="${%Add Credentials}" />

<l:ajax>

<j:set var="relativePath" value="${request2.getParameter('relativePath')}"/>

<j:choose>
<j:when test="${request2.getParameter('refill') == 'true'}">
<j:set var="query" value="?refill=true&amp;relativePath=${relativePath}"/>
</j:when>
<j:otherwise>
<j:set var="query" value="?relativePath=${relativePath}"/>
</j:otherwise>
</j:choose>

<form action="${relativePath}dialog2${query}" method="GET" name="dialog">
<fieldset class="jenkins-!-display-contents">
<div>
<legend class="jenkins-form-label">${%Select a type of credential}</legend>
<div class="jenkins-choice-list">
<j:forEach var="kind" items="${it.store.credentialsDescriptors}">
<div class="jenkins-choice-list__item">
<label>
<div class="jenkins-choice-list__item__icon">
<l:icon src="${kind.iconClassName}" />
</div>
<input type="radio" name="kind" value="${kind.id}" />
<div class="jenkins-choice-list__item__label">
${kind.displayName}
</div>
<j:if test="${kind.description != null}">
<div class="jenkins-choice-list__item__description">${kind.description}</div>
</j:if>
</label>
</div>
</j:forEach>
</div>
</div>
</fieldset>

<f:bottomButtonBar borderless="true">
<button id="cr-dialog-next" class="jenkins-button jenkins-button--primary cr-bottom-button" disabled="true">${%Next}</button>
</f:bottomButtonBar>
</form>
</l:ajax>
</j:jelly>
Loading
Loading