/* * RHQ Management Platform * Copyright (C) 2005-2014 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ package org.rhq.coregui.client.operation; import java.util.ArrayList; import java.util.EnumSet; import java.util.LinkedHashMap; import com.google.gwt.user.client.History; import com.google.gwt.user.client.rpc.AsyncCallback; import com.smartgwt.client.data.Criteria; import com.smartgwt.client.data.DSRequest; import com.smartgwt.client.data.SortSpecifier; import com.smartgwt.client.types.SortDirection; import com.smartgwt.client.widgets.Canvas; import com.smartgwt.client.widgets.form.fields.SelectItem; import com.smartgwt.client.widgets.form.fields.SpacerItem; import com.smartgwt.client.widgets.grid.ListGridField; import com.smartgwt.client.widgets.grid.ListGridRecord; import org.rhq.core.domain.common.EntityContext; import org.rhq.core.domain.operation.OperationRequestStatus; import org.rhq.coregui.client.CoreGUI; import org.rhq.coregui.client.IconEnum; import org.rhq.coregui.client.ImageManager; import org.rhq.coregui.client.components.form.DateFilterItem; import org.rhq.coregui.client.components.form.EnumSelectItem; import org.rhq.coregui.client.components.table.Table.TableActionInfo.TableActionInfoBuilder; import org.rhq.coregui.client.components.table.TableAction; import org.rhq.coregui.client.components.table.TableSection; import org.rhq.coregui.client.components.view.HasViewName; import org.rhq.coregui.client.components.view.ViewName; import org.rhq.coregui.client.gwt.GWTServiceLookup; import org.rhq.coregui.client.gwt.OperationGWTServiceAsync; import org.rhq.coregui.client.inventory.resource.detail.operation.history.ResourceOperationHistoryDetailsView; import org.rhq.coregui.client.util.enhanced.EnhancedIButton.ButtonColor; import org.rhq.coregui.client.util.message.Message; import org.rhq.coregui.client.util.message.Message.Option; import org.rhq.coregui.client.util.message.Message.Severity; /** * A view that displays a paginated table of operation history. Support exists of subsystem and resource contexts. * Group operation history is (currently) handled separately as the view is comprised of group operation history * entities, not [resource] operation history entities. ( * @author Jay Shaughnessy */ public class OperationHistoryView extends TableSection<OperationHistoryDataSource> implements HasViewName { public static final ViewName SUBSYSTEM_VIEW_ID = new ViewName("RecentOperations", MSG.common_title_recent_operations(), IconEnum.RECENT_OPERATIONS); private static final Criteria INITIAL_CRITERIA = new Criteria(); private static final SortSpecifier DEFAULT_SORT_SPECIFIER = new SortSpecifier( OperationHistoryDataSource.Field.CREATED_TIME, SortDirection.DESCENDING); protected SelectItem statusFilter; protected DateFilterItem startDateFilter; protected DateFilterItem endDateFilter; EntityContext context; boolean hasControlPermission; OperationHistoryDataSource dataSource; private boolean showNewScheduleButton = true; static { OperationRequestStatus[] statusValues = OperationRequestStatus.values(); String[] statusNames = new String[statusValues.length]; int i = 0; for (OperationRequestStatus s : statusValues) { statusNames[i++] = s.name(); } INITIAL_CRITERIA.addCriteria(OperationHistoryDataSource.Field.STATUS, statusNames); } // for subsystem views public OperationHistoryView() { this(SUBSYSTEM_VIEW_ID.getTitle(), EntityContext.forSubsystemView(), false); } public OperationHistoryView(EntityContext entityContext) { this(SUBSYSTEM_VIEW_ID.getTitle(), entityContext, false); } public OperationHistoryView(String tableTitle, EntityContext entityContext) { this(tableTitle, entityContext, false); } protected OperationHistoryView(String tableTitle, EntityContext context, boolean hasControlPermission) { super(tableTitle, INITIAL_CRITERIA, new SortSpecifier[] { DEFAULT_SORT_SPECIFIER }); this.context = context; this.hasControlPermission = hasControlPermission; setInitialCriteriaFixed(false); setDataSource(getDataSource()); } @Override public OperationHistoryDataSource getDataSource() { if (null == this.dataSource) { this.dataSource = new OperationHistoryDataSource(context); } return this.dataSource; } @Override protected void configureTableFilters() { LinkedHashMap<String, String> statusValues = new LinkedHashMap<String, String>(4); statusValues.put(OperationRequestStatus.SUCCESS.name(), MSG.common_status_success()); statusValues.put(OperationRequestStatus.INPROGRESS.name(), MSG.common_status_inprogress()); statusValues.put(OperationRequestStatus.CANCELED.name(), MSG.common_status_canceled()); statusValues.put(OperationRequestStatus.FAILURE.name(), MSG.common_status_failed()); LinkedHashMap<String, String> statusIcons = new LinkedHashMap<String, String>(3); statusIcons.put(OperationRequestStatus.SUCCESS.name(), ImageManager.getOperationResultsIcon(OperationRequestStatus.SUCCESS)); statusIcons.put(OperationRequestStatus.INPROGRESS.name(), ImageManager.getOperationResultsIcon(OperationRequestStatus.INPROGRESS)); statusIcons.put(OperationRequestStatus.CANCELED.name(), ImageManager.getOperationResultsIcon(OperationRequestStatus.CANCELED)); statusIcons.put(OperationRequestStatus.FAILURE.name(), ImageManager.getOperationResultsIcon(OperationRequestStatus.FAILURE)); statusFilter = new EnumSelectItem(OperationHistoryDataSource.Field.STATUS, MSG.common_title_operation_status(), OperationRequestStatus.class, statusValues, statusIcons); startDateFilter = new DateFilterItem(DateFilterItem.START_DATE_FILTER, MSG.filter_from_date()); endDateFilter = new DateFilterItem(DateFilterItem.END_DATE_FILTER, MSG.filter_to_date()); SpacerItem spacerItem = new SpacerItem(); spacerItem.setColSpan(2); if (isShowFilterForm()) { setFilterFormItems(statusFilter, startDateFilter, spacerItem, endDateFilter); } } @Override protected void configureTable() { ArrayList<ListGridField> dataSourceFields = getDataSource().getListGridFields(); getListGrid().setFields(dataSourceFields.toArray(new ListGridField[dataSourceFields.size()])); setupTableInteractions(); super.configureTable(); } protected boolean hasControlPermission() { return this.hasControlPermission; } protected void setupTableInteractions() { addTableAction(MSG.common_button_delete(), getDeleteConfirmMessage(), ButtonColor.RED, new TableAction() { public boolean isEnabled(ListGridRecord[] selection) { int count = selection.length; return (count >= 1 && hasControlPermission()); } public void executeAction(ListGridRecord[] selection, Object actionValue) { deleteSelectedRecords(); } }); addTableAction(MSG.view_operationHistoryList_button_forceDelete(), getDeleteConfirmMessage(), ButtonColor.RED, new TableAction() { public boolean isEnabled(ListGridRecord[] selection) { int count = selection.length; return (count >= 1 && hasControlPermission()); } public void executeAction(ListGridRecord[] selection, Object actionValue) { DSRequest requestProperties = new DSRequest(); requestProperties.setAttribute("force", true); deleteSelectedRecords(requestProperties); } }); addTableAction(MSG.common_button_cancel(), MSG.view_operationHistoryList_cancelConfirm(), new TableAction() { public boolean isEnabled(ListGridRecord[] selection) { int count = selection.length; for (ListGridRecord item : selection) { if (!OperationRequestStatus.INPROGRESS.name().equals( item.getAttribute(OperationHistoryDataSource.Field.STATUS))) { count--; // one selected item was not in-progress, it doesn't count } } return (count >= 1 && hasControlPermission()); } public void executeAction(ListGridRecord[] selection, Object actionValue) { int numCancelRequestsSubmitted = 0; OperationGWTServiceAsync opService = GWTServiceLookup.getOperationService(); for (ListGridRecord toBeCanceled : selection) { // only cancel those selected operations that are currently in progress if (OperationRequestStatus.INPROGRESS.name().equals( toBeCanceled.getAttribute(OperationHistoryDataSource.Field.STATUS))) { numCancelRequestsSubmitted++; final int historyId = toBeCanceled.getAttributeAsInt(OperationHistoryDataSource.Field.ID); opService.cancelOperationHistory(historyId, false, new AsyncCallback<Void>() { public void onSuccess(Void result) { Message msg = new Message(MSG.view_operationHistoryList_cancelSuccess(String .valueOf(historyId)), Severity.Info, EnumSet.of(Option.BackgroundJobResult)); CoreGUI.getMessageCenter().notify(msg); }; public void onFailure(Throwable caught) { Message msg = new Message(MSG.view_operationHistoryList_cancelFailure(String .valueOf(historyId)), caught, Severity.Error, EnumSet .of(Option.BackgroundJobResult)); CoreGUI.getMessageCenter().notify(msg); }; }); } } CoreGUI.getMessageCenter().notify( new Message(MSG.view_operationHistoryList_cancelSubmitted(String .valueOf(numCancelRequestsSubmitted)), Severity.Info)); refreshTableInfo(); } }); if (!context.isSubsystemView() && showNewScheduleButton) { TableActionInfo rescheduleAction = new TableActionInfoBuilder(MSG.common_button_reschedule(), new RescheduleTableAction()).setTooltip(MSG.common_button_reschedule_tooltip()) .setButtonColor(ButtonColor.BLUE).createTableActionInfo(); addTableAction(rescheduleAction); addTableAction(MSG.common_button_new() + " " + MSG.common_button_schedule(), ButtonColor.BLUE, new NewScheduleTableAction()); } } @Override protected void deleteSelectedRecords(DSRequest requestProperties) { disableAllFooterControls(); // wait for this to complete before we allow more... final ListGridRecord[] recordsToBeDeleted = getListGrid().getSelectedRecords(); final int numberOfRecordsToBeDeleted = recordsToBeDeleted.length; final Boolean forceValue = (requestProperties != null && requestProperties.getAttributeAsBoolean("force")); final boolean force = ((forceValue != null) && forceValue); final int[] idsToBeDeleted = new int[numberOfRecordsToBeDeleted]; int i = 0; for (ListGridRecord record : recordsToBeDeleted) { idsToBeDeleted[i++] = record.getAttributeAsInt(OperationHistoryDataSource.Field.ID); } GWTServiceLookup.getOperationService().deleteOperationHistories(idsToBeDeleted, force, new AsyncCallback<Void>() { public void onSuccess(Void result) { CoreGUI.getMessageCenter().notify( new Message(MSG.view_operationHistoryList_deleteSuccess(String .valueOf(numberOfRecordsToBeDeleted)))); refresh(); refreshTableInfo(); //enable proper buttons } public void onFailure(Throwable caught) { CoreGUI.getErrorHandler().handleError(MSG.view_operationHistoryList_deleteFailure(), caught); refresh(); refreshTableInfo(); // enable proper buttons } }); } public EntityContext getContext() { return context; } @Override public Canvas getDetailsView(Integer id) { return new ResourceOperationHistoryDetailsView(); } @Override protected String getTitleFieldName() { return OperationHistoryDataSource.Field.OPERATION_NAME; } @Override public ViewName getViewName() { return SUBSYSTEM_VIEW_ID; } public void setShowNewScheduleButton(boolean showNewScheduleButton) { this.showNewScheduleButton = showNewScheduleButton; } private class NewScheduleTableAction implements TableAction { public boolean isEnabled(ListGridRecord[] selection) { return hasControlPermission(); } public void executeAction(ListGridRecord[] selection, Object actionValue) { String url = getViewUrl(selection); if (url != null) { CoreGUI.goToView(url); } } protected String getViewUrl(ListGridRecord[] selection) { // CoreGUI.goToView(LinkManager.getEntityTabLink(context, "Operations", "Schedules/0")); // the above doesn't work because EntityContext doesn't know if it is autogroup or not // -> using the relative URL hack String url = History.getToken(); String lastChunk = url.substring(url.lastIndexOf("/") + 1); if ("Activity".equals(lastChunk)) { url = url.substring(0, url.lastIndexOf("/")); url = url.substring(0, url.lastIndexOf("/")) + "/Operations"; } else if ("History".equals(lastChunk)) { url = url.substring(0, url.lastIndexOf("/")); } else { try { Integer.parseInt(lastChunk); url += "/Operations"; } catch (NumberFormatException nfe) { // do nothing } } if ("Operations".equals(url.substring(url.lastIndexOf("/") + 1))) { url += "/Schedules/0"; return url; } return null; } } private class RescheduleTableAction extends NewScheduleTableAction { @Override public boolean isEnabled(ListGridRecord[] selection) { return super.isEnabled(selection) && selection.length == 1; } @Override protected String getViewUrl(ListGridRecord[] selection) { String viewUrl = super.getViewUrl(selection); if (viewUrl != null) { ListGridRecord selectedRecord = selection[0]; Integer operationHistoryId = selectedRecord.getAttributeAsInt(OperationHistoryDataSource.Field.ID); viewUrl += "/example=" + operationHistoryId; } return viewUrl; } } }