Skip to content

Commit

Permalink
Merge pull request #3 from parabuzzle/reactify
Browse files Browse the repository at this point in the history
Use react single page app for browsing registry
  • Loading branch information
parabuzzle committed May 15, 2016
2 parents cb3a66e + b64247e commit 88f6402
Show file tree
Hide file tree
Showing 44 changed files with 841 additions and 187 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
.env
node_modules
bower
public/bundle.js
5 changes: 1 addition & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ FROM niche/ruby-base:0.1
MAINTAINER Mike Heijmans <parabuzzle@gmail.com>

# Add env variables
ENV PORT 4567
ENV PORT 80
ENV REGISTRY_HOST localhost
ENV REGISTRY_PORT=5000
ENV REGISTRY_PROTO=https
Expand All @@ -25,8 +25,5 @@ WORKDIR $APP_HOME
# Add the app
ADD . $APP_HOME

# Expose needed ports
EXPOSE 4567

# Run the app
CMD bundle exec foreman start
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@ gem 'httparty'
gem 'pry'

gem 'memoist'

gem "sinatra-cross_origin", "~> 0.3.1"
4 changes: 3 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ GEM
rack (~> 1.4)
rack-protection (~> 1.4)
tilt (>= 1.3, < 3)
sinatra-cross_origin (0.3.2)
slim (3.0.6)
temple (~> 0.7.3)
tilt (>= 1.3.3, < 2.1)
Expand Down Expand Up @@ -56,9 +57,10 @@ DEPENDENCIES
rack (~> 1.6.0)
rake
sinatra
sinatra-cross_origin (~> 0.3.1)
slim
thin
unicorn

BUNDLED WITH
1.10.6
1.11.2
20 changes: 13 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
# CraneOperator
Just as crane operators can see where all the containers are in the shipyard, CraneOp gives you a simple web interface for browsing around a Docker Registry running version 2.0+
Just as crane operators can see where all the containers that are in the shipyard, CraneOp gives you a simple web interface for browsing around a Docker Registry running version 2.0+

[![Circle CI](https://circleci.com/gh/parabuzzle/craneoperator.svg?style=svg)](https://circleci.com/gh/parabuzzle/craneoperator)

![screenshots/demo.gif](screenshots/demo.gif)

## Why Crane Operator?

When you run your own internal docker registry, it can be challenging to find out what has been saved there. I wanted to create a simple and lightweight frontend for browsing my registry. Most solutions that exist are built for registry v1 and don't work with the newer registry v2. (to be honest, its hard enough to even get registry v2 working... browsing it shouldn't be)

## How do I run it?

```
docker run -d -p 4567:4567 parabuzzle/craneoperator:latest
docker run -d -p 80:80 parabuzzle/craneoperator:latest
```

## Customizing the Crane
## How do I configure it?

```
docker run -d \
-p 4567:4567 \
-p 80:80 \
-e REGISTRY_HOST=registry.yourdomain.com \
-e REGISTRY_PORT=443 \
-e REGISTRY_PROTO=https \
-e REGISTRY_SSL_VERIFY=false \
parabuzzle/craneoperator:latest
```


![https://raw.githubusercontent.com/parabuzzle/craneoperator/master/screenshots/image_info.png](https://raw.githubusercontent.com/parabuzzle/craneoperator/master/screenshots/image_info.png)
![screenshots/Crane_Operator.jpg](screenshots/Crane_Operator.jpg)
3 changes: 3 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ task :push => :tag do
end

task :build do
sh "npm install"
sh "npm install webpack"
sh "node_modules/webpack/bin/webpack.js"
sh "docker build -t parabuzzle/craneoperator:latest ."
end

Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.0
2.0
1 change: 1 addition & 0 deletions apiserver.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
apiserver.rb
8 changes: 8 additions & 0 deletions app/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from 'react';
import ReactDOM from 'react-dom';
import RepoBrowser from './components/RepoBrowser'

ReactDOM.render(
<RepoBrowser />,
document.getElementById('app')
);
52 changes: 52 additions & 0 deletions app/components/RepoBrowser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React from 'react';
import Footer from './sections/Footer';
import Header from './sections/Header';
import Repos from './Repos';
import Tags from './Tags';
import TagInfo from './TagInfo';

class RepoBrowser extends React.Component {
constructor(props){
super(props);
this.state = {
repo: undefined,
tag: undefined,
getinfo: false
}
}

handleSetTag(name){
this.setState({
tag: name,
getinfo: true
})
}

handleSetRepo(name){
this.setState({
getinfo: false,
repo: name
})
}

render(){
return(
<div className="main-container">
<Header />
<div className="container">
<div className="col-sm-3">
<Repos repo={this.state.repo} setRepo={(name) => this.handleSetRepo(name)}/>
</div>
<div className="col-sm-3">
<Tags repo={this.state.repo} setTag={(name) => this.handleSetTag(name)}/>
</div>
<div className="col-sm-6 col-left-border">
<TagInfo tag={this.state.tag} repo={this.state.repo} getinfo={this.state.getinfo}/>
</div>
</div>
<Footer />
</div>
)};
}

export default RepoBrowser;
15 changes: 15 additions & 0 deletions app/components/Repos.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';
import List from './Repos/List';

class Repos extends React.Component {
render(){
return(
<div>
<h3>Repos</h3>
<List setRepo={this.props.setRepo}/>
</div>
)
}
}

export default Repos;
69 changes: 69 additions & 0 deletions app/components/Repos/List.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React from 'react';
import axios from 'axios';
import Loader from 'react-loader';

import { Button } from 'react-bootstrap';

export default class List extends React.Component {
constructor(props){
super(props);
this.state = {
repos: [],
repo: undefined,
loaded: false,
error: undefined
}
}

init(){
this.props.setRepo;
this.getReposList()
.then(function(data){
this.setState({
repos: data,
loaded: true,
repo: this.props.repo
})
}.bind(this));
}

componentDidMount(){
this.init();
}

getReposList(){
return axios.get(`/containers.json`)
.then(function (response) {
return(response.data);
})
.catch(function (response){
this.setState({
loaded: true,
error: response
})
});
}

handleClick(name){
this.props.setRepo(name);
this.setState({
repo: name
})
}

render(){
return(
<ul className="list-group">
<Loader loaded={this.state.loaded} color="red" scale={0.75}>
{this.state.error && "Error Fetching Repos"}
{this.state.repos.map((repo, index) => (
this.state.repo === repo ?
<Button bsClass="list-group-item active" key={index} onClick={() => this.handleClick(repo)}>{repo}</Button>
:
<Button bsClass="list-group-item" key={index} onClick={() => this.handleClick(repo)}>{repo}</Button>
))}
</Loader>
</ul>
)
}
}
66 changes: 66 additions & 0 deletions app/components/Repos/RepoConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React from 'react';

export default class RepoConfig extends React.Component {

render() {
return (
<div>
<h3>Configuration</h3>
<div className="row">
<div className="col-md-3">
<b>Entrypoint:</b>
</div>
<div className="col-md-9">
{this.props.config.Entrypoint && this.props.config.Entrypoint.map((point, index) => (
<span key={index}>{point} </span>
))}
</div>
</div>
<hr/>
<div className="row">
<div className="col-md-3">
<b>CMD:</b>
</div>
<div className="col-md-9">
{this.props.config.Cmd && this.props.config.Cmd.map((cmd, index) => (
<span key={index}>{cmd} </span>
))}
</div>
</div>
<hr/>
<div className="row">
<div className="col-md-3">
<b>ENV:</b>
</div>
<div className="col-md-9">
{this.props.config.Env && this.props.config.Env.map((env, index) => (
<div key={index}>{env}</div>
))}
</div>
</div>
<hr/>
<div className="row">
<div className="col-md-3">
<b>Exposed Ports:</b>
</div>
<div className="col-md-9">
{this.props.config.ExposedPorts && Object.keys(this.props.config.ExposedPorts).map((port, index) => (
<div key={index}>{port}</div>
))}
</div>
</div>
<hr/>
<div className="row">
<div className="col-md-3">
<b>Volumes:</b>
</div>
<div className="col-md-9">
{this.props.config.Volumes && Object.keys(this.props.config.Volumes).map((volume, index) => (
<div key={index}>{volume}</div>
))}
</div>
</div>
</div>
);
}
}
48 changes: 48 additions & 0 deletions app/components/Repos/RepoInfo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from 'react';
import Time from 'react-time';
import Loader from 'react-loader';
import RepoConfig from './RepoConfig';


require('react-datetime');

export default class RepoTagInfo extends React.Component {

render(){
console.log(this.props.info)
return(
<div>
<div className="row">
<div className="col-md-3"><b>Architecture:</b></div>
<div className="col-md-7">{this.props.info.architecture}</div>
</div>
<div className="row">
<div className="col-md-3"><b>OS:</b></div>
<div className="col-md-7">{this.props.info.information && this.props.info.information.os}</div>
</div>
<div className="row">
<div className="col-md-3"><b>Created:</b></div>
<div className="col-md-7">
{this.props.info.information && <Time value={this.props.info.information.created_millis} format="MM/DD/YYYY hh:mma" />} UTC
<span className='small text-muted'> ({this.props.info.information && <Time value={this.props.info.information.created_millis} titleFormat="YYYY/MM/DD HH:mm" relative />})</span></div>
</div>
<div className="row">
<div className="col-md-3"><b>Author:</b></div>
<div className="col-md-7">{this.props.info.information && this.props.info.information.author}</div>
</div>
<div className="row">
<div className="col-md-3"><b>ID:</b></div>
<div className="col-md-7">{this.props.info.information && this.props.info.information.id}</div>
</div>
<div className="row">
<div className="col-md-3"><b>Container:</b></div>
<div className="col-md-7">{this.props.info.information && this.props.info.information.container}</div>
</div>
<div className="row">
<div className="col-md-3"><b>Docker Version:</b></div>
<div className="col-md-7">{this.props.info.information && this.props.info.information.docker_version}</div>
</div>
</div>
)
}
}
Loading

0 comments on commit 88f6402

Please # to comment.