Skip to content
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

New React-based UI for the plugin #58

Draft
wants to merge 11 commits into
base: master
Choose a base branch
from

Conversation

AbhyudayaSharma
Copy link
Member

New React-based UI for the plugin

@AbhyudayaSharma AbhyudayaSharma added the enhancement New feature or request label May 25, 2020
@AbhyudayaSharma
Copy link
Member Author

AbhyudayaSharma commented May 25, 2020

At the moment, React appears to be working from the configuration page.

image

The JavaScript for this is generated by Webpack and converted to a single minified JS file which is imported using a <script> tag.

Unlike working hours plugin, this doesn't use an iframe.

@timja
Copy link
Member

timja commented May 25, 2020

Nice! I didn't like how the working hours plugin ran separately

@AbhyudayaSharma

This comment has been minimized.

Co-authored-by: Tim Jacomb <t.jacomb@kainos.com>
@timja
Copy link
Member

timja commented May 26, 2020

cc @fqueiruga

Tabs look interesting, I wouldn't have the header colour though

@timja
Copy link
Member

timja commented May 26, 2020

Thinking aloud here, I've been considering the concept of 'Built-in roles',

or separating Roles from Scope

Consider the following roles:

  • Basic read - can see jobs and logs
  • Global Read - can see agent, job and system configuration
  • Admin
  • Builder - can trigger and cancel jobs

These are all very re-usable roles I would expect, and could be defined by the plugin by default.

A problem with the current implementation is that roles are defined at 'Global, Agent or Folder'

What if roles were defined separately and then assigned to a scope level?

Feel free to disregard as out of scope but bringing it up here because a UI re-design could be a good time to implement this

@AbhyudayaSharma
Copy link
Member Author

Tabs look interesting, I wouldn't have the header colour though

That's just the default color that comes with the library. They have a palette customization option: https://material-ui.com/customization/palette/

If there's a color theme specification for Jenkins, it can be easily added.

Consider the following roles:

  • Basic read - can see jobs and logs
  • Global Read - can see agent, job and system configuration
  • Admin
  • Builder - can trigger and cancel jobs

These are all very re-usable roles I would expect, and could be defined by the plugin by default.

An Admin role is automatically created when the plugin is initialized for the first time. All these things look like they are suitable for Global roles. Just like the admin role, we can create more roles if it helps.

@res0nance
Copy link
Contributor

Thinking aloud here, I've been considering the concept of 'Built-in roles',

or separating Roles from Scope

Consider the following roles:

* Basic read - can see jobs and logs

* Global Read - can see agent, job and system configuration

* Admin

* Builder - can trigger and cancel jobs

These are all very re-usable roles I would expect, and could be defined by the plugin by default.

A problem with the current implementation is that roles are defined at 'Global, Agent or Folder'

What if roles were defined separately and then assigned to a scope level?

Feel free to disregard as out of scope but bringing it up here because a UI re-design could be a good time to implement this

This sounds like its exactly https://docs.cloudbees.com/docs/admin-resources/latest/plugins/rbac

@timja
Copy link
Member

timja commented May 26, 2020

This sounds like its exactly https://docs.cloudbees.com/docs/admin-resources/latest/plugins/rbac

Looks very similar, although that plugin is proprietary and has a very dated looking UI 👅

@fqueiruga
Copy link

This is a great initiative. I have 2 pieces of feedback for now:

  • I would suggest using react hooks instead of class components. It's more future-proof and easier to use. I can help you out with this if you want.
  • I wouldn't use material UI. There are many examples of tabbars out there, and it's really easy to come up with styles for those. You could even copy & paste the bootstrap CSS for the tabs. The material-ui styles clash a lot with the Jenkins look & feel.

@res0nance
Copy link
Contributor

This sounds like its exactly https://docs.cloudbees.com/docs/admin-resources/latest/plugins/rbac

Looks very similar, although that plugin is proprietary and has a very dated looking UI 👅

It has one really nice feature which users who perhaps have folder level admin can grant other users permissions from that level onwards

@AbhyudayaSharma
Copy link
Member Author

AbhyudayaSharma commented May 27, 2020

Thanks @fqueiruga !

  • I would suggest using react hooks instead of class components. It's more future-proof and easier to use. I can help you out with this if you want.

Does that mean using function components along with useState()?

  • I wouldn't use material UI. There are many examples of tabbars out there, and it's really easy to come up with styles for those. You could even copy & paste the bootstrap CSS for the tabs. The material-ui styles clash a lot with the Jenkins look & feel.

Would you suggest using React Bootstrap or picking up components from npm and writing my own CSS?

@AbhyudayaSharma
Copy link
Member Author

I tried using react-bootstrap with Bootstrap 4 but the CSS conflicts with that exported by Jenkins. Will have to look for something else.

@timja
Copy link
Member

timja commented May 27, 2020

I tried using react-bootstrap with Bootstrap 4 but the CSS conflicts with that exported by Jenkins. Will have to look for something else.

there's a flag on layout.jelly you can use to not load the ~'bootstrap 3' grid
https://github.com/jenkinsci/jenkins/blob/master/core/src/main/resources/lib/layout/layout.jelly#L61

@AbhyudayaSharma
Copy link
Member Author

I tried using react-bootstrap with Bootstrap 4 but the CSS conflicts with that exported by Jenkins. Will have to look for something else.

there's a flag on layout.jelly you can use to not load the ~'bootstrap 3' grid
https://github.com/jenkinsci/jenkins/blob/master/core/src/main/resources/lib/layout/layout.jelly#L61

That looks interesting. I'll try it out. Thanks!

@@ -1,309 +1,10 @@
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:l="/lib/layout">
<l:layout permission="${app.ADMINISTER}" norefresh="true" title="${%title}">
<l:layout permission="${app.ADMINISTER}" norefresh="true" title="${%title}" nogrid="true">
Copy link
Member Author

Choose a reason for hiding this comment

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

That works (with some hacks) but the sidebar breaks when nogrid="true".

image

Would it make sense to remove the sidebar?

Copy link
Member

Choose a reason for hiding this comment

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

@uhafner thoughts? I'm guessing there's some minimal styles you can add to fix the sidebar, or the sidebar shouldn't be relying on those styles and should be fixed in Jenkins core, cc @fqueiruga

Copy link
Member

Choose a reason for hiding this comment

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

Which Jenkins version are you using? It still shows the old UI. Maybe that is the problem? I am already using the nogrid flag and the sidebar does not break.

Copy link
Member

Choose a reason for hiding this comment

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

When you use something that loads Bootstrap 4 then you also need jquery3, which leads to some additional problems. I needed to add the following fix on all my pages:
https://github.com/jenkinsci/bootstrap4-api-plugin/blob/master/src/main/webapp/js/no-prototype.js

Copy link
Member Author

@AbhyudayaSharma AbhyudayaSharma May 28, 2020

Choose a reason for hiding this comment

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

@uhafner Jenkins 2.235

When you use something that loads Bootstrap 4 then you also need jquery3, which leads to some additional problems. I needed to add the following fix on all my pages

I'm using react-bootstrap which does not need jquery. Quoting from their website:

React-Bootstrap replaces the Bootstrap JavaScript. Each component has been built from scratch as a true React component, without unneeded dependencies like jQuery.

So we only need the bootstrap css

Choose a reason for hiding this comment

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

@uhafner is there any way to load the bootstrap layout just for the CSS without loading the bootstrap JS? That would be a huge win for many plugins.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, that should be possible. Currently

<st:adjunct includes="io.jenkins.plugins.bootstrap4"/>

includes both. But you can already include it using

<link type="text/css" rel="stylesheet" href="${resURL}/plugin/bootstrap4-api/css/bootstrap.min.css"/>

The. problem is: you don't know which components require JS and which not.

Copy link
Member

Choose a reason for hiding this comment

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

@uhafner Jenkins 2.235

Maybe the problem is, that if you do not load the BS3 grid then you rather need to load the BS4 grid. So in my layouts I am using nogrid and BS4 grid. If you do not load a grid it might break things.

@@ -0,0 +1,5 @@
a.tab:link,
a.tab:visited {
color: #007bff;
Copy link
Member Author

Choose a reason for hiding this comment

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

Hack to unset global a:link and a:visited.

Choose a reason for hiding this comment

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

Yeah, that's a known PITA, I want to fix that

@AbhyudayaSharma AbhyudayaSharma requested a review from fqueiruga May 28, 2020 06:38
pom.xml Outdated
@@ -27,9 +27,11 @@
<properties>
<revision>1.3</revision>
<changelist>-SNAPSHOT</changelist>
<jenkins.version>2.164.1</jenkins.version>
<jenkins.version>2.235</jenkins.version>
Copy link
Member Author

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

@fqueiruga
Copy link

fqueiruga commented May 28, 2020

Does that mean using function components along with useState()?

Indeed.

Would you suggest using React Bootstrap or picking up components from npm and writing my own CSS?

Depends on what you're most comfortable doing. I'd vote for custom components. There is already CSS for tabs on Jenkins, and I don't see it changing. You could use those CSS classes (for tabbarFrame, tab, etc)

response.setCharacterEncoding("utf-8");
Writer writer = response.getWriter();
FolderBasedAuthorizationStrategyWrapper wrapper = new FolderBasedAuthorizationStrategyWrapper((FolderBasedAuthorizationStrategy) strategy);
JsonGenerator generator = jsonFactory.createGenerator(writer);
Copy link
Member Author

@AbhyudayaSharma AbhyudayaSharma Jun 13, 2020

Choose a reason for hiding this comment

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

net.sf.json was able to convert the AuthorizationStrategy to JSON but during the process it was generating over 1000 lines of warnings. I think using Jackson for it is a better solution. Please let me know if there is some better alternative.

pom.xml Outdated Show resolved Hide resolved
Writer writer = response.getWriter();
FolderBasedAuthorizationStrategyWrapper wrapper = new FolderBasedAuthorizationStrategyWrapper((FolderBasedAuthorizationStrategy) strategy);
JsonGenerator generator = jsonFactory.createGenerator(writer);
generator.setCodec(new ObjectMapper());
Copy link
Member

Choose a reason for hiding this comment

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

best to cache this, you only need to create one once

@vonEdfa
Copy link

vonEdfa commented Sep 11, 2021

Is it ok if I pick up work on this? I don't have much experience with Java, but I know js/ts and React pretty well and I think a new manage UI would be golden.

@AbhyudayaSharma
Copy link
Member Author

Is it ok if I pick up work on this? I don't have much experience with Java, but I know js/ts and React pretty well and I think a new manage UI would be golden.

@vonEdfa thanks a lot. This would be great! I started working on this last year but it got lost thanks to to me having way too much work. I will try to build this branch and share resources to help you get started tomorrow.

@vonEdfa
Copy link

vonEdfa commented Sep 12, 2021

I did a trial run and did get it up and running and made a small demo front-end design. I am tempted to update some dependencies on the node side, but I didn't really dare to at this point.
Nothing is pushed at this point though, but I could merge it in once the branch is ready?

Only snag I met was that the folder-auth api only provides the IDs for the enabled permissions and I think we'd need a list of all available permissions to get react to draw them (if we don't want to hard code them, that is, but I'm assuming that is risky as new permissions can be introduced by other plugins, right?). Could perhaps be done by changing the structure of the json so each role includes all permission IDs together with a bool or having a second set of data where we ask Jenkins to give us all currently available permissions for the role type we're editing right now.

@AbhyudayaSharma
Copy link
Member Author

I did a trial run and did get it up and running and made a small demo front-end design. I am tempted to update some dependencies on the node side, but I didn't really dare to at this point.

We use https://github.com/eirslett/frontend-maven-plugin which downloads and installs node and npm. Node is installed in /node. The node and npm versions are specified as properties in pom.xml. Most Jenkins plugins use plugin-pom which provides common Maven configuration. Because the file .mvn_exec_node exists, Maven and plugin-pom will ensure that npm run mvnbuild will be run before the plugin is built and Jenkins is started.

Webpack is configured to output the JS bundle to src/main/webapp/js/folder-auth-bundle.js. Jenkins plugins traditionally use Jelly, a templated XML format that generates HTML; UI resources are stored in src/main/webapp. For folder-auth, src/main/resources/io/jenkins/plugins/folderauth/FolderAuthorizationStrategyManagementLink/index.jelly is rendered on the server side by Jenkins when a user visits JENKINS_URL/folder-auth. Instead of putting the front-end logic in Jelly, we just create a div with id root and import the JS compiled by webpack using <script>. Then ReactDOM renders the new UI in #root.

Only snag I met was that the folder-auth api only provides the IDs for the enabled permissions and I think we'd need a list of all available permissions to get react to draw them.

Right. The plugin currently has no API that exposes loaded permissions and permission groups. There could be one from Jenkins core but I would need to check on that. Otherwise, we will need to build one.

if we don't want to hard code them, that is, but I'm assuming that is risky as new permissions can be introduced by other plugins, right?

Yes, permissions can be added by other plugins. Hard coding them is not really an option.

Could perhaps be done by changing the structure of the json so each role includes all permission IDs together with a bool or having a second set of data where we ask Jenkins to give us all currently available permissions for the role type we're editing right now.

The data visible inside the folder roles tab right now is just a slightly modified version of the JCasC YAML in JSON. I think that the current draft could actually be better version of #69.

Currently, there is no hot-reloading for the plugin UI. When you're running the plugin with mvn hpi:run and Jenkins is fully up and running, you can run npm build:dev in parallel to watch changes. You would need to hard refresh the folder-auth page to get the latest changes.

Another major change needed is to fix the sidebar CSS to not depend on bootstrap as described in #58 (comment). Again, we need to check with a new Jenkins version. I'll try to check that later today.

@vonEdfa Thanks a lot for working on this. I hope that this information is useful. If you have any other questions, I would be happy to help.

Copy link
Member Author

@AbhyudayaSharma AbhyudayaSharma left a comment

Choose a reason for hiding this comment

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

So all dependencies are now updated to the latest versions. Bumping up everything also fixed the broken sidebar.

image

@vonEdfa
Copy link

vonEdfa commented Sep 19, 2021

Nice! Seems I was starting it in the right way then (mvn hpi:run and npm build:dev)!

I noticed issues with my default system node versions not matching the repository's (which is quite common) and I do use version managers for node, so it it ok if I add such files to the repo? I don't know if nvm is still the most common one as I switched to asdf a while ago, but if we prefer nvm terms I think asdf supports it.

On to the look of things: I don't know if you already had anything in mind for the design to use. My initial thought was something similar to a permission matrix, but then I asked myself if we could build something more manageable? I personally don't find permissions matrices easy to use as they easily get too wide and selecting multiple bool checkboxes can be quite tedious. Let me know if I'm alone in this opinion.

Based on this, when I was playing around I took a similar approach to what Discord currently has for their server role management interface: First view is an overview listing all available roles which you'd then open to manage it's settings. My thinking is that you usually set a role and it's permissions up once and then you mostly don't need or want to edit it much (save for adding new members to it).

Here's an example of the overview list (built pre your latest commit):
image

I didn't implement the edit view in my demo, but if anyone's not familiar with Discord's edit role view it's a tab based design that looks like this:
image

@AbhyudayaSharma
Copy link
Member Author

I noticed issues with my default system node versions not matching the repository's (which is quite common) and I do use version managers for node, so it it ok if I add such files to the repo? I don't know if nvm is still the most common one as I switched to asdf a while ago, but if we prefer nvm terms I think asdf supports it.

@vonEdfa When you run mvn hpi:run, node is downloaded and installed in PROJECT_ROOT/node. To avoid conflicts with the global npm installation, we should run ./node/npm instead.

The UI prototype looks great! I was also thinking of something along these lines. I don't like the checkbox matrix either. It can get confusing when there are a lot of permissions.

Copying the discord permission modification view looks like a great idea. I would probably suggest a modal dialog instead of a taking to a new screen to avoid routing complications on the server side.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants