git-svn-id: http://svn.d4science-ii.research-infrastructures.eu/gcube/trunk/portlets/user/workspace@95806 82a268e6-3cf1-43bd-a215-b396298e98cf
This commit is contained in:
parent
25b7125dda
commit
789fe40149
|
@ -71,6 +71,8 @@ import org.gcube.portlets.user.workspace.client.event.SearchTextEvent;
|
|||
import org.gcube.portlets.user.workspace.client.event.SearchTextEventHandler;
|
||||
import org.gcube.portlets.user.workspace.client.event.SendMessageEvent;
|
||||
import org.gcube.portlets.user.workspace.client.event.SendMessageEventHandler;
|
||||
import org.gcube.portlets.user.workspace.client.event.StoreGridChangedEvent;
|
||||
import org.gcube.portlets.user.workspace.client.event.StoreGridChangedEventHandler;
|
||||
import org.gcube.portlets.user.workspace.client.event.TrashEvent;
|
||||
import org.gcube.portlets.user.workspace.client.event.TrashEventHandler;
|
||||
import org.gcube.portlets.user.workspace.client.event.VREChangePermissionsEvent;
|
||||
|
@ -82,7 +84,6 @@ import org.gcube.portlets.user.workspace.client.interfaces.EventsTypeEnum;
|
|||
import org.gcube.portlets.user.workspace.client.interfaces.SubscriberInterface;
|
||||
import org.gcube.portlets.user.workspace.client.model.FileGridModel;
|
||||
import org.gcube.portlets.user.workspace.client.model.FileModel;
|
||||
import org.gcube.portlets.user.workspace.client.model.FileTrashedModel;
|
||||
import org.gcube.portlets.user.workspace.client.model.FolderModel;
|
||||
import org.gcube.portlets.user.workspace.client.model.ScopeModel;
|
||||
import org.gcube.portlets.user.workspace.client.view.WorskpacePortlet;
|
||||
|
@ -174,6 +175,15 @@ public class AppController implements SubscriberInterface {
|
|||
private void bind() {
|
||||
|
||||
|
||||
eventBus.addHandler(StoreGridChangedEvent.TYPE, new StoreGridChangedEventHandler() {
|
||||
|
||||
@Override
|
||||
public void onStoreChanged(StoreGridChangedEvent storeGridChangedEvent) {
|
||||
|
||||
wsPortlet.getGxtCardLayoutResultPanel().getToolBarItemDetails().updateItemsNumber(storeGridChangedEvent.getSize());
|
||||
}
|
||||
});
|
||||
|
||||
eventBus.addHandler(TrashEvent.TYPE, new TrashEventHandler() {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -74,6 +74,7 @@ public class WorkspacePortlet implements EntryPoint {
|
|||
appController.getMainPanel().setHeight(rootHeight);
|
||||
appController.getMainPanel().setWidth(rootWidth);
|
||||
}
|
||||
|
||||
private void showGuidedTour() {
|
||||
GWT.log("oh");
|
||||
GWT.runAsync(GCUBEGuidedTour.class, new RunAsyncCallback() {
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package org.gcube.portlets.user.workspace.client.event;
|
||||
|
||||
import com.google.gwt.event.shared.GwtEvent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Francesco Mangiacrapa francesco.mangiacrapa@isti.cnr.it
|
||||
*
|
||||
*/
|
||||
public class StoreGridChangedEvent extends GwtEvent<StoreGridChangedEventHandler> {
|
||||
public static Type<StoreGridChangedEventHandler> TYPE = new Type<StoreGridChangedEventHandler>();
|
||||
|
||||
private int size = -1;
|
||||
|
||||
|
||||
/**
|
||||
* @param size
|
||||
*/
|
||||
public StoreGridChangedEvent(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type<StoreGridChangedEventHandler> getAssociatedType() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dispatch(StoreGridChangedEventHandler handler) {
|
||||
handler.onStoreChanged(this);
|
||||
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package org.gcube.portlets.user.workspace.client.event;
|
||||
|
||||
import com.google.gwt.event.shared.EventHandler;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Francesco Mangiacrapa francesco.mangiacrapa@isti.cnr.it
|
||||
*
|
||||
*/
|
||||
public interface StoreGridChangedEventHandler extends EventHandler {
|
||||
|
||||
/**
|
||||
* @param storeGridChangedEvent
|
||||
*/
|
||||
void onStoreChanged(StoreGridChangedEvent storeGridChangedEvent);
|
||||
}
|
|
@ -43,6 +43,6 @@ public class GroupingStoreModel implements StoreOperationsInterface{
|
|||
public void setListModel(List<FileGridModel> listModel) {
|
||||
this.store.removeAll();
|
||||
this.store.add(listModel);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ public class WorskpacePortlet {
|
|||
// Log.trace("Initializing WorskpacePortlet");
|
||||
this.basicTabContainer = new GxtBasicTabPanel();
|
||||
this.toolBarPathPanel = new GxtBreadcrumbPathPanel();
|
||||
this.searchAndFilterContainer = new GxtSeachAndFilterPanel(this.toolBarPathPanel.getToolBarPathPanel());
|
||||
this.searchAndFilterContainer = new GxtSeachAndFilterPanel(this.toolBarPathPanel);
|
||||
|
||||
this.gridFilterGroupContainer = new GxtGridFilterGroupPanel(activeGroup);
|
||||
this.listViewContainer = new GxtListView();
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.gcube.portlets.user.workspace.client.event.GridElementUnSelectedEvent
|
|||
import org.gcube.portlets.user.workspace.client.event.ImagePreviewEvent;
|
||||
import org.gcube.portlets.user.workspace.client.event.OpenContextMenuTreeEvent;
|
||||
import org.gcube.portlets.user.workspace.client.event.OpenReportsEvent;
|
||||
import org.gcube.portlets.user.workspace.client.event.StoreGridChangedEvent;
|
||||
import org.gcube.portlets.user.workspace.client.interfaces.GXTFolderItemTypeEnum;
|
||||
import org.gcube.portlets.user.workspace.client.model.FileGridModel;
|
||||
import org.gcube.portlets.user.workspace.client.model.FileModel;
|
||||
|
@ -32,6 +33,8 @@ import com.extjs.gxt.ui.client.event.SelectionChangedListener;
|
|||
import com.extjs.gxt.ui.client.store.GroupingStore;
|
||||
import com.extjs.gxt.ui.client.store.ListStore;
|
||||
import com.extjs.gxt.ui.client.store.Record;
|
||||
import com.extjs.gxt.ui.client.store.Store;
|
||||
import com.extjs.gxt.ui.client.store.StoreEvent;
|
||||
import com.extjs.gxt.ui.client.widget.ContentPanel;
|
||||
import com.extjs.gxt.ui.client.widget.LayoutContainer;
|
||||
import com.extjs.gxt.ui.client.widget.form.NumberField;
|
||||
|
@ -49,6 +52,7 @@ import com.extjs.gxt.ui.client.widget.grid.filters.StringFilter;
|
|||
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
|
||||
import com.google.gwt.i18n.client.DateTimeFormat;
|
||||
import com.google.gwt.i18n.client.NumberFormat;
|
||||
import com.google.gwt.user.client.Window;
|
||||
|
||||
/**
|
||||
* @author Francesco Mangiacrapa francesco.mangiacrapa@isti.cnr.it
|
||||
|
@ -257,14 +261,13 @@ public class GxtGridFilterGroupPanel extends LayoutContainer {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
new GridDragSource(grid);
|
||||
|
||||
|
||||
cp.add(grid);
|
||||
add(cp);
|
||||
|
||||
addDataChangedStoreListener();
|
||||
|
||||
}
|
||||
|
||||
public void disableGrouping() {
|
||||
|
@ -512,4 +515,49 @@ public class GxtGridFilterGroupPanel extends LayoutContainer {
|
|||
}
|
||||
}
|
||||
|
||||
private void addDataChangedStoreListener(){
|
||||
|
||||
store.addListener(Store.Add, new Listener<StoreEvent<ModelData>>(){
|
||||
|
||||
@Override
|
||||
public void handleEvent(StoreEvent<ModelData> be) {
|
||||
AppController.getEventBus().fireEvent(new StoreGridChangedEvent(storeSize()));
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
store.addListener(Store.Remove, new Listener<StoreEvent<ModelData>>(){
|
||||
|
||||
@Override
|
||||
public void handleEvent(StoreEvent<ModelData> be) {
|
||||
AppController.getEventBus().fireEvent(new StoreGridChangedEvent(storeSize()));
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
store.addListener(Store.Clear, new Listener<StoreEvent<ModelData>>(){
|
||||
|
||||
@Override
|
||||
public void handleEvent(StoreEvent<ModelData> be) {
|
||||
AppController.getEventBus().fireEvent(new StoreGridChangedEvent(storeSize()));
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return -1 if store is null. The size otherwise
|
||||
*/
|
||||
private int storeSize(){
|
||||
|
||||
if(store!=null && store.getModels()!=null){
|
||||
return store.getModels().size();
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -114,6 +114,16 @@ public class GxtBorderLayoutPanel extends ContentPanel {
|
|||
north.add(this.searchAndFilterContainer);
|
||||
west.add(this.expPanel);
|
||||
|
||||
|
||||
north.addListener(Events.Resize, new Listener<BoxComponentEvent>(){
|
||||
|
||||
@Override
|
||||
public void handleEvent(BoxComponentEvent be) {
|
||||
|
||||
searchAndFilterContainer.getToolbarPathPanel().refreshSize();
|
||||
}
|
||||
|
||||
});
|
||||
// center.add(this.toolbarContainer);
|
||||
|
||||
center.add(this.gxtCardLayoutResultPanel);
|
||||
|
|
|
@ -10,6 +10,8 @@ import org.gcube.portlets.user.workspace.client.event.ScopeChangeEvent;
|
|||
import org.gcube.portlets.user.workspace.client.event.SearchTextEvent;
|
||||
import org.gcube.portlets.user.workspace.client.model.ScopeModel;
|
||||
import org.gcube.portlets.user.workspace.client.view.GxtComboBox;
|
||||
import org.gcube.portlets.user.workspace.client.view.toolbars.GxtBreadcrumbPathPanel;
|
||||
import org.gcube.portlets.user.workspace.client.view.toolbars.GxtToolBarItemFunctionality;
|
||||
|
||||
import com.extjs.gxt.ui.client.Style.HorizontalAlignment;
|
||||
import com.extjs.gxt.ui.client.Style.VerticalAlignment;
|
||||
|
@ -44,7 +46,6 @@ public class GxtSeachAndFilterPanel extends LayoutContainer {
|
|||
|
||||
private GxtComboBox comboBoxGxt = null;
|
||||
private ComboBox<ScopeModel> cbViewScope = null;
|
||||
// private HTML txtViewScope = new HTML("<nobr>"+ConstantsPortlet.VIEWSPACE+":</nobr>");
|
||||
private final TextField<String> textSearch = new TextField<String>();
|
||||
private Button bSearch = new Button(ConstantsPortlet.SEARCH);
|
||||
private Button bCancel = new Button(ConstantsPortlet.CANCEL);
|
||||
|
@ -53,19 +54,17 @@ public class GxtSeachAndFilterPanel extends LayoutContainer {
|
|||
private DateField fromDate = new DateField();
|
||||
private DateField toDate = new DateField();
|
||||
private SimpleComboBox<String> cbNameFilter = null;
|
||||
private HorizontalPanel toolbarPathPanel = null;
|
||||
// private HorizontalPanel hpToolbarPathPanel = null;
|
||||
private boolean isSearchActive = false;
|
||||
private VerticalPanel cp = new VerticalPanel();
|
||||
|
||||
HorizontalPanel hp = new HorizontalPanel();
|
||||
HorizontalPanel hp2 = new HorizontalPanel();
|
||||
private HorizontalPanel hp = new HorizontalPanel();
|
||||
private HorizontalPanel hp2 = new HorizontalPanel();
|
||||
|
||||
HorizontalPanel hpMain = new HorizontalPanel();
|
||||
private HorizontalPanel hpMain = new HorizontalPanel();
|
||||
private GxtBreadcrumbPathPanel toolbarPahtPanel;
|
||||
|
||||
public GxtSeachAndFilterPanel(HorizontalPanel toolbarContainer) {
|
||||
|
||||
// txtViewScope.getElement().getStyle().setColor("#15428B");
|
||||
// txtViewScope.getElement().getStyle().setFontSize(12, Unit.PX);
|
||||
public GxtSeachAndFilterPanel(GxtBreadcrumbPathPanel toolBarPathPanel) {
|
||||
|
||||
setLayout(new FitLayout());
|
||||
setBorders(true);
|
||||
|
@ -78,14 +77,11 @@ public class GxtSeachAndFilterPanel extends LayoutContainer {
|
|||
this.cbViewScope.setWidth(360);
|
||||
// this.cbViewScope.setAutoWidth(true);
|
||||
|
||||
this.toolbarPathPanel = toolbarContainer;
|
||||
cp.add(this.toolbarPathPanel);
|
||||
this.toolbarPahtPanel = toolBarPathPanel;
|
||||
cp.add(this.toolbarPahtPanel.getToolBarPathPanel());
|
||||
|
||||
hp.setStyleAttribute("padding", "2px");
|
||||
|
||||
|
||||
// this.cbViewScope.setStyleAttribute("margin-right", "70px");
|
||||
|
||||
seVisibleButtonsCancelSave(false);
|
||||
|
||||
textSearch.setAllowBlank(true);
|
||||
|
@ -244,7 +240,6 @@ public class GxtSeachAndFilterPanel extends LayoutContainer {
|
|||
public void searchCancel(){
|
||||
resetFields();
|
||||
seVisibleButtonsCancelSave(false);
|
||||
// AppController.getEventBus().fireEvent(new SearchTextEvent(null));
|
||||
}
|
||||
|
||||
public boolean isSearchActive(){
|
||||
|
@ -262,7 +257,6 @@ public class GxtSeachAndFilterPanel extends LayoutContainer {
|
|||
}
|
||||
|
||||
public void setSearchActive(boolean isSearchActive) {
|
||||
// System.out.println("#################SET SEARCH ACTIVE in GRID " + isSearchActive);
|
||||
this.isSearchActive = isSearchActive;
|
||||
}
|
||||
|
||||
|
@ -274,4 +268,8 @@ public class GxtSeachAndFilterPanel extends LayoutContainer {
|
|||
textSearch.setEmptyText(emptyText);
|
||||
}
|
||||
|
||||
public GxtBreadcrumbPathPanel getToolbarPathPanel() {
|
||||
return toolbarPahtPanel;
|
||||
}
|
||||
|
||||
}
|
|
@ -10,14 +10,15 @@ import org.gcube.portlets.user.workspace.client.util.GetPermissionIconByACL;
|
|||
import org.gcube.portlets.user.workspace.shared.WorkspaceACL;
|
||||
import org.gcube.portlets.user.workspace.shared.WorkspaceTrashOperation;
|
||||
|
||||
import com.extjs.gxt.ui.client.Style.HorizontalAlignment;
|
||||
import com.extjs.gxt.ui.client.event.ButtonEvent;
|
||||
import com.extjs.gxt.ui.client.event.SelectionListener;
|
||||
import com.extjs.gxt.ui.client.widget.HorizontalPanel;
|
||||
import com.extjs.gxt.ui.client.widget.Label;
|
||||
import com.extjs.gxt.ui.client.widget.Text;
|
||||
import com.extjs.gxt.ui.client.widget.button.Button;
|
||||
import com.extjs.gxt.ui.client.widget.form.TextField;
|
||||
import com.extjs.gxt.ui.client.widget.menu.SeparatorMenuItem;
|
||||
import com.extjs.gxt.ui.client.widget.toolbar.FillToolItem;
|
||||
import com.extjs.gxt.ui.client.widget.toolbar.SeparatorToolItem;
|
||||
import com.extjs.gxt.ui.client.widget.toolbar.ToolBar;
|
||||
import com.google.gwt.user.client.ui.AbstractImagePrototype;
|
||||
|
||||
|
@ -49,6 +50,8 @@ public class GxtBottomToolBarItem extends ToolBar{
|
|||
private Button bRead;
|
||||
private Button btnGetTrash;
|
||||
private ACLDivInfo aclDivInfo;
|
||||
private Label labelItemsNumber = new Label();
|
||||
private HorizontalPanel hpItemsNumber;
|
||||
|
||||
public GxtBottomToolBarItem(){
|
||||
super();
|
||||
|
@ -116,9 +119,17 @@ public class GxtBottomToolBarItem extends ToolBar{
|
|||
|
||||
|
||||
add(btnGetTrash);
|
||||
add(new SeparatorMenuItem());
|
||||
// add(new SeparatorMenuItem());
|
||||
add(btnGetInfo);
|
||||
add(bHistory);
|
||||
|
||||
hpItemsNumber = new HorizontalPanel();
|
||||
hpItemsNumber.setStyleAttribute("margin-left", "10px");
|
||||
hpItemsNumber.setHorizontalAlign(HorizontalAlignment.CENTER);
|
||||
hpItemsNumber.add(labelItemsNumber);
|
||||
|
||||
// add(new FillToolItem());
|
||||
add(hpItemsNumber);
|
||||
add(new FillToolItem());
|
||||
add(aclDivInfo);
|
||||
|
||||
|
@ -182,4 +193,18 @@ public class GxtBottomToolBarItem extends ToolBar{
|
|||
else
|
||||
btnGetTrash.setIcon(Resources.getTrashEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param size
|
||||
*/
|
||||
public void updateItemsNumber(int size) {
|
||||
if(size<=0)
|
||||
labelItemsNumber.setText("No Items");
|
||||
else if(size==1)
|
||||
labelItemsNumber.setText("1 Item");
|
||||
else if(size>1)
|
||||
labelItemsNumber.setText(size +" Items");
|
||||
|
||||
hpItemsNumber.layout();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import com.extjs.gxt.ui.client.widget.HorizontalPanel;
|
|||
import com.extjs.gxt.ui.client.widget.Text;
|
||||
import com.extjs.gxt.ui.client.widget.WidgetComponent;
|
||||
import com.extjs.gxt.ui.client.widget.button.Button;
|
||||
import com.google.gwt.core.shared.GWT;
|
||||
import com.google.gwt.user.client.ui.Image;
|
||||
|
||||
/**
|
||||
|
@ -26,7 +27,7 @@ public class GxtBreadcrumbPathPanel {
|
|||
|
||||
private static final String ROOT_NAME = "Workspace";
|
||||
|
||||
private HorizontalPanel toolBar = new HorizontalPanel();
|
||||
private HorizontalPanel hpToolBar = new HorizontalPanel();
|
||||
private Text txtPath = new Text("PATH ");
|
||||
private LinkedHashMap<String, FileModel> hashFileModel = new LinkedHashMap<String, FileModel>();// Ordered-HashMap
|
||||
boolean rootAdded = false;
|
||||
|
@ -35,19 +36,22 @@ public class GxtBreadcrumbPathPanel {
|
|||
private FileModel lastParent;
|
||||
|
||||
public GxtBreadcrumbPathPanel() {
|
||||
toolBar = new HorizontalPanel();
|
||||
toolBar.setHeight("25px");
|
||||
hpToolBar = new HorizontalPanel();
|
||||
hpToolBar.setId("myToolbarPath");
|
||||
hpToolBar.setHeight("25px");
|
||||
initToolbar();
|
||||
}
|
||||
|
||||
public HorizontalPanel getToolBarPathPanel() {
|
||||
return toolBar;
|
||||
return hpToolBar;
|
||||
}
|
||||
|
||||
public void setPath(List<FileModel> parents) {
|
||||
|
||||
initToolbarWithoutFakeRoot();
|
||||
|
||||
refreshSize();
|
||||
|
||||
if (parents != null && parents.size() > 0) {
|
||||
|
||||
ArrayList<Button> listButtons = new ArrayList<Button>();
|
||||
|
@ -87,15 +91,22 @@ public class GxtBreadcrumbPathPanel {
|
|||
|
||||
int size = listButtons.size();
|
||||
for (int i = 0; i < size - 1; i++) {
|
||||
toolBar.add(listButtons.get(i));
|
||||
toolBar.add(new WidgetComponent(new Image(Resources.getImagePathSeparator())));
|
||||
|
||||
hpToolBar.add(listButtons.get(i));
|
||||
hpToolBar.add(new WidgetComponent(new Image(Resources.getImagePathSeparator())));
|
||||
// toolBar.getWidth();
|
||||
}
|
||||
|
||||
lastParent = parents.get(parents.size()-1);
|
||||
|
||||
toolBar.add(listButtons.get(size - 1)); // Add last element
|
||||
toolBar.layout(true);
|
||||
hpToolBar.add(listButtons.get(size - 1)); // Add last element
|
||||
hpToolBar.layout(true);
|
||||
|
||||
int currentWidth = hpToolBar.el().getChild(0).getRegion().right;
|
||||
int maxWidth = hpToolBar.getWidth();
|
||||
|
||||
// GWT.log("toolBar maxWidth width is: "+maxWidth);
|
||||
// GWT.log("toolBar currentWidth is: "+currentWidth);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,27 +124,36 @@ public class GxtBreadcrumbPathPanel {
|
|||
}
|
||||
|
||||
private void initToolbar() {
|
||||
toolBar.removeAll();
|
||||
toolBar.setStyleName("myToolbar");
|
||||
toolBar.setStyleAttribute("padding-top", "5px");
|
||||
hpToolBar.removeAll();
|
||||
hpToolBar.setStyleName("myToolbar");
|
||||
hpToolBar.setStyleAttribute("padding-top", "5px");
|
||||
txtPath.setStyleAttribute("padding-right", "10px");
|
||||
toolBar.add(new WidgetComponent(new Image(Resources.getImagePathSeparator())));
|
||||
toolBar.layout(true);
|
||||
hpToolBar.add(new WidgetComponent(new Image(Resources.getImagePathSeparator())));
|
||||
hpToolBar.layout(true);
|
||||
|
||||
Button butt = new Button(ROOT_NAME);
|
||||
butt.setId("");
|
||||
butt.setStyleAttribute("top", "-4px");
|
||||
butt.setStyleName("button-hyperlink");
|
||||
toolBar.add(butt);
|
||||
hpToolBar.add(butt);
|
||||
}
|
||||
|
||||
private void initToolbarWithoutFakeRoot() {
|
||||
toolBar.removeAll();
|
||||
toolBar.setStyleName("myToolbar");
|
||||
toolBar.setStyleAttribute("padding-top", "5px");
|
||||
hpToolBar.removeAll();
|
||||
hpToolBar.setStyleName("myToolbar");
|
||||
hpToolBar.setStyleAttribute("padding-top", "5px");
|
||||
txtPath.setStyleAttribute("padding-right", "10px");
|
||||
toolBar.add(new WidgetComponent(new Image(Resources.getImagePathSeparator())));
|
||||
toolBar.layout(true);
|
||||
hpToolBar.add(new WidgetComponent(new Image(Resources.getImagePathSeparator())));
|
||||
hpToolBar.layout(true);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void refreshSize() {
|
||||
|
||||
|
||||
GWT.log("Refreshed size");
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue