diff --git a/.circleci/config.yml b/.circleci/config.yml index fb64f5eb..755a8909 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -39,7 +39,7 @@ aliases: curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.5/install.sh | bash export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" - nvm install 12.15.0 && nvm alias default 12.15.0 + nvm install 12.15.0 && nvm name default 12.15.0 # Each step uses the same `$BASH_ENV`, so need to modify it echo 'export NVM_DIR="$HOME/.nvm"' >> $BASH_ENV echo "[ -s \"$NVM_DIR/nvm.sh\" ] && . \"$NVM_DIR/nvm.sh\"" >> $BASH_ENV diff --git a/.dredd/hooks/capabilities.go b/.dredd/hooks/capabilities.go index e41ee884..be793863 100644 --- a/.dredd/hooks/capabilities.go +++ b/.dredd/hooks/capabilities.go @@ -100,7 +100,7 @@ func resolveCapability(caps []string, resolved []string, uid string) { case "template": res, err := store.Sql().Exec( "insert into project__template "+ - "(project_id, inventory_id, repository_id, environment_id, alias, playbook, arguments, override_args, description, view_id) "+ + "(project_id, inventory_id, repository_id, environment_id, name, playbook, arguments, allow_override_args_in_task, description, view_id) "+ "values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", userProject.ID, inventoryID, repoID, environmentID, "Test-"+uid, "test-playbook.yml", "", false, "Hello, World!", view.ID) printError(err) diff --git a/.gitignore b/.gitignore index 1e45aa56..cca257b4 100644 --- a/.gitignore +++ b/.gitignore @@ -8,12 +8,14 @@ web2/.nyc_output web2/dist/**/* /config.json /.dredd/config.json -/database.bolt /database.boltdb +/database.boltdb.lock +/database2.boltdb .DS_Store node_modules/ -.idea/ +/.idea/ +/semaphore.iml /bin/ *-packr.go diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3326b537..0fa3d217 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -51,7 +51,7 @@ echo "create database semaphore;" | mysql -uroot -p ``` task compile go run cli/main.go setup -go run cli/main.go --config ./config.json +go run cli/main.go service --config ./config.json ``` Open [localhost:3000](http://localhost:3000) diff --git a/README.md b/README.md index d61106a5..2a80a123 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,22 @@ # Ansible Semaphore [![Circle CI](https://circleci.com/gh/ansible-semaphore/semaphore.svg?style=svg&circle-token=3702872acf2bec629017fa7dd99fdbea56aef7df)](https://circleci.com/gh/ansible-semaphore/semaphore) -[![Codacy Badge](https://api.codacy.com/project/badge/Grade/89e0129c6ba64fe2b1ebe983f72a4eff)](https://www.codacy.com/app/ansible-semaphore/semaphore?utm_source=github.com&utm_medium=referral&utm_content=ansible-semaphore/semaphore&utm_campaign=Badge_Grade) -[![Codacy Badge](https://api.codacy.com/project/badge/Coverage/89e0129c6ba64fe2b1ebe983f72a4eff)](https://www.codacy.com/app/ansible-semaphore/semaphore?utm_source=github.com&utm_medium=referral&utm_content=ansible-semaphore/semaphore&utm_campaign=Badge_Coverage) -[![Join the chat at https://gitter.im/AnsibleSemaphore/semaphore](https://badges.gitter.im/AnsibleSemaphore/semaphore.svg)](https://gitter.im/AnsibleSemaphore/semaphore?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - -Follow Semaphore on Twitter ([AnsibleSem](https://twitter.com/AnsibleSem)) and StackShare ([ansible-semaphore](https://stackshare.io/ansible-semaphore)). +[![Twitter](https://img.shields.io/twitter/follow/AnsibleSem?style=social&logo=twitter)](https://twitter.com/AnsibleSem) +[![Snap](https://img.shields.io/badge/snap-semaphore-005c63)](https://snapcraft.io/semaphore) +[![StackShare](https://img.shields.io/badge/tech-stack-008ff9)](https://stackshare.io/ansible-semaphore) +[![Join the chat at https://gitter.im/AnsibleSemaphore/semaphore](https://img.shields.io/gitter/room/AnsibleSemaphore/semaphore?logo=gitter)](https://gitter.im/AnsibleSemaphore/semaphore?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + + + Ansible Semaphore is a modern UI for Ansible. It lets you easily run Ansible playbooks, get notifications about fails, control access to deployment system. If your project has grown and deploying from the terminal is no longer for you then Ansible Semaphore is what you need. +Follow Semaphore on Twitter ([AnsibleSem](https://twitter.com/AnsibleSem)) and StackShare ([ansible-semaphore](https://stackshare.io/ansible-semaphore)). + ![responsive-ui-phone1](https://user-images.githubusercontent.com/914224/134777345-8789d9e4-ff0d-439c-b80e-ddc56b74fcee.png) + + + + + + + + + + + + + diff --git a/web2/src/App.vue b/web2/src/App.vue index 8187c6a4..9ef5adfb 100644 --- a/web2/src/App.vue +++ b/web2/src/App.vue @@ -51,7 +51,7 @@ class="breadcrumbs__item breadcrumbs__item--link" :to="`/project/${projectId}/templates/${template ? template.id : null}`" @click="taskLogDialog = false" - >{{ template ? template.alias : null }} + >{{ template ? template.name : null }} mdi-chevron-right Task #{{ task ? task.id : null }} @@ -162,7 +162,7 @@ {{ item.name }} - + mdi-plus @@ -187,6 +187,18 @@ + + + +
DEMO MODE
+
    +
  • You can run any tasks
  • +
  • You have read-only access
  • +
+
+
+
+ mdi-view-dashboard @@ -243,7 +255,7 @@ - Playbook Repositories + Repositories @@ -279,7 +291,7 @@ - + mdi-account-multiple @@ -299,27 +311,28 @@ - - - mdi-information - + + --> @@ -539,6 +552,7 @@ export default { return { drawer: null, user: null, + systemInfo: null, state: 'loading', snackbar: false, snackbarText: '', @@ -809,11 +823,18 @@ export default { if (!this.isAuthenticated) { return; } + this.user = (await axios({ method: 'get', url: '/api/user', responseType: 'json', })).data; + + this.systemInfo = (await axios({ + method: 'get', + url: '/api/info', + responseType: 'json', + })).data; }, getProjectColor(projectData) { diff --git a/web2/src/components/CronInput.vue b/web2/src/components/CronInput.vue new file mode 100644 index 00000000..e69de29b diff --git a/web2/src/components/EditDialog.vue b/web2/src/components/EditDialog.vue index 6ceccbea..46f3eb69 100644 --- a/web2/src/components/EditDialog.vue +++ b/web2/src/components/EditDialog.vue @@ -41,6 +41,7 @@ Can use used in tandem with ItemFormBase.js. See KeyForm.vue for example. color="blue darken-1" text @click="needSave = true" + v-if="saveButtonText != null" > {{ saveButtonText }} diff --git a/web2/src/components/EnvironmentForm.vue b/web2/src/components/EnvironmentForm.vue index 71a6e7e9..9bf62dfd 100644 --- a/web2/src/components/EnvironmentForm.vue +++ b/web2/src/components/EnvironmentForm.vue @@ -33,15 +33,11 @@ type="info" class="mt-4" > - Environment must be valid JSON. You may use the key ENV to pass - environment variables to ansible-playbook. + Environment must be valid JSON. Example:
{
   "var_available_in_playbook_1": 1245,
   "var_available_in_playbook_2": "test",
-  "ENV": {
-    "VAR1": "Read by lookup('env', 'VAR1')"
-  }
 }
diff --git a/web2/src/components/ItemFormBase.js b/web2/src/components/ItemFormBase.js index 85004b86..ca2acf2a 100644 --- a/web2/src/components/ItemFormBase.js +++ b/web2/src/components/ItemFormBase.js @@ -167,7 +167,9 @@ export default { }); } catch (err) { this.formError = getErrorMessage(err); - this.$emit('error', {}); + this.$emit('error', { + message: this.formError, + }); } finally { this.formSaving = false; } diff --git a/web2/src/components/ItemListPageBase.js b/web2/src/components/ItemListPageBase.js index be361e71..b37cb373 100644 --- a/web2/src/components/ItemListPageBase.js +++ b/web2/src/components/ItemListPageBase.js @@ -2,12 +2,15 @@ import axios from 'axios'; import EventBus from '@/event-bus'; import EditDialog from '@/components/EditDialog.vue'; import YesNoDialog from '@/components/YesNoDialog.vue'; +import ObjectRefsDialog from '@/components/ObjectRefsDialog.vue'; + import { getErrorMessage } from '@/lib/error'; export default { components: { YesNoDialog, EditDialog, + ObjectRefsDialog, }, props: { @@ -19,9 +22,13 @@ export default { return { headers: this.getHeaders(), items: null, + itemId: null, editDialog: null, deleteItemDialog: null, + + itemRefs: null, + itemRefsDialog: null, }; }, @@ -32,7 +39,8 @@ export default { methods: { // eslint-disable-next-line no-empty-function - async beforeLoadItems() { }, + async beforeLoadItems() { + }, getSingleItemUrl() { throw new Error('Not implemented'); @@ -54,8 +62,27 @@ export default { await this.loadItems(); }, - askDeleteItem(itemId) { + async askDeleteItem(itemId) { this.itemId = itemId; + + try { + this.itemRefs = (await axios({ + method: 'get', + url: `${this.getSingleItemUrl()}/refs`, + responseType: 'json', + })).data; + + if (this.itemRefs.templates.length > 0 + || this.itemRefs.repositories.length > 0 + || this.itemRefs.inventories.length > 0 + || this.itemRefs.schedules.length > 0) { + this.itemRefsDialog = true; + return; + } + } catch (e) { + // Do nothing + } + this.deleteItemDialog = true; }, diff --git a/web2/src/components/KeyForm.vue b/web2/src/components/KeyForm.vue index 8d186409..052f77ed 100644 --- a/web2/src/components/KeyForm.vue +++ b/web2/src/components/KeyForm.vue @@ -31,22 +31,6 @@ :disabled="formSaving || !canEditSecrets" /> - - - - + + + + + + + + + + + + + + + + Can't delete the {{ objectTitle }} + + + + + + + + Close + + + + + diff --git a/web2/src/components/ObjectRefsView.vue b/web2/src/components/ObjectRefsView.vue new file mode 100644 index 00000000..e37dc688 --- /dev/null +++ b/web2/src/components/ObjectRefsView.vue @@ -0,0 +1,63 @@ + + + diff --git a/web2/src/components/RepositoryForm.vue b/web2/src/components/RepositoryForm.vue index 21f60197..e93a58df 100644 --- a/web2/src/components/RepositoryForm.vue +++ b/web2/src/components/RepositoryForm.vue @@ -22,7 +22,7 @@ + + +
+ + + + + + + + + + + + + + + + Cancel + + + {{ editedVarIndex == null ? 'Add' : 'Save' }} + + + + +
+ Survey Variables + + + {{ v.title }} + + + + +
+
+ + + diff --git a/web2/src/components/TaskForm.vue b/web2/src/components/TaskForm.vue index 4e851b46..d4e913e3 100644 --- a/web2/src/components/TaskForm.vue +++ b/web2/src/components/TaskForm.vue @@ -1,61 +1,127 @@ diff --git a/web2/src/views/project/Repositories.vue b/web2/src/views/project/Repositories.vue index 909f022e..95f045ca 100644 --- a/web2/src/views/project/Repositories.vue +++ b/web2/src/views/project/Repositories.vue @@ -18,6 +18,13 @@ + + - Playbook Repositories + Repositories + + diff --git a/web2/src/views/project/Settings.vue b/web2/src/views/project/Settings.vue index 65dff562..7bf9d116 100644 --- a/web2/src/views/project/Settings.vue +++ b/web2/src/views/project/Settings.vue @@ -21,7 +21,7 @@
- +
@@ -78,17 +78,24 @@ export default { EventBus.$emit('i-show-drawer'); }, - async saveProject() { - const item = await this.$refs.form.save(); - if (!item) { - return; - } + onError(e) { + EventBus.$emit('i-snackbar', { + color: 'error', + text: e.message, + }); + }, + + onSave(e) { EventBus.$emit('i-project', { action: 'edit', - item, + item: e.item, }); }, + async saveProject() { + await this.$refs.form.save(); + }, + async deleteProject() { try { await axios({ diff --git a/web2/src/views/project/TemplateView.vue b/web2/src/views/project/TemplateView.vue index f5a2c02c..b3f6268e 100644 --- a/web2/src/views/project/TemplateView.vue +++ b/web2/src/views/project/TemplateView.vue @@ -1,105 +1,112 @@