├── .babelrc
├── .circleci
└── config.yml
├── .eslintrc
├── .github
└── ISSUE_TEMPLATE.md
├── .gitignore
├── .travis.yml
├── CONTRIBUTING.md
├── Gruntfile.js
├── LICENSE
├── MAINTAINERS
├── Makefile
├── README.md
├── ROADMAP.md
├── __integration__
├── HubUtil-integration.js
└── RegHubUtil-integration.js
├── __mocks__
├── app.js
├── electron.js
└── remote.js
├── __tests__
└── Util-test.js
├── docs
└── README.md
├── electron-builder.json
├── fonts
├── kitematic.eot
├── kitematic.svg
├── kitematic.ttf
└── kitematic.woff
├── images
├── boot2docker.png
├── boot2docker@2x.png
├── button-restart.png
├── button-restart@2x.png
├── button-start.png
├── button-start@2x.png
├── button-stop.png
├── button-stop@2x.png
├── button-terminal.png
├── button-terminal@2x.png
├── button-view.png
├── button-view@2x.png
├── cartoon-docker-compose.png
├── cartoon-docker-compose@2x.png
├── cartoon-docker-machine.png
├── cartoon-docker-machine@2x.png
├── cartoon-docker.png
├── cartoon-docker@2x.png
├── cartoon-kitematic.png
├── cartoon-kitematic@2x.png
├── close.png
├── close@2x.png
├── connect-art.png
├── connect-art@2x.png
├── connect-to-hub.png
├── connect-to-hub@2x.png
├── container-white.png
├── container-white@2x.png
├── container.png
├── container@2x.png
├── downloading-arrow-white.png
├── downloading-arrow-white@2x.png
├── downloading-arrow.png
├── downloading-arrow@2x.png
├── downloading-white.png
├── downloading-white@2x.png
├── downloading.png
├── downloading@2x.png
├── error.png
├── error@2x.png
├── feedback.png
├── feedback@2x.png
├── folder.png
├── folder@2x.png
├── fullscreen.png
├── fullscreen@2x.png
├── fullscreenclose.png
├── fullscreenclose@2x.png
├── inspection.png
├── inspection@2x.png
├── install-error.png
├── install-error@2x.png
├── loading-white.png
├── loading-white@2x.png
├── loading.png
├── loading@2x.png
├── logo-active.png
├── logo-active@2x.png
├── logo.png
├── logo@2x.png
├── minimize.png
├── minimize@2x.png
├── official.png
├── official@2x.png
├── paused.png
├── paused@2x.png
├── preferences.png
├── preferences@2x.png
├── private.png
├── private@2x.png
├── restarting.png
├── restarting@2x.png
├── running-white.png
├── running-white@2x.png
├── running.png
├── running@2x.png
├── runningwave-white.png
├── runningwave-white@2x.png
├── runningwave.png
├── runningwave@2x.png
├── still-white.png
├── still-white@2x.png
├── stopped-white.png
├── stopped-white@2x.png
├── stopped.png
├── stopped@2x.png
├── user.png
├── user@2x.png
├── userdropdown.png
├── userdropdown@2x.png
├── virtualbox.png
├── virtualbox@2x.png
├── wavy-white.png
├── wavy-white@2x.png
├── whaleicon.png
├── whaleicon@2x.png
├── windows-close.png
├── windows-close@2x.png
├── windows-fullscreen.png
├── windows-fullscreen@2x.png
├── windows-fullscreenclose.png
├── windows-fullscreenclose@2x.png
├── windows-minimize.png
└── windows-minimize@2x.png
├── index.html
├── jest-integration.json
├── jest-unit.json
├── package-lock.json
├── package.json
├── resources
├── MSYS_LICENSE
├── OPENSSH_LICENSE
├── msys-1.0.dll
├── msys-crypto-1.0.0.dll
├── msys-minires.dll
├── msys-z.dll
├── ssh.exe
└── terminal
├── src
├── actions
│ ├── AccountActions.js
│ ├── AccountServerActions.js
│ ├── ContainerActions.js
│ ├── ContainerServerActions.js
│ ├── ImageActions.js
│ ├── ImageServerActions.js
│ ├── NetworkActions.js
│ ├── RepositoryActions.js
│ ├── RepositoryServerActions.js
│ ├── SetupActions.js
│ ├── SetupServerActions.js
│ ├── TagActions.js
│ └── TagServerActions.js
├── alt.js
├── app.js
├── browser.js
├── components
│ ├── About.react.js
│ ├── Account.react.js
│ ├── AccountLogin.react.js
│ ├── AccountSignup.react.js
│ ├── ContainerDetails.react.js
│ ├── ContainerDetailsHeader.react.js
│ ├── ContainerDetailsSubheader.react.js
│ ├── ContainerHome.react.js
│ ├── ContainerHomeFolders.react.js
│ ├── ContainerHomeIpPortsPreview.react.js
│ ├── ContainerHomeLogs.react.js
│ ├── ContainerList.react.js
│ ├── ContainerListItem.react.js
│ ├── ContainerProgress.react.js
│ ├── ContainerSettings.react.js
│ ├── ContainerSettingsAdvanced.react.js
│ ├── ContainerSettingsGeneral.react.js
│ ├── ContainerSettingsNetwork.react.js
│ ├── ContainerSettingsPorts.react.js
│ ├── ContainerSettingsVolumes.react.js
│ ├── Containers.react.js
│ ├── Header.react.js
│ ├── ImageCard.react.js
│ ├── Loading.react.js
│ ├── NewContainerSearch.react.js
│ ├── Preferences.react.js
│ ├── Radial.react.js
│ └── Setup.react.js
├── main.js
├── main.js.map
├── main.ts
├── menutemplate.js
├── router.js
├── routes.js
├── stores
│ ├── AccountStore.js
│ ├── ContainerStore.js
│ ├── ImageStore.js
│ ├── NetworkStore.js
│ ├── RepositoryStore.js
│ ├── SetupStore.js
│ └── TagStore.js
└── utils
│ ├── ContainerUtil.js
│ ├── DockerMachineUtil.js
│ ├── DockerUtil.js
│ ├── HubUtil.js
│ ├── MetricsUtil.js
│ ├── RegHubUtil.js
│ ├── SetupUtil.js
│ ├── Util.js
│ ├── VirtualBoxUtil.js
│ └── WebUtil.js
├── styles
├── animation.less
├── bootstrap
│ ├── alerts.less
│ ├── badges.less
│ ├── bootstrap.less
│ ├── breadcrumbs.less
│ ├── button-groups.less
│ ├── buttons.less
│ ├── carousel.less
│ ├── close.less
│ ├── code.less
│ ├── component-animations.less
│ ├── dropdowns.less
│ ├── forms.less
│ ├── glyphicons.less
│ ├── grid.less
│ ├── input-groups.less
│ ├── jumbotron.less
│ ├── labels.less
│ ├── list-group.less
│ ├── media.less
│ ├── mixins.less
│ ├── mixins
│ │ ├── alerts.less
│ │ ├── background-variant.less
│ │ ├── border-radius.less
│ │ ├── buttons.less
│ │ ├── center-block.less
│ │ ├── clearfix.less
│ │ ├── forms.less
│ │ ├── gradients.less
│ │ ├── grid-framework.less
│ │ ├── grid.less
│ │ ├── hide-text.less
│ │ ├── image.less
│ │ ├── labels.less
│ │ ├── list-group.less
│ │ ├── nav-divider.less
│ │ ├── nav-vertical-align.less
│ │ ├── opacity.less
│ │ ├── pagination.less
│ │ ├── panels.less
│ │ ├── progress-bar.less
│ │ ├── reset-filter.less
│ │ ├── resize.less
│ │ ├── responsive-visibility.less
│ │ ├── size.less
│ │ ├── tab-focus.less
│ │ ├── table-row.less
│ │ ├── text-emphasis.less
│ │ ├── text-overflow.less
│ │ └── vendor-prefixes.less
│ ├── modals.less
│ ├── navbar.less
│ ├── navs.less
│ ├── normalize.less
│ ├── pager.less
│ ├── pagination.less
│ ├── panels.less
│ ├── popovers.less
│ ├── print.less
│ ├── progress-bars.less
│ ├── responsive-embed.less
│ ├── responsive-utilities.less
│ ├── scaffolding.less
│ ├── tables.less
│ ├── theme.less
│ ├── thumbnails.less
│ ├── tooltip.less
│ ├── type.less
│ ├── utilities.less
│ ├── variables.less
│ └── wells.less
├── container-home.less
├── container-logs.less
├── container-progress.less
├── container-settings.less
├── header.less
├── icons.less
├── layout.less
├── left-panel.less
├── loading.less
├── main.less
├── mixins.less
├── new-container.less
├── preferences.less
├── radial.less
├── retina.less
├── right-panel.less
├── setup.less
├── spinner.less
├── theme.less
└── variables.less
├── tsconfig.json
├── tslint.json
└── util
├── Info.plist
├── VirtualBox_Uninstall.tool
├── kitematic.icns
├── kitematic.ico
├── kitematic.png
├── loading.gif
├── prepare.js
├── reset
├── reset.ps1
├── setup.ico
└── testenv.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "env",
4 | "react"
5 | ],
6 | "plugins": [
7 | "transform-runtime",
8 | "transform-async-to-generator"
9 | ]
10 | }
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | jobs:
3 | test:
4 | macos:
5 | xcode: "9.0"
6 |
7 | steps:
8 | - run:
9 | name: Install node@10
10 | command: |
11 | set +e
12 | touch $BASH_ENV
13 | curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
14 | echo 'export NVM_DIR="$HOME/.nvm"' >> $BASH_ENV
15 | echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> $BASH_ENV
16 | echo 'nvm install 10' >> $BASH_ENV
17 | echo 'nvm alias default 10' >> $BASH_ENV
18 | - run:
19 | name: Install wine
20 | command: brew install wine
21 | - checkout
22 | - run: npm install
23 | - run: npm test
24 | - run: npm run release:mac
25 | - run: npm run release:windows
26 |
27 | workflows:
28 | version: 2
29 | test:
30 | jobs:
31 | - test
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | root: true
2 |
3 | plugins:
4 | - react
5 |
6 | parserOptions:
7 | ecmaVersion: 2017
8 | sourceType: module
9 |
10 | env:
11 | node: true
12 | es6: true
13 | browser: true
14 | jest: true
15 |
16 | extends:
17 | "eslint:recommended"
18 |
19 | rules:
20 | indent: [2, 2, {SwitchCase: 1}]
21 | brace-style: [2, "1tbs"]
22 | camelcase: [2, { properties: "never" }]
23 | callback-return: [2, ["cb", "callback", "next"]]
24 | comma-spacing: 2
25 | comma-style: [2, "last"]
26 | consistent-return: 2
27 | curly: [2, "all"]
28 | default-case: 2
29 | dot-notation: [2, { allowKeywords: true }]
30 | eol-last: 2
31 | eqeqeq: 2
32 | func-style: [2, "declaration"]
33 | guard-for-in: 2
34 | key-spacing: [2, { beforeColon: false, afterColon: true }]
35 | new-cap: 2
36 | new-parens: 2
37 | no-alert: 2
38 | no-array-constructor: 2
39 | no-caller: 2
40 | no-console: 0
41 | no-delete-var: 2
42 | no-empty-label: 2
43 | no-eval: 2
44 | no-extend-native: 2
45 | no-extra-bind: 2
46 | no-fallthrough: 2
47 | no-floating-decimal: 2
48 | no-implied-eval: 2
49 | no-invalid-this: 2
50 | no-iterator: 2
51 | no-label-var: 2
52 | no-labels: 2
53 | no-lone-blocks: 2
54 | no-loop-func: 2
55 | no-mixed-spaces-and-tabs: [2, false]
56 | no-multi-spaces: 2
57 | no-multi-str: 2
58 | no-native-reassign: 2
59 | no-nested-ternary: 2
60 | no-new: 2
61 | no-new-func: 2
62 | no-new-object: 2
63 | no-new-wrappers: 2
64 | no-octal: 2
65 | no-octal-escape: 2
66 | no-process-exit: 2
67 | no-proto: 2
68 | no-redeclare: 2
69 | no-return-assign: 2
70 | no-script-url: 2
71 | no-sequences: 2
72 | no-shadow: 2
73 | no-shadow-restricted-names: 2
74 | no-spaced-func: 2
75 | no-trailing-spaces: 2
76 | no-undef: 2
77 | no-undef-init: 2
78 | no-undefined: 2
79 | no-underscore-dangle: 2
80 | no-unused-expressions: 2
81 | no-unused-vars: [2, {vars: "all", args: "after-used"}]
82 | no-use-before-define: 2
83 | no-with: 2
84 | quotes: [2, "single"]
85 | radix: 2
86 | semi: 2
87 | semi-spacing: [2, {before: false, after: true}]
88 | space-after-keywords: [2, "always"]
89 | space-before-blocks: 2
90 | space-before-function-paren: [2, "always"]
91 | space-infix-ops: 2
92 | space-return-throw-case: 2
93 | space-unary-ops: [2, {words: true, nonwords: false}]
94 | spaced-comment: [2, "always", { exceptions: ["-"]}]
95 | strict: [2, "global"]
96 | valid-jsdoc: [2, { prefer: { "return": "returns"}}]
97 | wrap-iife: 2
98 | yoda: [2, "never"]
99 |
100 | # Previously on by default in node environment
101 | no-catch-shadow: 0
102 | no-mixed-requires: 2
103 | no-new-require: 2
104 | no-path-concat: 2
105 | global-strict: [0, "always"]
106 | handle-callback-err: [2, "err"]
107 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ### Expected behavior
2 |
3 | ### Actual behavior
4 |
5 | ### Information about the Issue
6 |
7 |
8 | ### Steps to reproduce the behavior
9 |
10 | 1. ...
11 | 2. ...
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .swp
3 | build
4 | dist
5 | dist-electron-builder/
6 | release
7 | src/**/*.js.map
8 | installer
9 | node_modules
10 | coverage
11 | npm-debug.log
12 |
13 | # Integration test environment
14 | integration
15 |
16 | # Resources
17 | resources/docker*
18 | resources/boot2docker*
19 |
20 | # Cache
21 | cache
22 |
23 | # Tests
24 | .test
25 | settings.json
26 |
27 | # IDEs
28 | .idea
29 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 |
3 | language: node_js
4 | node_js:
5 | - "8"
6 | - "10"
7 |
8 | cache:
9 | directories:
10 | - node_modules
11 |
12 | script:
13 | - npm install
14 | - npm test
15 |
16 | install: npm i
--------------------------------------------------------------------------------
/MAINTAINERS:
--------------------------------------------------------------------------------
1 | # Kitematic maintainers file
2 | #
3 | # This file describes who runs the docker/kitematic project and how.
4 | # This is a living document - if you see something out of date or missing, speak up!
5 | #
6 | # It is structured to be consumable by both humans and programs.
7 | # To extract its contents programmatically, use any TOML-compliant parser.
8 | #
9 | # This file is compiled into the MAINTAINERS file in docker/opensource.
10 | #
11 | [Org]
12 | [Org."Core maintainers"]
13 | people = [
14 | "elesant",
15 | "FrenchBen",
16 | "jeffdm",
17 | "mchiang0610",
18 | ]
19 |
20 | [people]
21 |
22 | # A reference list of all people associated with the project.
23 | # All other sections should refer to people by their canonical key
24 | # in the people section.
25 |
26 | # ADD YOURSELF HERE IN ALPHABETICAL ORDER
27 |
28 | [people.elesant]
29 | Name = "Sean Li"
30 | Email = "mail@shang.li"
31 | GitHub = "elesant"
32 |
33 | [people.FrenchBen]
34 | Name = "Ben French"
35 | Email = "frenchben@docker.com"
36 | GitHub = "FrenchBen"
37 |
38 | [people.jeffdm]
39 | Name = "Jeff Morgan"
40 | Email = "jmorgan@docker.com"
41 | GitHub = "jeffdm"
42 |
43 | [people.mchiang0610]
44 | Name = "Michael Chiang"
45 | Email = "mchiang@docker.com"
46 | GitHub = "mchiang0610"
47 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: docs docs-shell docs-build run
2 |
3 | VERSION := $(shell jq -r '.version' package.json)
4 |
5 | # TODO: clearly need to note pre-req's - OSX and node installed? - see contributing docs
6 |
7 | install:
8 | npm install
9 |
10 | run: install
11 | npm start
12 |
13 | release: install
14 | npm install electron-packager
15 | npm run release
16 | mv release/Kitematic-Mac.zip release/Kitematic-$(VERSION)-Mac.zip
17 | mv release/Kitematic-Ubuntu.zip release/Kitematic-$(VERSION)-Ubuntu.zip
18 | mv release/Kitematic-Windows.zip release/Kitematic-$(VERSION)-Windows.zip
19 |
20 | #zip:
21 | # docker container run --rm -it -w /to_zip -v $(PWD)/dist/Kitematic\ \(Beta\)-darwin-x64:/to_zip -v $(PWD)/dist:/out kramos/alpine-zip -r /out/Kitematic-$(VERSION)-Mac.zip .
22 |
23 | clean:
24 | -rm .DS_Store
25 | -rm -Rf build/
26 | -rm -Rf dist/
27 | -rm -Rf release/
28 | -rm -Rf node_modules/
29 |
30 |
31 | # Get the IP ADDRESS
32 | DOCKER_IP=$(shell python -c "import urlparse ; print urlparse.urlparse('$(DOCKER_HOST)').hostname or ''")
33 | HUGO_BASE_URL=$(shell test -z "$(DOCKER_IP)" && echo localhost || echo "$(DOCKER_IP)")
34 | HUGO_BIND_IP=0.0.0.0
35 |
36 | # import the existing docs build cmds from docker/docker
37 | DOCS_MOUNT := $(if $(DOCSDIR),-v $(CURDIR)/$(DOCSDIR):/$(DOCSDIR))
38 | DOCSPORT := 8000
39 | GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null)
40 | DOCKER_DOCS_IMAGE := kitematic-docs$(if $(GIT_BRANCH),:$(GIT_BRANCH))
41 | DOCKER_RUN_DOCS := docker run --rm -it $(DOCS_MOUNT)
42 |
43 | docs: docs-build
44 | $(DOCKER_RUN_DOCS) -p $(if $(DOCSPORT),$(DOCSPORT):)8000 "$(DOCKER_DOCS_IMAGE)" \
45 | hugo server \
46 | --port=$(DOCSPORT) --baseUrl=$(HUGO_BASE_URL) --bind=$(HUGO_BIND_IP)
47 |
48 | docs-shell: docs-build
49 | $(DOCKER_RUN_DOCS) -p $(if $(DOCSPORT),$(DOCSPORT):)8000 "$(DOCKER_DOCS_IMAGE)" bash
50 |
51 | docs-build:
52 | docker build -t "$(DOCKER_DOCS_IMAGE)" -f docs/Dockerfile .
53 |
54 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### :warning: Deprecation Notice: This project and repository is now deprecated and is no longer under active development, see [the related roadmap issue](https://github.com/docker/roadmap/issues/67). Please use [Docker Desktop](https://www.docker.com/products/docker-desktop) instead where possible.
2 |
3 | [](https://travis-ci.org/docker/kitematic)
4 |
5 |
6 | [](https://kitematic.com)
7 |
8 | Please give us feedback on the new [Docker Desktop Dashboard](https://docs.docker.com/docker-for-mac/edge-release-notes/)!
9 |
10 | In the latest Edge release of Docker Desktop we have introduced the new [Docker Desktop Dashboard](https://docs.docker.com/docker-for-mac/edge-release-notes/). As part of this, Docker is working on providing a common user experience to developers and bringing the best Kitematic features to its Desktop customers.
11 |
12 | As a result, we plan on achieving feature parity and archiving the Docker Kitematic Project during 2020. After we archive the Kitematic Project there will be no new releases of Kitematic.
13 |
14 |
15 |
16 | 
17 |
18 | Kitematic is a simple application for managing Docker containers on Mac, Linux and Windows.
19 |
20 |
21 | ## Installing Kitematic
22 |
23 | [Download the latest version](https://github.com/docker/kitematic/releases) of Kitematic via the github release page.
24 |
25 | ## Documentation
26 |
27 | Kitematic's documentation and other information can be found at [http://kitematic.com/docs](http://kitematic.com/docs).
28 |
29 | ## Security Disclosure
30 |
31 | Security is very important to us. If you have any issue regarding security, please disclose the information responsibly by sending an email to security@docker.com and not by creating a github issue.
32 |
33 |
34 | ## Archive FAQ
35 |
36 | **Why are you archiving Kitematic?**
37 | We are learning from the capabilities in Kitematic and incorporating them into a common developer User experience and benefit all Docker Desktop users.
38 |
39 | **When will this happen?**
40 | Once we have reached feature parity and provided the most important capabilities from the existing Kitematic UI. We aim to achieve this and then to archive Kitematic in 2020.
41 |
42 | **What can I do if the new UI doesn't support something I need?**
43 | Tell us! Please add requests on the Kitematic repo. We need you to tell us what features you use so we can bring them across into the new UI. We are very interested in your feedback starting with the Edge release.
44 |
45 |
46 | ## Bugs and Feature Requests
47 |
48 | Have a bug? Please first read the [Issue Guidelines](https://github.com/kitematic/kitematic/blob/master/CONTRIBUTING.md#using-the-issue-tracker) and search for existing and closed issues.
49 |
50 | If your idea is not in the new UI, [please open a new issue](https://github.com/kitematic/kitematic/issues/new).
51 |
52 |
53 | If your problem is not addressed yet, [please open a new issue](https://github.com/kitematic/kitematic/issues/new).
54 |
55 |
56 | ## Community
57 |
58 |
59 | - Ask questions on our [user forum](https://forums.docker.com/c/open-source-projects/kitematic).
60 | - Follow [@Docker on Twitter](https://twitter.com/docker).
61 |
62 | ## Uninstalling
63 |
64 | **Mac**
65 |
66 | - Remove Kitematic.app
67 | - Remove any unwanted Virtual Machines in VirtualBox
68 | ```bash
69 | # remove app data
70 | rm -rf ~/Library/Application\ Support/Kitematic
71 | ```
72 |
73 | **Windows**
74 |
75 | Open `Programs and Features` from `Control Panel`
76 |
77 | - Uninstall Kitematic
78 | - Uninstall Oracle VM VirtualBox
79 |
80 | ## Copyright and License
81 |
82 | Code released under the [Apache license](LICENSE).
83 | Images are copyrighted by [Docker, Inc](https://www.docker.com/).
84 |
--------------------------------------------------------------------------------
/ROADMAP.md:
--------------------------------------------------------------------------------
1 | ## Kitematic Roadmap
2 |
3 | **January 2015**
4 |
5 | * Automatic updates
6 | * Stability bug fixes
7 |
8 | **Februay 2015**
9 |
10 | * Docker machine support
11 | * Front-end refactor
12 | * Starting Unit tests
13 |
14 | **March 2015**
15 |
16 | * Kitematic re-design (container centric workflow)
17 | * Docker Hub pull / search for public Docker images
18 |
19 | **April 2015**
20 |
21 | * Custom URL protocol
22 |
23 | **May 2015**
24 |
25 | * Docker Hub - sign-up/sign-in
26 | * Allow users to sign-up / sign-in to Docker Hub from Kitematic.
27 | * Docker Hub - private repo view if user is logged-in to Docker Hub account
28 |
29 | **June 2015**
30 |
31 | * Microsoft Windows alpha
32 |
33 | **July 2015**
34 |
35 | * Refactor to Flux Architecture
36 | * Stability & code quality improvements
37 |
38 | **August 2015**
39 |
40 | * Make Kitematic part of the Docker Toolbox
41 | * Stability & code quality improvements
42 |
43 | **September 2015**
44 |
45 | * Better integration with new version of Docker Hub
46 | * Stability & code quality improvements
47 |
--------------------------------------------------------------------------------
/__integration__/HubUtil-integration.js:
--------------------------------------------------------------------------------
1 | jest.autoMockOff();
2 |
3 | jasmine.getEnv().defaultTimeoutInterval = 60000;
4 |
5 | let hubUtil = require('../src/utils/HubUtil');
6 | let Promise = require('bluebird');
7 |
8 | describe('HubUtil Integration Tests', () => {
9 | describe('auth', () => {
10 | pit('successfully authenticates', () => {
11 | return new Promise((resolve) => {
12 | hubUtil.auth(process.env.INTEGRATION_USER, process.env.INTEGRATION_PASSWORD, (error, response, body) => {
13 | expect(response.statusCode).toBe(200);
14 | expect(error).toBe(null);
15 |
16 | let data = JSON.parse(body);
17 | expect(data.token).toBeTruthy();
18 | resolve();
19 | });
20 | });
21 | });
22 |
23 | pit('provides a 401 if credentials are incorrect', () => {
24 | return new Promise((resolve) => {
25 | hubUtil.auth(process.env.INTEGRATION_USER, 'incorrectpassword', (error, response) => {
26 | expect(response.statusCode).toBe(401);
27 | resolve();
28 | });
29 | });
30 | });
31 | });
32 | });
33 |
--------------------------------------------------------------------------------
/__integration__/RegHubUtil-integration.js:
--------------------------------------------------------------------------------
1 | jest.autoMockOff();
2 |
3 | jasmine.getEnv().defaultTimeoutInterval = 60000;
4 |
5 | let _ = require('underscore');
6 | let regHubUtil = require('../src/utils/RegHubUtil');
7 | let hubUtil = require('../src/utils/HubUtil');
8 | let Promise = require('bluebird');
9 |
10 | describe('RegHubUtil Integration Tests', () => {
11 | describe('with login', () => {
12 | pit('lists private repos', () => {
13 | return new Promise((resolve) => {
14 | hubUtil.login(process.env.INTEGRATION_USER, process.env.INTEGRATION_PASSWORD, () => {
15 | regHubUtil.repos((error, repos) => {
16 | expect(_.findWhere(repos, {name: 'test_private', is_private: true})).toBeTruthy();
17 | resolve();
18 | });
19 | });
20 | });
21 | });
22 |
23 | pit('lists tags for a private repo', () => {
24 | return new Promise((resolve) => {
25 | hubUtil.login(process.env.INTEGRATION_USER, process.env.INTEGRATION_PASSWORD, () => {
26 | regHubUtil.tags(`${process.env.INTEGRATION_USER}/test_private`, (error, tags) => {
27 | expect(error).toBeFalsy();
28 | expect(tags.length).toEqual(1);
29 | expect(tags[0].name).toEqual('latest');
30 | resolve();
31 | });
32 | });
33 | });
34 | });
35 | });
36 |
37 | describe('public repos', () => {
38 | pit('lists repos', () => {
39 | return new Promise((resolve) => {
40 | hubUtil.login(process.env.INTEGRATION_USER, process.env.INTEGRATION_PASSWORD, () => {
41 | regHubUtil.repos((error, repos) => {
42 | expect(_.findWhere(repos, {name: 'test'})).toBeTruthy();
43 | resolve();
44 | });
45 | });
46 | });
47 | });
48 |
49 | pit('lists tags for a repo', () => {
50 | return new Promise((resolve) => {
51 | hubUtil.login(process.env.INTEGRATION_USER, process.env.INTEGRATION_PASSWORD, () => {
52 | regHubUtil.tags(`${process.env.INTEGRATION_USER}/test`, (error, tags) => {
53 | expect(error).toBeFalsy();
54 | expect(tags.length).toEqual(1);
55 | expect(tags[0].name).toEqual('latest');
56 | resolve();
57 | });
58 | });
59 | });
60 | });
61 | });
62 | });
63 |
--------------------------------------------------------------------------------
/__mocks__/app.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | require: jest.fn(),
3 | match: jest.fn(),
4 | on: jest.fn()
5 | };
6 |
--------------------------------------------------------------------------------
/__mocks__/electron.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | require: jest.fn(),
3 | match: jest.fn(),
4 | app: jest.fn(),
5 | remote: jest.fn(),
6 | dialog: jest.fn()
7 | };
8 |
--------------------------------------------------------------------------------
/__mocks__/remote.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | require: jest.fn(),
3 | match: jest.fn()
4 | };
5 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # The docs have been moved!
2 |
3 | The documentation for Kitematic has been merged into
4 | [the general documentation repo](https://github.com/docker/docker.github.io).
5 |
6 | The docs for Kitematic are now here:
7 | https://github.com/docker/docker.github.io/tree/master/kitematic
8 |
9 | As always, the docs remain open-source and we appreciate your feedback and
10 | pull requests!
11 |
--------------------------------------------------------------------------------
/electron-builder.json:
--------------------------------------------------------------------------------
1 | {
2 | "appId": "com.docker.kitematic",
3 | "asar": true,
4 | "directories": {
5 | "output": "./dist/"
6 | },
7 | "files": [
8 | {
9 | "filter": [
10 | "!./node_modules/**/*",
11 | "!./package.json"
12 | ],
13 | "from": "./build/",
14 | "to": "."
15 | },
16 | "packages.json"
17 | ],
18 | "linux": {},
19 | "mac": {
20 | "category": "public.app-category.developer-tools"
21 | },
22 | "msi": {
23 | "warningsAsErrors": false
24 | },
25 | "productName": "Kitematic",
26 | "win": {
27 | "extraResources": "./resources/**/*",
28 | "icon": "./util/kitematic.ico",
29 | "target": [
30 | {
31 | "target": "appx"
32 | },
33 | {
34 | "target": "msi"
35 | }
36 | ]
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/fonts/kitematic.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/fonts/kitematic.eot
--------------------------------------------------------------------------------
/fonts/kitematic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/fonts/kitematic.ttf
--------------------------------------------------------------------------------
/fonts/kitematic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/fonts/kitematic.woff
--------------------------------------------------------------------------------
/images/boot2docker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/boot2docker.png
--------------------------------------------------------------------------------
/images/boot2docker@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/boot2docker@2x.png
--------------------------------------------------------------------------------
/images/button-restart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/button-restart.png
--------------------------------------------------------------------------------
/images/button-restart@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/button-restart@2x.png
--------------------------------------------------------------------------------
/images/button-start.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/button-start.png
--------------------------------------------------------------------------------
/images/button-start@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/button-start@2x.png
--------------------------------------------------------------------------------
/images/button-stop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/button-stop.png
--------------------------------------------------------------------------------
/images/button-stop@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/button-stop@2x.png
--------------------------------------------------------------------------------
/images/button-terminal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/button-terminal.png
--------------------------------------------------------------------------------
/images/button-terminal@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/button-terminal@2x.png
--------------------------------------------------------------------------------
/images/button-view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/button-view.png
--------------------------------------------------------------------------------
/images/button-view@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/button-view@2x.png
--------------------------------------------------------------------------------
/images/cartoon-docker-compose.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/cartoon-docker-compose.png
--------------------------------------------------------------------------------
/images/cartoon-docker-compose@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/cartoon-docker-compose@2x.png
--------------------------------------------------------------------------------
/images/cartoon-docker-machine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/cartoon-docker-machine.png
--------------------------------------------------------------------------------
/images/cartoon-docker-machine@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/cartoon-docker-machine@2x.png
--------------------------------------------------------------------------------
/images/cartoon-docker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/cartoon-docker.png
--------------------------------------------------------------------------------
/images/cartoon-docker@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/cartoon-docker@2x.png
--------------------------------------------------------------------------------
/images/cartoon-kitematic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/cartoon-kitematic.png
--------------------------------------------------------------------------------
/images/cartoon-kitematic@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/cartoon-kitematic@2x.png
--------------------------------------------------------------------------------
/images/close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/close.png
--------------------------------------------------------------------------------
/images/close@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/close@2x.png
--------------------------------------------------------------------------------
/images/connect-art.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/connect-art.png
--------------------------------------------------------------------------------
/images/connect-art@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/connect-art@2x.png
--------------------------------------------------------------------------------
/images/connect-to-hub.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/connect-to-hub.png
--------------------------------------------------------------------------------
/images/connect-to-hub@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/connect-to-hub@2x.png
--------------------------------------------------------------------------------
/images/container-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/container-white.png
--------------------------------------------------------------------------------
/images/container-white@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/container-white@2x.png
--------------------------------------------------------------------------------
/images/container.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/container.png
--------------------------------------------------------------------------------
/images/container@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/container@2x.png
--------------------------------------------------------------------------------
/images/downloading-arrow-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/downloading-arrow-white.png
--------------------------------------------------------------------------------
/images/downloading-arrow-white@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/downloading-arrow-white@2x.png
--------------------------------------------------------------------------------
/images/downloading-arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/downloading-arrow.png
--------------------------------------------------------------------------------
/images/downloading-arrow@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/downloading-arrow@2x.png
--------------------------------------------------------------------------------
/images/downloading-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/downloading-white.png
--------------------------------------------------------------------------------
/images/downloading-white@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/downloading-white@2x.png
--------------------------------------------------------------------------------
/images/downloading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/downloading.png
--------------------------------------------------------------------------------
/images/downloading@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/downloading@2x.png
--------------------------------------------------------------------------------
/images/error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/error.png
--------------------------------------------------------------------------------
/images/error@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/error@2x.png
--------------------------------------------------------------------------------
/images/feedback.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/feedback.png
--------------------------------------------------------------------------------
/images/feedback@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/feedback@2x.png
--------------------------------------------------------------------------------
/images/folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/folder.png
--------------------------------------------------------------------------------
/images/folder@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/folder@2x.png
--------------------------------------------------------------------------------
/images/fullscreen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/fullscreen.png
--------------------------------------------------------------------------------
/images/fullscreen@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/fullscreen@2x.png
--------------------------------------------------------------------------------
/images/fullscreenclose.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/fullscreenclose.png
--------------------------------------------------------------------------------
/images/fullscreenclose@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/fullscreenclose@2x.png
--------------------------------------------------------------------------------
/images/inspection.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/inspection.png
--------------------------------------------------------------------------------
/images/inspection@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/inspection@2x.png
--------------------------------------------------------------------------------
/images/install-error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/install-error.png
--------------------------------------------------------------------------------
/images/install-error@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/install-error@2x.png
--------------------------------------------------------------------------------
/images/loading-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/loading-white.png
--------------------------------------------------------------------------------
/images/loading-white@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/loading-white@2x.png
--------------------------------------------------------------------------------
/images/loading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/loading.png
--------------------------------------------------------------------------------
/images/loading@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/loading@2x.png
--------------------------------------------------------------------------------
/images/logo-active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/logo-active.png
--------------------------------------------------------------------------------
/images/logo-active@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/logo-active@2x.png
--------------------------------------------------------------------------------
/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/logo.png
--------------------------------------------------------------------------------
/images/logo@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/logo@2x.png
--------------------------------------------------------------------------------
/images/minimize.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/minimize.png
--------------------------------------------------------------------------------
/images/minimize@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/minimize@2x.png
--------------------------------------------------------------------------------
/images/official.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/official.png
--------------------------------------------------------------------------------
/images/official@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/official@2x.png
--------------------------------------------------------------------------------
/images/paused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/paused.png
--------------------------------------------------------------------------------
/images/paused@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/paused@2x.png
--------------------------------------------------------------------------------
/images/preferences.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/preferences.png
--------------------------------------------------------------------------------
/images/preferences@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/preferences@2x.png
--------------------------------------------------------------------------------
/images/private.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/private.png
--------------------------------------------------------------------------------
/images/private@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/private@2x.png
--------------------------------------------------------------------------------
/images/restarting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/restarting.png
--------------------------------------------------------------------------------
/images/restarting@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/restarting@2x.png
--------------------------------------------------------------------------------
/images/running-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/running-white.png
--------------------------------------------------------------------------------
/images/running-white@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/running-white@2x.png
--------------------------------------------------------------------------------
/images/running.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/running.png
--------------------------------------------------------------------------------
/images/running@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/running@2x.png
--------------------------------------------------------------------------------
/images/runningwave-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/runningwave-white.png
--------------------------------------------------------------------------------
/images/runningwave-white@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/runningwave-white@2x.png
--------------------------------------------------------------------------------
/images/runningwave.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/runningwave.png
--------------------------------------------------------------------------------
/images/runningwave@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/runningwave@2x.png
--------------------------------------------------------------------------------
/images/still-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/still-white.png
--------------------------------------------------------------------------------
/images/still-white@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/still-white@2x.png
--------------------------------------------------------------------------------
/images/stopped-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/stopped-white.png
--------------------------------------------------------------------------------
/images/stopped-white@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/stopped-white@2x.png
--------------------------------------------------------------------------------
/images/stopped.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/stopped.png
--------------------------------------------------------------------------------
/images/stopped@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/stopped@2x.png
--------------------------------------------------------------------------------
/images/user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/user.png
--------------------------------------------------------------------------------
/images/user@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/user@2x.png
--------------------------------------------------------------------------------
/images/userdropdown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/userdropdown.png
--------------------------------------------------------------------------------
/images/userdropdown@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/userdropdown@2x.png
--------------------------------------------------------------------------------
/images/virtualbox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/virtualbox.png
--------------------------------------------------------------------------------
/images/virtualbox@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/virtualbox@2x.png
--------------------------------------------------------------------------------
/images/wavy-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/wavy-white.png
--------------------------------------------------------------------------------
/images/wavy-white@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/wavy-white@2x.png
--------------------------------------------------------------------------------
/images/whaleicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/whaleicon.png
--------------------------------------------------------------------------------
/images/whaleicon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/whaleicon@2x.png
--------------------------------------------------------------------------------
/images/windows-close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/windows-close.png
--------------------------------------------------------------------------------
/images/windows-close@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/windows-close@2x.png
--------------------------------------------------------------------------------
/images/windows-fullscreen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/windows-fullscreen.png
--------------------------------------------------------------------------------
/images/windows-fullscreen@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/windows-fullscreen@2x.png
--------------------------------------------------------------------------------
/images/windows-fullscreenclose.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/windows-fullscreenclose.png
--------------------------------------------------------------------------------
/images/windows-fullscreenclose@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/windows-fullscreenclose@2x.png
--------------------------------------------------------------------------------
/images/windows-minimize.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/windows-minimize.png
--------------------------------------------------------------------------------
/images/windows-minimize@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/images/windows-minimize@2x.png
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Kitematic
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/jest-integration.json:
--------------------------------------------------------------------------------
1 | {
2 | "testMatch": ["**/__integration__/**/*.js"],
3 | "transform": {".*": "/node_modules/babel-jest"},
4 | "setupFiles": ["/util/testenv.js"],
5 | "setupTestFrameworkScriptFile": "/util/prepare.js",
6 | "unmockedModulePathPatterns": [
7 | "babel",
8 | "core-js",
9 | "/node_modules/source-map-support"
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/jest-unit.json:
--------------------------------------------------------------------------------
1 | {
2 | "transform": { ".*": "/node_modules/babel-jest" },
3 | "setupFiles": ["/util/testenv.js"],
4 | "setupTestFrameworkScriptFile": "/util/prepare.js",
5 | "unmockedModulePathPatterns": [
6 | "alt",
7 | "stream",
8 | "tty",
9 | "net",
10 | "crypto",
11 | "babel",
12 | "bluebird",
13 | "object-assign",
14 | "underscore",
15 | "source-map-support",
16 | "/node_modules/.*JSONStream",
17 | "/node_modules/core-js"
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Kitematic",
3 | "version": "0.17.13",
4 | "author": "Kitematic",
5 | "license": "Apache-2.0",
6 | "description": "Simple Docker Container management for Mac OS X, Windows and Ubuntu.",
7 | "homepage": "https://kitematic.com/",
8 | "main": "browser.js",
9 | "repository": {
10 | "type": "git",
11 | "url": "git@github.com:kitematic/kitematic.git"
12 | },
13 | "bugs": "https://github.com/kitematic/kitematic/issues",
14 | "engines": {
15 | "node": "<10.0.0"
16 | },
17 | "scripts": {
18 | "build": "tsc && npm run tslint",
19 | "integration": "jest -c jest-integration.json",
20 | "prestart": "npm run build",
21 | "release:debian:x32": "grunt release:debian:x32",
22 | "release:debian:x64": "grunt release:debian:x64",
23 | "release:redhat:x32": "grunt release:redhat:x32",
24 | "release:redhat:x64": "grunt release:redhat:x64",
25 | "release:mac": "grunt release:mac",
26 | "release:windows": "grunt release:windows",
27 | "start": "grunt",
28 | "start-dev": "NODE_ENV=development grunt",
29 | "test": "jest -c jest-unit.json",
30 | "tslint": "tslint --fix --project ./tsconfig.json"
31 | },
32 | "electron-version": "7.2.4",
33 | "dependencies": {
34 | "JSONStream": "1.3.2",
35 | "alt": "0.16.10",
36 | "ansi-to-html": "0.3.0",
37 | "any-promise": "0.1.0",
38 | "async": "1.5.2",
39 | "babel-polyfill": "^6.26.0",
40 | "bluebird": "3.5.1",
41 | "bugsnag-js": "2.5.0",
42 | "cached-request": "1.1.2",
43 | "classnames": "2.2.5",
44 | "deep-extend": "^0.6.0",
45 | "dockerode": "3.0.1",
46 | "bl": "^1.2.3",
47 | "install": "0.1.8",
48 | "jquery": "^3.5.0",
49 | "mixpanel": "kitematic/mixpanel-node",
50 | "mkdirp": "0.5.1",
51 | "node-uuid": "1.4.8",
52 | "numeral": "1.5.6",
53 | "object-assign": "4.1.1",
54 | "osx-release": "1.1.0",
55 | "parseUri": "1.2.3-2",
56 | "react": "0.14.0",
57 | "react-bootstrap": "0.20.3",
58 | "react-retina-image": "1.3.3",
59 | "react-router": "0.13.6",
60 | "request": "^2.88.0",
61 | "request-progress": "0.3.1",
62 | "rimraf": "2.6.2",
63 | "underscore": "1.8.3",
64 | "validator": "4.9.0",
65 | "which": "1.3.0"
66 | },
67 | "devDependencies": {
68 | "@types/react": "16.0.38",
69 | "acorn": "^5.7.4",
70 | "babel-cli": "^6.26.0",
71 | "babel-jest": "^23.6.0",
72 | "babel-plugin-transform-async-to-generator": "^6.24.1",
73 | "babel-plugin-transform-runtime": "^6.23.0",
74 | "babel-preset-env": "^1.7.0",
75 | "babel-preset-react": "^6.24.1",
76 | "braces": "^2.3.1",
77 | "decompress-zip": "^0.3.2",
78 | "electron": "^7.2.4",
79 | "electron-packager": "^12.1.1",
80 | "eslint": "^4.18.2",
81 | "eslint-plugin-react": "3.16.1",
82 | "grunt": "^1.0.3",
83 | "grunt-babel": "^7.0.0",
84 | "grunt-chmod": "1.1.1",
85 | "grunt-cli": "^1.3.1",
86 | "grunt-contrib-clean": "^2.0.0",
87 | "grunt-contrib-compress": "^1.5.0",
88 | "grunt-contrib-copy": "^1.0.0",
89 | "grunt-contrib-less": "^2.0.0",
90 | "grunt-contrib-watch": "^1.1.0",
91 | "grunt-electron": "^11.0.0",
92 | "grunt-electron-installer": "^2.1.0",
93 | "grunt-electron-packager": "0.2.1",
94 | "grunt-if-missing": "1.0.1",
95 | "grunt-newer": "1.3.0",
96 | "grunt-plistbuddy": "^0.2.0",
97 | "grunt-rcedit": "^0.7.0",
98 | "grunt-shell": "^2.1.0",
99 | "handlebars": "^4.5.3",
100 | "jest-cli": "^23.6.0",
101 | "js-yaml": "^3.13.1",
102 | "load-grunt-tasks": "^4.0.0",
103 | "lodash": "^4.17.19",
104 | "lodash.template": "^4.5.0",
105 | "merge": ">=1.2.1",
106 | "minimatch": ">=3.0.4",
107 | "minimist": "1.2.3",
108 | "mixin-deep": "^1.3.2",
109 | "run-sequence": "^2.2.1",
110 | "set-value": "^2.0.1",
111 | "shell-escape": "0.2.0",
112 | "source-map-support": "0.3.3",
113 | "tslint": "^5.11.0",
114 | "typescript": "2.7.2",
115 | "yargs-parser": "^13.1.2"
116 | },
117 | "optionalDependencies": {
118 | "grunt-electron-installer-debian": "0.3.1",
119 | "grunt-electron-installer-redhat": "0.3.1"
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/resources/MSYS_LICENSE:
--------------------------------------------------------------------------------
1 | Kitematic includes (but does not link to) various DLLs included with the msysgit Git-1.9.5-preview20150319 distribution. Included is the MSYS runtime license.
2 | Source is available online at https://github.com/msysgit/git/tree/v1.9.5.msysgit.1
3 |
4 | File: MSYS_LICENSE
5 | Copyright (C): 2001, Earnie Boyd
6 | File $Revision$
7 | File Revision $Date$
8 | MSYS Release: 1.0.2
9 | MSYS Release Date: November 30th, 2001
10 |
11 | The software, both source and binary forms, are covered via differing licenses.
12 | Each license has it's own set of rules so please make sure you read them
13 | carefully to see how it applies to you, particularly if you're going to
14 | distribute the software.
15 |
16 | The MSYS runtime software source can found in the winsup/cygwin directory. The
17 | existing code portions of this source is covered by the CYGWIN_LICENSE which can
18 | be found in this directory in a file by the name of CYGWIN_LICENSE. MSYS
19 | specific software code added regardless of existing license is covered by the
20 | ESPL which can be found in a file by the same name.
21 |
--------------------------------------------------------------------------------
/resources/msys-1.0.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/resources/msys-1.0.dll
--------------------------------------------------------------------------------
/resources/msys-crypto-1.0.0.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/resources/msys-crypto-1.0.0.dll
--------------------------------------------------------------------------------
/resources/msys-minires.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/resources/msys-minires.dll
--------------------------------------------------------------------------------
/resources/msys-z.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/resources/msys-z.dll
--------------------------------------------------------------------------------
/resources/ssh.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docker/kitematic/445bfbae698ce977784c712756d6dc57c3fe6cbf/resources/ssh.exe
--------------------------------------------------------------------------------
/resources/terminal:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
4 | CMD="clear && $*"
5 |
6 | ITERM_EXISTS=`osascript < /dev/null < /dev/null < /dev/null < favoriteName !== name);
51 | } else {
52 | favorites = [...favorites, name];
53 | }
54 | localStorage.setItem('containers.favorites', JSON.stringify(favorites));
55 | this.dispatch({name});
56 | }
57 | }
58 |
59 | export default alt.createActions(ContainerActions);
60 |
--------------------------------------------------------------------------------
/src/actions/ContainerServerActions.js:
--------------------------------------------------------------------------------
1 | import alt from '../alt';
2 |
3 | class ContainerServerActions {
4 | constructor () {
5 | this.generateActions(
6 | 'added',
7 | 'allUpdated',
8 | 'destroyed',
9 | 'error',
10 | 'muted',
11 | 'pending',
12 | 'progress',
13 | 'started',
14 | 'unmuted',
15 | 'updated',
16 | 'waiting',
17 | 'kill',
18 | 'stopped',
19 | 'log',
20 | 'logs',
21 | 'toggleFavorite'
22 | );
23 | }
24 | }
25 |
26 | export default alt.createActions(ContainerServerActions);
27 |
--------------------------------------------------------------------------------
/src/actions/ImageActions.js:
--------------------------------------------------------------------------------
1 | import alt from '../alt';
2 | import dockerUtil from '../utils/DockerUtil';
3 |
4 | class ImageActions {
5 |
6 | all () {
7 | this.dispatch({});
8 | dockerUtil.refresh();
9 | }
10 |
11 | destroy (image) {
12 | dockerUtil.removeImage(image);
13 | }
14 | }
15 |
16 | export default alt.createActions(ImageActions);
17 |
--------------------------------------------------------------------------------
/src/actions/ImageServerActions.js:
--------------------------------------------------------------------------------
1 | import alt from '../alt';
2 |
3 | class ImageServerActions {
4 | constructor () {
5 | this.generateActions(
6 | 'added',
7 | 'updated',
8 | 'destroyed',
9 | 'error'
10 | );
11 | }
12 | }
13 |
14 | export default alt.createActions(ImageServerActions);
15 |
--------------------------------------------------------------------------------
/src/actions/NetworkActions.js:
--------------------------------------------------------------------------------
1 | import alt from '../alt';
2 |
3 | class NetworkActions {
4 | constructor () {
5 | this.generateActions(
6 | 'updated',
7 | 'error',
8 | 'pending',
9 | 'clearPending'
10 | );
11 | }
12 | }
13 |
14 | export default alt.createActions(NetworkActions);
15 |
--------------------------------------------------------------------------------
/src/actions/RepositoryActions.js:
--------------------------------------------------------------------------------
1 | import alt from '../alt';
2 | import regHubUtil from '../utils/RegHubUtil';
3 |
4 | class RepositoryActions {
5 | recommended () {
6 | this.dispatch({});
7 | regHubUtil.recommended();
8 | }
9 |
10 | search (query, page = 1) {
11 | this.dispatch({query, page});
12 | regHubUtil.search(query, page);
13 | }
14 |
15 | repos () {
16 | this.dispatch({});
17 | regHubUtil.repos();
18 | }
19 | }
20 |
21 | export default alt.createActions(RepositoryActions);
22 |
--------------------------------------------------------------------------------
/src/actions/RepositoryServerActions.js:
--------------------------------------------------------------------------------
1 | import alt from '../alt';
2 |
3 | class RepositoryServerActions {
4 | constructor () {
5 | this.generateActions(
6 | 'reposLoading',
7 | 'resultsUpdated',
8 | 'recommendedUpdated',
9 | 'reposUpdated',
10 | 'error'
11 | );
12 | }
13 | }
14 |
15 | export default alt.createActions(RepositoryServerActions);
16 |
--------------------------------------------------------------------------------
/src/actions/SetupActions.js:
--------------------------------------------------------------------------------
1 | import alt from '../alt';
2 | import setupUtil from '../utils/SetupUtil';
3 |
4 | class SetupActions {
5 | retry (removeVM) {
6 | this.dispatch({removeVM});
7 | setupUtil.retry(removeVM);
8 | }
9 |
10 | useVbox () {
11 | this.dispatch({});
12 | setupUtil.useVbox();
13 | }
14 | }
15 |
16 | export default alt.createActions(SetupActions);
17 |
--------------------------------------------------------------------------------
/src/actions/SetupServerActions.js:
--------------------------------------------------------------------------------
1 | import alt from '../alt';
2 |
3 | class SetupServerActions {
4 | constructor () {
5 | this.generateActions(
6 | 'progress',
7 | 'error',
8 | 'started'
9 | );
10 | }
11 | }
12 |
13 | export default alt.createActions(SetupServerActions);
14 |
--------------------------------------------------------------------------------
/src/actions/TagActions.js:
--------------------------------------------------------------------------------
1 | import alt from '../alt';
2 | import regHubUtil from '../utils/RegHubUtil';
3 |
4 | class TagActions {
5 | tags (repo) {
6 | this.dispatch({repo});
7 | regHubUtil.tags(repo);
8 | }
9 |
10 | localTags (repo, tags) {
11 | this.dispatch({repo, tags});
12 | }
13 | }
14 |
15 | export default alt.createActions(TagActions);
16 |
--------------------------------------------------------------------------------
/src/actions/TagServerActions.js:
--------------------------------------------------------------------------------
1 | import alt from '../alt';
2 |
3 | class TagServerActions {
4 | constructor () {
5 | this.generateActions(
6 | 'tagsUpdated',
7 | 'error'
8 | );
9 | }
10 | }
11 |
12 | export default alt.createActions(TagServerActions);
13 |
--------------------------------------------------------------------------------
/src/alt.js:
--------------------------------------------------------------------------------
1 | import Alt from 'alt';
2 | export default new Alt();
3 |
--------------------------------------------------------------------------------
/src/app.js:
--------------------------------------------------------------------------------
1 | import 'babel-polyfill';
2 | import electron from 'electron';
3 | const remote = electron.remote;
4 | const Menu = remote.Menu;
5 | // ipcRenderer is used as we're in the process
6 | const ipcRenderer = electron.ipcRenderer;
7 |
8 | import React from 'react';
9 | import Promise from 'bluebird';
10 |
11 | import metrics from './utils/MetricsUtil';
12 | import template from './menutemplate';
13 | import webUtil from './utils/WebUtil';
14 | import hubUtil from './utils/HubUtil';
15 | import setupUtil from './utils/SetupUtil';
16 | import docker from './utils/DockerUtil';
17 | import hub from './utils/HubUtil';
18 | import Router from 'react-router';
19 | import routes from './routes';
20 | import routerContainer from './router';
21 | import repositoryActions from './actions/RepositoryActions';
22 | import machine from './utils/DockerMachineUtil';
23 |
24 | Promise.config({cancellation: true});
25 |
26 | hubUtil.init();
27 |
28 | if (hubUtil.loggedin()) {
29 | repositoryActions.repos();
30 | }
31 |
32 | repositoryActions.recommended();
33 |
34 | webUtil.addWindowSizeSaving();
35 | webUtil.addLiveReload();
36 | webUtil.addBugReporting();
37 | webUtil.disableGlobalBackspace();
38 |
39 | Menu.setApplicationMenu(Menu.buildFromTemplate(template()));
40 |
41 | metrics.track('Started App');
42 | metrics.track('app heartbeat');
43 | setInterval(function () {
44 | metrics.track('app heartbeat');
45 | }, 14400000);
46 |
47 | var router = Router.create({
48 | routes: routes
49 | });
50 | router.run(Handler => React.render(, document.body));
51 | routerContainer.set(router);
52 |
53 |
54 |
55 | setupUtil.setup().then(() => {
56 | Menu.setApplicationMenu(Menu.buildFromTemplate(template()));
57 | docker.init();
58 | if (!hub.prompted() && !hub.loggedin()) {
59 | router.transitionTo('login');
60 | } else {
61 | router.transitionTo('search');
62 | }
63 | }).catch(err => {
64 | metrics.track('Setup Failed', {
65 | step: 'catch',
66 | message: err.message
67 | });
68 | throw err;
69 | });
70 |
71 |
72 | ipcRenderer.on('application:quitting', () => {
73 | docker.detachEvent();
74 | if (localStorage.getItem('settings.closeVMOnQuit') === 'true') {
75 | machine.stop();
76 | }
77 | });
78 |
79 | window.onbeforeunload = function () {
80 | docker.detachEvent();
81 | };
82 |
--------------------------------------------------------------------------------
/src/browser.js:
--------------------------------------------------------------------------------
1 | import electron from 'electron';
2 | const app = electron.app;
3 | const BrowserWindow = electron.BrowserWindow;
4 |
5 | import fs from 'fs';
6 | import os from 'os';
7 | import path from 'path';
8 | import child_process from 'child_process';
9 | let Promise = require('bluebird');
10 |
11 | process.env.NODE_PATH = path.join(__dirname, 'node_modules');
12 | process.env.RESOURCES_PATH = path.join(__dirname, '/../resources');
13 | if (process.platform !== 'win32') {
14 | process.env.PATH = '/usr/local/bin:' + process.env.PATH;
15 | }
16 | var exiting = false;
17 | var size = {}, settingsjson = {};
18 | try {
19 | size = JSON.parse(fs.readFileSync(path.join(app.getPath('userData'), 'size')));
20 | } catch (err) {}
21 |
22 | try {
23 | settingsjson = JSON.parse(fs.readFileSync(path.join(__dirname, 'settings.json'), 'utf8'));
24 | } catch (err) {}
25 |
26 | app.on('ready', function () {
27 | var mainWindow = new BrowserWindow({
28 | width: size.width || 1080,
29 | height: size.height || 680,
30 | minWidth: os.platform() === 'win32' ? 400 : 700,
31 | minHeight: os.platform() === 'win32' ? 260 : 500,
32 | 'standard-window': false,
33 | resizable: true,
34 | frame: false,
35 | backgroundColor: '#fff',
36 | show: false,
37 | webPreferences: {
38 | nodeIntegration: true,
39 | },
40 | });
41 |
42 | if (process.env.NODE_ENV === 'development') {
43 | mainWindow.openDevTools({mode: 'detach'});
44 | }
45 |
46 | mainWindow.loadURL(path.normalize('file://' + path.join(__dirname, 'index.html')));
47 |
48 | app.on('activate', function () {
49 | if (mainWindow) {
50 | mainWindow.show();
51 | }
52 | return false;
53 | });
54 |
55 |
56 | if (os.platform() === 'win32' || os.platform() === 'linux') {
57 | mainWindow.on('close', function (e) {
58 | mainWindow.webContents.send('application:quitting');
59 | if(!exiting){
60 | Promise.delay(1000).then(function(){
61 | mainWindow.close();
62 | });
63 | exiting = true;
64 | e.preventDefault();
65 | }
66 | });
67 |
68 | app.on('window-all-closed', function () {
69 | app.quit();
70 | });
71 | } else if (os.platform() === 'darwin') {
72 | app.on('before-quit', function () {
73 | mainWindow.webContents.send('application:quitting');
74 | });
75 | }
76 |
77 | mainWindow.webContents.on('new-window', function (e) {
78 | e.preventDefault();
79 | });
80 |
81 | mainWindow.webContents.on('will-navigate', function (e, url) {
82 | if (url.indexOf('build/index.html#') < 0) {
83 | e.preventDefault();
84 | }
85 | });
86 |
87 | mainWindow.webContents.on('did-finish-load', function () {
88 | mainWindow.setTitle('Kitematic');
89 | mainWindow.show();
90 | mainWindow.focus();
91 | });
92 | });
93 |
--------------------------------------------------------------------------------
/src/components/About.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react/addons';
2 | import metrics from '../utils/MetricsUtil';
3 | import utils from '../utils/Util';
4 | import Router from 'react-router';
5 | import RetinaImage from 'react-retina-image';
6 | var packages;
7 |
8 | try {
9 | packages = utils.packagejson();
10 | } catch (err) {
11 | packages = {};
12 | }
13 |
14 | var Preferences = React.createClass({
15 | mixins: [Router.Navigation],
16 | getInitialState: function () {
17 | return {
18 | metricsEnabled: metrics.enabled()
19 | };
20 | },
21 | handleGoBackClick: function () {
22 | this.goBack();
23 | metrics.track('Went Back From About');
24 | },
25 | render: function () {
26 | return (
27 |
28 |
29 |
Go Back
30 |
31 |
32 |
33 |
Docker {packages.name}
34 |
{packages.version}
35 |
36 |
37 |
Kitematic is built with:
38 |
39 |
40 |
41 |
Docker Engine
42 |
43 |
44 |
45 |
Docker Machine
46 |
{packages["docker-machine-version"]}
47 |
48 |
49 |
Third-Party Software
50 |
51 |
52 |
VirtualBox
53 |
{packages["virtualbox-version"]}
54 |
55 |
56 |
57 |
58 |
Electron
59 |
{packages["electron-version"]}
60 |
61 |
62 |
63 |
64 | );
65 | }
66 | });
67 |
68 | module.exports = Preferences;
69 |
--------------------------------------------------------------------------------
/src/components/Account.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react/addons';
2 | import Router from 'react-router';
3 | import RetinaImage from 'react-retina-image';
4 | import Header from './Header.react';
5 | import metrics from '../utils/MetricsUtil';
6 | import accountStore from '../stores/AccountStore';
7 | import accountActions from '../actions/AccountActions';
8 |
9 | module.exports = React.createClass({
10 | mixins: [Router.Navigation],
11 |
12 | getInitialState: function () {
13 | return accountStore.getState();
14 | },
15 |
16 | componentDidMount: function () {
17 | document.addEventListener('keyup', this.handleDocumentKeyUp, false);
18 | accountStore.listen(this.update);
19 | },
20 |
21 | componentWillUnmount: function () {
22 | document.removeEventListener('keyup', this.handleDocumentKeyUp, false);
23 | accountStore.unlisten(this.update);
24 | },
25 |
26 | componentWillUpdate: function (nextProps, nextState) {
27 | if (!this.state.username && nextState.username) {
28 | if (nextState.prompted) {
29 | this.goBack();
30 | } else {
31 | this.transitionTo('search');
32 | }
33 | }
34 | },
35 |
36 | handleSkip: function () {
37 | accountActions.skip();
38 | this.transitionTo('search');
39 | metrics.track('Skipped Login');
40 | },
41 |
42 | handleClose: function () {
43 | this.goBack();
44 | metrics.track('Closed Login');
45 | },
46 |
47 | update: function () {
48 | this.setState(accountStore.getState());
49 | },
50 |
51 | render: function () {
52 | let close = this.state.prompted ?
53 | Close :
54 | Skip For Now;
55 |
56 | return (
57 |
58 |
59 |
60 | {close}
61 |
62 |
63 |
64 |
65 |
66 |
67 |
Connect to Docker Hub
68 |
Pull and run private Docker Hub images by connecting your Docker Hub account to Kitematic.
69 |
70 |
71 |
72 |
73 | );
74 | }
75 | });
76 |
--------------------------------------------------------------------------------
/src/components/AccountLogin.react.js:
--------------------------------------------------------------------------------
1 | import _ from 'underscore';
2 | import React from 'react/addons';
3 | import Router from 'react-router';
4 | import validator from 'validator';
5 | import accountActions from '../actions/AccountActions';
6 | import metrics from '../utils/MetricsUtil';
7 | import {shell} from 'electron';
8 |
9 | module.exports = React.createClass({
10 | mixins: [Router.Navigation, React.addons.LinkedStateMixin],
11 |
12 | getInitialState: function () {
13 | return {
14 | username: '',
15 | password: '',
16 | errors: {}
17 | };
18 | },
19 |
20 | componentDidMount: function () {
21 | React.findDOMNode(this.refs.usernameInput).focus();
22 | },
23 |
24 | componentWillReceiveProps: function (nextProps) {
25 | this.setState({errors: nextProps.errors});
26 | },
27 |
28 | validate: function () {
29 | let errors = {};
30 |
31 | if (validator.isEmail(this.state.username)) {
32 | errors.username = 'Must be a valid username (not an email)';
33 | } else if (!validator.isLowercase(this.state.username) || !validator.isAlphanumeric(this.state.username) || !validator.isLength(this.state.username, 4, 30)) {
34 | errors.username = 'Must be 4-30 lower case letters or numbers';
35 | }
36 |
37 | if (!validator.isLength(this.state.password, 5)) {
38 | errors.password = 'Must be at least 5 characters long';
39 | }
40 |
41 | return errors;
42 | },
43 |
44 | handleBlur: function () {
45 | this.setState({errors: _.omit(this.validate(), (val, key) => !this.state[key].length)});
46 | },
47 |
48 | handleLogin: function () {
49 | let errors = this.validate();
50 | this.setState({errors});
51 |
52 | if (_.isEmpty(errors)) {
53 | accountActions.login(this.state.username, this.state.password);
54 | metrics.track('Clicked Log In');
55 | }
56 | },
57 |
58 | handleClickSignup: function () {
59 | if (!this.props.loading) {
60 | this.replaceWith('signup');
61 | metrics.track('Switched to Sign Up');
62 | }
63 | },
64 |
65 | handleClickForgotPassword: function () {
66 | shell.openExternal('https://hub.docker.com/reset-password/');
67 | },
68 |
69 | render: function () {
70 | let loading = this.props.loading ? : null;
71 | return (
72 |
86 | );
87 | }
88 | });
89 |
--------------------------------------------------------------------------------
/src/components/AccountSignup.react.js:
--------------------------------------------------------------------------------
1 | import _ from 'underscore';
2 | import React from 'react/addons';
3 | import Router from 'react-router';
4 | import validator from 'validator';
5 | import accountActions from '../actions/AccountActions';
6 | import metrics from '../utils/MetricsUtil';
7 |
8 | module.exports = React.createClass({
9 | mixins: [Router.Navigation, React.addons.LinkedStateMixin],
10 |
11 | getInitialState: function () {
12 | return {
13 | username: '',
14 | password: '',
15 | email: '',
16 | subscribe: true,
17 | errors: {}
18 | };
19 | },
20 |
21 | componentDidMount: function () {
22 | React.findDOMNode(this.refs.usernameInput).focus();
23 | },
24 |
25 | componentWillReceiveProps: function (nextProps) {
26 | this.setState({errors: nextProps.errors});
27 | },
28 |
29 | validate: function () {
30 | let errors = {};
31 | if (!validator.isLowercase(this.state.username) || !validator.isAlphanumeric(this.state.username) || !validator.isLength(this.state.username, 4, 30)) {
32 | errors.username = 'Must be 4-30 lower case letters or numbers';
33 | }
34 |
35 | if (!validator.isLength(this.state.password, 5)) {
36 | errors.password = 'Must be at least 5 characters long';
37 | }
38 |
39 | if (!validator.isEmail(this.state.email)) {
40 | errors.email = 'Must be a valid email address';
41 | }
42 | return errors;
43 | },
44 |
45 | handleBlur: function () {
46 | this.setState({errors: _.omit(this.validate(), (val, key) => !this.state[key].length)});
47 | },
48 |
49 | handleSignUp: function () {
50 | let errors = this.validate();
51 | this.setState({errors});
52 |
53 | if (_.isEmpty(errors)) {
54 | accountActions.signup(this.state.username, this.state.password, this.state.email, this.state.subscribe);
55 | metrics.track('Clicked Sign Up');
56 | }
57 | },
58 |
59 | handleClickLogin: function () {
60 | if (!this.props.loading) {
61 | this.replaceWith('login');
62 | metrics.track('Switched to Log In');
63 | }
64 | },
65 |
66 | render: function () {
67 | let loading = this.props.loading ? : null;
68 | return (
69 |
89 | );
90 | }
91 | });
92 |
--------------------------------------------------------------------------------
/src/components/ContainerDetails.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react/addons';
2 | import Router from 'react-router';
3 | import ContainerDetailsHeader from './ContainerDetailsHeader.react';
4 | import ContainerDetailsSubheader from './ContainerDetailsSubheader.react';
5 | import containerUtil from '../utils/ContainerUtil';
6 | import util from '../utils/Util';
7 | import _ from 'underscore';
8 |
9 | var ContainerDetails = React.createClass({
10 | contextTypes: {
11 | router: React.PropTypes.func
12 | },
13 |
14 | render: function () {
15 | if (!this.props.container) {
16 | return false;
17 | }
18 |
19 | let ports = containerUtil.ports(this.props.container);
20 | let defaultPort = _.find(_.keys(ports), port => {
21 | return util.webPorts.indexOf(port) !== -1;
22 | });
23 |
24 | return (
25 |
26 |
27 |
28 |
29 |
30 | );
31 | }
32 | });
33 |
34 | module.exports = ContainerDetails;
35 |
--------------------------------------------------------------------------------
/src/components/ContainerDetailsHeader.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react/addons';
2 |
3 | var ContainerDetailsHeader = React.createClass({
4 | render: function () {
5 | var state;
6 | if (!this.props.container) {
7 | return false;
8 | }
9 |
10 | if (this.props.container.State.Updating) {
11 | state = UPDATING;
12 | } else if (this.props.container.State.Stopping) {
13 | state = STOPPING;
14 | } else if (this.props.container.State.Paused) {
15 | state = PAUSED;
16 | } else if (this.props.container.State.Restarting) {
17 | state = RESTARTING;
18 | } else if (this.props.container.State.Running && !this.props.container.State.ExitCode) {
19 | state = RUNNING;
20 | } else if (this.props.container.State.Starting) {
21 | state = STARTING;
22 | } else if (this.props.container.State.Downloading) {
23 | state = DOWNLOADING;
24 | } else {
25 | state = STOPPED;
26 | }
27 | return (
28 |
29 |
30 | {this.props.container.Name}{state}
31 |
32 |
33 | );
34 | }
35 | });
36 |
37 | module.exports = ContainerDetailsHeader;
38 |
--------------------------------------------------------------------------------
/src/components/ContainerHomeFolders.react.js:
--------------------------------------------------------------------------------
1 | import _ from 'underscore';
2 | import React from 'react/addons';
3 | import RetinaImage from 'react-retina-image';
4 | import path from 'path';
5 | import {shell} from 'electron';
6 | import util from '../utils/Util';
7 | import metrics from '../utils/MetricsUtil';
8 | import containerActions from '../actions/ContainerActions';
9 | import electron from 'electron';
10 | const remote = electron.remote;
11 | const dialog = remote.dialog;
12 | import mkdirp from 'mkdirp';
13 |
14 | var ContainerHomeFolder = React.createClass({
15 | contextTypes: {
16 | router: React.PropTypes.func
17 | },
18 | handleClickFolder: function (source, destination) {
19 | metrics.track('Opened Volume Directory', {
20 | from: 'home'
21 | });
22 |
23 | if (source.indexOf(util.windowsToLinuxPath(util.home())) === -1) {
24 | dialog.showMessageBox({
25 | message: `Enable all volumes to edit files? This may not work with all database containers.`,
26 | buttons: ['Enable Volumes', 'Cancel']
27 | }).then(({response}) => {
28 | if (response === 0) {
29 | var mounts = _.clone(this.props.container.Mounts);
30 | var newSource = path.join(util.home(), util.documents(), 'Kitematic', this.props.container.Name, destination);
31 |
32 | mounts.forEach(m => {
33 | if (m.Destination === destination) {
34 | m.Source = util.windowsToLinuxPath(newSource);
35 | m.Driver = null;
36 | }
37 | });
38 |
39 | mkdirp(newSource, function (err) {
40 | console.log(err);
41 | if (!err) {
42 | shell.showItemInFolder(newSource);
43 | }
44 | });
45 |
46 | let binds = mounts.map(m => {
47 | return m.Source + ':' + m.Destination;
48 | });
49 |
50 | let hostConfig = _.extend(this.props.container.HostConfig, {Binds: binds});
51 |
52 | containerActions.update(this.props.container.Name, {Mounts: mounts, HostConfig: hostConfig});
53 | }
54 | });
55 | } else {
56 | let path = util.isWindows() ? util.linuxToWindowsPath(source) : source;
57 | shell.showItemInFolder(path);
58 | }
59 | },
60 | handleClickChangeFolders: function () {
61 | metrics.track('Viewed Volume Settings', {
62 | from: 'preview'
63 | });
64 | this.context.router.transitionTo('containerSettingsVolumes', {name: this.context.router.getCurrentParams().name});
65 | },
66 | render: function () {
67 | if (!this.props.container) {
68 | return false;
69 | }
70 |
71 | var folders = _.map(this.props.container.Mounts, (m, i) => {
72 | let destination = m.Destination;
73 | let source = m.Source;
74 | return (
75 |
76 |
77 |
{destination}
78 |
79 | );
80 | });
81 |
82 | return (
83 |
84 |
85 |
86 |
Volumes
87 |
88 |
89 |
90 |
91 |
92 | {folders}
93 |
94 |
95 |
96 | );
97 | }
98 | });
99 |
100 | module.exports = ContainerHomeFolder;
101 |
--------------------------------------------------------------------------------
/src/components/ContainerHomeIpPortsPreview.react.js:
--------------------------------------------------------------------------------
1 | import _ from 'underscore';
2 | import React from 'react/addons';
3 |
4 | var ContainerHomeIpPortsPreview = React.createClass({
5 | handleClickPortSettings: function () {
6 | this.props.handleClickPortSettings();
7 | },
8 |
9 | render: function () {
10 | var ports = _.map(_.pairs(this.props.ports), pair => {
11 | var key = pair[0];
12 | var val = pair[1];
13 | return (
14 |
15 | {key + '/' + val.portType} |
16 | {val.url} |
17 |
18 | );
19 | });
20 |
21 | return (
22 |
23 |
24 |
25 |
IP & PORTS
26 |
27 |
28 |
29 |
30 |
You can access this container using the following IP address and port:
31 |
32 |
33 |
34 | DOCKER PORT |
35 | ACCESS URL |
36 |
37 |
38 |
39 | {ports}
40 |
41 |
42 |
43 |
44 | );
45 | }
46 | });
47 |
48 | module.exports = ContainerHomeIpPortsPreview;
49 |
--------------------------------------------------------------------------------
/src/components/ContainerList.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react/addons';
2 | import ContainerListItem from './ContainerListItem.react';
3 |
4 | var ContainerList = React.createClass({
5 | componentWillMount: function () {
6 | this.start = Date.now();
7 | },
8 | render: function () {
9 | var containers = this.props.containers.map(container => {
10 | return (
11 |
12 | );
13 | });
14 | return (
15 |
18 | );
19 | }
20 | });
21 |
22 | module.exports = ContainerList;
23 |
--------------------------------------------------------------------------------
/src/components/ContainerProgress.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | /*
4 |
5 | Usage:
6 |
7 | */
8 | var ContainerProgress = React.createClass({
9 | render: function () {
10 | var pBar1Style = {
11 | height: this.props.pBar1 + '%'
12 | };
13 | var pBar2Style = {
14 | height: this.props.pBar2 + '%'
15 | };
16 | var pBar3Style = {
17 | height: this.props.pBar3 + '%'
18 | };
19 | var pBar4Style = {
20 | height: this.props.pBar4 + '%'
21 | };
22 | return (
23 |
37 | );
38 | }
39 | });
40 |
41 | module.exports = ContainerProgress;
42 |
--------------------------------------------------------------------------------
/src/components/ContainerSettings.react.js:
--------------------------------------------------------------------------------
1 | import $ from 'jquery';
2 | import _ from 'underscore';
3 | import React from 'react/addons';
4 | import Router from 'react-router';
5 |
6 | var ContainerSettings = React.createClass({
7 | contextTypes: {
8 | router: React.PropTypes.func
9 | },
10 | componentWillReceiveProps: function () {
11 | this.init();
12 | },
13 | componentDidMount: function() {
14 | this.init();
15 | this.handleResize();
16 | window.addEventListener('resize', this.handleResize);
17 | },
18 | componentWillUnmount: function() {
19 | window.removeEventListener('resize', this.handleResize);
20 | },
21 | componentDidUpdate: function () {
22 | this.handleResize();
23 | },
24 | handleResize: function () {
25 | $('.settings-panel').height(window.innerHeight - 210);
26 | },
27 | init: function () {
28 | var currentRoute = _.last(this.context.router.getCurrentRoutes()).name;
29 | if (currentRoute === 'containerSettings') {
30 | this.context.router.transitionTo('containerSettingsGeneral', {name: this.context.router.getCurrentParams().name});
31 | }
32 | },
33 | render: function () {
34 | var container = this.props.container;
35 | if (!container) {
36 | return ();
37 | }
38 | return (
39 |
40 |
41 |
42 |
43 |
44 | -
45 | General
46 |
47 |
48 |
49 | -
50 | Hostname / Ports
51 |
52 |
53 |
54 | -
55 | Volumes
56 |
57 |
58 |
59 | -
60 | Network
61 |
62 |
63 |
64 | -
65 | Advanced
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | );
74 | }
75 | });
76 |
77 | module.exports = ContainerSettings;
78 |
--------------------------------------------------------------------------------
/src/components/ContainerSettingsAdvanced.react.js:
--------------------------------------------------------------------------------
1 | import _ from 'underscore';
2 | import React from 'react/addons';
3 | import metrics from '../utils/MetricsUtil';
4 | import ContainerUtil from '../utils/ContainerUtil';
5 | import containerActions from '../actions/ContainerActions';
6 |
7 | var ContainerSettingsAdvanced = React.createClass({
8 | mixins: [React.addons.LinkedStateMixin],
9 |
10 | contextTypes: {
11 | router: React.PropTypes.func
12 | },
13 |
14 | getInitialState: function () {
15 | let [tty, openStdin, privileged, restartPolicy] = ContainerUtil.mode(this.props.container) || [true, true, false, {MaximumRetryCount: 0, Name: 'no'}];
16 | return {
17 | tty: tty,
18 | openStdin: openStdin,
19 | privileged: privileged,
20 | restartPolicy: restartPolicy.Name === 'always'
21 | };
22 | },
23 |
24 | handleSaveAdvancedOptions: function () {
25 | metrics.track('Saved Advanced Options');
26 | let tty = this.state.tty;
27 | let openStdin = this.state.openStdin;
28 | let privileged = this.state.privileged;
29 | let restartPolicy = this.state.restartPolicy? {MaximumRetryCount: 0, Name: 'always'} : {MaximumRetryCount: 0, Name: 'no'};
30 | let hostConfig = _.extend(this.props.container.HostConfig, {Privileged: privileged, RestartPolicy: restartPolicy});
31 | containerActions.update(this.props.container.Name, {Tty: tty, OpenStdin: openStdin, HostConfig: hostConfig});
32 | },
33 |
34 | handleChangeTty: function () {
35 | this.setState({
36 | tty: !this.state.tty
37 | });
38 | },
39 |
40 | handleChangeOpenStdin: function () {
41 | this.setState({
42 | openStdin: !this.state.openStdin
43 | });
44 | },
45 |
46 | handleChangePrivileged: function () {
47 | this.setState({
48 | privileged: !this.state.privileged
49 | });
50 | },
51 |
52 | handleChangeRestartPolicy: function () {
53 | this.setState({
54 | restartPolicy: !this.state.restartPolicy
55 | });
56 | },
57 |
58 | render: function () {
59 | if (!this.props.container) {
60 | return false;
61 | }
62 |
63 | return (
64 |
65 |
66 |
Advanced Options
67 |
73 |
Save
74 |
75 |
76 | );
77 | }
78 | });
79 |
80 | module.exports = ContainerSettingsAdvanced;
81 |
--------------------------------------------------------------------------------
/src/components/Loading.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react/addons';
2 | import Header from './Header.react';
3 |
4 | module.exports = React.createClass({
5 | render: function () {
6 | return (
7 |
13 | );
14 | }
15 | });
16 |
--------------------------------------------------------------------------------
/src/components/Radial.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classNames from 'classnames';
3 |
4 | var Radial = React.createClass({
5 | render: function () {
6 | var percentage;
7 | if ((this.props.progress !== null && this.props.progress !== undefined) && !this.props.spin && !this.props.error) {
8 | percentage = (
9 |
10 | );
11 | } else {
12 | percentage = ;
13 | }
14 | var classes = classNames({
15 | 'radial-progress': true,
16 | 'radial-spinner': this.props.spin,
17 | 'radial-negative': this.props.error,
18 | 'radial-thick': this.props.thick || false,
19 | 'radial-gray': this.props.gray || false,
20 | 'radial-transparent': this.props.transparent || false
21 | });
22 | return (
23 |
24 |
34 |
35 | {percentage}
36 |
37 |
38 | );
39 | }
40 | });
41 |
42 | module.exports = Radial;
43 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import "./app";
2 | //# sourceMappingURL=main.js.map
--------------------------------------------------------------------------------
/src/main.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"main.js","sourceRoot":"","sources":["main.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,CAAC"}
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import "./app";
2 |
--------------------------------------------------------------------------------
/src/router.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | router: null,
3 |
4 | get: function () {
5 | return this.router;
6 | },
7 |
8 | set: function (router) {
9 | this.router = router;
10 | }
11 | };
12 |
--------------------------------------------------------------------------------
/src/routes.js:
--------------------------------------------------------------------------------
1 | import React from 'react/addons';
2 | import Setup from './components/Setup.react';
3 | import Account from './components/Account.react';
4 | import AccountSignup from './components/AccountSignup.react';
5 | import AccountLogin from './components/AccountLogin.react';
6 | import Containers from './components/Containers.react';
7 | import ContainerDetails from './components/ContainerDetails.react';
8 | import ContainerHome from './components/ContainerHome.react';
9 | import ContainerSettings from './components/ContainerSettings.react';
10 | import ContainerSettingsGeneral from './components/ContainerSettingsGeneral.react';
11 | import ContainerSettingsPorts from './components/ContainerSettingsPorts.react';
12 | import ContainerSettingsVolumes from './components/ContainerSettingsVolumes.react';
13 | import ContainerSettingsNetwork from './components/ContainerSettingsNetwork.react';
14 | import ContainerSettingsAdvanced from './components/ContainerSettingsAdvanced.react';
15 | import Preferences from './components/Preferences.react';
16 | import About from './components/About.react';
17 | import Loading from './components/Loading.react';
18 | import NewContainerSearch from './components/NewContainerSearch.react';
19 | import Router from 'react-router';
20 |
21 | var Route = Router.Route;
22 | var DefaultRoute = Router.DefaultRoute;
23 | var RouteHandler = Router.RouteHandler;
24 |
25 | var App = React.createClass({
26 | render: function () {
27 | return (
28 |
29 | );
30 | }
31 | });
32 |
33 | var routes = (
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | );
58 |
59 | module.exports = routes;
60 |
--------------------------------------------------------------------------------
/src/stores/AccountStore.js:
--------------------------------------------------------------------------------
1 | import alt from '../alt';
2 | import accountServerActions from '../actions/AccountServerActions';
3 | import accountActions from '../actions/AccountActions';
4 |
5 | class AccountStore {
6 | constructor () {
7 | this.bindActions(accountServerActions);
8 | this.bindActions(accountActions);
9 |
10 | this.prompted = false;
11 | this.loading = false;
12 | this.errors = {};
13 |
14 | this.verified = false;
15 | this.username = null;
16 | }
17 |
18 | skip () {
19 | this.setState({
20 | prompted: true
21 | });
22 | }
23 |
24 | login () {
25 | this.setState({
26 | loading: true,
27 | errors: {}
28 | });
29 | }
30 |
31 | logout () {
32 | this.setState({
33 | loading: false,
34 | errors: {},
35 | username: null,
36 | verified: false
37 | });
38 | }
39 |
40 | signup () {
41 | this.setState({
42 | loading: true,
43 | errors: {}
44 | });
45 | }
46 |
47 | loggedin ({username, verified}) {
48 | this.setState({username, verified, errors: {}, loading: false});
49 | }
50 |
51 | loggedout () {
52 | this.setState({
53 | loading: false,
54 | errors: {},
55 | username: null,
56 | verified: false
57 | });
58 | }
59 |
60 | signedup ({username}) {
61 | this.setState({username, errors: {}, loading: false});
62 | }
63 |
64 | verify () {
65 | this.setState({loading: true});
66 | }
67 |
68 | verified ({verified}) {
69 | this.setState({verified, loading: false});
70 | }
71 |
72 | prompted ({prompted}) {
73 | this.setState({prompted});
74 | }
75 |
76 | errors ({errors}) {
77 | this.setState({errors, loading: false});
78 | }
79 | }
80 |
81 | export default alt.createStore(AccountStore);
82 |
--------------------------------------------------------------------------------
/src/stores/ImageStore.js:
--------------------------------------------------------------------------------
1 | import alt from '../alt';
2 | import imageActions from '../actions/ImageActions';
3 | import imageServerActions from '../actions/ImageServerActions';
4 |
5 | class ImageStore {
6 | constructor () {
7 | this.bindActions(imageActions);
8 | this.bindActions(imageServerActions);
9 | this.results = [];
10 | this.images = [];
11 | this.imagesLoading = false;
12 | this.resultsLoading = false;
13 | this.error = null;
14 | }
15 |
16 | error (error) {
17 | this.setState({error: error, imagesLoading: false, resultsLoading: false});
18 | }
19 |
20 | clearError () {
21 | this.setState({error: null});
22 | }
23 |
24 | destroyed (data) {
25 | let images = this.images;
26 | if ((data && data[1] && data[1].Deleted)) {
27 | delete images[data[1].Deleted];
28 | }
29 | this.setState({error: null});
30 | }
31 |
32 | updated (images) {
33 | let tags = {};
34 | let finalImages = [];
35 | images.map((image) => {
36 | if (image.RepoTags) {
37 | image.RepoTags.map(repoTags => {
38 | let [name, tag] = repoTags.split(':');
39 | if (typeof tags[name] !== 'undefined') {
40 | finalImages[tags[name]].tags.push(tag);
41 | if (image.inUse) {
42 | finalImages[tags[name]].inUse = image.inUse;
43 | }
44 | } else {
45 | image.tags = [tag];
46 | tags[name] = finalImages.length;
47 | finalImages.push(image);
48 | }
49 | });
50 | }
51 | });
52 | this.setState({error: null, images: finalImages, imagesLoading: false});
53 | }
54 |
55 | static all () {
56 | let state = this.getState();
57 | return state.images;
58 | }
59 | }
60 |
61 | export default alt.createStore(ImageStore);
62 |
--------------------------------------------------------------------------------
/src/stores/NetworkStore.js:
--------------------------------------------------------------------------------
1 | import alt from '../alt';
2 | import networkActions from '../actions/NetworkActions';
3 |
4 | class NetworkStore {
5 | constructor () {
6 | this.bindActions(networkActions);
7 | this.networks = [];
8 | this.pending = null;
9 | this.error = null;
10 | }
11 |
12 | error (error) {
13 | this.setState({error: error});
14 | }
15 |
16 | updated (networks) {
17 | this.setState({error: null, networks: networks});
18 | }
19 |
20 | pending () {
21 | this.setState({pending: true});
22 | }
23 |
24 | clearPending () {
25 | this.setState({pending: null});
26 | }
27 |
28 | static all () {
29 | let state = this.getState();
30 | return state.networks;
31 | }
32 | }
33 |
34 | export default alt.createStore(NetworkStore);
35 |
--------------------------------------------------------------------------------
/src/stores/RepositoryStore.js:
--------------------------------------------------------------------------------
1 | import _ from 'underscore';
2 | import alt from '../alt';
3 | import repositoryServerActions from '../actions/RepositoryServerActions';
4 | import repositoryActions from '../actions/RepositoryActions';
5 | import accountServerActions from '../actions/AccountServerActions';
6 | import accountStore from './AccountStore';
7 |
8 | class RepositoryStore {
9 | constructor () {
10 | this.bindActions(repositoryActions);
11 | this.bindActions(repositoryServerActions);
12 | this.bindActions(accountServerActions);
13 | this.results = [];
14 | this.recommended = [];
15 | this.repos = [];
16 | this.query = null;
17 | this.nextPage = null;
18 | this.previousPage = null;
19 | this.currentPage = 1;
20 | this.totalPage = null;
21 | this.reposLoading = false;
22 | this.recommendedLoading = false;
23 | this.resultsLoading = false;
24 | this.error = null;
25 | }
26 |
27 | error ({error}) {
28 | this.setState({error: error, reposLoading: false, recommendedLoading: false, resultsLoading: false});
29 | }
30 |
31 | repos () {
32 | this.setState({reposError: null, reposLoading: true});
33 | }
34 |
35 | reposLoading () {
36 | this.setState({reposLoading: true});
37 | }
38 |
39 | reposUpdated ({repos}) {
40 | let accountState = accountStore.getState();
41 |
42 | if (accountState.username && accountState.verified) {
43 | this.setState({repos, reposLoading: false});
44 | } else {
45 | this.setState({repos: [], reposLoading: false});
46 | }
47 | }
48 |
49 | search ({query, page}) {
50 | if (this.query === query) {
51 | let previousPage = (page - 1 < 1) ? 1 : page - 1;
52 | let nextPage = (page + 1 > this.totalPage) ? this.totalPage : page + 1;
53 | this.setState({query: query, error: null, resultsLoading: true, currentPage: page, nextPage: nextPage, previousPage: previousPage});
54 | } else {
55 | this.setState({query: query, error: null, resultsLoading: true, nextPage: null, previousPage: null, currentPage: 1, totalPage: null});
56 | }
57 | }
58 |
59 | resultsUpdated ({repos, page, previous, next, total}) {
60 | this.setState({results: repos, currentPage: page, previousPage: previous, nextPage: next, totalPage: total, resultsLoading: false});
61 | }
62 |
63 | recommended () {
64 | this.setState({error: null, recommendedLoading: true});
65 | }
66 |
67 | recommendedUpdated ({repos}) {
68 | this.setState({recommended: repos, recommendedLoading: false, error: null});
69 | }
70 |
71 | loggedout () {
72 | this.setState({repos: []});
73 | }
74 |
75 | static all () {
76 | let state = this.getState();
77 | let all = state.recommended.concat(state.repos).concat(state.results);
78 | return _.uniq(all, false, repo => repo.namespace + '/' + repo.name);
79 | }
80 |
81 | static loading () {
82 | let state = this.getState();
83 | return state.recommendedLoading || state.resultsLoading || state.reposLoading;
84 | }
85 | }
86 |
87 | export default alt.createStore(RepositoryStore);
88 |
--------------------------------------------------------------------------------
/src/stores/SetupStore.js:
--------------------------------------------------------------------------------
1 | import alt from '../alt';
2 | import setupServerActions from '../actions/SetupServerActions';
3 | import setupActions from '../actions/SetupActions';
4 |
5 | class SetupStore {
6 | constructor () {
7 | this.bindActions(setupActions);
8 | this.bindActions(setupServerActions);
9 | this.started = false;
10 | this.progress = null;
11 | this.error = null;
12 | }
13 |
14 | started ({started}) {
15 | this.setState({error: null, started});
16 | }
17 |
18 | error ({error}) {
19 | this.setState({error, progress: null});
20 | }
21 |
22 | progress ({progress}) {
23 | this.setState({progress});
24 | }
25 | }
26 |
27 | export default alt.createStore(SetupStore);
28 |
--------------------------------------------------------------------------------
/src/stores/TagStore.js:
--------------------------------------------------------------------------------
1 | import alt from '../alt';
2 | import tagActions from '../actions/TagActions';
3 | import tagServerActions from '../actions/TagServerActions';
4 | import accountServerActions from '../actions/AccountServerActions';
5 |
6 | class TagStore {
7 | constructor () {
8 | this.bindActions(tagActions);
9 | this.bindActions(tagServerActions);
10 | this.bindActions(accountServerActions);
11 |
12 | // maps 'namespace/name' => [list of tags]
13 | this.tags = {};
14 |
15 | // maps 'namespace/name' => true / false
16 | this.loading = {};
17 | }
18 |
19 | tags ({repo}) {
20 | this.loading[repo] = true;
21 | this.emitChange();
22 | }
23 |
24 | localTags ({repo, tags}) {
25 | let data = [];
26 | tags.map((value) => {
27 | data.push({'name': value});
28 | });
29 | this.loading[repo] = true;
30 | this.tagsUpdated({repo, tags: data || []});
31 | }
32 |
33 | tagsUpdated ({repo, tags}) {
34 | this.tags[repo] = tags;
35 | this.loading[repo] = false;
36 | this.emitChange();
37 | }
38 |
39 | remove ({repo}) {
40 | delete this.tags[repo];
41 | delete this.loading[repo];
42 | this.emitChange();
43 | }
44 |
45 | loggedout () {
46 | this.loading = {};
47 | this.tags = {};
48 | this.emitChange();
49 | }
50 |
51 | error ({repo}) {
52 | this.loading[repo] = false;
53 | this.emitChange();
54 | }
55 | }
56 |
57 | export default alt.createStore(TagStore);
58 |
--------------------------------------------------------------------------------
/src/utils/ContainerUtil.js:
--------------------------------------------------------------------------------
1 | import _ from 'underscore';
2 | import docker from '../utils/DockerUtil';
3 |
4 | var ContainerUtil = {
5 | env: function (container) {
6 | if (!container || !container.Config || !container.Config.Env) {
7 | return [];
8 | }
9 | return _.map(container.Config.Env, env => {
10 | var i = env.indexOf('=');
11 | var splits = [env.slice(0, i), env.slice(i + 1)];
12 | return splits;
13 | });
14 | },
15 |
16 | // Provide Foreground options
17 | mode: function (container) {
18 | return [
19 | (container && container.Config) ? container.Config.Tty : true,
20 | (container && container.Config) ? container.Config.OpenStdin : true,
21 | (container && container.HostConfig) ? container.HostConfig.Privileged : false,
22 | (container && container.HostConfig) ? container.HostConfig.RestartPolicy : {MaximumRetryCount: 0, Name: 'no'}
23 | ];
24 | },
25 |
26 | // TODO: inject host here instead of requiring Docker
27 | ports: function (container) {
28 | if (!container || !container.NetworkSettings) {
29 | return {};
30 | }
31 | var res = {};
32 | var ip = docker.host;
33 | var ports = (container.NetworkSettings.Ports) ? container.NetworkSettings.Ports : ((container.HostConfig.PortBindings) ? container.HostConfig.PortBindings : container.Config.ExposedPorts);
34 | _.each(ports, function (value, key) {
35 | var [dockerPort, portType] = key.split('/');
36 | var localUrl = null;
37 | var port = null;
38 | if (value && value.length) {
39 | port = value[0].HostPort;
40 | }
41 | localUrl = (port) ? ip + ':' + port : ip + ':' + '';
42 |
43 | res[dockerPort] = {
44 | url: localUrl,
45 | ip: ip,
46 | port: port,
47 | portType: portType
48 | };
49 | });
50 | return res;
51 | },
52 |
53 | links: function (container) {
54 | if (!container || !container.HostConfig || !container.HostConfig.Links) {
55 | return [];
56 | }
57 |
58 | var res = _.map(container.HostConfig.Links, (link, key) => {
59 | return {
60 | "container": link.split(":")[0].split("/")[1],
61 | "alias": link.split(":")[1].split("/")[2],
62 | }
63 | });
64 |
65 | return res;
66 | },
67 |
68 | normalizeLinksPath: function (container, links) {
69 | var res = _.map(links, (link) => {
70 | return "/"+link.container+":/"+container.Name+"/"+link.alias;
71 | });
72 |
73 | return res;
74 | }
75 |
76 | };
77 |
78 | module.exports = ContainerUtil;
79 |
--------------------------------------------------------------------------------
/src/utils/MetricsUtil.js:
--------------------------------------------------------------------------------
1 | import assign from 'object-assign';
2 | import Mixpanel from 'mixpanel';
3 | import uuid from 'node-uuid';
4 | import fs from 'fs';
5 | import path from 'path';
6 | import util from './Util';
7 | import os from 'os';
8 | import osxRelease from 'osx-release';
9 | var settings;
10 |
11 | try {
12 | settings = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'settings.json'), 'utf8'));
13 | } catch (err) {
14 | settings = {};
15 | }
16 |
17 | var token = process.env.NODE_ENV === 'development' ? settings['mixpanel-dev'] : settings.mixpanel;
18 | if (!token) {
19 | token = 'none';
20 | }
21 |
22 | var mixpanel = Mixpanel.init(token);
23 |
24 | if (localStorage.getItem('metrics.enabled') === null) {
25 | localStorage.setItem('metrics.enabled', true);
26 | }
27 |
28 | var Metrics = {
29 | enabled: function () {
30 | return localStorage.getItem('metrics.enabled') === 'true';
31 | },
32 | setEnabled: function (enabled) {
33 | localStorage.setItem('metrics.enabled', !!enabled);
34 | },
35 | track: function (name, data) {
36 | data = data || {};
37 | if (!name) {
38 | return;
39 | }
40 |
41 | if (localStorage.getItem('metrics.enabled') !== 'true') {
42 | return;
43 | }
44 |
45 | let id = localStorage.getItem('metrics.id');
46 | if (!id) {
47 | id = uuid.v4();
48 | localStorage.setItem('metrics.id', id);
49 | }
50 |
51 | let osName = os.platform();
52 | let osVersion = util.isWindows() ? os.release() : osxRelease(os.release()).version;
53 |
54 | mixpanel.track(name, assign({
55 | distinct_id: id,
56 | version: util.packagejson().version,
57 | 'Operating System': osName,
58 | 'Operating System Version': osVersion,
59 | 'Operating System Architecture': os.arch()
60 | }, data));
61 | },
62 |
63 | };
64 | module.exports = Metrics;
65 |
--------------------------------------------------------------------------------
/src/utils/VirtualBoxUtil.js:
--------------------------------------------------------------------------------
1 | import fs from 'fs';
2 | import path from 'path';
3 | import util from './Util';
4 | import Promise from 'bluebird';
5 |
6 | var VirtualBox = {
7 | command: function () {
8 | if (util.isWindows()) {
9 | if (process.env.VBOX_MSI_INSTALL_PATH) {
10 | return path.join(process.env.VBOX_MSI_INSTALL_PATH, 'VBoxManage.exe');
11 | } else {
12 | return path.join(process.env.VBOX_INSTALL_PATH, 'VBoxManage.exe');
13 | }
14 | } else {
15 | return '/Applications/VirtualBox.app/Contents/MacOS/VBoxManage';
16 | }
17 | },
18 | installed: function () {
19 | if (util.isWindows() && !process.env.VBOX_INSTALL_PATH && !process.env.VBOX_MSI_INSTALL_PATH) {
20 | return false;
21 | }
22 | return fs.existsSync(this.command());
23 | },
24 | active: function () {
25 | return fs.existsSync('/dev/vboxnetctl');
26 | },
27 | version: function () {
28 | return util.execFile([this.command(), '-v']).then(stdout => {
29 | let matchlist = stdout.match(/(\d+\.\d+\.\d+).*/);
30 | if (!matchlist || matchlist.length < 2) {
31 | Promise.reject('VBoxManage -v output format not recognized.');
32 | }
33 | return Promise.resolve(matchlist[1]);
34 | }).catch(() => {
35 | return Promise.resolve(null);
36 | });
37 | },
38 | mountSharedDir: function (vmName, pathName, hostPath) {
39 | return util.execFile([this.command(), 'sharedfolder', 'add', vmName, '--name', pathName, '--hostpath', hostPath, '--automount']);
40 | },
41 | vmExists: function (name) {
42 | return util.execFile([this.command(), 'list', 'vms']).then(out => {
43 | return out.indexOf('"' + name + '"') !== -1;
44 | }).catch(() => {
45 | return false;
46 | });
47 | }
48 | };
49 |
50 | module.exports = VirtualBox;
51 |
--------------------------------------------------------------------------------
/src/utils/WebUtil.js:
--------------------------------------------------------------------------------
1 | import electron from 'electron';
2 | const remote = electron.remote;
3 | const app = remote.app;
4 | import fs from 'fs';
5 | import util from './Util';
6 | import path from 'path';
7 | import bugsnag from 'bugsnag-js';
8 | import metrics from './MetricsUtil';
9 |
10 | var WebUtil = {
11 | addWindowSizeSaving: function () {
12 | window.addEventListener('resize', function () {
13 | fs.writeFileSync(path.join(app.getPath('userData'), 'size'), JSON.stringify({
14 | width: window.outerWidth,
15 | height: window.outerHeight
16 | }));
17 | });
18 | },
19 | addLiveReload: function () {
20 | if (process.env.NODE_ENV === 'development') {
21 | var head = document.getElementsByTagName('head')[0];
22 | var script = document.createElement('script');
23 | script.type = 'text/javascript';
24 | script.src = 'http://localhost:35729/livereload.js';
25 | head.appendChild(script);
26 | }
27 | },
28 | addBugReporting: function () {
29 | var settingsjson = util.settingsjson();
30 |
31 | if (settingsjson.bugsnag) {
32 | bugsnag.apiKey = settingsjson.bugsnag;
33 | bugsnag.autoNotify = true;
34 | bugsnag.releaseStage = process.env.NODE_ENV === 'development' ? 'development' : 'production';
35 | bugsnag.notifyReleaseStages = ['production'];
36 | bugsnag.appVersion = app.getVersion();
37 |
38 | bugsnag.beforeNotify = function(payload) {
39 | if (!metrics.enabled()) {
40 | return false;
41 | }
42 |
43 | payload.stacktrace = util.removeSensitiveData(payload.stacktrace);
44 | payload.context = util.removeSensitiveData(payload.context);
45 | payload.file = util.removeSensitiveData(payload.file);
46 | payload.message = util.removeSensitiveData(payload.message);
47 | payload.url = util.removeSensitiveData(payload.url);
48 | payload.name = util.removeSensitiveData(payload.name);
49 | payload.file = util.removeSensitiveData(payload.file);
50 |
51 | for(var key in payload.metaData) {
52 | payload.metaData[key] = util.removeSensitiveData(payload.metaData[key]);
53 | }
54 | };
55 | }
56 | },
57 | disableGlobalBackspace: function () {
58 | document.onkeydown = function (e) {
59 | e = e || window.event;
60 | var doPrevent;
61 | if (e.keyCode === 8) {
62 | var d = e.srcElement || e.target;
63 | if (d.tagName.toUpperCase() === 'INPUT' || d.tagName.toUpperCase() === 'TEXTAREA') {
64 | doPrevent = d.readOnly || d.disabled;
65 | } else {
66 | doPrevent = true;
67 | }
68 | } else {
69 | doPrevent = false;
70 | }
71 | if (doPrevent) {
72 | e.preventDefault();
73 | }
74 | };
75 | },
76 | };
77 |
78 | module.exports = WebUtil;
79 |
--------------------------------------------------------------------------------
/styles/animation.less:
--------------------------------------------------------------------------------
1 | @-webkit-keyframes spin {
2 | from {
3 | -webkit-transform: rotate(0deg);
4 | }
5 | to {
6 | -webkit-transform: rotate(360deg);
7 | }
8 | }
9 |
10 | @-webkit-keyframes translatewave {
11 | from {
12 | -webkit-transform: translateX(0px);
13 | }
14 | to {
15 | -webkit-transform: translateX(20px);
16 | }
17 | }
18 |
19 | @-webkit-keyframes translatedownload {
20 | 0% {
21 | -webkit-transform: translateY(6px);
22 | opacity: 0;
23 | }
24 | 25% {
25 | opacity: 1;
26 | -webkit-transform: translateY(6px);
27 | }
28 | 50% {
29 | opacity: 1;
30 | -webkit-transform: translateY(20px);
31 | }
32 | 100% {
33 | opacity: 1;
34 | -webkit-transform: translateY(20px);
35 | }
36 | }
37 |
38 | @-webkit-keyframes fadein {
39 | from {
40 | opacity: 0;
41 | }
42 | to {
43 | opacity: 1;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/styles/bootstrap/alerts.less:
--------------------------------------------------------------------------------
1 | //
2 | // Alerts
3 | // --------------------------------------------------
4 |
5 |
6 | // Base styles
7 | // -------------------------
8 |
9 | .alert {
10 | padding: @alert-padding;
11 | margin-bottom: @line-height-computed;
12 | border: 1px solid transparent;
13 | border-radius: @alert-border-radius;
14 |
15 | // Headings for larger alerts
16 | h4 {
17 | margin-top: 0;
18 | // Specified for the h4 to prevent conflicts of changing @headings-color
19 | color: inherit;
20 | }
21 | // Provide class for links that match alerts
22 | .alert-link {
23 | font-weight: @alert-link-font-weight;
24 | }
25 |
26 | // Improve alignment and spacing of inner content
27 | > p,
28 | > ul {
29 | margin-bottom: 0;
30 | }
31 | > p + p {
32 | margin-top: 5px;
33 | }
34 | }
35 |
36 | // Dismissible alerts
37 | //
38 | // Expand the right padding and account for the close button's positioning.
39 |
40 | .alert-dismissable, // The misspelled .alert-dismissable was deprecated in 3.2.0.
41 | .alert-dismissible {
42 | padding-right: (@alert-padding + 20);
43 |
44 | // Adjust close link position
45 | .close {
46 | position: relative;
47 | top: -2px;
48 | right: -21px;
49 | color: inherit;
50 | }
51 | }
52 |
53 | // Alternate styles
54 | //
55 | // Generate contextual modifier classes for colorizing the alert.
56 |
57 | .alert-success {
58 | .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text);
59 | }
60 | .alert-info {
61 | .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text);
62 | }
63 | .alert-warning {
64 | .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text);
65 | }
66 | .alert-danger {
67 | .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text);
68 | }
69 |
--------------------------------------------------------------------------------
/styles/bootstrap/badges.less:
--------------------------------------------------------------------------------
1 | //
2 | // Badges
3 | // --------------------------------------------------
4 |
5 |
6 | // Base class
7 | .badge {
8 | display: inline-block;
9 | min-width: 10px;
10 | padding: 3px 7px;
11 | font-size: @font-size-small;
12 | font-weight: @badge-font-weight;
13 | color: @badge-color;
14 | line-height: @badge-line-height;
15 | vertical-align: baseline;
16 | white-space: nowrap;
17 | text-align: center;
18 | background-color: @badge-bg;
19 | border-radius: @badge-border-radius;
20 |
21 | // Empty badges collapse automatically (not available in IE8)
22 | &:empty {
23 | display: none;
24 | }
25 |
26 | // Quick fix for badges in buttons
27 | .btn & {
28 | position: relative;
29 | top: -1px;
30 | }
31 | .btn-xs & {
32 | top: 0;
33 | padding: 1px 5px;
34 | }
35 |
36 | // Hover state, but only for links
37 | a& {
38 | &:hover,
39 | &:focus {
40 | color: @badge-link-hover-color;
41 | text-decoration: none;
42 | cursor: pointer;
43 | }
44 | }
45 |
46 | // Account for badges in navs
47 | .list-group-item.active > &,
48 | .nav-pills > .active > a > & {
49 | color: @badge-active-color;
50 | background-color: @badge-active-bg;
51 | }
52 | .list-group-item > & {
53 | float: right;
54 | }
55 | .list-group-item > & + & {
56 | margin-right: 5px;
57 | }
58 | .nav-pills > li > a > & {
59 | margin-left: 3px;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/styles/bootstrap/bootstrap.less:
--------------------------------------------------------------------------------
1 | // Core variables and mixins
2 | @import "variables.less";
3 | @import "mixins.less";
4 |
5 | // Reset and dependencies
6 | @import "normalize.less";
7 | @import "print.less";
8 | @import "glyphicons.less";
9 |
10 | // Core CSS
11 | @import "scaffolding.less";
12 | @import "type.less";
13 | @import "code.less";
14 | @import "grid.less";
15 | @import "tables.less";
16 | @import "forms.less";
17 | @import "buttons.less";
18 |
19 | // Components
20 | @import "component-animations.less";
21 | @import "dropdowns.less";
22 | @import "button-groups.less";
23 | @import "input-groups.less";
24 | @import "navs.less";
25 | @import "navbar.less";
26 | @import "breadcrumbs.less";
27 | @import "pagination.less";
28 | @import "pager.less";
29 | @import "labels.less";
30 | @import "badges.less";
31 | @import "jumbotron.less";
32 | @import "thumbnails.less";
33 | @import "alerts.less";
34 | @import "progress-bars.less";
35 | @import "media.less";
36 | @import "list-group.less";
37 | @import "panels.less";
38 | @import "responsive-embed.less";
39 | @import "wells.less";
40 | @import "close.less";
41 |
42 | // Components w/ JavaScript
43 | @import "modals.less";
44 | @import "tooltip.less";
45 | @import "popovers.less";
46 | @import "carousel.less";
47 |
48 | // Utility classes
49 | @import "utilities.less";
50 | @import "responsive-utilities.less";
51 |
--------------------------------------------------------------------------------
/styles/bootstrap/breadcrumbs.less:
--------------------------------------------------------------------------------
1 | //
2 | // Breadcrumbs
3 | // --------------------------------------------------
4 |
5 |
6 | .breadcrumb {
7 | padding: @breadcrumb-padding-vertical @breadcrumb-padding-horizontal;
8 | margin-bottom: @line-height-computed;
9 | list-style: none;
10 | background-color: @breadcrumb-bg;
11 | border-radius: @border-radius-base;
12 |
13 | > li {
14 | display: inline-block;
15 |
16 | + li:before {
17 | content: "@{breadcrumb-separator}\00a0"; // Unicode space added since inline-block means non-collapsing white-space
18 | padding: 0 5px;
19 | color: @breadcrumb-color;
20 | }
21 | }
22 |
23 | > .active {
24 | color: @breadcrumb-active-color;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/styles/bootstrap/close.less:
--------------------------------------------------------------------------------
1 | //
2 | // Close icons
3 | // --------------------------------------------------
4 |
5 |
6 | .close {
7 | float: right;
8 | font-size: (@font-size-base * 1.5);
9 | font-weight: @close-font-weight;
10 | line-height: 1;
11 | color: @close-color;
12 | text-shadow: @close-text-shadow;
13 | .opacity(.2);
14 |
15 | &:hover,
16 | &:focus {
17 | color: @close-color;
18 | text-decoration: none;
19 | cursor: pointer;
20 | .opacity(.5);
21 | }
22 |
23 | // Additional properties for button version
24 | // iOS requires the button element instead of an anchor tag.
25 | // If you want the anchor version, it requires `href="#"`.
26 | button& {
27 | padding: 0;
28 | cursor: pointer;
29 | background: transparent;
30 | border: 0;
31 | -webkit-appearance: none;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/styles/bootstrap/code.less:
--------------------------------------------------------------------------------
1 | //
2 | // Code (inline and block)
3 | // --------------------------------------------------
4 |
5 |
6 | // Inline and block code styles
7 | code,
8 | kbd,
9 | pre,
10 | samp {
11 | font-family: @font-family-monospace;
12 | }
13 |
14 | // Inline code
15 | code {
16 | padding: 2px 4px;
17 | font-size: 90%;
18 | color: @code-color;
19 | background-color: @code-bg;
20 | border-radius: @border-radius-base;
21 | }
22 |
23 | // User input typically entered via keyboard
24 | kbd {
25 | padding: 2px 4px;
26 | font-size: 90%;
27 | color: @kbd-color;
28 | background-color: @kbd-bg;
29 | border-radius: @border-radius-small;
30 | box-shadow: inset 0 -1px 0 rgba(0,0,0,.25);
31 |
32 | kbd {
33 | padding: 0;
34 | font-size: 100%;
35 | font-weight: bold;
36 | box-shadow: none;
37 | }
38 | }
39 |
40 | // Blocks of code
41 | pre {
42 | display: block;
43 | padding: ((@line-height-computed - 1) / 2);
44 | margin: 0 0 (@line-height-computed / 2);
45 | font-size: (@font-size-base - 1); // 14px to 13px
46 | line-height: @line-height-base;
47 | word-break: break-all;
48 | word-wrap: break-word;
49 | color: @pre-color;
50 | background-color: @pre-bg;
51 | border: 1px solid @pre-border-color;
52 | border-radius: @border-radius-base;
53 |
54 | // Account for some code outputs that place code tags in pre tags
55 | code {
56 | padding: 0;
57 | font-size: inherit;
58 | color: inherit;
59 | white-space: pre-wrap;
60 | background-color: transparent;
61 | border-radius: 0;
62 | }
63 | }
64 |
65 | // Enable scrollable blocks of code
66 | .pre-scrollable {
67 | max-height: @pre-scrollable-max-height;
68 | overflow-y: scroll;
69 | }
70 |
--------------------------------------------------------------------------------
/styles/bootstrap/component-animations.less:
--------------------------------------------------------------------------------
1 | //
2 | // Component animations
3 | // --------------------------------------------------
4 |
5 | // Heads up!
6 | //
7 | // We don't use the `.opacity()` mixin here since it causes a bug with text
8 | // fields in IE7-8. Source: https://github.com/twbs/bootstrap/pull/3552.
9 |
10 | .fade {
11 | opacity: 0;
12 | .transition(opacity .15s linear);
13 | &.in {
14 | opacity: 1;
15 | }
16 | }
17 |
18 | .collapse {
19 | display: none;
20 | visibility: hidden;
21 |
22 | &.in { display: block; visibility: visible; }
23 | tr&.in { display: table-row; }
24 | tbody&.in { display: table-row-group; }
25 | }
26 |
27 | .collapsing {
28 | position: relative;
29 | height: 0;
30 | overflow: hidden;
31 | .transition-property(~"height, visibility");
32 | .transition-duration(.35s);
33 | .transition-timing-function(ease);
34 | }
35 |
--------------------------------------------------------------------------------
/styles/bootstrap/grid.less:
--------------------------------------------------------------------------------
1 | //
2 | // Grid system
3 | // --------------------------------------------------
4 |
5 |
6 | // Container widths
7 | //
8 | // Set the container width, and override it for fixed navbars in media queries.
9 |
10 | .container {
11 | .container-fixed();
12 |
13 | @media (min-width: @screen-sm-min) {
14 | width: @container-sm;
15 | }
16 | @media (min-width: @screen-md-min) {
17 | width: @container-md;
18 | }
19 | @media (min-width: @screen-lg-min) {
20 | width: @container-lg;
21 | }
22 | }
23 |
24 |
25 | // Fluid container
26 | //
27 | // Utilizes the mixin meant for fixed width containers, but without any defined
28 | // width for fluid, full width layouts.
29 |
30 | .container-fluid {
31 | .container-fixed();
32 | }
33 |
34 |
35 | // Row
36 | //
37 | // Rows contain and clear the floats of your columns.
38 |
39 | .row {
40 | .make-row();
41 | }
42 |
43 |
44 | // Columns
45 | //
46 | // Common styles for small and large grid columns
47 |
48 | .make-grid-columns();
49 |
50 |
51 | // Extra small grid
52 | //
53 | // Columns, offsets, pushes, and pulls for extra small devices like
54 | // smartphones.
55 |
56 | .make-grid(xs);
57 |
58 |
59 | // Small grid
60 | //
61 | // Columns, offsets, pushes, and pulls for the small device range, from phones
62 | // to tablets.
63 |
64 | @media (min-width: @screen-sm-min) {
65 | .make-grid(sm);
66 | }
67 |
68 |
69 | // Medium grid
70 | //
71 | // Columns, offsets, pushes, and pulls for the desktop device range.
72 |
73 | @media (min-width: @screen-md-min) {
74 | .make-grid(md);
75 | }
76 |
77 |
78 | // Large grid
79 | //
80 | // Columns, offsets, pushes, and pulls for the large desktop device range.
81 |
82 | @media (min-width: @screen-lg-min) {
83 | .make-grid(lg);
84 | }
85 |
--------------------------------------------------------------------------------
/styles/bootstrap/jumbotron.less:
--------------------------------------------------------------------------------
1 | //
2 | // Jumbotron
3 | // --------------------------------------------------
4 |
5 |
6 | .jumbotron {
7 | padding: @jumbotron-padding (@jumbotron-padding / 2);
8 | margin-bottom: @jumbotron-padding;
9 | color: @jumbotron-color;
10 | background-color: @jumbotron-bg;
11 |
12 | h1,
13 | .h1 {
14 | color: @jumbotron-heading-color;
15 | }
16 | p {
17 | margin-bottom: (@jumbotron-padding / 2);
18 | font-size: @jumbotron-font-size;
19 | font-weight: 200;
20 | }
21 |
22 | > hr {
23 | border-top-color: darken(@jumbotron-bg, 10%);
24 | }
25 |
26 | .container &,
27 | .container-fluid & {
28 | border-radius: @border-radius-large; // Only round corners at higher resolutions if contained in a container
29 | }
30 |
31 | .container {
32 | max-width: 100%;
33 | }
34 |
35 | @media screen and (min-width: @screen-sm-min) {
36 | padding: (@jumbotron-padding * 1.6) 0;
37 |
38 | .container &,
39 | .container-fluid & {
40 | padding-left: (@jumbotron-padding * 2);
41 | padding-right: (@jumbotron-padding * 2);
42 | }
43 |
44 | h1,
45 | .h1 {
46 | font-size: (@font-size-base * 4.5);
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/styles/bootstrap/labels.less:
--------------------------------------------------------------------------------
1 | //
2 | // Labels
3 | // --------------------------------------------------
4 |
5 | .label {
6 | display: inline;
7 | padding: .2em .6em .3em;
8 | font-size: 75%;
9 | font-weight: bold;
10 | line-height: 1;
11 | color: @label-color;
12 | text-align: center;
13 | white-space: nowrap;
14 | vertical-align: baseline;
15 | border-radius: .25em;
16 |
17 | // Add hover effects, but only for links
18 | a& {
19 | &:hover,
20 | &:focus {
21 | color: @label-link-hover-color;
22 | text-decoration: none;
23 | cursor: pointer;
24 | }
25 | }
26 |
27 | // Empty labels collapse automatically (not available in IE8)
28 | &:empty {
29 | display: none;
30 | }
31 |
32 | // Quick fix for labels in buttons
33 | .btn & {
34 | position: relative;
35 | top: -1px;
36 | }
37 | }
38 |
39 | // Colors
40 | // Contextual variations (linked labels get darker on :hover)
41 |
42 | .label-default {
43 | .label-variant(@label-default-bg);
44 | }
45 |
46 | .label-primary {
47 | .label-variant(@label-primary-bg);
48 | }
49 |
50 | .label-success {
51 | .label-variant(@label-success-bg);
52 | }
53 |
54 | .label-info {
55 | .label-variant(@label-info-bg);
56 | }
57 |
58 | .label-warning {
59 | .label-variant(@label-warning-bg);
60 | }
61 |
62 | .label-danger {
63 | .label-variant(@label-danger-bg);
64 | }
65 |
--------------------------------------------------------------------------------
/styles/bootstrap/list-group.less:
--------------------------------------------------------------------------------
1 | //
2 | // List groups
3 | // --------------------------------------------------
4 |
5 |
6 | // Base class
7 | //
8 | // Easily usable on , , or .
9 |
10 | .list-group {
11 | // No need to set list-style: none; since .list-group-item is block level
12 | margin-bottom: 20px;
13 | padding-left: 0; // reset padding because ul and ol
14 | }
15 |
16 |
17 | // Individual list items
18 | //
19 | // Use on `li`s or `div`s within the `.list-group` parent.
20 |
21 | .list-group-item {
22 | position: relative;
23 | display: block;
24 | padding: 10px 15px;
25 | // Place the border on the list items and negative margin up for better styling
26 | margin-bottom: -1px;
27 | background-color: @list-group-bg;
28 | border: 1px solid @list-group-border;
29 |
30 | // Round the first and last items
31 | &:first-child {
32 | .border-top-radius(@list-group-border-radius);
33 | }
34 | &:last-child {
35 | margin-bottom: 0;
36 | .border-bottom-radius(@list-group-border-radius);
37 | }
38 | }
39 |
40 |
41 | // Linked list items
42 | //
43 | // Use anchor elements instead of `li`s or `div`s to create linked list items.
44 | // Includes an extra `.active` modifier class for showing selected items.
45 |
46 | a.list-group-item {
47 | color: @list-group-link-color;
48 |
49 | .list-group-item-heading {
50 | color: @list-group-link-heading-color;
51 | }
52 |
53 | // Hover state
54 | &:hover,
55 | &:focus {
56 | text-decoration: none;
57 | color: @list-group-link-hover-color;
58 | background-color: @list-group-hover-bg;
59 | }
60 | }
61 |
62 | .list-group-item {
63 | // Disabled state
64 | &.disabled,
65 | &.disabled:hover,
66 | &.disabled:focus {
67 | background-color: @list-group-disabled-bg;
68 | color: @list-group-disabled-color;
69 | cursor: @cursor-disabled;
70 |
71 | // Force color to inherit for custom content
72 | .list-group-item-heading {
73 | color: inherit;
74 | }
75 | .list-group-item-text {
76 | color: @list-group-disabled-text-color;
77 | }
78 | }
79 |
80 | // Active class on item itself, not parent
81 | &.active,
82 | &.active:hover,
83 | &.active:focus {
84 | z-index: 2; // Place active items above their siblings for proper border styling
85 | color: @list-group-active-color;
86 | background-color: @list-group-active-bg;
87 | border-color: @list-group-active-border;
88 |
89 | // Force color to inherit for custom content
90 | .list-group-item-heading,
91 | .list-group-item-heading > small,
92 | .list-group-item-heading > .small {
93 | color: inherit;
94 | }
95 | .list-group-item-text {
96 | color: @list-group-active-text-color;
97 | }
98 | }
99 | }
100 |
101 |
102 | // Contextual variants
103 | //
104 | // Add modifier classes to change text and background color on individual items.
105 | // Organizationally, this must come after the `:hover` states.
106 |
107 | .list-group-item-variant(success; @state-success-bg; @state-success-text);
108 | .list-group-item-variant(info; @state-info-bg; @state-info-text);
109 | .list-group-item-variant(warning; @state-warning-bg; @state-warning-text);
110 | .list-group-item-variant(danger; @state-danger-bg; @state-danger-text);
111 |
112 |
113 | // Custom content options
114 | //
115 | // Extra classes for creating well-formatted content within `.list-group-item`s.
116 |
117 | .list-group-item-heading {
118 | margin-top: 0;
119 | margin-bottom: 5px;
120 | }
121 | .list-group-item-text {
122 | margin-bottom: 0;
123 | line-height: 1.3;
124 | }
125 |
--------------------------------------------------------------------------------
/styles/bootstrap/media.less:
--------------------------------------------------------------------------------
1 | .media {
2 | // Proper spacing between instances of .media
3 | margin-top: 15px;
4 |
5 | &:first-child {
6 | margin-top: 0;
7 | }
8 | }
9 |
10 | .media-right,
11 | .media > .pull-right {
12 | padding-left: 10px;
13 | }
14 |
15 | .media-left,
16 | .media > .pull-left {
17 | padding-right: 10px;
18 | }
19 |
20 | .media-left,
21 | .media-right,
22 | .media-body {
23 | display: table-cell;
24 | vertical-align: top;
25 | }
26 |
27 | .media-middle {
28 | vertical-align: middle;
29 | }
30 |
31 | .media-bottom {
32 | vertical-align: bottom;
33 | }
34 |
35 | // Reset margins on headings for tighter default spacing
36 | .media-heading {
37 | margin-top: 0;
38 | margin-bottom: 5px;
39 | }
40 |
41 | // Media list variation
42 | //
43 | // Undo default ul/ol styles
44 | .media-list {
45 | padding-left: 0;
46 | list-style: none;
47 | }
48 |
--------------------------------------------------------------------------------
/styles/bootstrap/mixins.less:
--------------------------------------------------------------------------------
1 | // Mixins
2 | // --------------------------------------------------
3 |
4 | // Utilities
5 | @import "mixins/hide-text.less";
6 | @import "mixins/opacity.less";
7 | @import "mixins/image.less";
8 | @import "mixins/labels.less";
9 | @import "mixins/reset-filter.less";
10 | @import "mixins/resize.less";
11 | @import "mixins/responsive-visibility.less";
12 | @import "mixins/size.less";
13 | @import "mixins/tab-focus.less";
14 | @import "mixins/text-emphasis.less";
15 | @import "mixins/text-overflow.less";
16 | @import "mixins/vendor-prefixes.less";
17 |
18 | // Components
19 | @import "mixins/alerts.less";
20 | @import "mixins/buttons.less";
21 | @import "mixins/panels.less";
22 | @import "mixins/pagination.less";
23 | @import "mixins/list-group.less";
24 | @import "mixins/nav-divider.less";
25 | @import "mixins/forms.less";
26 | @import "mixins/progress-bar.less";
27 | @import "mixins/table-row.less";
28 |
29 | // Skins
30 | @import "mixins/background-variant.less";
31 | @import "mixins/border-radius.less";
32 | @import "mixins/gradients.less";
33 |
34 | // Layout
35 | @import "mixins/clearfix.less";
36 | @import "mixins/center-block.less";
37 | @import "mixins/nav-vertical-align.less";
38 | @import "mixins/grid-framework.less";
39 | @import "mixins/grid.less";
40 |
--------------------------------------------------------------------------------
/styles/bootstrap/mixins/alerts.less:
--------------------------------------------------------------------------------
1 | // Alerts
2 |
3 | .alert-variant(@background; @border; @text-color) {
4 | background-color: @background;
5 | border-color: @border;
6 | color: @text-color;
7 |
8 | hr {
9 | border-top-color: darken(@border, 5%);
10 | }
11 | .alert-link {
12 | color: darken(@text-color, 10%);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/styles/bootstrap/mixins/background-variant.less:
--------------------------------------------------------------------------------
1 | // Contextual backgrounds
2 |
3 | .bg-variant(@color) {
4 | background-color: @color;
5 | a&:hover {
6 | background-color: darken(@color, 10%);
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/styles/bootstrap/mixins/border-radius.less:
--------------------------------------------------------------------------------
1 | // Single side border-radius
2 |
3 | .border-top-radius(@radius) {
4 | border-top-right-radius: @radius;
5 | border-top-left-radius: @radius;
6 | }
7 | .border-right-radius(@radius) {
8 | border-bottom-right-radius: @radius;
9 | border-top-right-radius: @radius;
10 | }
11 | .border-bottom-radius(@radius) {
12 | border-bottom-right-radius: @radius;
13 | border-bottom-left-radius: @radius;
14 | }
15 | .border-left-radius(@radius) {
16 | border-bottom-left-radius: @radius;
17 | border-top-left-radius: @radius;
18 | }
19 |
--------------------------------------------------------------------------------
/styles/bootstrap/mixins/buttons.less:
--------------------------------------------------------------------------------
1 | // Button variants
2 | //
3 | // Easily pump out default styles, as well as :hover, :focus, :active,
4 | // and disabled options for all buttons
5 |
6 | .button-variant(@color; @background; @border) {
7 | color: @color;
8 | background-color: @background;
9 | border-color: @border;
10 |
11 | &:hover,
12 | &:focus,
13 | &.focus,
14 | &:active,
15 | &.active,
16 | .open > .dropdown-toggle& {
17 | color: @color;
18 | background-color: darken(@background, 10%);
19 | border-color: darken(@border, 12%);
20 | }
21 | &:active,
22 | &.active,
23 | .open > .dropdown-toggle& {
24 | background-image: none;
25 | }
26 | &.disabled,
27 | &[disabled],
28 | fieldset[disabled] & {
29 | &,
30 | &:hover,
31 | &:focus,
32 | &.focus,
33 | &:active,
34 | &.active {
35 | background-color: @background;
36 | border-color: @border;
37 | }
38 | }
39 |
40 | .badge {
41 | color: @background;
42 | background-color: @color;
43 | }
44 | }
45 |
46 | // Button sizes
47 | .button-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {
48 | padding: @padding-vertical @padding-horizontal;
49 | font-size: @font-size;
50 | line-height: @line-height;
51 | border-radius: @border-radius;
52 | }
53 |
--------------------------------------------------------------------------------
/styles/bootstrap/mixins/center-block.less:
--------------------------------------------------------------------------------
1 | // Center-align a block level element
2 |
3 | .center-block() {
4 | display: block;
5 | margin-left: auto;
6 | margin-right: auto;
7 | }
8 |
--------------------------------------------------------------------------------
/styles/bootstrap/mixins/clearfix.less:
--------------------------------------------------------------------------------
1 | // Clearfix
2 | //
3 | // For modern browsers
4 | // 1. The space content is one way to avoid an Opera bug when the
5 | // contenteditable attribute is included anywhere else in the document.
6 | // Otherwise it causes space to appear at the top and bottom of elements
7 | // that are clearfixed.
8 | // 2. The use of `table` rather than `block` is only necessary if using
9 | // `:before` to contain the top-margins of child elements.
10 | //
11 | // Source: http://nicolasgallagher.com/micro-clearfix-hack/
12 |
13 | .clearfix() {
14 | &:before,
15 | &:after {
16 | content: " "; // 1
17 | display: table; // 2
18 | }
19 | &:after {
20 | clear: both;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/styles/bootstrap/mixins/forms.less:
--------------------------------------------------------------------------------
1 | // Form validation states
2 | //
3 | // Used in forms.less to generate the form validation CSS for warnings, errors,
4 | // and successes.
5 |
6 | .form-control-validation(@text-color: #555; @border-color: #ccc; @background-color: #f5f5f5) {
7 | // Color the label and help text
8 | .help-block,
9 | .control-label,
10 | .radio,
11 | .checkbox,
12 | .radio-inline,
13 | .checkbox-inline,
14 | &.radio label,
15 | &.checkbox label,
16 | &.radio-inline label,
17 | &.checkbox-inline label {
18 | color: @text-color;
19 | }
20 | // Set the border and box shadow on specific inputs to match
21 | .form-control {
22 | border-color: @border-color;
23 | .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work
24 | &:focus {
25 | border-color: darken(@border-color, 10%);
26 | @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@border-color, 20%);
27 | .box-shadow(@shadow);
28 | }
29 | }
30 | // Set validation states also for addons
31 | .input-group-addon {
32 | color: @text-color;
33 | border-color: @border-color;
34 | background-color: @background-color;
35 | }
36 | // Optional feedback icon
37 | .form-control-feedback {
38 | color: @text-color;
39 | }
40 | }
41 |
42 |
43 | // Form control focus state
44 | //
45 | // Generate a customized focus state and for any input with the specified color,
46 | // which defaults to the `@input-border-focus` variable.
47 | //
48 | // We highly encourage you to not customize the default value, but instead use
49 | // this to tweak colors on an as-needed basis. This aesthetic change is based on
50 | // WebKit's default styles, but applicable to a wider range of browsers. Its
51 | // usability and accessibility should be taken into account with any change.
52 | //
53 | // Example usage: change the default blue border and shadow to white for better
54 | // contrast against a dark gray background.
55 | .form-control-focus(@color: @input-border-focus) {
56 | @color-rgba: rgba(red(@color), green(@color), blue(@color), .6);
57 | &:focus {
58 | border-color: @color;
59 | outline: 0;
60 | .box-shadow(~"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px @{color-rgba}");
61 | }
62 | }
63 |
64 | // Form control sizing
65 | //
66 | // Relative text size, padding, and border-radii changes for form controls. For
67 | // horizontal sizing, wrap controls in the predefined grid classes. `