-
-
Notifications
You must be signed in to change notification settings - Fork 26
New React-based UI for the plugin #58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 10 commits
9a15314
e588d7c
b974e18
44c9790
d1f09b8
bb19ea8
ef95ac1
9861540
32534c5
dcf5ed8
4f30320
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| { | ||
| "name": "folder-auth-plugin", | ||
| "version": "1.0.0", | ||
| "description": "Jenkins Folder Auth plugin", | ||
| "private": true, | ||
| "main": "index.js", | ||
| "directories": { | ||
| "doc": "docs" | ||
| }, | ||
| "scripts": { | ||
| "mvnbuild": "npm run build", | ||
| "build": "webpack --mode production", | ||
| "build:dev": "webpack --mode development --watch", | ||
| "test": "echo \"Error: no test specified\" && exit 1" | ||
| }, | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "git+https://github.com/jenkinsci/folder-auth-plugin.git" | ||
| }, | ||
| "author": "", | ||
| "license": "MIT", | ||
| "bugs": { | ||
| "url": "https://github.com/jenkinsci/folder-auth-plugin/issues" | ||
| }, | ||
| "homepage": "https://github.com/jenkinsci/folder-auth-plugin#readme", | ||
| "dependencies": { | ||
| "bootstrap": "^4.5.0", | ||
| "react": "^16.13.1", | ||
| "react-bootstrap": "^1.0.1", | ||
| "react-dom": "^16.13.1" | ||
| }, | ||
| "devDependencies": { | ||
| "@babel/core": "^7.9.6", | ||
| "@babel/preset-env": "^7.9.6", | ||
| "@babel/preset-react": "^7.9.4", | ||
| "@types/react": "^16.9.35", | ||
| "@types/react-bootstrap": "^1.0.1", | ||
| "@types/react-dom": "^16.9.8", | ||
| "babel-loader": "^8.1.0", | ||
| "css-loader": "^3.5.3", | ||
| "source-map-loader": "^0.2.4", | ||
| "style-loader": "^1.2.1", | ||
| "ts-loader": "^7.0.5", | ||
| "typescript": "^3.9.3", | ||
| "webpack": "^4.43.0", | ||
| "webpack-cli": "^3.3.11" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| import * as React from 'react'; | ||
| import { FunctionComponent, useEffect, useState } from 'react'; | ||
| import Tab from 'react-bootstrap/Tab'; | ||
| import Tabs from 'react-bootstrap/Tabs'; | ||
|
|
||
| import RoleType from './model/RoleType'; | ||
|
|
||
| import './css/App.css'; | ||
| import 'bootstrap/dist/css/bootstrap.min.css'; | ||
|
|
||
| // @ts-ignore | ||
| const rootUrl = rootURL; | ||
| // @ts-ignore | ||
| const csrfCrumb = crumb.value; | ||
|
|
||
|
|
||
| const App: FunctionComponent = () => { | ||
| const [authorizationStrategy, setAuthorizationStrategy] = useState(null); | ||
|
|
||
| useEffect(() => { | ||
| (async () => { | ||
| const request = await fetch(`${rootUrl}/folder-auth/authorizationStrategy`, { | ||
| headers: { | ||
| 'Jenkins-Crumb': csrfCrumb, | ||
| }, | ||
| }); | ||
| const data = await request.json(); | ||
| setAuthorizationStrategy(data); | ||
| })().catch(err => { | ||
| throw new Error(`Unable to load authorization strategy: ${err}`); | ||
| }); | ||
| }, []); | ||
|
|
||
| return ( | ||
| <Tabs defaultActiveKey={RoleType.GLOBAL} id='role-type-tabs' variant='tabs'> | ||
| <Tab eventKey={RoleType.GLOBAL} title='Global Roles' tabClassName='tab'> | ||
| Hello world - Global Roles | ||
| </Tab> | ||
| <Tab eventKey={RoleType.FOLDER} title='Folder Roles' tabClassName='tab'> | ||
| Hello world - Folder Roles <br/> | ||
| {authorizationStrategy && JSON.stringify(authorizationStrategy)} | ||
| </Tab> | ||
| <Tab eventKey={RoleType.AGENT} title='Agent Roles' tabClassName='tab'> | ||
| Hello world - Agent Roles | ||
| </Tab> | ||
| </Tabs> | ||
| ); | ||
| } | ||
|
|
||
| export default App; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| a.tab:link, | ||
| a.tab:visited { | ||
| color: #007bff; | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hack to unset global There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, that's a known PITA, I want to fix that |
||
| text-decoration: none !important; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import * as React from 'react'; | ||
| import * as ReactDOM from 'react-dom'; | ||
|
|
||
| import App from './App'; | ||
| import { resetEnvironment } from './resetEnvironment'; | ||
|
|
||
| resetEnvironment(); | ||
| const root = document.getElementById('root'); | ||
| ReactDOM.render(<App/>, root); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| enum RoleType { | ||
| GLOBAL, | ||
| FOLDER, | ||
| AGENT, | ||
| } | ||
|
|
||
| export default RoleType; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| export function resetEnvironment(): void; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| /** | ||
| * Reset JS environment set up by prototype.js to not interfere with | ||
| * our react components. | ||
| * | ||
| * @see https://github.com/jenkinsci/jenkins/blob/75468da366c1d257a51655dcbe952d55b8aeeb9c/war/src/main/js/util/jenkins.js#L22 | ||
| */ | ||
| export function resetEnvironment() { | ||
| if (Array.prototype.toJSON) { | ||
| delete Array.prototype.toJSON; | ||
| delete Object.prototype.toJSON; | ||
| delete Hash.prototype.toJSON; | ||
| delete String.prototype.toJSON; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,9 @@ | ||
| package io.jenkins.plugins.folderauth; | ||
|
|
||
| import com.cloudbees.hudson.plugins.folder.AbstractFolder; | ||
| import com.fasterxml.jackson.core.JsonFactory; | ||
| import com.fasterxml.jackson.core.JsonGenerator; | ||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||
| import hudson.Extension; | ||
| import hudson.model.AbstractItem; | ||
| import hudson.model.Api; | ||
|
|
@@ -17,6 +20,7 @@ | |
| import hudson.security.Permission; | ||
| import hudson.security.PermissionGroup; | ||
| import io.jenkins.plugins.folderauth.misc.AgentRoleCreationRequest; | ||
| import io.jenkins.plugins.folderauth.misc.FolderBasedAuthorizationStrategyWrapper; | ||
| import io.jenkins.plugins.folderauth.misc.FolderRoleCreationRequest; | ||
| import io.jenkins.plugins.folderauth.misc.GlobalRoleCreationRequest; | ||
| import io.jenkins.plugins.folderauth.misc.PermissionWrapper; | ||
|
|
@@ -29,6 +33,7 @@ | |
| import org.kohsuke.accmod.restrictions.NoExternalUse; | ||
| import org.kohsuke.stapler.QueryParameter; | ||
| import org.kohsuke.stapler.Stapler; | ||
| import org.kohsuke.stapler.StaplerResponse; | ||
| import org.kohsuke.stapler.export.ExportedBean; | ||
| import org.kohsuke.stapler.interceptor.RequirePOST; | ||
| import org.kohsuke.stapler.json.JsonBody; | ||
|
|
@@ -39,6 +44,7 @@ | |
| import javax.annotation.ParametersAreNonnullByDefault; | ||
| import javax.servlet.ServletException; | ||
| import java.io.IOException; | ||
| import java.io.Writer; | ||
| import java.util.Arrays; | ||
| import java.util.HashSet; | ||
| import java.util.List; | ||
|
|
@@ -54,6 +60,7 @@ | |
| @ParametersAreNonnullByDefault | ||
| public class FolderAuthorizationStrategyManagementLink extends ManagementLink { | ||
| private static final Logger LOGGER = Logger.getLogger(FolderAuthorizationStrategyManagementLink.class.getName()); | ||
| private static final JsonFactory jsonFactory = new JsonFactory(); | ||
|
|
||
| @CheckForNull | ||
| @Override | ||
|
|
@@ -413,6 +420,7 @@ public void doRemoveSidFromFolderRole(@QueryParameter(required = true) String ro | |
| FolderAuthorizationStrategyAPI.removeSidFromFolderRole(sid, roleName); | ||
| redirect(); | ||
| } | ||
|
|
||
| /** | ||
| * Removes {@code sid} from the agent role identified by {@code roleName}. | ||
| * | ||
|
|
@@ -430,4 +438,23 @@ public void doRemoveSidFromAgentRole(@QueryParameter(required = true) String rol | |
| FolderAuthorizationStrategyAPI.removeSidFromAgentRole(sid, roleName); | ||
| redirect(); | ||
| } | ||
|
|
||
| @GET | ||
| @Restricted(NoExternalUse.class) | ||
| public void doAuthorizationStrategy(StaplerResponse response) throws IllegalStateException, IOException { | ||
| Jenkins jenkins = Jenkins.get(); | ||
| jenkins.checkPermission(Jenkins.ADMINISTER); | ||
| AuthorizationStrategy strategy = jenkins.getAuthorizationStrategy(); | ||
| if (!(strategy instanceof FolderBasedAuthorizationStrategy)) { | ||
| throw new IllegalStateException("Folder Based Authorization Strategy is not active."); | ||
| } | ||
| response.setContentType("application/json"); | ||
| response.setCharacterEncoding("utf-8"); | ||
| Writer writer = response.getWriter(); | ||
| FolderBasedAuthorizationStrategyWrapper wrapper = new FolderBasedAuthorizationStrategyWrapper((FolderBasedAuthorizationStrategy) strategy); | ||
| JsonGenerator generator = jsonFactory.createGenerator(writer); | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| generator.setCodec(new ObjectMapper()); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. best to cache this, you only need to create one once |
||
| generator.writeObject(wrapper); | ||
| writer.flush(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| package io.jenkins.plugins.folderauth.misc; | ||
|
|
||
| import io.jenkins.plugins.folderauth.FolderBasedAuthorizationStrategy; | ||
| import io.jenkins.plugins.folderauth.roles.AgentRole; | ||
| import io.jenkins.plugins.folderauth.roles.FolderRole; | ||
| import io.jenkins.plugins.folderauth.roles.GlobalRole; | ||
| import org.kohsuke.accmod.Restricted; | ||
| import org.kohsuke.accmod.restrictions.NoExternalUse; | ||
|
|
||
| import javax.annotation.ParametersAreNonnullByDefault; | ||
| import java.util.Set; | ||
|
|
||
| @Restricted(NoExternalUse.class) | ||
| @ParametersAreNonnullByDefault | ||
| public class FolderBasedAuthorizationStrategyWrapper { | ||
| private final Set<GlobalRole> globalRoles; | ||
| private final Set<FolderRole> folderRoles; | ||
| private final Set<AgentRole> agentRoles; | ||
|
|
||
| public FolderBasedAuthorizationStrategyWrapper(FolderBasedAuthorizationStrategy strategy) { | ||
| this.globalRoles = strategy.getGlobalRoles(); | ||
| this.folderRoles = strategy.getFolderRoles(); | ||
| this.agentRoles = strategy.getAgentRoles(); | ||
| } | ||
|
|
||
| public Set<GlobalRole> getGlobalRoles() { | ||
| return globalRoles; | ||
| } | ||
|
|
||
| public Set<FolderRole> getFolderRoles() { | ||
| return folderRoles; | ||
| } | ||
|
|
||
| public Set<AgentRole> getAgentRoles() { | ||
| return agentRoles; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also needs a version bump to at least 2.235