This is an automated email from the ASF dual-hosted git repository. jlli pushed a commit to branch add-doc-experiment-with-pinot in repository https://gitbox.apache.org/repos/asf/incubator-pinot.git
commit f456b46186b719c2dbfcb43c77e924cfff36517e Author: Harley Jackson <[email protected]> AuthorDate: Tue Mar 19 10:24:01 2019 -0700 [TE] frontend - harleyjj/report-anomaly - adds back report-anomaly modal to alert overview (#3985) --- docs/getting_started.rst | 138 +++++++++++++++++++ .../app/pods/components/alert-details/component.js | 146 +++++++++++++++++++-- .../app/pods/components/alert-details/template.hbs | 50 +++++++ .../components/alert-report-modal/component.js | 55 ++++---- .../components/alert-report-modal/template.hbs | 61 ++++----- .../app/pods/components/yaml-editor/component.js | 8 +- .../app/pods/manage/explore/template.hbs | 1 + thirdeye/thirdeye-frontend/app/utils/anomaly.js | 4 +- .../thirdeye-frontend/app/utils/api/anomaly.js | 4 +- .../tests/unit/utils/api/anomaly-test.js | 2 +- 10 files changed, 391 insertions(+), 78 deletions(-) diff --git a/docs/getting_started.rst b/docs/getting_started.rst index e3d2416..78a9250 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -94,3 +94,141 @@ show up in Pinot. To show new events appearing, one can run :sql:`SELECT * FROM meetupRsvp ORDER BY mtime DESC LIMIT 50` repeatedly, which shows the last events that were ingested by Pinot. +Experimenting with Pinot +~~~~~~~~~~~~~~~~~~~~~~~~ + +Now we have a quick start Pinot cluster running locally. The below shows a step-by-step instruction on +how to add a simple table to the Pinot system, how to upload segments, and how to query it. + +Suppose we have a transcript in CSV format containing students' basic info and their scores of each subject. + ++------------+------------+-----------+-----------+-----------+-----------+ +| StudentID | firstName | lastName | gender | subject | score | ++============+============+===========+===========+===========+===========+ +| 200 | Lucy | Smith | Female | Maths | 3.8 | ++------------+------------+-----------+-----------+-----------+-----------+ +| 200 | Lucy | Smith | Female | English | 3.5 | ++------------+------------+-----------+-----------+-----------+-----------+ +| 201 | Bob | King | Male | Maths | 3.2 | ++------------+------------+-----------+-----------+-----------+-----------+ +| 202 | Nick | Young | Male | Physics | 3.6 | ++------------+------------+-----------+-----------+-----------+-----------+ + +Firstly in order to set up a table, we need to specify the schema of this transcript. + +.. code-block:: none + + { + "schemaName": "transcript", + "dimensionFieldSpecs": [ + { + "name": "studentID", + "dataType": "STRING" + }, + { + "name": "firstName", + "dataType": "STRING" + }, + { + "name": "lastName", + "dataType": "STRING" + }, + { + "name": "gender", + "dataType": "STRING" + }, + { + "name": "subject", + "dataType": "STRING" + } + ], + "metricFieldSpecs": [ + { + "name": "score", + "dataType": "INT" + } + ] + } + +To upload the schema, we can use the command below: + +.. code-block:: none + + $ ./pinot-distribution/target/apache-pinot-incubating-0.1.0-SNAPSHOT-bin/apache-pinot-incubating-0.1.0-SNAPSHOT-bin/bin/pinot-admin.sh AddSchema -schemaFile /Users/jlli/transcript-schema.json -exec + Executing command: AddSchema -controllerHost 172.25.119.20 -controllerPort 9000 -schemaFilePath /Users/jlli/transcript-schema.json -exec + Sending request: http://172.25.119.20:9000/schemas to controller: jlli-mn2.linkedin.biz, version: 0.1.0-SNAPSHOT-2c5d42a908213122ab0ad8b7ac9524fcf390e4cb + +Then, we need to specify the table config which links the schema to this table: + +.. code-block:: none + + { + "tableName": "transcript", + "segmentsConfig" : { + "replication" : "1", + "schemaName" : "transcript", + "segmentAssignmentStrategy" : "BalanceNumSegmentAssignmentStrategy" + }, + "tenants" : { + "broker":"DefaultTenant", + "server":"DefaultTenant" + }, + "tableIndexConfig" : { + "invertedIndexColumns" : [], + "loadMode" : "HEAP", + "lazyLoad" : "false" + }, + "tableType":"OFFLINE", + "metadata": {} + } + +And upload the table config to Pinot cluster: + +.. code-block:: none + + $ ./pinot-distribution/target/apache-pinot-incubating-0.1.0-SNAPSHOT-bin/apache-pinot-incubating-0.1.0-SNAPSHOT-bin/bin/pinot-admin.sh AddTable -filePath /Users/jlli/transcript-table-config.json -exec + Executing command: AddTable -filePath /Users/jlli/transcript-table-config.json -controllerHost 172.25.119.20 -controllerPort 9000 -exec + {"status":"Table transcript_OFFLINE successfully added"} + +In order to upload our data to Pinot cluster, we need to convert our CSV file to Pinot Segment: + +.. code-block:: none + + $ ./pinot-distribution/target/apache-pinot-incubating-0.1.0-SNAPSHOT-bin/apache-pinot-incubating-0.1.0-SNAPSHOT-bin/bin/pinot-admin.sh CreateSegment -dataDir /Users/jlli/Desktop/test/ -format CSV -outDir /Users/jlli/Desktop/test2/ -tableName transcript -segmentName transcript_0 -overwrite -schemaFile /Users/jlli/transcript-schema.json + Executing command: CreateSegment -generatorConfigFile null -dataDir /Users/jlli/Desktop/test/ -format CSV -outDir /Users/jlli/Desktop/test2/ -overwrite true -tableName transcript -segmentName transcript_0 -timeColumnName null -schemaFile /Users/jlli/transcript-schema.json -readerConfigFile null -enableStarTreeIndex false -starTreeIndexSpecFile null -hllSize 9 -hllColumns null -hllSuffix _hll -numThreads 1 + Accepted files: [/Users/jlli/Desktop/test/Transcript.csv] + Finished building StatsCollector! + Collected stats for 4 documents + Created dictionary for STRING column: studentID with cardinality: 1, max length in bytes: 4, range: null to null + Created dictionary for STRING column: firstName with cardinality: 3, max length in bytes: 4, range: Bob to Nick + Created dictionary for STRING column: lastName with cardinality: 3, max length in bytes: 5, range: King to Young + Created dictionary for INT column: score with cardinality: 1, range: 0 to 0 + Created dictionary for STRING column: gender with cardinality: 1, max length in bytes: 4, range: null to null + Created dictionary for STRING column: subject with cardinality: 1, max length in bytes: 4, range: null to null + Start building IndexCreator! + Finished records indexing in IndexCreator! + Finished segment seal! + Converting segment: /Users/jlli/Desktop/test2/transcript_0_0 to v3 format + v3 segment location for segment: transcript_0_0 is /Users/jlli/Desktop/test2/transcript_0_0/v3 + Deleting files in v1 segment directory: /Users/jlli/Desktop/test2/transcript_0_0 + Driver, record read time : 0 + Driver, stats collector time : 0 + Driver, indexing time : 1 + +Once we have the Pinot segment, we can upload this segment to our cluster: + +.. code-block:: none + + $ ./pinot-distribution/target/apache-pinot-incubating-0.1.0-SNAPSHOT-bin/apache-pinot-incubating-0.1.0-SNAPSHOT-bin/bin/pinot-admin.sh UploadSegment -segmentDir /Users/jlli/Desktop/test2/ + Executing command: UploadSegment -controllerHost 172.25.119.20 -controllerPort 9000 -segmentDir /Users/jlli/Desktop/test2/ + Compressing segment transcript_0_0 + Uploading segment transcript_0_0.tar.gz + Sending request: http://172.25.119.20:9000/v2/segments to controller: jlli-mn2.linkedin.biz, version: 0.1.0-SNAPSHOT-2c5d42a908213122ab0ad8b7ac9524fcf390e4cb + +Now we can query the data we just uploaded to Pinot: + +.. code-block:: none + + $ ./pinot-distribution/target/apache-pinot-incubating-0.1.0-SNAPSHOT-bin/apache-pinot-incubating-0.1.0-SNAPSHOT-bin/bin/pinot-admin.sh PostQuery -brokerPort 8000 -query "select count(*) from transcript" + Executing command: PostQuery -brokerHost 172.25.119.20 -brokerPort 8000 -query select count(*) from transcript + Result: {"aggregationResults":[{"function":"count_star","value":"4"}],"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numDocsScanned":4,"numEntriesScannedInFilter":0,"numEntriesScannedPostFilter":0,"numGroupsLimitReached":false,"totalDocs":4,"timeUsedMs":7,"segmentStatistics":[],"traceInfo":{}} diff --git a/thirdeye/thirdeye-frontend/app/pods/components/alert-details/component.js b/thirdeye/thirdeye-frontend/app/pods/components/alert-details/component.js index b70b5d5..f93e432 100644 --- a/thirdeye/thirdeye-frontend/app/pods/components/alert-details/component.js +++ b/thirdeye/thirdeye-frontend/app/pods/components/alert-details/component.js @@ -14,9 +14,9 @@ */ import Component from '@ember/component'; -import { computed, observer, set, get, getProperties, getWithDefault } from '@ember/object'; +import { computed, observer, set, get, getProperties } from '@ember/object'; import { later } from '@ember/runloop'; -import { checkStatus, humanizeFloat } from 'thirdeye-frontend/utils/utils'; +import { checkStatus, humanizeFloat, postProps } from 'thirdeye-frontend/utils/utils'; import { colorMapping, toColor, makeTime, toMetricLabel, extractTail } from 'thirdeye-frontend/utils/rca-utils'; import { getYamlPreviewAnomalies, getAnomaliesByAlertId, @@ -90,10 +90,16 @@ export default Component.extend({ currentPage: 1, isPreviewMode: false, alertId: null, + alertData: null, feedbackOptions: ['Not reviewed yet', 'Yes - unexpected', 'Expected temporary change', 'Expected permanent change', 'No change observed'], labelMap: anomalyResponseMapNew, labelResponse: {}, selectedDimension: null, + isReportSuccess: false, + isReportFailure: false, + openReportModal: false, + missingAnomalyProps: {}, + updateVisuals: observer( @@ -170,6 +176,24 @@ export default Component.extend({ ), /** + * date-time-picker: indicates the date format to be used based on granularity + * @type {String} + */ + uiDateFormat: computed('alertData.windowUnit', function() { + const rawGranularity = this.get('alertData.bucketUnit'); + const granularity = rawGranularity ? rawGranularity.toLowerCase() : ''; + + switch(granularity) { + case 'days': + return 'MMM D, YYYY'; + case 'hours': + return 'MMM D, YYYY h a'; + default: + return 'MMM D, YYYY hh:mm a'; + } + }), + + /** * Table pagination: creates the page Array for view * @type {Array} */ @@ -645,6 +669,54 @@ export default Component.extend({ } }, + /** + * Send a POST request to the report anomaly API (2-step process) + * http://go/te-ss-alert-flow-api + * @method reportAnomaly + * @param {String} id - The alert id + * @param {Object} data - The input values from 'report new anomaly' modal + * @return {Promise} + */ + _reportAnomaly(id, metricUrn, data) { + const reportUrl = `/detection/report-anomaly/${id}?metricUrn=${metricUrn}`; + const requiredProps = ['startTime', 'endTime', 'feedbackType']; + let missingData = false; + requiredProps.forEach(prop => { + if (!data[prop]) { + missingData = true; + } + }); + let queryStringUrl = reportUrl; + + if (missingData) { + return Promise.reject(new Error('missing data')); + } else { + Object.entries(data).forEach(([key, value]) => { + queryStringUrl += `&${encodeURIComponent(key)}=${encodeURIComponent(value)}`; + }); + // Step 1: Report the anomaly + return fetch(queryStringUrl, postProps('')).then((res) => checkStatus(res, 'post')); + } + }, + + /** + * Modal opener for "report missing anomaly". + * @method _triggerOpenReportModal + * @return {undefined} + */ + _triggerOpenReportModal() { + this.setProperties({ + isReportSuccess: false, + isReportFailure: false, + openReportModal: true + }); + // We need the C3/D3 graph to render after its containing parent elements are rendered + // in order to avoid strange overflow effects. + later(() => { + this.set('renderModalContent', true); + }); + }, + actions: { /** * Handle dynamically saving anomaly feedback responses @@ -664,11 +736,9 @@ export default Component.extend({ // Save anomaly feedback await updateAnomalyFeedback(anomalyRecord.anomalyId, responseObj.value); // We make a call to ensure our new response got saved - const anomaly = await verifyAnomalyFeedback(anomalyRecord.anomalyId, responseObj.status); - const filterMap = getWithDefault(anomaly, 'searchFilters.statusFilterMap', null); - // This verifies that the status change got saved as key in the anomaly statusFilterMap property - const keyPresent = filterMap && Object.keys(filterMap).find(key => responseObj.status.includes(key)); - if (keyPresent) { + const anomaly = await verifyAnomalyFeedback(anomalyRecord.anomalyId); + + if (anomaly.feedback && responseObj.value === anomaly.feedback.feedbackType) { this.set('labelResponse', { anomalyId: anomalyRecord.anomalyId, showResponseSaved: true, @@ -680,7 +750,13 @@ export default Component.extend({ let found = false; while (i < anomalies.length && !found) { if (anomalies[i].id === anomalyRecord.anomalyId) { - anomalies[i].feedback.feedbackType = newFeedbackValue; + if (anomalies[i].feedback) { + anomalies[i].feedback.feedbackType = newFeedbackValue; + } else { + anomalies[i].feedback = { + feedbackType: newFeedbackValue + }; + } found = true; } i++; @@ -700,6 +776,60 @@ export default Component.extend({ set(this, 'renderStatusIcon', true); }, + /** + * Handle missing anomaly modal cancel + */ + onCancel() { + this.setProperties({ + isReportSuccess: false, + isReportFailure: false, + openReportModal: false, + renderModalContent: false + }); + }, + + /** + * Open modal for missing anomalies + */ + onClickReportAnomaly() { + this._triggerOpenReportModal(); + }, + + /** + * Received bubbled-up action from modal + * @param {Object} all input field values + */ + onInputMissingAnomaly(inputObj) { + this.set('missingAnomalyProps', inputObj); + }, + + /** + * Handle submission of missing anomaly form from alert-report-modal + */ + onSave() { + const { alertId, missingAnomalyProps, metricUrn } = this.getProperties('alertId', 'missingAnomalyProps', 'metricUrn'); + this._reportAnomaly(alertId, metricUrn, missingAnomalyProps) + .then(() => { + const rangeFormat = 'YYYY-MM-DD HH:mm'; + const startStr = moment(missingAnomalyProps.startTime).format(rangeFormat); + const endStr = moment(missingAnomalyProps.endTime).format(rangeFormat); + this.setProperties({ + isReportSuccess: true, + isReportFailure: false, + openReportModal: false, + reportedRange: `${startStr} - ${endStr}` + }); + }) + // If failure, leave modal open and report + .catch(() => { + this.setProperties({ + missingAnomalyProps: {}, + isReportFailure: true, + isReportSuccess: false + }); + }); + }, + onSelectDimension(selected) { const metricUrnList = get(this, 'metricUrnList'); const newMetricUrn = metricUrnList.find(urn => { diff --git a/thirdeye/thirdeye-frontend/app/pods/components/alert-details/template.hbs b/thirdeye/thirdeye-frontend/app/pods/components/alert-details/template.hbs index 287fc98..c0f479d 100644 --- a/thirdeye/thirdeye-frontend/app/pods/components/alert-details/template.hbs +++ b/thirdeye/thirdeye-frontend/app/pods/components/alert-details/template.hbs @@ -49,12 +49,30 @@ {{/if}} </div> + {{#if isReportSuccess}} + {{#bs-alert type="success" class="te-form__banner te-form__banner--success"}} + <strong>Success:</strong> Anomaly reported for dates <strong>{{reportedRange}}</strong>. Refresh page to see new anomalies... + {{/bs-alert}} + {{/if}} + + {{#if isReportFailure}} + {{#bs-alert type="danger" class="te-form__banner te-form__banner--failure"}} + <strong>Error:</strong> Failed to save reported anomaly. + {{/bs-alert}} + {{/if}} + <div class="te-content-block"> {{#if alertHasDimensions}} <h4 class="te-self-serve__block-title">Anomalies over time for dimension {{selectedDimension}}</h4> {{else}} <h4 class="te-self-serve__block-title">Anomalies over time </h4> {{/if}} + + {{#unless isPreviewMode}} + <a class="te-self-serve__side-link te-self-serve__side-link--high" {{action "onClickReportAnomaly" this}}>Report missing anomaly</a> + {{/unless}} + + {{!-- Dimension selector --}} {{#if alertHasDimensions}} <div class="te-form__select te-form__select--wider col-md-3"> {{#power-select @@ -73,6 +91,38 @@ {{/power-select}} </div> {{/if}} + + {{!-- Missing anomaly modal --}} + {{#te-modal + cancelButtonText="Cancel" + submitButtonText="Report" + submitAction=(action "onSave") + cancelAction=(action "onCancel") + isShowingModal=openReportModal + headerText="Report Undetected Anomaly" + }} + {{#if renderModalContent}} + {{alert-report-modal + series=series + colorMapping=colorMapping + axis=axis + zoom=zoom + legend=legend + metricName=alertData.metric + alertName=alertData.detectionName + predefinedRanges=predefinedRanges + dimensionOptions=dimensionOptions + selectedDimension=selectedDimension + alertHasDimensions=alertHasDimensions + isMetricDataLoading=isMetricDataLoading + isMetricDataInvalid=isMetricDataInvalid + inputAction=(action "onInputMissingAnomaly") + }} + {{else}} + {{ember-spinner}} + {{/if}} + {{/te-modal}} + <div class="col-xs-12 te-graph-container"> {{timeseries-chart series=series diff --git a/thirdeye/thirdeye-frontend/app/pods/components/alert-report-modal/component.js b/thirdeye/thirdeye-frontend/app/pods/components/alert-report-modal/component.js index 8ca639a..df87958 100644 --- a/thirdeye/thirdeye-frontend/app/pods/components/alert-report-modal/component.js +++ b/thirdeye/thirdeye-frontend/app/pods/components/alert-report-modal/component.js @@ -3,26 +3,22 @@ * @module components/alert-report-modal * @property {String} metricName - text for read-only metric field * @property {String} alertName - text for read-only alert field - * @property {Array} dimensionOptions - options for dimension select field * @property {Number} timePickerIncrement - config for time-range-picker - * @property {String} maxTime - timestamp for loading anomaly graph * @property {String} viewRegionStart - range start timestamp * @property {String} viewRegionEnd - range end timestamp * @property {Object} predefinedRanges - needed for time-range-picker * @property {String} uiDateFormat - date format desired for time-range-picker - * @property {String} graphMessageText - text for graph in loading state * @example {{alert-report-modal metricName="mobile_notification_errors" alertName="notification_sessions_mobile" - dimensionOptions=['dimension 1', 'dimension 2'] + selectedDimension='dimension' + alertHasDimensions=true timePickerIncrement=200 - maxTime="1513137100914" viewRegionStart="2017-10-12 23:59" viewRegionEnd="2017-12-11 23:59" predefinedRanges=predefinedRanges uiDateFormat="MMM D, YYYY hh:mm a" - graphMessageText="Loading graph" inputAction=(action "onInputMissingAnomaly") }} * @exports alert-report-modal @@ -37,19 +33,7 @@ export default Component.extend({ containerClassNames: 'alert-report-modal', isNewTrend: false, showTimePicker: true, - timePickerIncrement: 30, - - /** - * Pre-select all dimensions option if none else available - * TODO: use this.get('dimensionOptions.firstObject') - */ - init() { - this._super(...arguments); - const dimensionOptions = this.get('dimensionOptions'); - if (dimensionOptions && dimensionOptions.length === 1 && dimensionOptions[0] === 'All Dimensions') { - this.set('selectedDimension', dimensionOptions[0]); - } - }, + timePickerIncrement: 5, /** * Collects all input data for the post request @@ -68,7 +52,7 @@ export default Component.extend({ startTime: moment(this.get('viewAnomalyStart')).utc().valueOf(), endTime: moment(this.get('viewAnomalyEnd')).utc().valueOf(), feedbackType: this.get('isNewTrend') ? 'ANOMALY_NEW_TREND' : 'ANOMALY', - dimension: this.get('selectedDimension') || null, + dimension: this.get('showDimension') ? this.get('selectedDimension') || null : null, comment: this.get('anomalyComments') || null, externalURL: this.get('anomalyLinks') || null }; @@ -78,6 +62,24 @@ export default Component.extend({ ), /** + * Collects all input data for the post request + * @method reportAnomalyPayload + * @return {Object} Post data + */ + showDimension: computed( + 'alertHasDimensions', + 'selectedDimension', + function() { + const { + alertHasDimensions, + selectedDimension + } = this.getProperties('alertHasDimensions', 'selectedDimension'); + + return (alertHasDimensions && selectedDimension !== 'Choose a dimension'); + } + ), + + /** * Sends post object as is to parent * @method bubbleModalInput */ @@ -98,9 +100,9 @@ export default Component.extend({ }, /** - * Handle selected dimension filter - * @method onSelectDimension - * @param {Object} selectedObj - the user-selected dimension to filter by + * Handle selected feedback type + * @method onFeedbackTypeSelection + * @param {Object} selectedObj - the user-selected feedback type */ onFeedbackTypeSelection(trendSelection) { this.set('isNewTrend', trendSelection); @@ -108,11 +110,10 @@ export default Component.extend({ }, /** - * Handle selected dimension filter - * @method onFeedbackComments - * @param {String} comment field value + * Handle changes to anomaly input + * @method onAnomalyInput */ - onAnomalyInput(value) { + onAnomalyInput() { this.bubbleModalInput(); } diff --git a/thirdeye/thirdeye-frontend/app/pods/components/alert-report-modal/template.hbs b/thirdeye/thirdeye-frontend/app/pods/components/alert-report-modal/template.hbs index 76c12c6..4520f01 100644 --- a/thirdeye/thirdeye-frontend/app/pods/components/alert-report-modal/template.hbs +++ b/thirdeye/thirdeye-frontend/app/pods/components/alert-report-modal/template.hbs @@ -1,9 +1,15 @@ <main class="te-form alert-report-modal__body"> <fieldset class="te-form__section te-form__section--first row" id="select-target1"> - <div class="col-xs-12"> - <legend class="te-report-title">Specify Metric, Alert, and Dimensions</legend> - </div> + {{#if showDimension}} + <div class="col-xs-12"> + <legend class="te-report-title">Specify Metric, Alert, and Dimensions</legend> + </div> + {{else}} + <div class="col-xs-12"> + <legend class="te-report-title">Specify Metric and Alert</legend> + </div> + {{/if}} <div class="form-group col-xs-5"> <label for="select-metric" class="control-label te-label required">Metric</label> @@ -27,23 +33,18 @@ }} </div> - <div class="form-group col-xs-7"> - <label for="report-select-dimension" class="control-label te-label">Dimensions</label> - {{#power-select - triggerId="report-select-dimension" - triggerClass="te-form__select" - verticalPosition="below" - placeholder="Select a dimension" - renderInPlace=true - options=dimensionOptions - searchEnabled=false - selected=selectedDimension - onchange=(action "onSelectDimension") - as |dimension| - }} - {{dimension}} - {{/power-select}} - </div> + {{#if showDimension}} + <div class="form-group col-xs-7"> + <label for="report-select-dimension" class="control-label te-label">Dimensions</label> + {{input + type="text" + id="report-select-dimension" + class="form-control te-input" + value=selectedDimension + disabled=true + }} + </div> + {{/if}} </fieldset> <fieldset class="te-form__section row"> @@ -69,20 +70,12 @@ </fieldset> <fieldset class="te-form__section te-form__section--graph"> - {{self-serve-graph - isMetricDataLoading=isMetricDataLoading - isMetricDataInvalid=isMetricDataInvalid - isFetchingDimensions=isFetchingDimensions - isDimensionFetchDone=isDimensionFetchDone - availableDimensions=availableDimensions - selectedDimension=alertDimension - graphMailtoLink=graphMailtoLink - isTopDimensionsAllowed=false - isDimensionError=false - isMetricSelected=true - metricData=metricData - topDimensions=topDimensions - componentId='report-anomaly' + {{timeseries-chart + series=series + colorMapping=colorMapping + axis=axis + zoom=zoom + legend=legend }} </fieldset> diff --git a/thirdeye/thirdeye-frontend/app/pods/components/yaml-editor/component.js b/thirdeye/thirdeye-frontend/app/pods/components/yaml-editor/component.js index 07f384a..1777b90 100644 --- a/thirdeye/thirdeye-frontend/app/pods/components/yaml-editor/component.js +++ b/thirdeye/thirdeye-frontend/app/pods/components/yaml-editor/component.js @@ -305,6 +305,7 @@ export default Component.extend({ if(value.yaml) { set(this, 'currentYamlSettings', value.yaml); set(this, 'groupName', value); + set(this, 'subscriptionGroupId', value.id); } }, @@ -419,12 +420,11 @@ export default Component.extend({ async saveEditYamlAction() { const { alertYaml, - detectionSettingsYaml, + currentYamlSettings, notifications, alertId, subscriptionGroupId - } = getProperties(this, 'alertYaml', 'detectionSettingsYaml', 'notifications', 'alertId', 'subscriptionGroupId'); - + } = getProperties(this, 'alertYaml', 'currentYamlSettings', 'notifications', 'alertId', 'subscriptionGroupId'); //PUT alert const alert_url = `/yaml/${alertId}`; const alertPostProps = { @@ -450,7 +450,7 @@ export default Component.extend({ const setting_url = `/yaml/subscription/${subscriptionGroupId}`; const settingsPostProps = { method: 'PUT', - body: detectionSettingsYaml, + body: currentYamlSettings, headers: { 'content-type': 'text/plain' } }; try { diff --git a/thirdeye/thirdeye-frontend/app/pods/manage/explore/template.hbs b/thirdeye/thirdeye-frontend/app/pods/manage/explore/template.hbs index d0f178b..c5698d8 100644 --- a/thirdeye/thirdeye-frontend/app/pods/manage/explore/template.hbs +++ b/thirdeye/thirdeye-frontend/app/pods/manage/explore/template.hbs @@ -29,6 +29,7 @@ showDetails=true dataIsCurrent=true alertId=model.alertId + alertData=model.alertData metricUrn=model.metricUrn metricUrnList=model.metricUrnList }} diff --git a/thirdeye/thirdeye-frontend/app/utils/anomaly.js b/thirdeye/thirdeye-frontend/app/utils/anomaly.js index 84c44a4..ed74925 100644 --- a/thirdeye/thirdeye-frontend/app/utils/anomaly.js +++ b/thirdeye/thirdeye-frontend/app/utils/anomaly.js @@ -89,7 +89,7 @@ anomalyResponseObjNew.forEach((obj) => { * @return {Ember.RSVP.Promise} */ export function updateAnomalyFeedback(anomalyId, feedbackType) { - const url = `/anomalies/updateFeedback/${anomalyId}`; + const url = `/dashboard/anomaly-merged-result/feedback/${anomalyId}`; const data = { feedbackType, comment: '' }; return fetch(url, postProps(data)).then((res) => checkStatus(res, 'post')); } @@ -127,7 +127,7 @@ export function getAnomaliesByAlertId(alertId, startTime, endTime) { * @return {Ember.RSVP.Promise} */ export function verifyAnomalyFeedback(anomalyId) { - const url = `${anomalyApiUrls.getAnomalyDataUrl()}${anomalyId}`; + const url = `${anomalyApiUrls.getAnomalyDataUrl(anomalyId)}`; return fetch(url).then(checkStatus); } diff --git a/thirdeye/thirdeye-frontend/app/utils/api/anomaly.js b/thirdeye/thirdeye-frontend/app/utils/api/anomaly.js index 77e7905..de4aa5a 100644 --- a/thirdeye/thirdeye-frontend/app/utils/api/anomaly.js +++ b/thirdeye/thirdeye-frontend/app/utils/api/anomaly.js @@ -5,8 +5,8 @@ * @returns {String} the complete anomaly data url * @example getAnomalyDataUrl(1491804013000, 1491890413000) // yields => /anomalies/search/anomalyIds/1491804013000/1491890413000/1?anomalyIds= */ -export function getAnomalyDataUrl(startStamp = 0, endStamp = 0) { - return `/anomalies/search/anomalyIds/${startStamp}/${endStamp}/1?anomalyIds=`; +export function getAnomalyDataUrl(anomalyId) { + return `/dashboard/anomalies/view/${anomalyId}`; } /** diff --git a/thirdeye/thirdeye-frontend/tests/unit/utils/api/anomaly-test.js b/thirdeye/thirdeye-frontend/tests/unit/utils/api/anomaly-test.js index c841f24..2e7e57c 100644 --- a/thirdeye/thirdeye-frontend/tests/unit/utils/api/anomaly-test.js +++ b/thirdeye/thirdeye-frontend/tests/unit/utils/api/anomaly-test.js @@ -4,5 +4,5 @@ import { getAnomalyDataUrl } from 'thirdeye-frontend/utils/api/anomaly'; module('Unit | Utility | api/anomaly'); test('it returns anomaly data url correctly', function(assert) { - assert.equal(getAnomalyDataUrl(0, 0), '/anomalies/search/anomalyIds/0/0/1?anomalyIds=', 'it returns anomaly data url duration ok'); + assert.equal(getAnomalyDataUrl(0), '/dashboard/anomalies/view/0', 'it returns anomaly data url duration ok'); }); --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
