diff --git a/static/directives/manage-trigger-githost.html b/static/directives/manage-trigger-githost.html deleted file mode 100644 index 6746085b4..000000000 --- a/static/directives/manage-trigger-githost.html +++ /dev/null @@ -1,333 +0,0 @@ -
-
- - -
-
-

Select {{ namespaceTitle }}

- - Please select the {{ namespaceTitle }} under which the repository lives - - -
-
- - -
-
- - - - - - - - - - - - - -
- {{ namespaceTitle }} -
- - - - {{ namespace.id }} -
-
-
No matching {{ namespaceTitle }} found.
-
Try expanding your filtering terms.
-
-
- -
- Retrieving {{ namespaceTitle }}s -
- -
- - -
- -
-

Select Repository

- - Select a repository in - - {{ local.selectedNamespace.id }} - - -
-
- - -
- -
-
-
- - - - - - - - - - - - - - - -
- Repository Name - - Last Updated -
- - - - - - - {{ repository.name }} - - -
-
-
No matching repositories found.
-
Try expanding your filtering terms.
-
-
- -
- Retrieving repositories -
- - -
- - -
-
-

Configure Trigger

- - Configure trigger options for - - {{ local.selectedNamespace.id }}/{{ local.selectedRepository.name }} - - -
- -
-
- -
-
- -
- Retrieving repository refs -
- -
- - -
-
-
- {{ local.dockerfileLocations.message }} -
-
- -
-

Select Dockerfile

- - Please select the location of the Dockerfile to build when this trigger is invoked {{ local.paths }} - - - -
- -
- Retrieving Dockerfile locations -
- -
- - -
- -
-

Verification Error

- - There was an error when verifying the state of - {{ local.selectedNamespace.id }}/{{ local.selectedRepository.name }} - - - {{ local.triggerAnalysis.message }} -
- - -
-

Verification Warning

- {{ local.triggerAnalysis.message }} -
- - -
-

Ready to go!

- Click "Create Trigger" to complete setup of this build trigger -
- - -
-

Robot Account Required

-

The selected Dockerfile in the selected repository depends upon a private base image

-

A robot account with access to the base image is required to setup this trigger, but you are not the administrator of this namespace.

-

Administrative access is required to continue to ensure security of the robot credentials.

-
- - -
-

Select Robot Account

- - The selected Dockerfile in the selected repository depends upon a private base image. Select a robot account with access: - - -
-
- - -
-
- - - - - - - - - - - - - -
- Robot Account - - Has Read Access -
- - - - - Can Read - Read access will be added if selected -
-
-
No matching robot accounts found.
-
Try expanding your filtering terms.
-
-
- - -
- -
\ No newline at end of file diff --git a/static/js/directives/ui/linear-workflow/linear-workflow-section.component.html b/static/js/directives/ui/linear-workflow/linear-workflow-section.component.html new file mode 100644 index 000000000..e69de29bb diff --git a/static/js/directives/ui/linear-workflow/linear-workflow-section.component.spec.ts b/static/js/directives/ui/linear-workflow/linear-workflow-section.component.spec.ts new file mode 100644 index 000000000..e69de29bb diff --git a/static/js/directives/ui/linear-workflow/linear-workflow-section.component.ts b/static/js/directives/ui/linear-workflow/linear-workflow-section.component.ts new file mode 100644 index 000000000..e69de29bb diff --git a/static/js/directives/ui/linear-workflow/linear-workflow.component.html b/static/js/directives/ui/linear-workflow/linear-workflow.component.html new file mode 100644 index 000000000..e69de29bb diff --git a/static/js/directives/ui/linear-workflow/linear-workflow.component.spec.ts b/static/js/directives/ui/linear-workflow/linear-workflow.component.spec.ts new file mode 100644 index 000000000..e69de29bb diff --git a/static/js/directives/ui/linear-workflow/linear-workflow.component.ts b/static/js/directives/ui/linear-workflow/linear-workflow.component.ts new file mode 100644 index 000000000..e69de29bb diff --git a/static/js/directives/ui/manage-trigger-githost.js b/static/js/directives/ui/manage-trigger-githost.js deleted file mode 100644 index 3a4a24f4b..000000000 --- a/static/js/directives/ui/manage-trigger-githost.js +++ /dev/null @@ -1,306 +0,0 @@ -/** - * An element which displays the setup and management workflow for a normal SCM git trigger. - */ -angular.module('quay').directive('manageTriggerGithost', function () { - var directiveDefinitionObject = { - priority: 0, - templateUrl: '/static/directives/manage-trigger-githost.html', - replace: false, - transclude: true, - restrict: 'C', - scope: { - 'repository': '=repository', - 'trigger': '=trigger', - 'activateTrigger': '&activateTrigger' - }, - controller: function($scope, $element, ApiService, TableService, TriggerService, RolesService) { - $scope.TableService = TableService; - - $scope.config = {}; - $scope.local = {}; - $scope.currentState = null; - - $scope.namespacesPerPage = 10; - $scope.repositoriesPerPage = 10; - $scope.robotsPerPage = 10; - - $scope.local.namespaceOptions = { - 'filter': '', - 'predicate': 'score', - 'reverse': false, - 'page': 0 - }; - - $scope.local.repositoryOptions = { - 'filter': '', - 'predicate': 'last_updated', - 'reverse': false, - 'page': 0, - 'hideStale': true - }; - - $scope.local.robotOptions = { - 'filter': '', - 'predicate': 'can_read', - 'reverse': false, - 'page': 0 - }; - - $scope.getTriggerIcon = function() { - return TriggerService.getIcon($scope.trigger.service); - }; - - $scope.createTrigger = function() { - console.log($scope.local); - var config = { - 'build_source': $scope.local.selectedRepository.full_name, - 'subdir': $scope.local.dockerfilePath.substr(1) // Remove starting / - }; - - if ($scope.local.triggerOptions.hasBranchTagFilter && - $scope.local.triggerOptions.branchTagFilter) { - config['branchtag_regex'] = $scope.local.triggerOptions.branchTagFilter; - } - - var activate = function() { - $scope.activateTrigger({'config': config, 'pull_robot': $scope.local.robotAccount}); - }; - - if ($scope.local.robotAccount) { - if ($scope.local.robotAccount.can_read) { - activate(); - } else { - // Add read permission onto the base repository for the robot and then activate the - // trigger. - var robot_name = $scope.local.robotAccount.name; - RolesService.setRepositoryRole($scope.repository, 'read', 'robot', robot_name, activate); - } - } else { - activate(); - } - }; - - var buildOrderedNamespaces = function() { - if (!$scope.local.namespaces) { - return; - } - - var namespaces = $scope.local.namespaces || []; - $scope.local.orderedNamespaces = TableService.buildOrderedItems(namespaces, - $scope.local.namespaceOptions, - ['id'], - ['score']) - - $scope.local.maxScore = 0; - namespaces.forEach(function(namespace) { - $scope.local.maxScore = Math.max(namespace.score, $scope.local.maxScore); - }); - }; - - var loadNamespaces = function() { - $scope.local.namespaces = null; - $scope.local.selectedNamespace = null; - $scope.local.orderedNamespaces = null; - - $scope.local.selectedRepository = null; - $scope.local.orderedRepositories = null; - - var params = { - 'repository': $scope.repository.namespace + '/' + $scope.repository.name, - 'trigger_uuid': $scope.trigger.id - }; - - ApiService.listTriggerBuildSourceNamespaces(null, params).then(function(resp) { - $scope.local.namespaces = resp['namespaces']; - $scope.local.repositories = null; - buildOrderedNamespaces(); - }, ApiService.errorDisplay('Could not retrieve the list of ' + $scope.namespaceTitle)) - }; - - var buildOrderedRepositories = function() { - if (!$scope.local.repositories) { - return; - } - - var repositories = $scope.local.repositories || []; - repositories.forEach(function(repository) { - repository['last_updated_datetime'] = new Date(repository['last_updated'] * 1000); - }); - - if ($scope.local.repositoryOptions.hideStale) { - var existingRepositories = repositories; - - repositories = repositories.filter(function(repository) { - var older_date = moment(repository['last_updated_datetime']).add(1, 'months'); - return !moment().isAfter(older_date); - }); - - if (existingRepositories.length > 0 && repositories.length == 0) { - repositories = existingRepositories; - } - } - - $scope.local.orderedRepositories = TableService.buildOrderedItems(repositories, - $scope.local.repositoryOptions, - ['name', 'description'], - []); - }; - - var loadRepositories = function(namespace) { - $scope.local.repositories = null; - $scope.local.selectedRepository = null; - $scope.local.repositoryRefs = null; - $scope.local.triggerOptions = { - 'hasBranchTagFilter': false - }; - - $scope.local.orderedRepositories = null; - - var params = { - 'repository': $scope.repository.namespace + '/' + $scope.repository.name, - 'trigger_uuid': $scope.trigger.id - }; - - var data = { - 'namespace': namespace.id - }; - - ApiService.listTriggerBuildSources(data, params).then(function(resp) { - if (namespace == $scope.local.selectedNamespace) { - $scope.local.repositories = resp['sources']; - buildOrderedRepositories(); - } - }, ApiService.errorDisplay('Could not retrieve repositories')); - }; - - var loadRepositoryRefs = function(repository) { - $scope.local.repositoryRefs = null; - $scope.local.triggerOptions = { - 'hasBranchTagFilter': false - }; - - var params = { - 'repository': $scope.repository.namespace + '/' + $scope.repository.name, - 'trigger_uuid': $scope.trigger.id, - 'field_name': 'refs' - }; - - var config = { - 'build_source': repository.full_name - }; - - ApiService.listTriggerFieldValues(config, params).then(function(resp) { - if (repository == $scope.local.selectedRepository) { - $scope.local.repositoryRefs = resp['values']; - $scope.local.repositoryFullRefs = resp['values'].map(function(ref) { - var kind = ref.kind == 'branch' ? 'heads' : 'tags'; - var icon = ref.kind == 'branch' ? 'fa-code-fork' : 'fa-tag'; - return { - 'value': kind + '/' + ref.name, - 'icon': icon, - 'title': ref.name - }; - }); - } - }, ApiService.errorDisplay('Could not retrieve repository refs')); - }; - - var loadDockerfileLocations = function(repository) { - $scope.local.dockerfilePath = null; - - var params = { - 'repository': $scope.repository.namespace + '/' + $scope.repository.name, - 'trigger_uuid': $scope.trigger.id - }; - - var config = { - 'build_source': repository.full_name - }; - - ApiService.listBuildTriggerSubdirs(config, params).then(function(resp) { - if (repository == $scope.local.selectedRepository) { - $scope.local.dockerfileLocations = resp; - } - }, ApiService.errorDisplay('Could not retrieve Dockerfile locations')); - }; - - var buildOrderedRobotAccounts = function() { - if (!$scope.local.triggerAnalysis || !$scope.local.triggerAnalysis.robots) { - return; - } - - var robots = $scope.local.triggerAnalysis.robots; - $scope.local.orderedRobotAccounts = TableService.buildOrderedItems(robots, - $scope.local.robotOptions, - ['name'], - []); - }; - - var checkDockerfilePath = function(repository, path) { - $scope.local.triggerAnalysis = null; - $scope.local.robotAccount = null; - - var params = { - 'repository': $scope.repository.namespace + '/' + $scope.repository.name, - 'trigger_uuid': $scope.trigger.id - }; - - var config = { - 'build_source': repository.full_name, - 'subdir': path.substr(1) - }; - - var data = { - 'config': config - }; - - ApiService.analyzeBuildTrigger(data, params).then(function(resp) { - $scope.local.triggerAnalysis = resp; - buildOrderedRobotAccounts(); - }, ApiService.errorDisplay('Could not analyze trigger')); - }; - - $scope.$watch('trigger', function(trigger) { - if (trigger && $scope.repository) { - $scope.config = trigger['config'] || {}; - $scope.namespaceTitle = 'organization'; - $scope.local.selectedNamespace = null; - loadNamespaces(); - } - }); - - $scope.$watch('local.selectedNamespace', function(namespace) { - if (namespace) { - loadRepositories(namespace); - } - }); - - $scope.$watch('local.selectedRepository', function(repository) { - if (repository) { - loadRepositoryRefs(repository); - loadDockerfileLocations(repository); - } - }); - - $scope.$watch('local.dockerfilePath', function(path) { - if (path && $scope.local.selectedRepository) { - checkDockerfilePath($scope.local.selectedRepository, path); - } - }); - - $scope.$watch('local.namespaceOptions.predicate', buildOrderedNamespaces); - $scope.$watch('local.namespaceOptions.reverse', buildOrderedNamespaces); - $scope.$watch('local.namespaceOptions.filter', buildOrderedNamespaces); - - $scope.$watch('local.repositoryOptions.predicate', buildOrderedRepositories); - $scope.$watch('local.repositoryOptions.reverse', buildOrderedRepositories); - $scope.$watch('local.repositoryOptions.filter', buildOrderedRepositories); - $scope.$watch('local.repositoryOptions.hideStale', buildOrderedRepositories); - - $scope.$watch('local.robotOptions.predicate', buildOrderedRobotAccounts); - $scope.$watch('local.robotOptions.reverse', buildOrderedRobotAccounts); - $scope.$watch('local.robotOptions.filter', buildOrderedRobotAccounts); - } - }; - return directiveDefinitionObject; -}); \ No newline at end of file diff --git a/static/js/directives/ui/manage-trigger-githost/manage-trigger-githost.component.html b/static/js/directives/ui/manage-trigger-githost/manage-trigger-githost.component.html index ad35aa864..de8dc9bc9 100644 --- a/static/js/directives/ui/manage-trigger-githost/manage-trigger-githost.component.html +++ b/static/js/directives/ui/manage-trigger-githost/manage-trigger-githost.component.html @@ -8,7 +8,7 @@
+ section-valid="$ctrl.local.selectedNamespace">

Select {{ $ctrl.namespaceTitle }}

@@ -22,21 +22,21 @@ current-page="$ctrl.local.namespaceOptions.page" page-size="$ctrl.namespacesPerPage">
- - - + + + + ng-value="namespace"> @@ -133,7 +133,7 @@ -
- {{ $ctrl.namespaceTitle }} - + {{ $ctrl.namespaceTitle }} +
- - {{ $ctrl.namespace.id }} + + {{ namespace.id }}
@@ -200,7 +200,7 @@
Regular Expression: - +
Examples: heads/master, tags/tagname, heads/.+

Select Dockerfile

- Please select the location of the Dockerfile to build when this trigger is invoked {{ $ctrl.local.paths }} + Please select the location of the Dockerfile to build when this trigger is invoked { var rolesServiceMock: any; var repository: any; var trigger: Trigger; + var $scope: ng.IScope; - beforeEach(() => { + beforeEach(inject(($injector: ng.auto.IInjectorService) => { apiServiceMock = jasmine.createSpyObj('apiServiceMock', ['listTriggerBuildSourceNamespaces']); tableServiceMock = jasmine.createSpyObj('tableServiceMock', ['buildOrderedItems']); triggerServiceMock = jasmine.createSpyObj('triggerServiceMock', ['getIcon']); rolesServiceMock = jasmine.createSpyObj('rolesServiceMock', ['setRepositoryRole']); - component = new ManageTriggerGithostComponent(apiServiceMock, tableServiceMock, triggerServiceMock, rolesServiceMock); + $scope = $injector.get('$rootScope'); + component = new ManageTriggerGithostComponent(apiServiceMock, + tableServiceMock, + triggerServiceMock, + rolesServiceMock, + $scope); trigger = {service: "serviceMock", id: 1}; component.trigger = trigger; - }); + })); describe("constructor", () => { diff --git a/static/js/directives/ui/manage-trigger-githost/manage-trigger-githost.component.ts b/static/js/directives/ui/manage-trigger-githost/manage-trigger-githost.component.ts index 473bde6eb..a6815d8ad 100644 --- a/static/js/directives/ui/manage-trigger-githost/manage-trigger-githost.component.ts +++ b/static/js/directives/ui/manage-trigger-githost/manage-trigger-githost.component.ts @@ -1,6 +1,10 @@ import { Input, Output, Component } from 'angular-ts-decorators'; +import * as moment from 'moment'; +/** + * A component that lets the user set up a build trigger for a public Git repository host service. + */ @Component({ selector: 'manageTriggerGithost', templateUrl: '/static/js/directives/ui/manage-trigger-githost/manage-trigger-githost.component.html' @@ -11,7 +15,7 @@ export class ManageTriggerGithostComponent implements ng.IComponentController { @Input('=') public trigger: Trigger; @Output() public activateTrigger: (trigger: {config: any, pull_robot: any}) => void; private config: any; - private local: Local = { + private local: any = { namespaceOptions: { filter: '', predicate: 'score', @@ -36,16 +40,65 @@ export class ManageTriggerGithostComponent implements ng.IComponentController { private namespacesPerPage: number = 10; private repositoriesPerPage: number = 10; private robotsPerPage: number = 10; + private namespaceTitle: string; + private namespace: any; constructor(private ApiService: any, private TableService: any, private TriggerService: any, - private RolesService: any) { - + private RolesService: any, + private $scope: ng.IScope) { + // FIXME: Here binding methods to class context in order to pass them as arguments to $scope.$watch + this.buildOrderedNamespaces = this.buildOrderedNamespaces.bind(this); + this.loadNamespaces = this.loadNamespaces.bind(this); + this.buildOrderedRepositories = this.buildOrderedRepositories.bind(this); + this.loadRepositories = this.loadRepositories.bind(this); + this.loadRepositoryRefs = this.loadRepositoryRefs.bind(this); + this.buildOrderedRobotAccounts = this.buildOrderedRobotAccounts.bind(this); + this.loadDockerfileLocations = this.loadDockerfileLocations.bind(this); + this.checkDockerfilePath = this.checkDockerfilePath.bind(this); } public $onInit(): void { + // TODO: Replace $scope.$watch with @Output methods for child component mutations or $onChanges for parent mutations + this.$scope.$watch(() => this.trigger, (trigger) => { + if (trigger && this.repository) { + this.config = trigger['config'] || {}; + this.namespaceTitle = 'organization'; + this.local.selectedNamespace = null; + this.loadNamespaces(); + } + }); + this.$scope.$watch(() => this.local.selectedNamespace, (namespace) => { + if (namespace) { + this.loadRepositories(namespace); + } + }); + + this.$scope.$watch(() => this.local.selectedRepository, (repository) => { + if (repository) { + this.loadRepositoryRefs(repository); + this.loadDockerfileLocations(repository); + } + }); + + this.$scope.$watch(() => this.local.dockerfilePath, (path) => { + if (path && this.local.selectedRepository) { + this.checkDockerfilePath(this.local.selectedRepository, path); + } + }); + + this.$scope.$watch(() => this.local.namespaceOptions.predicate, this.buildOrderedNamespaces); + this.$scope.$watch(() => this.local.namespaceOptions.reverse, this.buildOrderedNamespaces); + this.$scope.$watch(() => this.local.namespaceOptions.filter, this.buildOrderedNamespaces); + this.$scope.$watch(() => this.local.repositoryOptions.predicate, this.buildOrderedRepositories); + this.$scope.$watch(() => this.local.repositoryOptions.reverse, this.buildOrderedRepositories); + this.$scope.$watch(() => this.local.repositoryOptions.filter, this.buildOrderedRepositories); + this.$scope.$watch(() => this.local.repositoryOptions.hideStale, this.buildOrderedRepositories); + this.$scope.$watch(() => this.local.robotOptions.predicate, this.buildOrderedRobotAccounts); + this.$scope.$watch(() => this.local.robotOptions.reverse, this.buildOrderedRobotAccounts); + this.$scope.$watch(() => this.local.robotOptions.filter, this.buildOrderedRobotAccounts); } public $onChanges(changes: ng.IOnChangesObject): void { @@ -86,35 +139,186 @@ export class ManageTriggerGithostComponent implements ng.IComponentController { } private buildOrderedNamespaces(): void { + if (!this.local.namespaces) { + return; + } + var namespaces = this.local.namespaces || []; + this.local.orderedNamespaces = this.TableService.buildOrderedItems(namespaces, + this.local.namespaceOptions, + ['id'], + ['score']); + + this.local.maxScore = 0; + namespaces.forEach((namespace) => { + this.local.maxScore = Math.max(namespace.score, this.local.maxScore); + }); } private loadNamespaces(): void { + this.local.namespaces = null; + this.local.selectedNamespace = null; + this.local.orderedNamespaces = null; + this.local.selectedRepository = null; + this.local.orderedRepositories = null; + + var params = { + 'repository': this.repository.namespace + '/' + this.repository.name, + 'trigger_uuid': this.trigger.id + }; + + this.ApiService.listTriggerBuildSourceNamespaces(null, params) + .then((resp) => { + this.local.namespaces = resp['namespaces']; + this.local.repositories = null; + this.buildOrderedNamespaces(); + }, this.ApiService.errorDisplay('Could not retrieve the list of ' + this.namespaceTitle)); } private buildOrderedRepositories(): void { + if (!this.local.repositories) { + return; + } + var repositories = this.local.repositories || []; + repositories.forEach((repository) => { + repository['last_updated_datetime'] = new Date(repository['last_updated'] * 1000); + }); + + if (this.local.repositoryOptions.hideStale) { + var existingRepositories = repositories; + + repositories = repositories.filter((repository) => { + var older_date = moment(repository['last_updated_datetime']).add(1, 'months'); + return !moment().isAfter(older_date); + }); + + if (existingRepositories.length > 0 && repositories.length == 0) { + repositories = existingRepositories; + } + } + + this.local.orderedRepositories = this.TableService.buildOrderedItems(repositories, + this.local.repositoryOptions, + ['name', 'description'], + []); } - private loadRepositories(): void { + private loadRepositories(namespace: any): void { + this.local.repositories = null; + this.local.selectedRepository = null; + this.local.repositoryRefs = null; + this.local.triggerOptions = { + 'hasBranchTagFilter': false + }; + this.local.orderedRepositories = null; + + var params = { + 'repository': this.repository.namespace + '/' + this.repository.name, + 'trigger_uuid': this.trigger.id + }; + + var data = { + 'namespace': namespace.id + }; + + this.ApiService.listTriggerBuildSources(data, params).then((resp) => { + if (namespace == this.local.selectedNamespace) { + this.local.repositories = resp['sources']; + this.buildOrderedRepositories(); + } + }, this.ApiService.errorDisplay('Could not retrieve repositories')); } private loadRepositoryRefs(repository: any): void { + this.local.repositoryRefs = null; + this.local.triggerOptions = { + 'hasBranchTagFilter': false + }; + var params = { + 'repository': this.repository.namespace + '/' + this.repository.name, + 'trigger_uuid': this.trigger.id, + 'field_name': 'refs' + }; + + var config = { + 'build_source': repository.full_name + }; + + this.ApiService.listTriggerFieldValues(config, params).then((resp) => { + if (repository == this.local.selectedRepository) { + this.local.repositoryRefs = resp['values']; + this.local.repositoryFullRefs = resp['values'].map((ref) => { + var kind = ref.kind == 'branch' ? 'heads' : 'tags'; + var icon = ref.kind == 'branch' ? 'fa-code-fork' : 'fa-tag'; + return { + 'value': kind + '/' + ref.name, + 'icon': icon, + 'title': ref.name + }; + }); + } + }, this.ApiService.errorDisplay('Could not retrieve repository refs')); } private loadDockerfileLocations(repository: any): void { + this.local.dockerfilePath = null; + var params = { + 'repository': this.repository.namespace + '/' + this.repository.name, + 'trigger_uuid': this.trigger.id + }; + + var config = { + 'build_source': repository.full_name + }; + + this.ApiService.listBuildTriggerSubdirs(config, params) + .then((resp) => { + if (repository == this.local.selectedRepository) { + this.local.dockerfileLocations = resp; + } + }, this.ApiService.errorDisplay('Could not retrieve Dockerfile locations')); } private buildOrderedRobotAccounts(): void { + if (!this.local.triggerAnalysis || !this.local.triggerAnalysis.robots) { + return; + } + var robots = this.local.triggerAnalysis.robots; + this.local.orderedRobotAccounts = this.TableService.buildOrderedItems(robots, + this.local.robotOptions, + ['name'], + []); } private checkDockerfilePath(repository: any, path: string): void { + this.local.triggerAnalysis = null; + this.local.robotAccount = null; + var params = { + 'repository': this.repository.namespace + '/' + this.repository.name, + 'trigger_uuid': this.trigger.id + }; + + var config = { + 'build_source': repository.full_name, + 'subdir': path.substr(1) + }; + + var data = { + 'config': config + }; + + this.ApiService.analyzeBuildTrigger(data, params) + .then((resp) => { + this.local.triggerAnalysis = resp; + this.buildOrderedRobotAccounts(); + }, this.ApiService.errorDisplay('Could not analyze trigger')); } } diff --git a/static/partials/trigger-setup.html b/static/partials/trigger-setup.html index 79f676508..7f1fad28d 100644 --- a/static/partials/trigger-setup.html +++ b/static/partials/trigger-setup.html @@ -51,8 +51,10 @@
-
+
diff --git a/test/data/test.db b/test/data/test.db index b089c3c80..203537eee 100644 Binary files a/test/data/test.db and b/test/data/test.db differ