-
Notifications
You must be signed in to change notification settings - Fork 91
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
Implement listing images/containers using React JSX #3
Conversation
@martinpitt PTAL |
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.
Great work already! I reviewed roughly a third of this PR, but a lot of comments apply to several places in the code. Also, this needs to grow integration tests along with the code, to ensure it is (and stays) working (also with newer podman versions).
src/ContainerDetails.js
Outdated
class ContainerDetails extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
} |
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.
This component has no state, so it should be a functional component. (another interesting blog post). Also, it's custom to explicitly spell out the properties that you support/expect, like this:
const ContainerDetails({container}) => (
<div> ...
<dt>{ container.Created.. }</dt>
</div>
);
package.json
Outdated
"bootstrap-less": "^3.3.8", | ||
"create-react-class": "^15.6.3", | ||
"exenv": "^1.2.2", | ||
"jquery": "^3.3.1", |
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.
Please avoid introducing jQuery in new code, and particularly not with react. I don't see it actually being used here? I think this can just be dropped. Likewise, please comb the list for other unused stuff, like "exenv" -- it just unnecessarily enlarges npm install
time, and all of these dependencies introduce maintenance. react-create-class
also sounds like dead weight -- use proper ES6 classes instead.
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.
I changed it. But dockerUI uses Id.
src/ContainerDetails.js
Outdated
return ( | ||
<div className='listing-ct-body'> | ||
<dl> | ||
<dt>{_("Id")} </dt> <dd>{ container.ID }</dd> |
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.
Please avoid the extra whitespace in the element. Perhaps they are not rendered, but it might still cause some layout issues. Also please be consistent with putting the <dd>
s into a new line.
"Id" should be spelled "ID", as it's an acronym.
src/Containers.js
Outdated
class Containers extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
console.log(props.containers); |
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.
Debugging leftover.
src/Containers.js
Outdated
if (state.Status) | ||
return state.Status; | ||
if (state.Running) | ||
return "running"; |
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.
Needs i18n (_("")
wrapper)
src/Containers.js
Outdated
} | ||
|
||
render() { | ||
console.log(this.props.onlyShowRunning); |
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.
debugging leftover
src/Containers.js
Outdated
//TODO | ||
let emptyCaption = _("No containers"); | ||
|
||
let filtered = this.props.containers.filter((container)=>{ |
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.
Missing spaces around operator, and unnecessary braces around a single argument.
src/Containers.js
Outdated
let filtered = this.props.containers.filter((container)=>{ | ||
if (this.props.onlyShowRunning && !container.State.Running) | ||
return false; | ||
return true; |
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.
write this more succinctly as `filter(container => (!this.props.onlyShowRunning || container.State.Running));
src/ContainersRunImageModal.js
Outdated
constructor(props) { | ||
super(props); | ||
|
||
} |
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.
Unnecessary if you don't do anything other than calling the parent. Also, this component can be functional, it doesn't have any state.
src/ContainersRunImageModal.js
Outdated
return ( | ||
<Modal | ||
isOpen={this.props.show} | ||
> |
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.
IMHO this looks really ugly - just write it as one line, it's short enough.
I fixed the review issues you found. @martinpitt PTAL |
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.
Thanks, nice progress! Still a bunch of small issues, and two large ones:
-
This still does not update the tests, they fail now. It's acceptable to not cover all the new functionality with tests right away, this can happen in follow-up PRs (but must happen nevertheless). But they at least must succeed.
-
Please use consistent indentation. 8 spaces seems rather excessive and makes a lot of code rather "narrow". We use 4 everywhere else.
src/index.html
Outdated
<link rel="stylesheet" href="../base1/patternfly.css"> | ||
<link href="docker.css" type="text/css" rel="stylesheet" id="term-style"> |
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.
Please rename this to podman.css (same for the file) to avoid confusion.
src/Containers.js
Outdated
"", | ||
// TODO: MemoryUsage, MemoryLimit | ||
"", | ||
state, |
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.
This should still be i18n'ed, but I'm happy for this to be a // TODO: i18n
comment for now.
src/Containers.js
Outdated
let columns = [ | ||
{ name: container.Name, header: true }, | ||
image, | ||
container.Config.Entrypoint === "" ? container.Config.Cmd.join(" ") : container.Config.Cmd.join(""), |
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.
The second join is still confusing, please add a comment what it does.
webpack.config.js
Outdated
{ | ||
test: /\.es6$/, | ||
loader: "babel-loader" | ||
}, |
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.
These all already exist above and are duplicated.
src/ContainerDetails.js
Outdated
@@ -0,0 +1,33 @@ | |||
import React from 'react'; |
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.
This file must be named .jsx, to apply correct babel and eslint rules. It's not "classic" non-ES6 JavaScript. Same applies to the other *.js files in this PR.
webpack.config.js
Outdated
{ | ||
test: /views\/[^\/]+\.html$/, | ||
loader: "ng-cache?prefix=[dir]" | ||
}, |
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.
This looks unrelated and should be a separate commit with a proper justification.
webpack.config.js
Outdated
}, | ||
{ | ||
test: /[\/]angular\.js$/, | ||
loader: "exports?angular" | ||
} | ||
] |
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.
There's no angular in this code, and you should stay really far away from introducing it :-) Please drop this.
src/ContainerHeader.js
Outdated
import cockpit from 'cockpit'; | ||
import Select from '../lib/cockpit-components-select.jsx'; | ||
|
||
const _ = cockpit.gettext;cockpit.gett |
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.
There's some junk here
src/ContainerHeader.js
Outdated
filterText: '' | ||
}; | ||
|
||
this.filterChanged = this.filterChanged.bind(this); |
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.
This doesn't seem necessary, you only call this from a method that already has a correct this
.
src/ContainerHeader.js
Outdated
|
||
handleFilterChange (value) { | ||
this.setState({ filter: value }); | ||
this.props.onChange(value); |
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.
Should check if the onChange
property is actually defined. Or declare it a mandatory property.
f3c2e83
to
d529ae8
Compare
@martinpitt I have made the changes you requested. Sorry, I am still getting used to the github workflow. |
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.
Some more issues inline, also you still didn't update the tests. Please make sure that make check
works.
But this PR really isn't working like that, so some things about development and review in general:
-
Don't add more and more new features (like the vuln scanning) to this single PR. It is already immensely large and really difficult to review, and at this rate it gets worse faster than it gets better.
-
You should do lots of small PRs, each of which implement one self-contained new feature or bug fix, together with comprehensive integration tests. A small PR is much easier and faster to review and understand, both by you and the reviewer.
For example, you could do one PR to move the varlink interface into a new utils.es6, one PR to add a container list, one PR to add an image list, etc.
- Finish one PR and get it landed before working on new stuff. If you don't finish the old one, nothing will land at the end.
This isn't meant to be offensive or discouraging, I just want to guide you how you can actually land changes effectively.
Thanks! FYI, I'll be on PTO the next two weeks, so please ask in #cockpit for reviewers.
src/Containers.jsx
Outdated
container.Config.Entrypoint === "" ? container.Config.Cmd.join(" ") : container.Config.Cmd.join(""), | ||
container.State.Running ? utils.format_cpu_percent(container.HostConfig.CpuPercent) : "", | ||
containerStats ? utils.format_memory_and_limit(containerStats.mem_usage, containerStats.mem_limit) : "", | ||
state, |
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.
As I said, please add a TODO: i18n
comment here.
src/Containers.jsx
Outdated
let columns = [ | ||
{ name: container.Name, header: true }, | ||
image, | ||
//Concat the cmd directly if has entrypoint, otherwise join cmd with space. |
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.
This doesn't really explain anything, it's just translating JS to English. It's quite clear what the code does. It's also clear why we want to join the container entrypoint command array with spaces. But it needs to be explained why the config command does not get spaces without an entry point. It's still a comand array, isn't it? How does that not look broken?
webpack.config.js
Outdated
{ | ||
test: /\.jsx$/, | ||
loader: "babel-loader" | ||
}, |
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.
This is still duplicated from above. You shouldn't/can't have to loaders for .js and .jsx. You need to merge the strict and babel loader into one list, if you really need both.
{ | ||
test: /\.less$/, | ||
loader: extract.extract("css-loader?sourceMap&minimize=!less-loader?sourceMap&compress=false") | ||
}, |
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.
Why do you need the css and less handlers? For some node dependencies? That usually isn't required in your own project (but I could miss something there)
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.
Because I used cockpit-components-listing.jsx from docker UI, it import the less
src/ContainerHeader.jsx
Outdated
filter: 'running', | ||
filterText: '' | ||
}; | ||
this.filterChanged = this.filterChanged.bind(this); |
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.
Already from the previous review, but it now got hidden; This doesn't seem necessary, you only call this from a method that already has a correct this
.
src/Images.jsx
Outdated
this.handleCancelImageDeleteModal = this.handleCancelImageDeleteModal.bind(this); | ||
this.handleRemoveImage = this.handleRemoveImage.bind(this); | ||
this.handleCancelImageRemoveError = this.handleCancelImageRemoveError.bind(this); | ||
this.handleForceRemoveImage = this.handleForceRemoveImage.bind(this); |
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.
Please don't just wholesale bind all of your methods. This is only required if you use them as handler attributes in a HTML tag, like <button onClick={this.myHandler}
. As soon as you call it from one of the class'es methods or even from an arrow method (<button onClick={() => this.myHandler(...)
) you don't need this bind. E. g. at least renderRow()
and navigateToImage()
are unnecessary binds.
(This is a nitpicking of course, and doesn't really hurt - but it makes the code longer, and it's good to understand what this actually does).
src/Images.jsx
Outdated
} | ||
|
||
showRunImageDialog(e) { | ||
e.preventDefault() |
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.
preventDefault is a rather large axe, especially if it's unconditional for all events. This always needs a comment that justifies why it's necessary.
src/app.jsx
Outdated
@@ -21,110 +21,149 @@ | |||
import cockpit from 'cockpit'; | |||
import React from 'react'; | |||
import './app.scss'; |
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.
Either drop src/app.scss and this import, or move your podman.scss definitions in there. Don't keep two, that's confusing.
src/index.html
Outdated
@@ -23,6 +23,7 @@ | |||
<meta name="viewport" content="width=device-width, initial-scale=1"> | |||
|
|||
<link rel="stylesheet" href="../base1/patternfly.css"> | |||
<link href="podman.css" type="text/css" rel="stylesheet" id="term-style"> |
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.
Please don't do this. Nothing in the .html file itself should need the CSS, only the App JSX object. Import it in src/app.jsx like it currently imports app.scss (see above, there should only be one file).
47d8f40
to
bb15d9c
Compare
@martinpitt @garrett @andreasn @stefwalter @larskarlitski I've added some tests. PTAL. |
@QiWang19: Hey! I saw your request in IRC. I'm replying here to let you know you were heard. 😉 If you have design questions or some HTML and/or CSS questions, I'm happy to help. I even know JavaScript pretty OK. However, I don't know React/JSX... outside of modifying it to make HTML/CSS/JS a bit better. As your PR looks like a lot of JSX, I probably can't help at this time in this particular PR. That all said, I've been a fan of Podman (and everything related, like Buildah) for a while and I'm really looking forward to having Podman support in Cockpit! |
Back from PTO, having a look. Tests on master started failing with
as podman apparently renamed the socket. This will also break this PR. |
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.
After PR #4 to fix the socket path this now needs a rebase, and applying the socket renaming to your branch. I also found a few small issues which I am fixing myself.
The test also fails:
File "test/check-application", line 40, in testBasic
b.wait_visible('#containers-containers tr:contains("busybox:latest")')
File "test/common/testlib.py", line 285, in wait_visible
return self.wait_js_func('ph_is_visible', selector)
File "test/common/testlib.py", line 270, in wait_js_func
self.wait_js_cond("%s(%s)" % (func, ','.join(map(jsquote, args))))
File "test/common/testlib.py", line 267, in wait_js_cond
self.raise_cdp_exception("timeout\nwait_js_cond", cond, result["exceptionDetails"], trailer)
File "test/common/testlib.py", line 167, in raise_cdp_exception
raise Error("%s(%s): %s" % (func, arg, msg))
testlib.Error: timeout
wait_js_cond(ph_is_visible("#containers-containers tr:contains(\"busybox:latest\")")): #containers-containers tr:contains("busybox:latest") not found
I am going to investigate this, and then force-push your branch, to unblock this.
.gitignore
Outdated
@@ -13,3 +13,5 @@ test/common/ | |||
test/images/ | |||
*.pot | |||
POTFILES* | |||
tmp/* | |||
/src/test.jsx |
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.
This looks like a debugging leftover. Don't add such local files to .gitignore, you are going to forget about them.
test/check-application
Outdated
# create a container | ||
m.execute("podman run -d --name swamped-crate busybox sleep 1000") | ||
# m.execute("podman run -d --name swamped-crate alpine sleep 10000") |
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.
Leftover stuff, should be dropped.
test/check-application
Outdated
|
||
# FIXME: UI needs to listen to change signals and update automatically | ||
b.reload() |
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.
This reload should now be dropped as well.
test/vm.install
Outdated
@@ -15,3 +15,4 @@ fi | |||
# grab a few images to play with; tests run offline, so they cannot download images | |||
podman pull busybox | |||
podman pull docker.io/alpine | |||
# podman rm eager_murdock |
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.
Leftover.
test/check-application
Outdated
b.wait_visible('#containers-images tbody tr:contains("busybox:latest") + tr button.btn-delete') | ||
|
||
# show all containers to interact with stopped ones | ||
m.execute("podman run -d --name swamped-crate busybox sh") |
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.
This cannot work, the container will exit immediately. This is why in my initial tests I ran sleep 10000
in it.
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.
Oh, I see, it's supposed to be in the "exited" state, as you switch to "everything".
I did an initial force push to fix the conflict and make the test actually work. Note that I had to put back the |
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.
I did another force push to fix the tab damage, and a few other minor issues. Let's land this now, to unblock this.
Please do a follow-up PR with completing the tests. For example:
- Start a running container and make sure that it appears so.
- Check that container names and container commands are shown correctly. Particularly with commands that have more than one word, to cover correct spacing.
- Cover the "Commit", "Delete", and "Start" buttons in container details. The latter currently causes a crash, this needs to be fixed as well.
- Image details and deletion.
Tests succeeded, landing. Thanks! |
Signed-off-by: Qi Wang qiwan@redhat.com