| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| |
| <div class="row flex"> |
| <div class="col-md-4"> |
| <div class="box box-primary"> |
| <div class="box-header with-border"> |
| <span class="fa fa-rocket"></span> |
| <h3 class="box-title"> |
| Source Stream |
| </h3> |
| <div class="box-tools pull-right"> |
| <div class="btn-group" data-toggle="btn-toggle"> |
| <button class="btn btn-default btn-sm" ng-class="{active: sourceTab === 'all'}" ng-click="setSourceTab('all')"> |
| All |
| </button> |
| <button class="btn btn-default btn-sm" ng-class="{active: sourceTab === 'selected'}" ng-click="setSourceTab('selected')"> |
| Selected |
| </button> |
| </div> |
| </div> |
| </div> |
| <div class="box-body"> |
| <div class="form-group"> |
| <label>* Site</label> |
| <select class="form-control" ng-model="policy.siteId"> |
| <option ng-repeat="site in Site.list track by $index" value="{{site.siteId}}"> |
| {{site.siteName || site.siteId}} |
| </option> |
| </select> |
| </div> |
| <hr /> |
| |
| <div ng-show="sourceTab === 'all'"> |
| <div class="input-with-icon"> |
| <input type="text" class="form-control" placeholder="Filter..." ng-model="searchSourceKey" /> |
| <span class="fa fa-search"></span> |
| </div> |
| |
| <p ng-hide="getSearchApplication()" class="text-warning">No stream match</p> |
| <div ng-show="getSearchApplication()"> |
| <div ng-repeat="(app, streams) in getSearchApplication() track by app" class="policy-app-list"> |
| <a data-toggle="collapse" href="[data-id='SP_{{app}}']"> |
| <strong class="text-break"> |
| <span class="fa" ng-class="searchType === 'site' ? 'fa-server' : 'fa-cube'"></span> |
| {{app}} |
| </strong> |
| </a> |
| <ul data-id="SP_{{app}}" class="collapse list-unstyled"> |
| <li ng-repeat="stream in streams track by stream.streamId"> |
| <a data-toggle="collapse" href="[data-id='SP_{{app}}_{{stream.streamId}}']" class="text-break"> |
| <span class="fa fa-{{isInputStreamSelected(stream.streamId) ? 'check-square' : 'square'}}"></span> |
| {{stream.streamId}} |
| </a> |
| <ul data-id="SP_{{app}}_{{stream.streamId}}" class="collapse"> |
| <li ng-repeat="column in stream.columns track by $index"> |
| <span class="text-primary">[{{column.type}}]</span> |
| {{column.name}} |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| <div ng-show="sourceTab === 'selected'"> |
| <div ng-repeat="stream in policy.inputStreams"> |
| <a data-toggle="collapse" href="[data-id='SS_{{stream}}']"> |
| <strong>{{stream}}</strong> |
| </a> |
| <ul class="sm-padding collapse in" data-id="SS_{{stream}}"> |
| <li ng-repeat="column in streams[stream].columns track by $index"> |
| <span class="text-primary">[{{column.type}}]</span> |
| {{column.name}} |
| </li> |
| </ul> |
| </div> |
| <p class="text-muted" ng-if="policy.inputStreams.length === 0">No Stream selected</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="col-md-8"> |
| <div class="box box-primary"> |
| <div class="box-header with-border"> |
| <span class="fa fa-pencil"></span> |
| <h3 class="box-title">Policy Editor</h3> |
| </div> |
| <div class="box-body"> |
| |
| |
| <div class="row"> |
| <div class="col-md-12"> |
| <div class="form-group" ng-class="{'has-error': checkPolicyName()}"> |
| <label> |
| Name * |
| <small ng-if="checkPolicyName()">({{checkPolicyName()}})</small> |
| </label> |
| <input type="text" class="form-control" ng-model="policy.name" ng-readonly="!newPolicy" ng-disabled="policyLock" /> |
| </div> |
| </div> |
| </div> |
| |
| <div class="form-group"> |
| <label>Description</label> |
| <textarea class="form-control" ng-model="policy.description" ng-change="autoPolicyDescription = false" rows="2" ng-disabled="policyLock"></textarea> |
| </div> |
| |
| <!--label> |
| Input Stream Partition |
| </label> |
| <ul class="sm-padding"> |
| <li ng-repeat="partition in policy.partitionSpec track by $index"> |
| <[<a class="fa fa-times" ng-click="removePartition(partition)"></a>]> |
| <strong class="text-primary">{{partition.streamId}}:</strong> |
| <p> |
| <strong>{{partition.type}}</strong> on |
| <strong class="text-success">[{{partition.columns.join(", ")}}]</strong> |
| <span ng-if="partition.sortSpec.windowPeriod"> |
| sort in window: |
| <strong class="text-info">[{{partition.sortSpec.windowPeriod}}]</strong> |
| </span> |
| </p> |
| </li> |
| <li class="text-warning" ng-if="policy.partitionSpec.length === 0">No partition yet.</li> |
| <li> |
| <a ng-click="addPartition()">+ Add Partition</a> |
| </li> |
| </ul--> |
| |
| <div class="form-group" ng-class="{'has-error': !!definitionMessage}"> |
| <label>Policy Definition *</label> |
| <div editor ng-model="policy.definition.value" ng-change="checkDefinition()"></div> |
| <!--textarea class="form-control" ng-model="policy.definition.value" rows="10" ng-change="checkDefinition()" ng-disabled="policyLock"></textarea--> |
| <p class="text-danger">{{definitionMessage}}</p> |
| </div> |
| |
| <ul class="sm-padding"> |
| <li class="text-danger" ng-if="policy.outputStreams.length === 0"><i class="fa fa-fw fa-warning"></i> No alert stream defined</li> |
| <li ng-repeat="stream in outputStreams track by $index"> |
| <label> |
| <input type="checkbox" ng-checked="isOutputStreamSelected(stream)" ng-click="checkOutputStream(stream)" ng-disabled="policyLock" /> |
| {{stream}} |
| </label> |
| </li> |
| </ul> |
| |
| <label>Alert Definition*</label><br/> |
| <div class="form-group"> |
| <p class="text-muted">Category</p> |
| <input class="form-control" type="text" ng-model="policy.alertDefinition.category" ng-disabled="policyLock" /> |
| </div> |
| |
| <div class="form-group"> |
| <p class="text-muted">Severity</p> |
| <select class="form-control" ng-model="policy.alertDefinition.severity" ng-disabled="policyLock" > |
| <option value="WARNING" class="text-{{Policy.getSeverityClass('WARNING')}}">WARNING</option> |
| <option value="CRITICAL" class="text-{{Policy.getSeverityClass('CRITICAL')}}">CRITICAL</option> |
| <option value="FATAL" class="text-{{Policy.getSeverityClass('FATAL')}}">FATAL</option> |
| <option value="OK" class="text-{{Policy.getSeverityClass('OK')}}">OK</option> |
| </select> |
| </div> |
| |
| <div class="form-group"> |
| <p class="text-muted"> |
| Alert Subject |
| <span class="fa fa-question-circle ng-scope" |
| uib-tooltip="Alert subject, support template with alert stream fields and built-in context like: STREAM_ID, ALERT_ID, CREATED_BY, POLICY_ID, CREATED_TIMESTAMP, CREATED_TIME, ALERT_TIMESTAMP, ALERT_TIME, ALERT_SCHEMA, POLICY_DESC, POLICY_TYPE, POLICY_DEFINITION, POLICY_HANDLER"> |
| </span> |
| </p> |
| <input type="text" class="form-control" placeholder="Please input alert subject (support template)" ng-model="policy.alertDefinition.subject" ng-disabled="policyLock"/> |
| </div> |
| |
| <div class="form-group"> |
| <p class="text-muted"> |
| Alert Body |
| <span class="fa fa-question-circle ng-scope" |
| uib-tooltip="Alert body, support template with alert stream fields and built-in context like: STREAM_ID, ALERT_ID, CREATED_BY, POLICY_ID, CREATED_TIMESTAMP, CREATED_TIME, ALERT_TIMESTAMP, ALERT_TIME, ALERT_SCHEMA, POLICY_DESC, POLICY_TYPE, POLICY_DEFINITION, POLICY_HANDLER"> |
| </span> |
| </p> |
| <div editor placeholder="Please input alert body (support template)" ng-model="policy.alertDefinition.body" ng-disabled="policyLock"></div> |
| </div> |
| |
| <label> |
| Publish Alerts |
| </label> |
| |
| <ul class="sm-padding"> |
| <li class="text-danger" ng-if="policyPublisherList.length === 0"><i class="fa fa-fw fa-warning"></i> No alert publisher defined </li> |
| <li ng-repeat="publisher in policyPublisherList track by $index"> |
| <span> |
| [<a class="fa fa-times" ng-click="removePublisher(publisher)"></a>] |
| <strong> |
| <span>({{Policy.publisherTypes[publisher.type].name}})</span> |
| {{publisher.name}} |
| </strong> |
| </span> |
| |
| <ul> |
| <li class="offset" ng-repeat="field in Policy.publisherTypes[publisher.type].displayFields track by $index"> |
| <span>{{field.name}}:</span> |
| <span>{{publisher.properties[field.name]}}</span> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a ng-click="addPublisher()">+ Add Publisher</a> |
| </li> |
| </ul> |
| |
| <div class="row"> |
| <div class="col-md-12"> |
| <div class="form-group"> |
| <label>Schedule Parallelism *</label> |
| <input type="text" class="form-control" ng-model="policy.parallelismHint" ng-disabled="policyLock" /> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| <div class="text-right"> |
| <button class="btn btn-primary" ng-disabled="!saveCheck()" ng-click="saveConfirm()"> |
| <span class="fa fa-floppy-o"></span> |
| Apply |
| </button> |
| </div> |
| |
| <!------------------------- Modal: Partition -------------------------> |
| <div class="modal fade" tabindex="-1" data-id="partitionMDL"> |
| <div class="modal-dialog" role="document"> |
| <div class="modal-content"> |
| <div class="modal-header"> |
| <button type="button" class="close" data-dismiss="modal"> |
| <span aria-hidden="true">×</span> |
| </button> |
| <h4 class="modal-title">Add Partition</h4> |
| </div> |
| <div class="modal-body"> |
| <div class="form-group"> |
| <label>Stream</label> |
| <select class="form-control" ng-model="partition.streamId"> |
| <option ng-repeat="stream in policy.inputStreams track by stream">{{stream}}</option> |
| </select> |
| </div> |
| <div class="form-group"> |
| <label>Type</label> |
| <select class="form-control" ng-model="partition.type"> |
| <option value="GROUPBY">GroupBy</option> |
| <option value="GLOBAL">Global</option> |
| <option value="SHUFFLE">Shuffle</option> |
| </select> |
| </div> |
| <div class="form-group"> |
| <label>columns</label> |
| <ul class="list-unstyled"> |
| <li ng-repeat="column in streams[partition.streamId].columns track by $index"> |
| <label> |
| <input type="checkbox" ng-checked="newPartitionCheckColumn(column.name)" |
| ng-click="newPartitionClickColumn(column.name)" /> |
| <span class="text-primary">[{{column.type}}]</span> |
| {{column.name}} |
| </label> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="modal-footer"> |
| <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> |
| <button type="button" class="btn btn-primary" data-dismiss="modal" |
| ng-disabled="partition.columns.length === 0" ng-click="addPartitionConfirm()">Add</button> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| <!------------------------- Modal: Publisher -------------------------> |
| <div class="modal fade" tabindex="-1" data-id="publisherMDL"> |
| <div class="modal-dialog" role="document"> |
| <div class="modal-content"> |
| <div class="modal-header"> |
| <button type="button" class="close" data-dismiss="modal"> |
| <span aria-hidden="true">×</span> |
| </button> |
| <h4 class="modal-title">Add Publisher</h4> |
| </div> |
| <div class="modal-body"> |
| <div class="radio" ng-show="publisherList.length > 0"> |
| <label class="radio-inline"> |
| <input type="radio" value="exist" ng-model="addPublisherType"> |
| From exist publisher |
| </label> |
| <label class="radio-inline"> |
| <input type="radio" value="new" ng-model="addPublisherType"> |
| Create new publisher |
| </label> |
| </div> |
| |
| <!-- Publisher: Exist --> |
| <div ng-if="addPublisherType === 'exist'"> |
| <div class="form-group"> |
| <label>Publisher</label> |
| <select class="form-control" ng-model="publisher.existPublisher" |
| ng-options="publisher as publisher.name for publisher in publisherList track by publisher.name"></select> |
| </div> |
| </div> |
| |
| <div ng-if="addPublisherType === 'new'"> |
| <div class="form-group" ng-class="{'has-error': checkPublisherName()}"> |
| <label> |
| Name |
| <small ng-if="checkPublisherName()">({{checkPublisherName()}})</small> |
| </label> |
| <input class="form-control" ng-model="publisher.name" /> |
| </div> |
| <div class="form-group"> |
| <label>Dedup-Interval Minutes</label> |
| <input class="form-control" ng-model="publisher.dedupIntervalMin" /> |
| </div> |
| <div class="form-group"> |
| <label>Type</label> |
| <select class="form-control" ng-model="publisher.type"> |
| <option ng-repeat="(type, fields) in Policy.publisherTypes track by type">{{type}}</option> |
| </select> |
| </div> |
| <div class="form-group" ng-repeat="field in Policy.publisherTypes[publisher.type].fields track by $index"> |
| <label>{{field.name}}</label> |
| <input class="form-control" ng-model="publisher.properties[field.name]" /> |
| </div> |
| </div> |
| </div> |
| |
| <div class="modal-footer"> |
| <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> |
| <button type="button" class="btn btn-primary" data-dismiss="modal" |
| ng-disabled="addPublisherType === 'new' && !publisher.name" ng-click="addPublisherConfirm()">Add</button> |
| </div> |
| </div> |
| </div> |
| </div> |