diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 21febb49bd..59c8d9f32b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,18 +17,18 @@ Before you file an issue or a pull request, read the following tips on how to ke - [License](#license) -### Prerequisites for developing Kitematic on Mac -You will need to install: +### Prerequisites for developing Kitematic on Mac +You will need to install: - The [Docker Toolbox](https://docker.com/toolbox) - [Node.js](https://nodejs.org/) - Wine `brew install wine` (only if you want to generate a Windows release on OS X) -- The latest Xcode from the Apple App Store. +- The latest Xcode from the Apple App Store. -### Prerequisites for developing Kitematic on Windows -You will need to install: +### Prerequisites for developing Kitematic on Windows +You will need to install: - The [Docker Toolbox](https://docker.com/toolbox) - [Node.js](https://nodejs.org/) -- Open a command prompt (`cmd`) and run the command `mkdir ~/AppData/Roaming/npm` +- Open a command prompt (`cmd`) and run the command `mkdir ~/AppData/Roaming/npm` - [Visual Studio 2013 Community](https://www.visualstudio.com/en-us/products/visual-studio-community-vs.aspx) (or similar) - You do not need to install any optional packages during install. - [Python](https://www.python.org/downloads/release/python-2710/) diff --git a/src/actions/ContainerActions.js b/src/actions/ContainerActions.js index a9c2f4a61c..5470a241b6 100644 --- a/src/actions/ContainerActions.js +++ b/src/actions/ContainerActions.js @@ -35,8 +35,8 @@ class ContainerActions { this.dispatch(); } - run (name, repo, tag) { - dockerUtil.run(name, repo, tag); + run (name, repo, tag, local=false) { + dockerUtil.run(name, repo, tag, local); } active (name) { diff --git a/src/actions/ImageActions.js b/src/actions/ImageActions.js new file mode 100644 index 0000000000..fe91c7d9b9 --- /dev/null +++ b/src/actions/ImageActions.js @@ -0,0 +1,16 @@ +import alt from '../alt'; +import dockerUtil from '../utils/DockerUtil'; + +class ImageActions { + + all () { + this.dispatch({}); + dockerUtil.refresh(); + } + + destroy (image) { + dockerUtil.removeImage(image); + } +} + +export default alt.createActions(ImageActions); diff --git a/src/actions/ImageServerActions.js b/src/actions/ImageServerActions.js new file mode 100644 index 0000000000..e5c49e7bbd --- /dev/null +++ b/src/actions/ImageServerActions.js @@ -0,0 +1,14 @@ +import alt from '../alt'; + +class ImageServerActions { + constructor () { + this.generateActions( + 'added', + 'updated', + 'destroyed', + 'error' + ); + } +} + +export default alt.createActions(ImageServerActions); diff --git a/src/actions/TagActions.js b/src/actions/TagActions.js index 36ffd843e1..27e071cdd2 100644 --- a/src/actions/TagActions.js +++ b/src/actions/TagActions.js @@ -6,6 +6,10 @@ class TagActions { this.dispatch({repo}); regHubUtil.tags(repo); } + + localTags (repo, tags) { + this.dispatch({repo, tags}); + } } export default alt.createActions(TagActions); diff --git a/src/components/ImageCard.react.js b/src/components/ImageCard.react.js index fe979c9ef1..2816757695 100644 --- a/src/components/ImageCard.react.js +++ b/src/components/ImageCard.react.js @@ -5,6 +5,7 @@ import shell from 'shell'; import RetinaImage from 'react-retina-image'; import metrics from '../utils/MetricsUtil'; import containerActions from '../actions/ContainerActions'; +import imageActions from '../actions/ImageActions'; import containerStore from '../stores/ContainerStore'; import tagStore from '../stores/TagStore'; import tagActions from '../actions/TagActions'; @@ -14,8 +15,8 @@ var ImageCard = React.createClass({ mixins: [Router.Navigation], getInitialState: function () { return { - tags: [], - chosenTag: 'latest' + tags: this.props.tags || [], + chosenTag: this.props.chosenTag || 'latest' }; }, componentDidMount: function () { @@ -49,11 +50,14 @@ var ImageCard = React.createClass({ private: this.props.image.is_private, official: this.props.image.namespace === 'library', userowned: this.props.image.is_user_repo, - recommended: this.props.image.is_recommended + recommended: this.props.image.is_recommended, + local: this.props.image.is_local || false }); let name = containerStore.generateName(this.props.image.name); - let repo = this.props.image.namespace === 'library' ? this.props.image.name : this.props.image.namespace + '/' + this.props.image.name; - containerActions.run(name, repo, this.state.chosenTag); + let localImage = this.props.image.is_local || false; + let repo = (this.props.image.namespace === 'library' || this.props.image.namespace === 'local') ? this.props.image.name : this.props.image.namespace + '/' + this.props.image.name; + + containerActions.run(name, repo, this.state.chosenTag, localImage); this.transitionTo('containerHome', {name}); }, handleMenuOverlayClick: function () { @@ -67,7 +71,12 @@ var ImageCard = React.createClass({ handleTagOverlayClick: function () { let $tagOverlay = $(this.getDOMNode()).find('.tag-overlay'); $tagOverlay.fadeIn(300); - tagActions.tags(this.props.image.namespace + '/' + this.props.image.name); + let localImage = this.props.image.is_local || false; + if (localImage) { + tagActions.localTags(this.props.image.namespace + '/' + this.props.image.name, this.props.tags); + } else { + tagActions.tags(this.props.image.namespace + '/' + this.props.image.name); + } }, handleCloseTagOverlay: function () { let $menuOverlay = $(this.getDOMNode()).find('.menu-overlay'); @@ -75,6 +84,11 @@ var ImageCard = React.createClass({ var $tagOverlay = $(this.getDOMNode()).find('.tag-overlay'); $tagOverlay.fadeOut(300); }, + handleDeleteImgClick: function (image) { + if (this.state.chosenTag && !this.props.image.inUse) { + imageActions.destroy(image.RepoTags[0].split(':')[0] + ':' + this.state.chosenTag); + } + }, handleRepoClick: function () { var repoUri = 'https://hub.docker.com/'; if (this.props.image.namespace === 'library') { @@ -108,10 +122,9 @@ var ImageCard = React.createClass({ } else if(this.props.image.short_description){ description = this.props.image.short_description; } else { - description = "No description."; + description = 'No description.'; } var logoStyle = { - //backgroundImage: `linear-gradient(-180deg, ${this.props.image.gradient_start} 4%, ${this.props.image.gradient_end} 100%)` backgroundColor: this.props.image.gradient_start }; var imgsrc; @@ -150,21 +163,74 @@ var ImageCard = React.createClass({ ); } - let favCount = (this.props.image.star_count < 1000) ? numeral(this.props.image.star_count).value() : numeral(this.props.image.star_count).format('0.0a').toUpperCase(); - let pullCount = (this.props.image.pull_count < 1000) ? numeral(this.props.image.pull_count).value() : numeral(this.props.image.pull_count).format('0a').toUpperCase(); - return ( -
To delete, remove all containers
using the above image
Please select an image tag.
{tags} @@ -187,20 +253,7 @@ var ImageCard = React.createClass({ {description}