jihaozh commented on a change in pull request #5593:
URL: https://github.com/apache/incubator-pinot/pull/5593#discussion_r443010483
##########
File path: thirdeye/thirdeye-frontend/app/utils/yaml-tools.js
##########
@@ -338,12 +339,159 @@ export function postYamlProps(postData) {
};
}
+export function enrichAlertResponseObject(alerts, subscriptionGroups) {
+ for (let yamlAlert of alerts) {
+ let dimensions = '';
+ let dimensionsArray = yamlAlert.dimensionExploration ?
yamlAlert.dimensionExploration.dimensions : null;
+ if (Array.isArray(dimensionsArray)) {
+ dimensionsArray.forEach(dim => {
+ dimensions = dimensions + `${dim}, `;
+ });
+ dimensions = dimensions.substring(0, dimensions.length-2);
+ }
+ Object.assign(yamlAlert, {
+ functionName: yamlAlert.name,
+ collection: yamlAlert.datasetNames.toString(),
+ granularity: yamlAlert.monitoringGranularity.toString(),
+ type: _detectionType(yamlAlert),
+ exploreDimensions: dimensions,
+ filters: formatYamlFilter(yamlAlert.filters),
+ isNewPipeline: true
+ });
+ }
+
+ // Iterate through detection alerter to enhance all yaml alert with extra
properties (group name, application)
+ for (let subscriptionGroup of subscriptionGroups){
+ const detectionConfigIds = subscriptionGroup.detectionConfigIds;
+ for (let id of detectionConfigIds) {
+ let foundAlert = alerts.find(yamlAlert => yamlAlert.id === id);
+ if (foundAlert) {
+ Object.assign(foundAlert, {
+ application: foundAlert.application ? foundAlert.application + ", "
+ subscriptionGroup.application : subscriptionGroup.application,
+ group: foundAlert.group ? foundAlert.group + ", " +
subscriptionGroup.name : subscriptionGroup.name
+ });
+ }
+ }
+ }
+
+ return alerts;
+}
+
+/**
+ * Grab detection type if available, else return yamlAlert.pipelineType
+ */
+function _detectionType(yamlAlert) {
+ if (yamlAlert.rules && Array.isArray(yamlAlert.rules) &&
yamlAlert.rules.length > 0) {
+ if (yamlAlert.rules[0].detection &&
Array.isArray(yamlAlert.rules[0].detection) &&
yamlAlert.rules[0].detection.length > 0) {
+ return yamlAlert.rules[0].detection[0].type;
+ }
+ }
+ return yamlAlert.pipelineType;
+}
+
+// Maps filter name to alert property for filtering
+export const filterToPropertyMap = {
+ application: 'application',
+ subscription: 'group',
+ owner: 'createdBy',
+ type: 'type',
+ metric: 'metric',
+ dataset: 'collection',
+ granularity: 'granularity'
+};
+
+// Maps filter name to alerts API params for filtering
+export const filterToParamsMap = {
+ application: 'application',
+ subscription: 'subscriptionGroup',
+ owner: 'createdBy',
+ type: 'ruleType',
+ metric: 'metric',
+ dataset: 'dataset',
+ granularity: 'granularity',
+ status: 'active',
+ names: 'names'
+};
+
+export function populateFiltersLocal(originalAlerts, rules) {
+ // This filter category is "secondary". To add more, add an entry here and
edit the controller's "filterToPropertyMap"
+ const filterBlocksLocal = [
+ {
+ name: 'status',
+ title: 'Status',
+ type: 'checkbox',
+ selected: ['Active', 'Inactive'],
+ filterKeys: ['Active', 'Inactive']
+ },
+ {
+ name: 'application',
+ title: 'Applications',
+ type: 'search',
+ matchWidth: true,
+ hasNullOption: true, // allow searches for 'none'
+ filterKeys: []
+ },
+ {
+ name: 'subscription',
+ title: 'Subscription Groups',
+ hasNullOption: true, // allow searches for 'none'
+ type: 'search',
+ filterKeys: []
+ },
+ {
+ name: 'owner',
+ title: 'Owners',
+ type: 'search',
+ matchWidth: true,
+ filterKeys: []
+ },
+ {
+ name: 'type',
+ title: 'Detection Type',
+ type: 'select',
+ filterKeys: rules
+ },
+ {
+ name: 'metric',
+ title: 'Metrics',
+ type: 'search',
+ filterKeys: []
+ },
+ {
+ name: 'dataset',
+ title: 'Datasets',
+ type: 'search',
+ filterKeys: []
+ },
+ {
+ name: 'granularity',
Review comment:
seems we can remove this filter in the UI because the endpoint can't
perform this search?
##########
File path: thirdeye/thirdeye-frontend/app/utils/api/self-serve.js
##########
@@ -142,20 +102,93 @@ const createNewDataset = '/onboard/create';
*/
const setAlertActivationUrl = (detectionId, active) =>
`/yaml/activation/${detectionId}?active=${active}`;
+/**
+ * GET autocomplete request for alert by name
+ * @param {String} functionName: alert name
+ * @see {@link https://tinyurl.com/ybelagey|class DataResource}
+ */
+const alertByName = functionName =>
`/data/autocomplete/detection?name=${encodeURIComponent(functionName)}`;
+
+/**
+ * GET autocomplete request for application
+ * @param {String} app: application name
+ */
+const application = app =>
`/data/autocomplete/application?name=${encodeURIComponent(app)}`;
+
+/**
+ * GET autocomplete request for dataset
+ * @param {String} type: dataset name
+ */
+const dataset = name =>
`/data/autocomplete/dataset?name=${encodeURIComponent(name)}`;
+
+/**
+ * GET autocomplete request for detection type
+ * @param {String} type: detection type
+ */
+const detectionType = type =>
`/data/autocomplete/ruleType?name=${encodeURIComponent(type)}`;
+
+/**
+ * GET autocomplete request for metric data by name
+ * @param {String} metricName: metric name
+ * @see {@link https://tinyurl.com/y7hhzm33|class DataResource}
+ */
+const metric = metricName =>
`/data/autocomplete/metric?name=${encodeURIComponent(metricName)}`;
+
+/**
+ * GET autocomplete request for alerty owner
+ * @param {String} name: owner name
+ */
+const owner = name =>
`/data/autocomplete/detection-createdby?name=${encodeURIComponent(name)}`;
+
+/**
+ * GET autocomplete request for subscription group by name
+ * @param {String} name: group name
+ */
+const subscriptionGroup = name =>
`/data/autocomplete/subscription?name=${encodeURIComponent(name)}`;
+
+/**
+ * GET alerts, filtered and paginated according to params
+ * @param {Object} params: params to query alerts by
+ */
+const getPaginatedAlertsUrl = params => {
+ const paramKeys = Object.keys(params || {});
+ let url = '/alerts';
+ if (paramKeys.length === 0) {
+ return url;
+ }
+ url += '?';
+ let index = 0;
+ paramKeys.forEach(key => {
+ const paramString = `${key}=${encodeURIComponent(params[key])}`;
Review comment:
It seems the request URL for when there are multiple values is
incorrect. it should be
`/alerts?limit=10&offset=0&application=app1&application=app2` not
`/alerts?limit=10&offset=0&application=app1%2Capp2`. Otherwise, it won't get
the right result. Could you double check?
##########
File path: thirdeye/thirdeye-frontend/app/pods/manage/alerts/index/route.js
##########
@@ -27,213 +20,44 @@ export default Route.extend(AuthenticatedRouteMixin, {
model() {
return hash({
- applications: fetch('/thirdeye/entity/APPLICATION').then(checkStatus),
- detectionAlertConfig:
fetch('/detection/subscription-groups').then(checkStatus),
- polishedDetectionYaml: fetch('/yaml/list').then(checkStatus)
+ subscriptionGroupConfig:
fetch('/detection/subscription-groups').then(checkStatus),
Review comment:
It shouldn't need to get all subscription groups anymore, is it?
##########
File path: thirdeye/thirdeye-frontend/app/pods/manage/alerts/index/controller.js
##########
@@ -281,146 +297,50 @@ export default Controller.extend({
),
/**
- * We are recalculating the options of each selection field. The values come
from the aggregated
- * properties across all filtered alerts. For example, it returns all
possible values for 'application'
- * @method _recalculateFilterKeys
- * @param {Array} alertsCollection - array of alerts we are extracting
values from
- * @param {Object} blockItem - the current search filter object
- * @returns {Array} - a deduped array of values to use as select options
- * @private
+ * flag meaning alerts are loading for current page
+ * @type {Boolean}
*/
- _recalculateFilterKeys(alertsCollection, blockItem) {
- const filterToPropertyMap = get(this, 'filterToPropertyMap');
- // Aggregate all existing values for our target properties in the current
array collection
- let alertPropsAsKeys = [];
- // Make sure subscription groups are not bundled for filter parameters
- if (blockItem.name === 'subscription') {
- alertsCollection.forEach(alert => {
- let groups = alert[filterToPropertyMap[blockItem.name]];
- if (groups) {
- groups.split(", ").forEach(g => {
- alertPropsAsKeys.push(g);
- });
- }
- });
- } else if (blockItem.name === 'application') {
- // Make sure applications are not bundled for filter parameters
- alertsCollection.forEach(alert => {
- let applications = alert[filterToPropertyMap[blockItem.name]];
- if (applications) {
- applications.split(", ").forEach(a => {
- alertPropsAsKeys.push(a);
- });
- }
- });
- } else {
- alertPropsAsKeys = alertsCollection.map(alert =>
alert[filterToPropertyMap[blockItem.name]]);
+ isLoading: computed(
+ '_getAlerts.isIdle',
+ function() {
+ return !get(this, '_getAnomalies.isIdle');
}
- // Add 'none' select option if allowed
- const canInsertNullOption = alertPropsAsKeys.includes(undefined) &&
blockItem.hasNullOption;
- if (canInsertNullOption) { alertPropsAsKeys.push('none'); }
- // Return a deduped array containing all of the values for this property
in the current set of alerts
- return [ ...new Set(powerSort(alertPropsAsKeys.filter(val =>
isPresent(val)), null)) ];
- },
+ ),
/**
- * This is the core filtering method which acts upon a set of initial alerts
to return a subset
- * @method _filterAlerts
- * @param {Array} initialAlerts - array of all alerts to start with
- * @param {Object} filters - filter key/values to process
- * @example
- * {
- * application: ['app name a', 'app name b'],
- * status: ['active'],
- * owner: ['[email protected], [email protected]'],
- * type: null
- * }
- * @returns {undefined}
- * @private
+ * subscription groups which user is part of
+ * @type {Array}
*/
- _filterAlerts(initialAlerts, filters) {
- const filterToPropertyMap = get(this, 'filterToPropertyMap');
- // A click on a primary alert filter will reset 'filteredAlerts'
- if (filters.primary) {
- this._processPrimaryFilters(initialAlerts, filters.primary);
- }
- // Pick up cached alert array for the secondary filters
- let filteredAlerts = get(this, 'filteredAlerts');
- // If there is a secondary filter present, filter by it, using the keys
we've set up in our filter map
- Object.keys(filterToPropertyMap).forEach((filterKey) => {
- let filterValueArray = filters[filterKey];
- if (filterValueArray && filterValueArray.length) {
- let newAlerts = filteredAlerts.filter(alert => {
- // See 'filterToPropertyMap' in route. For filterKey = 'owner' this
would map alerts by alert['createdBy'] = x
- const targetAlertPropertyValue =
alert[filterToPropertyMap[filterKey]];
- let alertMeetsCriteria = false;
- // In the cases for subscription and application, there can be
multiple values. We just need to match on one
- if (filterKey === "subscription") {
- if (targetAlertPropertyValue) {
- filterValueArray.forEach(val => {
- if (targetAlertPropertyValue.includes(val)) {
- alertMeetsCriteria = true;
- }
- });
- }
- } else if (filterKey === "application") {
- if (targetAlertPropertyValue) {
- filterValueArray.forEach(val => {
- if (targetAlertPropertyValue.includes(val)) {
- alertMeetsCriteria = true;
- }
- });
- }
- } else {
- alertMeetsCriteria = targetAlertPropertyValue &&
filterValueArray.includes(targetAlertPropertyValue);
- }
- const isMatchForNone =
!alert.hasOwnProperty(filterToPropertyMap[filterKey]) &&
filterValueArray.includes('none');
- return alertMeetsCriteria || isMatchForNone;
- });
- filteredAlerts = newAlerts;
- }
- });
-
- // If status filter is present, we re-build the results array to contain
only active alerts, inactive alerts, or both.
- if (filters.status) {
- const concatStatus = filters.status.length ?
filters.status.join().toLowerCase() : 'active';
- const requireAll = filters.status.includes('Active') &&
filters.status.includes('Inactive');
- const alertsByState = {
- active: filteredAlerts.filter(alert => alert.active),
- inactive: filteredAlerts.filter(alert => !alert.active)
- };
- filteredAlerts = requireAll ? [ ...alertsByState.active,
...alertsByState.inactive ] : alertsByState[concatStatus];
+ mySubscriptionGroups: computed(
+ 'subscriptionGroupConfig',
+ 'user',
+ function() {
+ const {
+ user,
+ subscriptionGroupConfig
+ } = this.getProperties('user', 'subscriptionGroupConfig');
+
+ // Find subscription groups current user is associated with
+ return subscriptionGroupConfig.filter((group) => {
Review comment:
For searching the alerts the user is subscribed to, there is a param in
the `alerts` endpoint called `subscribedBy`. The UI can get the related alerts
directly by passing the user name into endpoint.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]