You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by sr...@apache.org on 2013/06/12 01:56:22 UTC

svn commit: r1492013 [1/2] - in /incubator/ambari/branches/branch-1.4.0: ambari-server/src/main/java/org/apache/ambari/eventdb/db/ ambari-server/src/main/java/org/apache/ambari/eventdb/model/ ambari-server/src/main/java/org/apache/ambari/eventdb/webser...

Author: srimanth
Date: Tue Jun 11 23:56:21 2013
New Revision: 1492013

URL: http://svn.apache.org/r1492013
Log:
AMBARI-2332. Support Jobs display for Tez and MR2 in Ambari. (billie via srimanth)

Added:
    incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/model/Apps.java   (with props)
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/apps/
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/apps/mapreduce_201301280808_0001.json
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/apps/mapreduce_201301280808_0003.json
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/apps/mapreduce_201301280808_0004.json
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/apps/pig_f9957a11-a902-4f01-ac53-9679ce3a4b13.json
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/runs2.json
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/classes/app_class.js   (with props)
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/mappers/apps_mapper.js   (with props)
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/models/apps.js   (with props)
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/templates/main/apps/item/app.hbs
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/utils/app_graph.js   (with props)
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/views/main/apps/item/app_view.js   (with props)
Modified:
    incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/db/DBConnector.java
    incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/db/PostgresConnector.java
    incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/model/WorkflowContext.java
    incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/model/Workflows.java
    incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/webservice/WorkflowJsonService.java
    incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/classes/run_class.js
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/controllers/main/apps/item_controller.js
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/controllers/main/apps_controller.js
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/initialize.js
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/mappers/runs_mapper.js
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/messages.js
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/models.js
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/models/run.js
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/routes/main.js
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/styles/apps.less
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/templates/main/apps.hbs
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/templates/main/apps/list_row.hbs
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/views.js
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/views/main/apps/item_view.js
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/views/main/apps_view.js
    incubator/ambari/branches/branch-1.4.0/ambari-web/app/views/main/menu.js

Modified: incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/db/DBConnector.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/db/DBConnector.java?rev=1492013&r1=1492012&r2=1492013&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/db/DBConnector.java (original)
+++ incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/db/DBConnector.java Tue Jun 11 23:56:21 2013
@@ -19,11 +19,8 @@ package org.apache.ambari.eventdb.db;
 import java.io.IOException;
 import java.util.List;
 
-import org.apache.ambari.eventdb.model.DataTable;
+import org.apache.ambari.eventdb.model.*;
 import org.apache.ambari.eventdb.model.Jobs.JobDBEntry;
-import org.apache.ambari.eventdb.model.TaskAttempt;
-import org.apache.ambari.eventdb.model.WorkflowContext;
-import org.apache.ambari.eventdb.model.Workflows;
 import org.apache.ambari.eventdb.model.Workflows.WorkflowDBEntry.WorkflowFields;
 
 public interface DBConnector {
@@ -37,9 +34,11 @@ public interface DBConnector {
   
   public DataTable fetchWorkflows(int offset, int limit, String searchTerm, int echo, WorkflowFields field, boolean sortAscending, String searchWorkflowId,
       String searchWorkflowName, String searchWorkflowType, String searchUserName, int minJobs, int maxJobs, long minInputBytes, long maxInputBytes,
-      long minOutputBytes, long maxOutputBytes, long minDuration, long maxDuration, long minStartTime, long maxStartTime, long minFinishTime, long maxFinishTime)
-      throws IOException;
-  
+      long minOutputBytes, long maxOutputBytes, long minDuration, long maxDuration, long minStartTime, long maxStartTime, long minFinishTime, 
+      long maxFinishTime, String tagSearchTerm) throws IOException;
+
+  public List<Apps.AppDBEntry> fetchAppDetails(String workflowId) throws IOException;
+
   public List<JobDBEntry> fetchJobDetails(String workflowID) throws IOException;
   
   public List<JobDBEntry> fetchJobDetails(long minFinishTime, long maxStartTime) throws IOException;

Modified: incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/db/PostgresConnector.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/db/PostgresConnector.java?rev=1492013&r1=1492012&r2=1492013&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/db/PostgresConnector.java (original)
+++ incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/db/PostgresConnector.java Tue Jun 11 23:56:21 2013
@@ -27,20 +27,18 @@ import java.util.EnumMap;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.ambari.eventdb.model.DataTable;
+import org.apache.ambari.eventdb.model.*;
 import org.apache.ambari.eventdb.model.DataTable.AvgData;
 import org.apache.ambari.eventdb.model.DataTable.Summary;
 import org.apache.ambari.eventdb.model.DataTable.Summary.SummaryFields;
 import org.apache.ambari.eventdb.model.DataTable.Times;
 import org.apache.ambari.eventdb.model.Jobs.JobDBEntry;
 import org.apache.ambari.eventdb.model.Jobs.JobDBEntry.JobFields;
-import org.apache.ambari.eventdb.model.TaskAttempt;
 import org.apache.ambari.eventdb.model.TaskAttempt.TaskAttemptFields;
-import org.apache.ambari.eventdb.model.WorkflowContext;
-import org.apache.ambari.eventdb.model.Workflows;
 import org.apache.ambari.eventdb.model.Workflows.WorkflowDBEntry;
 import org.apache.ambari.eventdb.model.Workflows.WorkflowDBEntry.WorkflowFields;
 import org.apache.commons.lang.NotImplementedException;
+import org.apache.commons.lang.StringUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.codehaus.jackson.JsonParseException;
@@ -50,6 +48,7 @@ import org.codehaus.jackson.map.ObjectMa
 public class PostgresConnector implements DBConnector {
   private static Log LOG = LogFactory.getLog(PostgresConnector.class);
   private static final String WORKFLOW_TABLE_NAME = "workflow";
+  private static final String APP_TABLE_NAME = "application";
   private static final String JOB_TABLE_NAME = "job";
   private static final String TASK_ATTEMPT_TABLE_NAME = "taskattempt";
   public static final String SORT_ASC = "ASC";
@@ -75,6 +74,7 @@ public class PostgresConnector implement
         + getAvg(WorkflowFields.DURATION, SummaryFields.avgDuration, SummaryFields.minDuration, SummaryFields.maxDuration) + ", min("
         + WorkflowFields.STARTTIME + ") as " + SummaryFields.youngest + ", max(" + WorkflowFields.STARTTIME + ") as " + SummaryFields.oldest + " FROM "
         + WORKFLOW_TABLE_NAME),
+    FAD_PS("SELECT " + Apps.AppDBEntry.APP_FIELDS + " FROM " + APP_TABLE_NAME + " WHERE " + Apps.AppDBEntry.AppFields.WORKFLOWID.toString() + " = ?"),
     FJD_PS("SELECT " + JobDBEntry.JOB_FIELDS + " FROM " + JOB_TABLE_NAME + " WHERE " + JobFields.WORKFLOWID.toString() + " = ?"),
     FJD_TIMERANGE_PS("SELECT " + JobDBEntry.JOB_FIELDS + " FROM " + JOB_TABLE_NAME + " WHERE " + JobFields.FINISHTIME.toString() + " >= ? AND "
         + JobFields.SUBMITTIME.toString() + " <= ? ORDER BY " + JobFields.WORKFLOWID + ", " + JobFields.JOBID),
@@ -213,6 +213,7 @@ public class PostgresConnector implement
     w.setOutputBytes(WorkflowFields.OUTPUTBYTES.getLong(rs));
     w.setNumJobsCompleted(WorkflowFields.NUMJOBSCOMPLETED.getInt(rs));
     w.setWorkflowContext(jsonMapper.readValue(WorkflowFields.WORKFLOWCONTEXT.getString(rs), WorkflowContext.class));
+    w.setWorkflowTags(WorkflowFields.WORKFLOWTAGS.getString(rs));
     return w;
   }
   
@@ -227,8 +228,8 @@ public class PostgresConnector implement
   @Override
   public DataTable fetchWorkflows(int offset, int limit, String searchTerm, int echo, WorkflowFields col, boolean sortAscending, String searchWorkflowId,
       String searchWorkflowName, String searchWorkflowType, String searchUserName, int minJobs, int maxJobs, long minInputBytes, long maxInputBytes,
-      long minOutputBytes, long maxOutputBytes, long minDuration, long maxDuration, long minStartTime, long maxStartTime, long minFinishTime, long maxFinishTime)
-      throws IOException {
+      long minOutputBytes, long maxOutputBytes, long minDuration, long maxDuration, long minStartTime, long maxStartTime, long minFinishTime, 
+      long maxFinishTime, String tagSearchTerm) throws IOException {
     int total = 0;
     PreparedStatement ps = getPS(Statements.FW_COUNT_PS);
     ResultSet rs = null;
@@ -248,7 +249,8 @@ public class PostgresConnector implement
     }
     
     String searchClause = buildSearchClause(searchTerm, searchWorkflowId, searchWorkflowName, searchWorkflowType, searchUserName, minJobs, maxJobs,
-        minInputBytes, maxInputBytes, minOutputBytes, maxOutputBytes, minDuration, maxDuration, minStartTime, maxStartTime, minFinishTime, maxFinishTime);
+        minInputBytes, maxInputBytes, minOutputBytes, maxOutputBytes, minDuration, maxDuration, minStartTime, maxStartTime, minFinishTime, maxFinishTime,
+        tagSearchTerm);
     List<WorkflowDBEntry> workflows = fetchWorkflows(getQualifiedPS(Statements.FW_PS, searchClause, col, sortAscending, offset, limit));
     Summary summary = fetchSummary(getQualifiedPS(Statements.FW_SUMMARY_PS, searchClause));
     DataTable table = new DataTable();
@@ -266,7 +268,54 @@ public class PostgresConnector implement
     table.setSummary(summary);
     return table;
   }
-  
+
+  private static Apps.AppDBEntry getAppDBEntry(ResultSet rs) throws SQLException {
+    Apps.AppDBEntry a = new Apps.AppDBEntry();
+    a.setWorkflowId(Apps.AppDBEntry.AppFields.WORKFLOWID.getString(rs));
+    a.setWorkflowEntityName(Apps.AppDBEntry.AppFields.WORKFLOWENTITYNAME.getString(rs));
+    a.setAppId(Apps.AppDBEntry.AppFields.APPID.getString(rs));
+    a.setAppName(Apps.AppDBEntry.AppFields.APPNAME.getString(rs));
+    a.setAppType(Apps.AppDBEntry.AppFields.APPTYPE.getString(rs));
+    a.setFinishTime(Apps.AppDBEntry.AppFields.FINISHTIME.getLong(rs));
+    a.setLaunchTime(Apps.AppDBEntry.AppFields.LAUNCHTIME.getLong(rs));
+    a.setQueue(Apps.AppDBEntry.AppFields.QUEUE.getString(rs));
+    String[] stageStrings = StringUtils.split(Apps.AppDBEntry.AppFields.APPINFO.getString(rs), "-");
+    List<Integer> stages = new ArrayList<Integer>();
+    for (String s : stageStrings)
+      stages.add(Integer.parseInt(s));
+    a.setStages(stages);
+    a.setStatus(Apps.AppDBEntry.AppFields.STATUS.getString(rs));
+    a.setSubmitTime(Apps.AppDBEntry.AppFields.SUBMITTIME.getLong(rs));
+    a.setUserName(Apps.AppDBEntry.AppFields.USERNAME.getString(rs));
+    return a;
+  }
+
+  @Override
+  public List<Apps.AppDBEntry> fetchAppDetails(String workflowId) throws IOException {
+    PreparedStatement ps = getPS(Statements.FAD_PS);
+    List<Apps.AppDBEntry> apps = new ArrayList<Apps.AppDBEntry>();
+    ResultSet rs = null;
+    try {
+      ps.setString(1, workflowId);
+      rs = ps.executeQuery();
+      while (rs.next()) {
+        apps.add(getAppDBEntry(rs));
+      }
+      rs.close();
+    } catch (SQLException e) {
+      throw new IOException(e);
+    } finally {
+      if (rs != null)
+        try {
+          rs.close();
+        } catch (SQLException e) {
+          LOG.error("Exception while closing ResultSet", e);
+        }
+
+    }
+    return apps;
+  }
+
   private static JobDBEntry getJobDBEntry(ResultSet rs) throws SQLException {
     JobDBEntry j = new JobDBEntry();
     j.setConfPath(JobFields.CONFPATH.getString(rs));
@@ -288,7 +337,7 @@ public class PostgresConnector implement
     j.setWorkflowId(JobFields.WORKFLOWID.getString(rs));
     return j;
   }
-  
+
   @Override
   public List<JobDBEntry> fetchJobDetails(String workflowId) throws IOException {
     PreparedStatement ps = getPS(Statements.FJD_PS);
@@ -310,11 +359,11 @@ public class PostgresConnector implement
         } catch (SQLException e) {
           LOG.error("Exception while closing ResultSet", e);
         }
-      
+
     }
     return jobs;
   }
-  
+
   @Override
   public List<JobDBEntry> fetchJobDetails(long minFinishTime, long maxStartTime) throws IOException {
     PreparedStatement ps = getPS(Statements.FJD_TIMERANGE_PS);
@@ -547,7 +596,7 @@ public class PostgresConnector implement
   
   private static String buildSearchClause(String searchTerm, String searchWorkflowId, String searchWorkflowName, String searchWorkflowType,
       String searchUserName, int minJobs, int maxJobs, long minInputBytes, long maxInputBytes, long minOutputBytes, long maxOutputBytes, long minDuration,
-      long maxDuration, long minStartTime, long maxStartTime, long minFinishTime, long maxFinishTime) {
+      long maxDuration, long minStartTime, long maxStartTime, long minFinishTime, long maxFinishTime, String searchTags) {
     StringBuilder sb = new StringBuilder();
     sb.append(WHERE);
     if (searchTerm != null && searchTerm.length() > 0) {
@@ -567,6 +616,8 @@ public class PostgresConnector implement
       append(sb, startsWith(WorkflowFields.WORKFLOWID, searchWorkflowType));
     if (searchUserName != null)
       append(sb, equals(WorkflowFields.USERNAME, searchUserName));
+    if (searchTags != null)
+      append(sb, like(WorkflowFields.WORKFLOWTAGS, searchTags));
     addRangeSearch(sb, WorkflowFields.NUMJOBSTOTAL, minJobs, maxJobs);
     addRangeSearch(sb, WorkflowFields.INPUTBYTES, minInputBytes, maxInputBytes);
     addRangeSearch(sb, WorkflowFields.OUTPUTBYTES, minOutputBytes, maxOutputBytes);

Added: incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/model/Apps.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/model/Apps.java?rev=1492013&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/model/Apps.java (added)
+++ incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/model/Apps.java Tue Jun 11 23:56:21 2013
@@ -0,0 +1,193 @@
+/**
+ * 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.
+ */
+package org.apache.ambari.eventdb.model;
+
+import org.apache.commons.lang.StringUtils;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class Apps {
+  List<AppDBEntry> apps;
+
+  public static class AppDBEntry {
+    public static enum AppFields {
+      APPID,
+      APPNAME,
+      APPTYPE,
+      STATUS,
+      USERNAME,
+      QUEUE,
+      SUBMITTIME,
+      LAUNCHTIME,
+      FINISHTIME,
+      APPINFO,
+      WORKFLOWID,
+      WORKFLOWENTITYNAME;
+
+      public String getString(ResultSet rs) throws SQLException {
+        return rs.getString(this.toString());
+      }
+
+      public int getInt(ResultSet rs) throws SQLException {
+        return rs.getInt(this.toString());
+      }
+
+      public long getLong(ResultSet rs) throws SQLException {
+        return rs.getLong(this.toString());
+      }
+
+      public static String join() {
+        String[] tmp = new String[AppFields.values().length];
+        for (int i = 0; i < tmp.length; i++)
+          tmp[i] = AppFields.values()[i].toString();
+        return StringUtils.join(tmp, ",");
+      }
+    }
+
+    @XmlTransient
+    public static final String APP_FIELDS = AppFields.join();
+
+    private String appId;
+    private String appName;
+    private String appType;
+    private String status;
+    private String userName;
+    private String queue;
+    private long submitTime;
+    private long launchTime;
+    private long finishTime;
+    private List<Integer> stages;
+    private String workflowId;
+    private String workflowEntityName;
+
+    public AppDBEntry() {
+      /* Required by JAXB. */
+    }
+
+    public String getAppId() {
+      return appId;
+    }
+
+    public void setAppId(String appId) {
+      this.appId = appId;
+    }
+
+    public String getAppName() {
+      return appName;
+    }
+
+    public void setAppName(String appName) {
+      this.appName = appName;
+    }
+
+    public String getAppType() {
+      return appType;
+    }
+
+    public void setAppType(String appType) {
+      this.appType = appType;
+    }
+
+    public String getStatus() {
+      return status;
+    }
+
+    public void setStatus(String status) {
+      this.status = status;
+    }
+
+    public String getUserName() {
+      return userName;
+    }
+
+    public void setUserName(String userName) {
+      this.userName = userName;
+    }
+
+    public String getQueue() {
+      return queue;
+    }
+
+    public void setQueue(String queue) {
+      this.queue = queue;
+    }
+
+    public long getSubmitTime() {
+      return submitTime;
+    }
+
+    public void setSubmitTime(long submitTime) {
+      this.submitTime = submitTime;
+    }
+
+    public long getLaunchTime() {
+      return launchTime;
+    }
+
+    public void setLaunchTime(long launchTime) {
+      this.launchTime = launchTime;
+    }
+
+    public long getFinishTime() {
+      return finishTime;
+    }
+
+    public void setFinishTime(long finishTime) {
+      this.finishTime = finishTime;
+    }
+
+    public List<Integer> getStages() {
+      return stages;
+    }
+
+    public void setStages(List<Integer> stages) {
+      this.stages = stages;
+    }
+
+    public String getWorkflowId() {
+      return workflowId;
+    }
+
+    public void setWorkflowId(String workflowId) {
+      this.workflowId = workflowId;
+    }
+
+    public String getWorkflowEntityName() {
+      return workflowEntityName;
+    }
+
+    public void setWorkflowEntityName(String workflowEntityName) {
+      this.workflowEntityName = workflowEntityName;
+    }
+  }
+
+  public List<AppDBEntry> getApps() {
+    return apps;
+  }
+
+  public void setApps(List<AppDBEntry> apps) {
+    this.apps = apps;
+  }
+}

Propchange: incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/model/Apps.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/model/WorkflowContext.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/model/WorkflowContext.java?rev=1492013&r1=1492012&r2=1492013&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/model/WorkflowContext.java (original)
+++ incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/model/WorkflowContext.java Tue Jun 11 23:56:21 2013
@@ -29,6 +29,7 @@ public class WorkflowContext {
   private String workflowId;
   private String workflowName;
   private String workflowEntityName;
+  private String workflowTags;
   
   private WorkflowDag workflowDag;
   
@@ -51,6 +52,10 @@ public class WorkflowContext {
     return this.workflowEntityName;
   }
   
+  public String getWorkflowTags() {
+    return workflowTags;
+  }
+  
   public WorkflowDag getWorkflowDag() {
     return this.workflowDag;
   }
@@ -72,6 +77,10 @@ public class WorkflowContext {
     this.workflowEntityName = wfEntityName;
   }
   
+  public void setWorkflowTags(String workflowTags) {
+    this.workflowTags = workflowTags;
+  }
+  
   public void setWorkflowDag(WorkflowDag wfDag) {
     this.workflowDag = wfDag;
   }

Modified: incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/model/Workflows.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/model/Workflows.java?rev=1492013&r1=1492012&r2=1492013&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/model/Workflows.java (original)
+++ incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/model/Workflows.java Tue Jun 11 23:56:21 2013
@@ -47,7 +47,8 @@ public class Workflows {
       INPUTBYTES,
       OUTPUTBYTES,
       PARENTWORKFLOWID,
-      WORKFLOWCONTEXT;
+      WORKFLOWCONTEXT,
+      WORKFLOWTAGS;
       
       public String getString(ResultSet rs) throws SQLException {
         return rs.getString(this.toString());
@@ -83,6 +84,7 @@ public class Workflows {
     private int numJobsCompleted;
     private String parentWorkflowId;
     private WorkflowContext workflowContext;
+    private String workflowTags;
     
     public WorkflowDBEntry() {
       /* Required by JAXB. */
@@ -124,6 +126,10 @@ public class Workflows {
       return workflowContext;
     }
     
+    public String getWorkflowTags() {
+      return workflowTags;
+    }
+    
     public void setWorkflowId(String workflowId) {
       this.workflowId = workflowId;
     }
@@ -160,6 +166,10 @@ public class Workflows {
       this.workflowContext = workflowContext;
     }
     
+    public void setWorkflowTags(String workflowTags) {
+      this.workflowTags = workflowTags;
+    }
+    
     public long getInputBytes() {
       return inputBytes;
     }

Modified: incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/webservice/WorkflowJsonService.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/webservice/WorkflowJsonService.java?rev=1492013&r1=1492012&r2=1492013&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/webservice/WorkflowJsonService.java (original)
+++ incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/java/org/apache/ambari/eventdb/webservice/WorkflowJsonService.java Tue Jun 11 23:56:21 2013
@@ -36,15 +36,10 @@ import javax.ws.rs.core.MediaType;
 import org.apache.ambari.eventdb.db.MySQLConnector;
 import org.apache.ambari.eventdb.db.OracleConnector;
 import org.apache.ambari.eventdb.db.PostgresConnector;
-import org.apache.ambari.eventdb.model.DataTable;
-import org.apache.ambari.eventdb.model.Jobs;
+import org.apache.ambari.eventdb.model.*;
 import org.apache.ambari.eventdb.model.Jobs.JobDBEntry;
-import org.apache.ambari.eventdb.model.TaskAttempt;
-import org.apache.ambari.eventdb.model.TaskData;
 import org.apache.ambari.eventdb.model.TaskData.Point;
-import org.apache.ambari.eventdb.model.TaskLocalityData;
 import org.apache.ambari.eventdb.model.TaskLocalityData.DataPoint;
-import org.apache.ambari.eventdb.model.Workflows;
 import org.apache.ambari.eventdb.model.Workflows.WorkflowDBEntry;
 import org.apache.ambari.eventdb.model.Workflows.WorkflowDBEntry.WorkflowFields;
 import org.apache.ambari.server.configuration.Configuration;
@@ -67,6 +62,7 @@ public class WorkflowJsonService {
   
   private static final Workflows EMPTY_WORKFLOWS = new Workflows();
   private static final List<JobDBEntry> EMPTY_JOBS = Collections.emptyList();
+  private static final List<Apps.AppDBEntry> EMPTY_APPS = Collections.emptyList();
   {
     List<WorkflowDBEntry> emptyWorkflows = Collections.emptyList();
     EMPTY_WORKFLOWS.setWorkflows(emptyWorkflows);
@@ -138,7 +134,8 @@ public class WorkflowJsonService {
       @DefaultValue("-1") @QueryParam("minOutputBytes") long minOutputBytes, @DefaultValue("-1") @QueryParam("maxOutputBytes") long maxOutputBytes,
       @DefaultValue("-1") @QueryParam("minDuration") long minDuration, @DefaultValue("-1") @QueryParam("maxDuration") long maxDuration,
       @DefaultValue("-1") @QueryParam("minStartTime") long minStartTime, @DefaultValue("-1") @QueryParam("maxStartTime") long maxStartTime,
-      @DefaultValue("-1") @QueryParam("minFinishTime") long minFinishTime, @DefaultValue("-1") @QueryParam("maxFinishTime") long maxFinishTime) {
+      @DefaultValue("-1") @QueryParam("minFinishTime") long minFinishTime, @DefaultValue("-1") @QueryParam("maxFinishTime") long maxFinishTime,
+      @QueryParam("tagSearch") String tagSearchTerm) {
     
     if (start < 0)
       start = 0;
@@ -163,22 +160,25 @@ public class WorkflowJsonService {
       case 3: // userName
         field = WorkflowFields.USERNAME;
         break;
-      case 4: // numJobsTotal
+      case 4: // tags
+        field = WorkflowFields.WORKFLOWTAGS;
+        break;
+      case 5: // numJobsTotal
         field = WorkflowFields.NUMJOBSTOTAL;
         break;
-      case 5: // inputBytes
+      case 6: // inputBytes
         field = WorkflowFields.INPUTBYTES;
         break;
-      case 6: // outputBytes
+      case 7: // outputBytes
         field = WorkflowFields.OUTPUTBYTES;
         break;
-      case 7: // duration
+      case 8: // duration
         field = WorkflowFields.DURATION;
         break;
-      case 8: // startTime
+      case 9: // startTime
         field = WorkflowFields.STARTTIME;
         break;
-      case 9: // lastUpdateTime
+      case 10: // lastUpdateTime
         field = WorkflowFields.LASTUPDATETIME;
         break;
       default:
@@ -190,7 +190,8 @@ public class WorkflowJsonService {
     try {
       conn = getConnector();
       table = conn.fetchWorkflows(start, amount, searchTerm, echo, field, sortAscending, workflowId, workflowName, workflowType, userName, minJobs, maxJobs,
-          minInputBytes, maxInputBytes, minOutputBytes, maxOutputBytes, minDuration, maxDuration, minStartTime, maxStartTime, minFinishTime, maxFinishTime);
+          minInputBytes, maxInputBytes, minOutputBytes, maxOutputBytes, minDuration, maxDuration, minStartTime, maxStartTime, minFinishTime, maxFinishTime,
+          tagSearchTerm);
     } catch (IOException e) {
       LOG.error("Error interacting with RCA database ", e);
     } finally {
@@ -200,7 +201,28 @@ public class WorkflowJsonService {
     }
     return table;
   }
-  
+
+  @GET
+  @Produces(MediaType.APPLICATION_JSON)
+  @Path("/app")
+  public Apps getApps(@QueryParam("workflowId") String workflowId) {
+    Apps apps = new Apps();
+    apps.setApps(EMPTY_APPS);
+    PostgresConnector conn = null;
+    try {
+      conn = getConnector();
+      if (workflowId != null)
+        apps.setApps(conn.fetchAppDetails(workflowId));
+    } catch (IOException e) {
+      LOG.error("Error interacting with RCA database ", e);
+    } finally {
+      if (conn != null) {
+        conn.close();
+      }
+    }
+    return apps;
+  }
+
   @GET
   @Produces(MediaType.APPLICATION_JSON)
   @Path("/job")
@@ -224,7 +246,7 @@ public class WorkflowJsonService {
     }
     return jobs;
   }
-  
+
   @GET
   @Produces(MediaType.APPLICATION_JSON)
   @Path("/task")

Modified: incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql?rev=1492013&r1=1492012&r2=1492013&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql (original)
+++ incubator/ambari/branches/branch-1.4.0/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql Tue Jun 11 23:56:21 2013
@@ -198,13 +198,28 @@ CREATE TABLE workflow (
   startTime BIGINT, lastUpdateTime BIGINT,
   numJobsTotal INTEGER, numJobsCompleted INTEGER,
   inputBytes BIGINT, outputBytes BIGINT,
-  duration BIGINT,
+  duration BIGINT, workflowTags TEXT,
   PRIMARY KEY (workflowId),
   FOREIGN KEY (parentWorkflowId) REFERENCES workflow(workflowId)
 );
 
 GRANT ALL PRIVILEGES ON TABLE workflow TO "mapred";
 
+CREATE TABLE application (
+  appId TEXT,
+  workflowId TEXT,
+  appName TEXT,
+  workflowEntityName TEXT,
+  userName TEXT, queue TEXT,
+  submitTime BIGINT, launchTime BIGINT, finishTime BIGINT,
+  appType TEXT,
+  status TEXT,
+  appInfo TEXT,
+  PRIMARY KEY(appId), FOREIGN KEY(workflowId) REFERENCES workflow(workflowId)
+);
+
+GRANT ALL PRIVILEGES ON TABLE application TO "mapred";
+
 CREATE TABLE job (
   jobId TEXT, workflowId TEXT, jobName TEXT, workflowEntityName TEXT,
   userName TEXT, queue TEXT, acls TEXT, confPath TEXT, 

Added: incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/apps/mapreduce_201301280808_0001.json
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/apps/mapreduce_201301280808_0001.json?rev=1492013&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/apps/mapreduce_201301280808_0001.json (added)
+++ incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/apps/mapreduce_201301280808_0001.json Tue Jun 11 23:56:21 2013
@@ -0,0 +1,16 @@
+{
+  "apps": [
+    {
+      "appId": "job_201301280808_0001",
+      "appName": "word count",
+      "appType": "MAPREDUCE",
+      "status": "SUCCESS",
+      "userName": "ambari_qa",
+      "submitTime": 1359378637135,
+      "finishTime": 1359378667350,
+      "stages": [1,1],
+      "workflowId": "mapreduce_201301280808_0001",
+      "workflowEntityName": "1"
+    }
+  ]
+}

Added: incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/apps/mapreduce_201301280808_0003.json
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/apps/mapreduce_201301280808_0003.json?rev=1492013&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/apps/mapreduce_201301280808_0003.json (added)
+++ incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/apps/mapreduce_201301280808_0003.json Tue Jun 11 23:56:21 2013
@@ -0,0 +1,16 @@
+{
+  "apps": [
+    {
+      "appId": "job_201301280808_0003",
+      "appName": "oozie:launcher:T\\=map-reduce:W\\=map-reduce-wf:A\\=mr-node:ID\\=0000000-130128081151371-oozie-oozi-W",
+      "appType": "MAPREDUCE",
+      "status": "SUCCESS",
+      "userName": "ambari_qa",
+      "submitTime": 1359378907927,
+      "finishTime": 1359378927213,
+      "stages": [1,0],
+      "workflowId": "mapreduce_201301280808_0003",
+      "workflowEntityName": "3"
+    }
+  ]
+}

Added: incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/apps/mapreduce_201301280808_0004.json
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/apps/mapreduce_201301280808_0004.json?rev=1492013&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/apps/mapreduce_201301280808_0004.json (added)
+++ incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/apps/mapreduce_201301280808_0004.json Tue Jun 11 23:56:21 2013
@@ -0,0 +1,40 @@
+{
+  "apps": [
+    {
+      "appId": "job_201301280808_0002",
+      "appName": "oozie:action:T\\=map-reduce:W\\=map-reduce-wf:A\\=mr-node:ID\\=0000000-130128081151371-oozie-oozi-W",
+      "appType": "MAPREDUCE",
+      "status": "SUCCESS",
+      "userName": "ambari_qa",
+      "submitTime": 1359378922503,
+      "finishTime": 1359378949583,
+      "stages": [1,1],
+      "workflowId": "mapreduce_201301280808_0002",
+      "workflowEntityName": "2"
+    },
+    {
+      "appId": "job_201301280808_0004",
+      "appName": "oozie:action:T\\=map-reduce:W\\=map-reduce-wf:A\\=mr-node:ID\\=0000000-130128081151371-oozie-oozi-W",
+      "appType": "MAPREDUCE",
+      "status": "SUCCESS",
+      "userName": "ambari_qa",
+      "submitTime": 1359378922503,
+      "finishTime": 1359378949583,
+      "stages": [1,1],
+      "workflowId": "mapreduce_201301280808_0004",
+      "workflowEntityName": "4"
+    },
+    {
+      "appId": "job_201301280808_0003",
+      "appName": "oozie:action:T\\=map-reduce:W\\=map-reduce-wf:A\\=mr-node:ID\\=0000000-130128081151371-oozie-oozi-W",
+      "appType": "MAPREDUCE",
+      "status": "SUCCESS",
+      "userName": "ambari_qa",
+      "submitTime": 1359378922503,
+      "finishTime": 1359378949583,
+      "stages": [1,1],
+      "workflowId": "mapreduce_201301280808_0003",
+      "workflowEntityName": "3"
+    }
+  ]
+}

Added: incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/apps/pig_f9957a11-a902-4f01-ac53-9679ce3a4b13.json
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/apps/pig_f9957a11-a902-4f01-ac53-9679ce3a4b13.json?rev=1492013&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/apps/pig_f9957a11-a902-4f01-ac53-9679ce3a4b13.json (added)
+++ incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/apps/pig_f9957a11-a902-4f01-ac53-9679ce3a4b13.json Tue Jun 11 23:56:21 2013
@@ -0,0 +1,16 @@
+{
+  "apps": [
+    {
+      "appId": "job_201301280808_0002",
+      "appName": "PigLatin:pigSmoke\\.sh",
+      "appType": "MAPREDUCE",
+      "status": "SUCCESS",
+      "userName": "ambari_qa",
+      "submitTime": 1359378741973,
+      "finishTime": 1359378760098,
+      "stages": [1,0],
+      "workflowId": "pig_f9957a11-a902-4f01-ac53-9679ce3a4b13",
+      "workflowEntityName": "scope-5"
+    }
+  ]
+}

Added: incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/runs2.json
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/runs2.json?rev=1492013&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/runs2.json (added)
+++ incubator/ambari/branches/branch-1.4.0/ambari-web/app/assets/data/apps/runs2.json Tue Jun 11 23:56:21 2013
@@ -0,0 +1,130 @@
+{
+  "sEcho": 0,
+  "iTotalRecords": 4,
+  "iTotalDisplayRecords": 4,
+  "startIndex": 0,
+  "endIndex": 3,
+  "aaData": [
+    {
+      "workflowId": "mapreduce_201301280808_0001",
+      "workflowName": "word count",
+      "userName": "ambari_qa",
+      "startTime": 1359378637135,
+      "elapsedTime": 30215,
+      "inputBytes": 0,
+      "outputBytes": 0,
+      "numJobsTotal": 1,
+      "numJobsCompleted": 1,
+      "workflowTags": "tag",
+      "workflowContext": {
+        "workflowDag": {
+          "entries": [
+            {
+              "source": "1",
+              "targets": [
+
+              ]
+            }
+          ]
+        }
+      }
+    },
+    {
+      "workflowId": "mapreduce_201301280808_0003",
+      "workflowName": "oozie:launcher:T\\=map-reduce:W\\=map-reduce-wf:A\\=mr-node:ID\\=0000000-130128081151371-oozie-oozi-W",
+      "userName": "ambari_qa",
+      "startTime": 1359378907927,
+      "elapsedTime": 19186,
+      "inputBytes": 0,
+      "outputBytes": 0,
+      "numJobsTotal": 1,
+      "numJobsCompleted": 1,
+      "workflowContext": {
+        "workflowDag": {
+          "entries": [
+            {
+              "source": "3",
+              "targets": [
+
+              ]
+            }
+          ]
+        }
+      }
+    },
+    {
+      "workflowId": "mapreduce_201301280808_0004",
+      "workflowName": "oozie:action:T\\=map-reduce:W\\=map-reduce-wf:A\\=mr-node:ID\\=0000000-130128081151371-oozie-oozi-W",
+      "userName": "ambari_qa",
+      "startTime": 1359378922503,
+      "elapsedTime": 27080,
+      "inputBytes": 0,
+      "outputBytes": 0,
+      "numJobsTotal": 3,
+      "numJobsCompleted": 1,
+      "workflowTags": "tag",
+      "workflowContext": {
+        "workflowDag": {
+          "entries": [
+            {
+              "source": "4",
+              "targets": [
+
+              ]
+            }
+          ]
+        }
+      }
+    },
+    {
+      "workflowId": "pig_f9957a11-a902-4f01-ac53-9679ce3a4b13",
+      "workflowName": "\/tmp\/pigSmoke.sh",
+      "userName": "ambari_qa",
+      "startTime": 1359378741973,
+      "elapsedTime": 18125,
+      "inputBytes": 0,
+      "outputBytes": 0,
+      "numJobsTotal": 1,
+      "numJobsCompleted": 1,
+      "workflowContext": {
+        "workflowDag": {
+          "entries": [
+            {
+              "source": "scope-5",
+              "targets": [
+
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ],
+  "summary": {
+    "numRows": 4,
+    "jobs": {
+      "avg": 1,
+      "min": 1,
+      "max": 1
+    },
+    "input": {
+      "avg": 0,
+      "min": 0,
+      "max": 0
+    },
+    "output": {
+      "avg": 0,
+      "min": 0,
+      "max": 0
+    },
+    "duration": {
+      "avg": 23651.5,
+      "min": 18125,
+      "max": 30215
+    },
+    "times": {
+      "oldest": 1359378922503,
+      "youngest": 1359378637135
+    }
+  }
+}

Added: incubator/ambari/branches/branch-1.4.0/ambari-web/app/classes/app_class.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-web/app/classes/app_class.js?rev=1492013&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-web/app/classes/app_class.js (added)
+++ incubator/ambari/branches/branch-1.4.0/ambari-web/app/classes/app_class.js Tue Jun 11 23:56:21 2013
@@ -0,0 +1,38 @@
+/**
+ * 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.
+ */
+
+
+var App = require('app');
+var date = require('utils/date');
+var misc = require('utils/misc');
+
+App.App2 = Ember.Object.extend({
+
+  app_id: "", //string
+  app_name: "", //string
+  app_type: "", //string
+  workflow_entity_name: "", //string
+  user_name: "", //string
+  queue: "", //string
+  submit_time: 0, //number
+  launch_time: 0, //number
+  finish_time: 0, //number
+  num_stages: 0, //number
+  stages: [], //number
+  status: "", //string
+});

Propchange: incubator/ambari/branches/branch-1.4.0/ambari-web/app/classes/app_class.js
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: incubator/ambari/branches/branch-1.4.0/ambari-web/app/classes/run_class.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-web/app/classes/run_class.js?rev=1492013&r1=1492012&r2=1492013&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-web/app/classes/run_class.js (original)
+++ incubator/ambari/branches/branch-1.4.0/ambari-web/app/classes/run_class.js Tue Jun 11 23:56:21 2013
@@ -32,6 +32,7 @@ App.Run2 = Ember.Object.extend({
   workflowContext: null, //string
   input: 0, //number
   output: 0, //number
+  tags: null, //string
 
   /**
    * Will set to true when we load all jobs related to this run
@@ -95,9 +96,9 @@ App.Run2 = Ember.Object.extend({
     if (this.get('id').indexOf('hive_') === 0) {
       return 'Hive';
     }
-    if (this.get('id').indexOf('mr_') === 0) {
+    if (this.get('id').indexOf('mr_') === 0 || this.get('id').indexOf('mapreduce_') === 0) {
       return 'MapReduce';
     }
     return 'Undefined';
   }.property('id')
-});
\ No newline at end of file
+});

Modified: incubator/ambari/branches/branch-1.4.0/ambari-web/app/controllers/main/apps/item_controller.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-web/app/controllers/main/apps/item_controller.js?rev=1492013&r1=1492012&r2=1492013&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-web/app/controllers/main/apps/item_controller.js (original)
+++ incubator/ambari/branches/branch-1.4.0/ambari-web/app/controllers/main/apps/item_controller.js Tue Jun 11 23:56:21 2013
@@ -17,6 +17,7 @@
  */
 
 var App = require('app');
+var stringUtils = require('utils/string_utils');
 
 App.MainAppsItemController = Em.Controller.extend({
   name:'mainAppsItemController',
@@ -39,16 +40,29 @@ App.MainAppsItemController = Em.Controll
     this.set('lastJobId', currentId);
     var self = this;
 
-    var url = App.testMode ? '/data/apps/jobs/'+ currentId +'.json' :
-      App.apiPrefix + "/jobhistory/job?workflowId=" + currentId;
-
-    var mapper = App.jobsMapper;
-    mapper.set('controller', this);
-    App.HttpClient.get(url, mapper,{
-      complete:function(jqXHR, textStatus) {
-        self.set('content.loadAllJobs', true);
-      }
-    });
+    if (!App.testMode && stringUtils.compareVersions(App.get('currentStackVersionNumber'), "2.0") === -1) {
+      var url = App.testMode ? '/data/apps/jobs/'+ currentId +'.json' :
+        App.apiPrefix + "/jobhistory/job?workflowId=" + currentId;
+
+      var mapper = App.jobsMapper;
+      mapper.set('controller', this);
+      App.HttpClient.get(url, mapper,{
+        complete:function(jqXHR, textStatus) {
+          self.set('content.loadAllJobs', true);
+        }
+      });
+    } else {
+      var url = App.testMode ? '/data/apps/apps/'+ currentId +'.json' :
+        App.apiPrefix + "/jobhistory/app?workflowId=" + currentId;
+
+      var mapper = App.appsMapper;
+      mapper.set('controller', this);
+      App.HttpClient.get(url, mapper,{
+        complete:function(jqXHR, textStatus) {
+          self.set('content.loadAllJobs', true);
+        }
+      });
+    }
   }.observes('content')
 
 })

Modified: incubator/ambari/branches/branch-1.4.0/ambari-web/app/controllers/main/apps_controller.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-web/app/controllers/main/apps_controller.js?rev=1492013&r1=1492012&r2=1492013&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-web/app/controllers/main/apps_controller.js (original)
+++ incubator/ambari/branches/branch-1.4.0/ambari-web/app/controllers/main/apps_controller.js Tue Jun 11 23:56:21 2013
@@ -19,6 +19,7 @@
 var App = require('app');
 var misc = require('utils/misc');
 var date = require('utils/date');
+var stringUtils = require('utils/string_utils');
 
 App.MainAppsController = Em.ArrayController.extend({
 
@@ -48,7 +49,7 @@ App.MainAppsController = Em.ArrayControl
     var self = this;
 
     //var runsUrl = App.testMode ? "/data/apps/runs.json" : App.apiPrefix + "/jobhistory/workflow?orderBy=startTime&sortDir=DESC&limit=" + App.maxRunsForAppBrowser;
-    var runsUrl = App.testMode ? "/data/apps/runs.json" : App.apiPrefix + this.get("runUrl");
+    var runsUrl = App.testMode ? "/data/apps/runs2.json" : App.apiPrefix + this.get("runUrl");
 
     App.HttpClient.get(runsUrl, App.runsMapper, {
       complete:function (jqXHR, textStatus) {
@@ -101,6 +102,7 @@ App.MainAppsController = Em.ArrayControl
     iDisplayStart:"",
     iSortCol_0:"",
     sSortDir_0:"",
+    tagSearch:"",
 
     allFilterActivated:false,
     filteredDisplayRecords:null,
@@ -114,7 +116,10 @@ App.MainAppsController = Em.ArrayControl
     runType:"",
     onRunTypeChange:function(){
       if(this.runType == "MapReduce"){
-        this.set("sSearch_2","mr");
+        if (!App.testMode && stringUtils.compareVersions(App.get('currentStackVersionNumber'), "2.0") === -1)
+          this.set("sSearch_2","mr");
+        else
+          this.set("sSearch_2","mapreduce");
       }else if(this.runType == "Hive"){
         this.set("sSearch_2","hive");
       }else if(this.runType == "Pig"){
@@ -323,7 +328,7 @@ App.MainAppsController = Em.ArrayControl
         "maxJobs", "minInputBytes", "maxInputBytes", "minOutputBytes",
         "maxOutputBytes", "minDuration", "maxDuration", "minStartTime",
         "maxStartTime", "sSearch", "iDisplayLength", "iDisplayStart",
-        "iSortCol_0", "sSortDir_0"
+        "iSortCol_0", "sSortDir_0", "tagSearch"
       ];
 
       for (var n=0; n<arr.length;n++) {
@@ -363,6 +368,7 @@ App.MainAppsController = Em.ArrayControl
     obj.set("output","");
     obj.set("duration","");
     obj.set("runDate","Any");
+    obj.set("tagSearch","");
   },
 
 
@@ -409,7 +415,8 @@ App.MainAppsController = Em.ArrayControl
       'filterObject.iDisplayStart',
       'filterObject.iSortCol_0',
       'filterObject.sSortDir_0',
-      'filterObject.viewType'
+      'filterObject.viewType',
+      'filterObject.tagSearch'
   ),
 
   serverData: "",
@@ -486,11 +493,12 @@ App.MainAppsController = Em.ArrayControl
       { name: Em.I18n.t('common.name'), index: 1 },
       { name: Em.I18n.t('common.type'), index: 2 },
       { name: Em.I18n.t('common.user'), index: 3 },
-      { name: Em.I18n.t('apps.avgTable.jobs'), index: 4 },
-      { name: Em.I18n.t('apps.avgTable.input'), index: 5 },
-      { name: Em.I18n.t('apps.avgTable.output'), index: 6 },
-      { name: Em.I18n.t('apps.avgTable.duration'), index: 7 },
-      { name: Em.I18n.t('apps.table.column.runDate'), index: 8 }
+      { name: Em.I18n.t('common.tags'), index: 4 },
+      { name: Em.I18n.t('apps.avgTable.jobs'), index: 5 },
+      { name: Em.I18n.t('apps.avgTable.input'), index: 6 },
+      { name: Em.I18n.t('apps.avgTable.output'), index: 7 },
+      { name: Em.I18n.t('apps.avgTable.duration'), index: 8 },
+      { name: Em.I18n.t('apps.table.column.runDate'), index: 9 }
     ]
   })
 

Modified: incubator/ambari/branches/branch-1.4.0/ambari-web/app/initialize.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-web/app/initialize.js?rev=1492013&r1=1492012&r2=1492013&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-web/app/initialize.js (original)
+++ incubator/ambari/branches/branch-1.4.0/ambari-web/app/initialize.js Tue Jun 11 23:56:21 2013
@@ -40,6 +40,7 @@ require('mappers/status_mapper');
 require('mappers/hosts_mapper');
 require('mappers/cluster_mapper');
 require('mappers/jobs_mapper');
+require('mappers/apps_mapper');
 require('mappers/runs_mapper');
 require('mappers/racks_mapper');
 require('mappers/alerts_mapper');

Added: incubator/ambari/branches/branch-1.4.0/ambari-web/app/mappers/apps_mapper.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-web/app/mappers/apps_mapper.js?rev=1492013&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-web/app/mappers/apps_mapper.js (added)
+++ incubator/ambari/branches/branch-1.4.0/ambari-web/app/mappers/apps_mapper.js Tue Jun 11 23:56:21 2013
@@ -0,0 +1,60 @@
+/**
+ * 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.
+ */
+
+var App = require('app');
+
+App.appsMapper = App.QuickDataMapper.create({
+  model:App.App,
+  map:function (json) {
+    if (!this.get('model')) {
+      return;
+    }
+    if (json.apps) {
+      var result = [];
+      json.apps.forEach(function (item) {
+        var a = this.parseIt(item, this.config);
+        a.elapsed_time = a.finish_time - a.submit_time;
+        a.num_stages = a.stages.length;
+        result.push(a);
+      }, this);
+
+      var r = Ember.ArrayProxy.create({"content":[]});
+      result.forEach(function(item){
+        r.content.push(App.App2.create(item));
+      });
+
+      this.set('controller.content.jobs', r.content);
+    }
+  },
+  config:{
+    id:'appId',
+    run_id:'workflowId',
+    app_name:'appName',
+    app_type:'appType',
+    workflow_entity_name:'workflowEntityName',
+    user_name:'userName',
+    queue:'queue',
+    submit_time:'submitTime',
+    launch_time:'launchTime',
+    finish_time:'finishTime',
+    num_stages:'numStages',
+    stages:'stages',
+    status:'status',
+    elapsed_time:'elapsedTime'
+  }
+});

Propchange: incubator/ambari/branches/branch-1.4.0/ambari-web/app/mappers/apps_mapper.js
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: incubator/ambari/branches/branch-1.4.0/ambari-web/app/mappers/runs_mapper.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-web/app/mappers/runs_mapper.js?rev=1492013&r1=1492012&r2=1492013&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-web/app/mappers/runs_mapper.js (original)
+++ incubator/ambari/branches/branch-1.4.0/ambari-web/app/mappers/runs_mapper.js Tue Jun 11 23:56:21 2013
@@ -81,6 +81,7 @@ App.runsMapper = App.QuickDataMapper.cre
     startTime: 'startTime',
     elapsedTime: 'elapsedTime',
     input: 'inputBytes',
-    output: 'outputBytes'
+    output: 'outputBytes',
+    tags: 'workflowTags'
   }
 });

Modified: incubator/ambari/branches/branch-1.4.0/ambari-web/app/messages.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-web/app/messages.js?rev=1492013&r1=1492012&r2=1492013&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-web/app/messages.js (original)
+++ incubator/ambari/branches/branch-1.4.0/ambari-web/app/messages.js Tue Jun 11 23:56:21 2013
@@ -133,6 +133,7 @@ Em.I18n.translations = {
   'common.errorPopup.header': 'An error has been encountered',
   'common.use': 'Use',
   'common.stacks': 'Stacks',
+  'common.tags': 'Tags',
 
   'requestInfo.installComponents':'Install Components',
   'requestInfo.installServices':'Install Services',
@@ -1068,7 +1069,10 @@ Em.I18n.translations = {
 
   'apps.item.dag.job': 'Job',
   'apps.item.dag.jobId': 'Job Id',
+  'apps.item.dag.type': 'Job Type',
   'apps.item.dag.status': 'Status',
+  'apps.item.dag.num_stages': 'Total Stages',
+  'apps.item.dag.stages': 'Tasks per Stage',
   'apps.item.dag.maps': 'Maps',
   'apps.item.dag.reduces': 'Reduces',
   'apps.item.dag.input': 'Input',

Modified: incubator/ambari/branches/branch-1.4.0/ambari-web/app/models.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-web/app/models.js?rev=1492013&r1=1492012&r2=1492013&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-web/app/models.js (original)
+++ incubator/ambari/branches/branch-1.4.0/ambari-web/app/models.js Tue Jun 11 23:56:21 2013
@@ -48,4 +48,4 @@ require('models/dataset');
 require('models/dataset_job');
 require('classes/run_class');
 require('classes/job_class');
-require('classes/job_class');
\ No newline at end of file
+require('classes/app_class');

Added: incubator/ambari/branches/branch-1.4.0/ambari-web/app/models/apps.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-web/app/models/apps.js?rev=1492013&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-web/app/models/apps.js (added)
+++ incubator/ambari/branches/branch-1.4.0/ambari-web/app/models/apps.js Tue Jun 11 23:56:21 2013
@@ -0,0 +1,42 @@
+/**
+ * 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.
+ */
+
+
+var App = require('app');
+var date = require('utils/date');
+var misc = require('utils/misc');
+
+App.App = DS.Model.extend({
+
+  run: DS.belongsTo('App.Run'),
+
+  appId: DS.attr('string'),
+  appName: DS.attr('string'),
+  appType: DS.attr('string'),
+  workflowEntityName: DS.attr('string'),
+  userName: DS.attr('string'),
+  queue: DS.attr('string'),
+  submitTime: DS.attr('number'),
+  launchTime: DS.attr('number'),
+  finishTime: DS.attr('number'),
+  numStages: DS.attr('number'),
+  stages: DS.attr('object'),
+  status: DS.attr('string'),
+});
+
+App.App.FIXTURES = [];

Propchange: incubator/ambari/branches/branch-1.4.0/ambari-web/app/models/apps.js
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: incubator/ambari/branches/branch-1.4.0/ambari-web/app/models/run.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-web/app/models/run.js?rev=1492013&r1=1492012&r2=1492013&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-web/app/models/run.js (original)
+++ incubator/ambari/branches/branch-1.4.0/ambari-web/app/models/run.js Tue Jun 11 23:56:21 2013
@@ -32,6 +32,7 @@ App.Run = DS.Model.extend({
   workflowContext:DS.attr('string'),
   input: DS.attr('number'),
   output: DS.attr('number'),
+  tags: DS.attr('string'),
 
   loadAllJobs : false,
 
@@ -107,7 +108,7 @@ App.Run = DS.Model.extend({
     if (this.get('id').indexOf('hive_') === 0) {
       return 'Hive';
     }
-    if (this.get('id').indexOf('mr_') === 0) {
+    if (this.get('id').indexOf('mr_') === 0 || this.get('id').indexOf('mapreduce_') === 0) {
       return 'MapReduce';
     }
   }.property('id')

Modified: incubator/ambari/branches/branch-1.4.0/ambari-web/app/routes/main.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-web/app/routes/main.js?rev=1492013&r1=1492012&r2=1492013&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-web/app/routes/main.js (original)
+++ incubator/ambari/branches/branch-1.4.0/ambari-web/app/routes/main.js Tue Jun 11 23:56:21 2013
@@ -98,15 +98,7 @@ module.exports = Em.Route.extend({
   apps: Em.Route.extend({
     route: '/apps',
     connectOutlets: function (router) {
-      if (stringUtils.compareVersions(App.get('currentStackVersionNumber'), "2.0") === 1 ||
-        stringUtils.compareVersions(App.get('currentStackVersionNumber'), "2.0") === 0) {
-        Em.run.next(function () {
-          router.transitionTo('main.dashboard');
-        });
-      } else {
-        router.get('mainAppsController').loadRuns();
-        router.get('mainController').connectOutlet('mainApps');
-      }
+      router.get('mainController').connectOutlet('mainApps');
     }
   }),
 
@@ -869,4 +861,4 @@ module.exports = Em.Route.extend({
     router.get('mainHostController').filterByComponent(component.context);
     router.transitionTo('hosts.index');
   }
-});
\ No newline at end of file
+});

Modified: incubator/ambari/branches/branch-1.4.0/ambari-web/app/styles/apps.less
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-web/app/styles/apps.less?rev=1492013&r1=1492012&r2=1492013&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-web/app/styles/apps.less (original)
+++ incubator/ambari/branches/branch-1.4.0/ambari-web/app/styles/apps.less Tue Jun 11 23:56:21 2013
@@ -60,7 +60,7 @@
     }
 
     input, select{
-      width: 76%;
+      width: 75%;
     }
 
     .no-data{
@@ -68,7 +68,7 @@
     }
 
     input.input-super-mini{
-      width: 47px;
+      width: 46px;
       max-width: 57%;
     }
 
@@ -78,22 +78,22 @@
     .col0,
     td:first-child,
     th:first-child {
-      width: 16%;
+      width: 14%;
     }
     .col1,
     td:first-child + td + td,
     th:first-child + th + th{
-      width: 15%;
+      width: 14%;
     }
     .col2,
     td:first-child + td + td + td,
     th:first-child + th + th + th{
-      width: 11%;
+      width: 9%;
     }
     .col3,
     td:first-child + td + td + td + td,
     th:first-child + th + th + th + th{
-      width: 11%;
+      width: 8%;
     }
     .col4,.col5,.col6,.col7,
     td:first-child + td + td + td + td + td,
@@ -105,12 +105,17 @@
     td:first-child + td + td + td + td + td + td + td + td,
     th:first-child + th + th + th + th + th + th + th + th
     {
-      width: 9%;
+      width: 8%;
     }
     .col8,
     td:first-child + td + td + td + td + td + td + td + td + td,
     th:first-child + th + th + th + th + th + th + th + th + th{
-      width: 13%;
+      width: 8%;
+    }
+    .col9,
+    td:first-child + td + td + td + td + td + td + td + td + td + td,
+    th:first-child + th + th + th + th + th + th + th + th + th + th{
+      width: 9%;
     }
   }
 
@@ -482,3 +487,154 @@
 }
 
 /*Big modal window end*/
+
+/*
+ * D3  visualization components 
+ * Styles for App Graph
+ */
+.wfdag {
+  width: 100%;
+}
+
+#app_graph .axis path,
+#app_graph .axis line {
+  fill: none;
+  stroke: #000;
+  shape-rendering: crispEdges;
+}
+
+#app_graph line.link,
+#app_graph path.link {
+  fill: none;
+  stroke: #666;
+  stroke-width: 2.5px;
+}
+
+#app_graph line.link.finished,
+#app_graph path.link.finished {
+  stroke: #444;
+}
+
+#app_graph path.link.stage {
+  stroke: #fff;
+}
+
+#app_graph marker#finished {
+  fill: #444;
+}
+
+#app_graph marker#circle {
+  fill: #666;
+  stroke: none;
+}
+
+#app_graph marker#stage {
+  fill: #fff;
+}
+
+#app_graph line.source.mark,
+#app_graph line.target.mark {
+  stroke: #666;
+  stroke-width: 2.5px;
+}
+
+#app_graph rect {
+  fill: #ccc;
+  stroke: #333;
+  stroke-width: 1px;
+}
+
+#app_graph rect.finished {
+  fill: green;
+  fill-opacity: 0.8;
+}
+
+#app_graph text.joblabel {
+  pointer-events: none;
+  text-anchor: middle;
+}
+
+#app_graph text.axislabel {
+  pointer-events: none;
+  text-anchor: end;
+  font-size: 11px;
+  font-weight: bold;
+}
+
+#app_graph text.shadow {
+  stroke: #fff;
+  stroke-width: 3px;
+  stroke-opacity: .8;
+}
+#app_graph .y.axis {
+  font-size: 10px;
+}
+
+#app_graph circle.stage {
+  fill: lightblue;
+  stroke: black;
+}
+
+#app_graph circle.stage.first {
+  fill: lightblue;
+  stroke: white;
+}
+
+#app_graph text.stagelabel {
+  stroke: black;
+  pointer-events: none;
+  text-anchor: middle;
+  dominant-baseline: central;
+  font-weight: bold;
+}
+
+#app_graph_legend {
+  border: 1px solid #DDDDDD;
+  padding: 10px;
+  padding-left: 20px;
+  margin: 0 auto;
+  width: 50%;
+  height: 40px;
+  ul {
+    list-style: none;
+    padding: 0;
+    margin: 0;
+  }
+  li {
+    display: block;
+    width: 50%;
+    float: left;
+  }
+  span {
+    width: 15px;
+    height: 15px;
+    display: block;
+    float: left;
+    margin-right: 5px;
+  }
+  span.stage {
+    margin-right: 8px;
+  }
+  .job {
+    border: 1px solid #333;
+    background: #ccc;
+  }
+  svg rect.jobdone {
+    stroke: 1px solid #333;
+    fill: rgba(0,128,0,0.8);
+  }
+  .jobdone {
+    border: 1px solid #333;
+    background: rgba(0,128,0,0.8);
+  }
+  #map {
+    stroke: white;
+    fill: lightblue;
+  }
+  #reduce {
+    stroke: black;
+    fill: lightblue;
+  }
+}
+
+/* App Graph end */

Modified: incubator/ambari/branches/branch-1.4.0/ambari-web/app/templates/main/apps.hbs
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-web/app/templates/main/apps.hbs?rev=1492013&r1=1492012&r2=1492013&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-web/app/templates/main/apps.hbs (original)
+++ incubator/ambari/branches/branch-1.4.0/ambari-web/app/templates/main/apps.hbs Tue Jun 11 23:56:21 2013
@@ -80,6 +80,7 @@
       <th>{{view view.nameFilterView}}</th>
       <th>{{view view.typeFilterView}}</th>
       <th>{{view view.userFilterView}}</th>
+      <th>{{view view.tagFilterView}}</th>
       <th>{{view view.jobsFilterView}}</th>
       <th>{{view view.inputFilterView}}</th>
       <th>{{view view.outputFilterView}}</th>

Added: incubator/ambari/branches/branch-1.4.0/ambari-web/app/templates/main/apps/item/app.hbs
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-web/app/templates/main/apps/item/app.hbs?rev=1492013&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-web/app/templates/main/apps/item/app.hbs (added)
+++ incubator/ambari/branches/branch-1.4.0/ambari-web/app/templates/main/apps/item/app.hbs Tue Jun 11 23:56:21 2013
@@ -0,0 +1,70 @@
+{{!
+* 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 id="app_graph"></div>
+
+    <div id="app_graph_legend">
+      <ul>
+        <li><span class="job"></span>Unfinished Job</li>
+        <li><span class="stage">
+          <svg width="18" height="18">
+            <rect class="jobdone" x="0" y="0" width="18" height="18"/>
+            <circle id="map" r="8" cx="9" cy="9"/>
+            <text x="9" y="14" style="text-anchor:middle">#</text>
+          </svg></span>Map Stage with # Tasks</li>
+        <li><span class="jobdone"></span>Finished Job</li>
+        <li><span class="stage">
+          <svg width="18" height="18">
+            <rect class="jobdone" x="0" y="0" width="18" height="18"/>
+            <circle id="reduce" r="8" cx="9" cy="9"/>
+            <text x="9" y="14" style="text-anchor:middle">#</text>
+          </svg></span>Reduce Stage with # Tasks</li>
+      </ul>
+    </div>
+
+    <table class="table table-bordered table-striped" id="innerTable">
+      <thead>
+      <tr>
+        {{#view view.sortView contentBinding="controller.content.jobs"}}
+          {{#if view.parentView.hasManyJobs}}{{view view.parentView.nameSort}}{{/if}}
+          {{view view.parentView.idSort}}
+          {{view view.parentView.typeSort}}
+          {{view view.parentView.statusSort}}
+          {{view view.parentView.numStagesSort}}
+          {{view view.parentView.stagesSort}}
+          {{view view.parentView.durationSort}}
+        {{/view}}
+      </tr>
+      </thead>
+      <tbody>
+      {{#if view.loaded}}
+        {{#each job in view.jobs}}
+        <tr>
+          {{#if view.hasManyJobs}}<td>{{job.entityName}}</td>{{/if}}
+          <td>{{job.name}}</td>
+          <td>{{job.type}}</td>
+          <td>{{job.status}}</td>
+          <td>{{job.numStages}}</td>
+          <td>{{job.stages}}</td>
+          <td>{{job.elapsedTime}}</td>
+        </tr>
+        {{/each}}
+      {{/if}}
+      </tbody>
+    </table>
+
+

Modified: incubator/ambari/branches/branch-1.4.0/ambari-web/app/templates/main/apps/list_row.hbs
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-web/app/templates/main/apps/list_row.hbs?rev=1492013&r1=1492012&r2=1492013&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-web/app/templates/main/apps/list_row.hbs (original)
+++ incubator/ambari/branches/branch-1.4.0/ambari-web/app/templates/main/apps/list_row.hbs Tue Jun 11 23:56:21 2013
@@ -20,6 +20,7 @@
 <td>{{unbound run.appName}}</td>
 <td>{{unbound run.type}}</td>
 <td>{{unbound run.userName}}</td>
+<td>{{unbound run.tags}}</td>
 <td>{{unbound run.numJobsTotal}}</td>
 <td>{{unbound run.inputFormatted}}</td>
 <td>{{unbound run.outputFormatted}}</td>

Added: incubator/ambari/branches/branch-1.4.0/ambari-web/app/utils/app_graph.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-web/app/utils/app_graph.js?rev=1492013&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-web/app/utils/app_graph.js (added)
+++ incubator/ambari/branches/branch-1.4.0/ambari-web/app/utils/app_graph.js Tue Jun 11 23:56:21 2013
@@ -0,0 +1,455 @@
+/**
+ * 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.
+ */
+
+
+module.exports = {
+  create:function(domId, wfData, jobData, svgw, svgh, nodeHeight, labelFontSize, maxLabelWidth, axisPadding, stageFontSize) {
+    // initialize variables
+    var nodes = new Array();
+    var links = new Array();
+    var numNodes = 0;
+    var id = domId;
+    var formatDuration = this.formatDuration;
+
+    // create map from entity names to nodes
+    var existingNodes = new Array();
+    var jobData = (jobData) ? jobData : new Array();
+    var minStartTime = 0;
+    if (jobData.length > 0)
+      minStartTime = jobData[0].submitTime;
+    var maxFinishTime = 0;
+    // iterate through job data
+    for (var i = 0; i < jobData.length; i++) {
+      jobData[i].info = "jobId:"+jobData[i].name+"  \n"+
+        "nodeName:"+jobData[i].entityName+"  \n"+
+        "status:"+jobData[i].status+"  \n"+
+        "startTime:"+(new Date(jobData[i].submitTime).toUTCString())+"  \n"+
+        "duration:"+formatDuration(jobData[i].finishTime - jobData[i].submitTime);
+console.log("info "+jobData[i].info);
+      jobData[i].state = jobData[i].status.substr(0,4)=="SUCC";
+      minStartTime = Math.min(minStartTime, jobData[i].submitTime);
+      maxFinishTime = Math.max(maxFinishTime, jobData[i].finishTime);
+      // add a node to the nodes array and to a provided map of entity names to nodes
+      existingNodes[jobData[i].entityName] = jobData[i];
+      nodes.push(jobData[i]);
+      numNodes++;
+    }
+    var dag = eval('(' + wfData + ')').dag;
+    var sourceMarker = new Array();
+    var targetMarker = new Array();
+    var sourceMap = new Array();
+    // for each source node in the context, create links between it and its target nodes
+    for (var source in dag) {
+      var sourceNode = null;
+      if (source in existingNodes)
+        sourceNode = existingNodes[source];
+      for (var i = 0; i < dag[source].length; i++) {
+        var targetNode = null;
+        if (dag[source][i] in existingNodes)
+          targetNode = existingNodes[dag[source][i]];
+        // add a link between sourceNode and targetNode
+        // if source or target is null, add marker indicating unsubmitted job and return
+        if (sourceNode==null) {
+          if (targetNode==null)
+            continue;
+          sourceMarker.push(targetNode);
+          continue;
+        }
+        if (targetNode==null) {
+          targetMarker.push(sourceNode);
+          continue;
+        }
+        // add link between nodes
+        var state = false;
+        if (sourceNode.state && targetNode.state)
+          state = true;
+        links.push({"source":sourceNode, "target":targetNode, "state":state, "value":sourceNode.output});
+        // add source to map of targets to sources
+        if (!(targetNode.name in sourceMap))
+          sourceMap[targetNode.name] = new Array();
+        sourceMap[targetNode.name].push(sourceNode);
+      }
+    }
+  
+    // display the graph
+    // rules of thumb: nodeHeight = 20, labelFontSize = 14, maxLabelWidth = 180
+    //                 nodeHeight = 15, labelFontSize = 10, maxLabelWidth = 120
+    //                 nodeHeight = 40, labelFontSize = 20, maxLabelWidth = 260
+    //                 nodeHeight = 30, labelFontSize = 16
+    var nodeHeight = nodeHeight || 26;
+    var labelFontSize = labelFontSize || 14;
+    var maxLabelWidth = maxLabelWidth || 165;
+    var axisPadding = axisPadding || 30;
+    var stageFontSize = stageFontSize || 16;
+
+    // draw timeline graph
+    var margin = {"vertical":10, "horizontal":50};
+    var w = svgw - 2*margin.horizontal;
+
+    var startTime = minStartTime;
+    var elapsedTime = maxFinishTime - minStartTime;
+    var x = d3.time.scale.utc()
+      .domain([startTime, startTime+elapsedTime])
+      .range([0, w]);
+    var xrel = d3.time.scale()
+      .domain([0, elapsedTime])
+      .range([0, w]);
+
+    // process nodes and determine their x and y positions, width and height
+    var minNodeSpacing = nodeHeight/2;
+    var ends = new Array();
+    var maxIndex = 0;
+    nodes.sort(function(a,b){return a.name.localeCompare(b.name);});
+    for (var i = 0; i < numNodes; i++) {
+      var d = nodes[i];
+      d.x = x(d.submitTime);
+      d.w = x(d.finishTime) - x(d.submitTime);
+      if (d.w < d.stages.length*(nodeHeight-4)) {
+        d.w = d.stages.length*(nodeHeight-4);
+        if (d.x + d.w > w)
+          d.x = w - d.w;
+      }
+      var effectiveX = d.x
+      var effectiveWidth = d.w;
+      if (d.w < maxLabelWidth) {
+        effectiveWidth = maxLabelWidth;
+        if (d.x + effectiveWidth > w)
+          effectiveX = w - effectiveWidth;
+        else if (d.x > 0)
+          effectiveX = d.x+(d.w-maxLabelWidth)/2;
+      }
+      // select "lane" (slot for y-position) for this node
+      // starting at the slot above the node's closest source node (or 0, if none exists)
+      // and moving down until a slot is found that has no nodes within minNodeSpacing of this node
+      // excluding slots that contain more than one source of this node
+      var index = 0;
+      var rejectIndices = new Array();
+      if (d.name in sourceMap) {
+        var sources = sourceMap[d.name];
+        var closestSource = sources[0];
+        var indices = new Array();
+        for (var j = 0; j < sources.length; j++) {
+          if (sources[j].index in indices)
+            rejectIndices[sources[j].index] = true;
+          indices[sources[j].index] = true;
+          if (sources[j].submitTime + sources[j].elapsedTime > closestSource.submitTime + closestSource.elapsedTime)
+            closestSource = sources[j];
+        }
+        index = Math.max(0, closestSource.index-1);
+      }
+      while ((index in ends) && ((index in rejectIndices) || (ends[index]+minNodeSpacing >= effectiveX))) {
+        index++
+      }
+      ends[index] = Math.max(effectiveX + effectiveWidth);
+      maxIndex = Math.max(maxIndex, index);
+      d.y = index*2*nodeHeight + axisPadding;
+      d.h = nodeHeight;
+      d.index = index;
+    }
+
+    var h = 2*axisPadding + 2*nodeHeight*(maxIndex+1);
+    var realh = svgh - 2*margin.vertical;
+    var scale = 1;
+    if (h > realh)
+      scale = realh / h;
+    svgh = Math.min(svgh, h + 2*margin.vertical);
+    var svg = d3.select("div#" + id).append("svg:svg")
+      .attr("width", svgw+"px")
+      .attr("height", svgh+"px");
+    
+    var svgg = svg.append("g")
+      .attr("transform", "translate("+margin.horizontal+","+margin.vertical+") scale("+scale+")");
+
+    // add an untranslated white rectangle below everything
+    // so mouse doesn't have to be over nodes for panning/zooming
+    svgg.append("svg:rect")
+      .attr("x", 0)
+      .attr("y", 0)
+      .attr("width", svgw)
+      .attr("height", svgh/scale)
+      .attr("style", "fill:white;stroke:none");
+ 
+    // create axes
+    var topAxis = d3.svg.axis()
+      .scale(x)
+      .orient("bottom");
+    var bottomAxis = d3.svg.axis()
+      .scale(xrel)
+      .orient("top")
+      .tickFormat(function(x) { return formatDuration(x.getTime()); });
+    var topg = svgg.append("g")
+      .attr("class", "x axis top")
+      .call(topAxis);
+    topg.append("svg:text")
+      .attr("class", "axislabel")
+      .attr("x", -9)
+      .attr("y", 13)
+      .text("Time");
+    var botg = svgg.append("g")
+      .attr("class", "x axis bottom")
+      .call(bottomAxis)
+      .attr("transform", "translate(0,"+h+")")
+    botg.append("svg:text")
+      .attr("class", "axislabel")
+      .attr("x", -9)
+      .attr("y", -19)
+      .text("Elapsed");
+    botg.append("svg:text")
+      .attr("class", "axislabel")
+      .attr("x", -9)
+      .attr("y", -4)
+      .text("Time");
+
+  
+    // create a rectangle for each node
+    var boxes = svgg.append("svg:g").selectAll("rect")
+      .data(nodes)
+      .enter().append("svg:rect")
+      .attr("x", function(d) { return d.x; } )
+      .attr("y", function(d) { return d.y; } )
+      .attr("width", function(d) { return d.w; } )
+      .attr("height", function(d) { return d.h; } )
+      .attr("class", function (d) {
+        return "node " + (d.state ? " finished" : "");
+      })
+      .attr("id", function (d) {
+        return d.name;
+      })
+      .append("title")
+      .text(function(d) { return d.info; });
+  
+    // defs for arrowheads marked as to whether they link finished jobs or not
+    svgg.append("svg:defs").selectAll("arrowmarker")
+      .data(["finished", "unfinished", "stage"])
+      .enter().append("svg:marker")
+      .attr("id", String)
+      .attr("viewBox", "0 -5 10 10")
+      .attr("markerWidth", 6)
+      .attr("markerHeight", 6)
+      .attr("refX", function(d) { return (d==="stage") ? 5 : 3 })
+      .attr("orient", "auto")
+      .append("svg:path")
+      .attr("d", function(d) { return (d==="stage") ? "M0,-2L6,0L0,2" : "M0,-3L8,0L0,3" });
+    // defs for unsubmitted node marker
+    svgg.append("svg:defs").selectAll("circlemarker")
+      .data(["circle"])
+      .enter().append("svg:marker")
+      .attr("id", String)
+      .attr("viewBox", "-2 -2 18 18")
+      .attr("markerWidth", 10)
+      .attr("markerHeight", 10)
+      .attr("refX", 10)
+      .attr("refY", 5)
+      .attr("orient", "auto")
+      .append("svg:circle")
+      .attr("cx", 5)
+      .attr("cy", 5)
+      .attr("r", 5);
+
+    // create dangling links representing unsubmitted jobs
+    var markerWidth = nodeHeight/2;
+    var sourceMarker = svgg.append("svg:g").selectAll("line")
+      .data(sourceMarker)
+      .enter().append("svg:line")
+      .attr("x1", function(d) { return d.x - markerWidth; } )
+      .attr("x2", function(d) { return d.x; } )
+      .attr("y1", function(d) { return d.y; } )
+      .attr("y2", function(d) { return d.y + 3; } )
+      .attr("class", "source mark")
+      .attr("marker-start", "url(#circle)");
+    var targetMarker = svgg.append("svg:g").selectAll("line")
+      .data(targetMarker)
+      .enter().append("svg:line")
+      .attr("x1", function(d) { return d.x + d.w + markerWidth; } )
+      .attr("x2", function(d) { return d.x + d.w; } )
+      .attr("y1", function(d) { return d.y + d.h; } )
+      .attr("y2", function(d) { return d.y + d.h - 3; } )
+      .attr("class", "target mark")
+      .attr("marker-start", "url(#circle)");
+
+    // create links between the nodes
+    var lines = svgg.append("svg:g").selectAll("path")
+      .data(links)
+      .enter().append("svg:path")
+      .attr("d", function(d) {
+        var s = d.source;
+        var t = d.target;
+        var x1 = s.x + s.w;
+        var x2 = t.x;
+        var y1 = s.y;
+        var y2 = t.y;
+        if (y1==y2) {
+          y1 += s.h/2;
+          y2 += t.h/2;
+        } else if (y1 < y2) {
+          y1 += s.h;
+        } else {
+          y2 += t.h;
+        }
+        return "M "+x1+" "+y1+" L "+((x2+x1)/2)+" "+((y2+y1)/2)+" L "+x2+" "+y2;
+      } )
+      .attr("class", function (d) {
+        return "link" + (d.state ? " finished" : "");
+      })
+      .attr("marker-mid", function (d) {
+        return "url(#" + (d.state ? "finished" : "unfinished") + ")";
+      });
+  
+    // create text group for each node label
+    var text = svgg.append("svg:g").selectAll("g")
+      .data(nodes)
+      .enter().append("svg:g");
+  
+    // add a shadow copy of the node label (will have a lighter color and thicker
+    // stroke for legibility)
+    text.append("svg:text")
+      .attr("x", function(d) {
+        var goal = d.x + d.w/2;
+        var halfLabel = maxLabelWidth/2;
+        if (goal < halfLabel) return halfLabel;
+        else if (goal > w-halfLabel) return w-halfLabel;
+        return goal;
+      } )
+      .attr("y", function(d) { return d.y + d.h + labelFontSize; } )
+      .attr("class", "joblabel shadow")
+      .attr("style", "font: "+labelFontSize+"px sans-serif")
+      .text(function (d) {
+        return d.name;
+      });
+  
+    // add the main node label
+    text.append("svg:text")
+      .attr("x", function(d) {
+        var goal = d.x + d.w/2;
+        var halfLabel = maxLabelWidth/2;
+        if (goal < halfLabel) return halfLabel;
+        else if (goal > w-halfLabel) return w-halfLabel;
+        return goal;
+      } )
+      .attr("y", function(d) { return d.y + d.h + labelFontSize; } )
+      .attr("class", "joblabel")
+      .attr("style", "font: "+labelFontSize+"px sans-serif")
+      .text(function (d) {
+        return d.name;
+      });
+
+    // add node stage information
+    var topstageg = svgg.append("svg:g");
+    var mouseg = svgg.append("svg:g");
+    var allstageg = topstageg.selectAll("g")
+      .data(nodes)
+      .enter().append("svg:g");
+    var stageg = allstageg.selectAll("g")
+      .data(function(d,i) { 
+        var stagedata = new Array(d.stages.length);
+        var cr = d.h / 2 - 2;
+        var cy = d.y + cr + 2;
+        var cxSpacing = d.w / stagedata.length;
+        if (cxSpacing < 2*cr)
+          cxSpacing = 2*cr;
+        var cxBase = d.x + cxSpacing / 2;
+        for (var j = 0; j < stagedata.length; j++)
+          stagedata[j] = {"data": d.stages[j],
+            "index": i,
+            "num": stagedata.length,
+            "cr": cr,
+            "cy": cy,
+            "cx":cxBase+j*cxSpacing,
+            "cxSpacing":cxSpacing};
+        return stagedata;
+      })
+      .enter().append("svg:g");
+    var path = stageg.append("svg:path")
+      .attr("class", function(d,i) {
+        if (i==d.num-1 || d.cxSpacing==2*d.cr) {
+          return "nopath";
+        } else {
+          return "link stage";
+        }
+      });
+    stageg.selectAll(".nopath").remove();
+    path.attr("d", function(d,i) {
+        var x1 = d.cx + d.cr;
+        var x2 = d.cx + d.cxSpacing - d.cr;
+        return "M "+x1+" "+d.cy+" L "+((x1+x2)/2)+" "+d.cy+" L "+x2+" "+d.cy;
+      } )
+      .attr("marker-end", function (d) {
+        return "url(#stage)";
+      });
+    stageg.append("svg:circle")
+      .attr("class", function(d,i) { return (i==0) ? "stage first" : "stage" })
+      .attr("r", function(d) { return d.cr })
+      .attr("cx", function(d) { return d.cx })
+      .attr("cy", function(d) { return d.cy })
+      .append("title")
+      .text(function(d,i) {
+        var t = "stage with "+d.data+" task";
+        if (d.data!=1)
+          t = t+"s";
+        if (i==0) 
+          t = "Map "+t;
+        else
+          t = "Reduce "+t;
+        return t;
+      });
+
+    stageg.append("svg:text")
+      .attr("class", "stagelabel")
+      .attr("x", function(d) { return d.cx })
+      .attr("y", function(d) { return d.cy })
+      .text(function(d) { return d.data })
+      .attr("style", function(d) {
+        var fontSize = stageFontSize;
+        if (d.data > 9) fontSize = fontSize - 2;
+        if (d.data > 99) fontSize = fontSize - 4;
+        if (d.data > 999) fontSize = fontSize - 2;
+        if (d.data > 9999) fontSize = fontSize - 1;
+        return "font: "+fontSize+"px sans-serif";
+      });
+
+    svg.call(d3.behavior.zoom().on("zoom", function() {
+      var left = Math.min(Math.max(d3.event.translate[0]+margin.horizontal, margin.horizontal-w*d3.event.scale*scale), margin.horizontal+w);
+      var top = Math.min(Math.max(d3.event.translate[1]+margin.vertical, margin.vertical-h*d3.event.scale*scale), margin.vertical+h);
+      svgg.attr("transform", "translate("+left+","+top+") scale("+(d3.event.scale*scale)+")");
+    }));
+  },
+  formatDuration:function(d) {
+    if (d==0) { return "0" }
+    var seconds = Math.floor(parseInt(d) / 1000);
+    if ( seconds < 60 )
+      return seconds + "s";
+    var minutes = Math.floor(seconds / 60);
+    if ( minutes < 60 ) {
+      var x = seconds - 60*minutes;
+      return minutes + "m" + (x==0 ? "" : " " + x + "s");
+    }
+    var hours = Math.floor(minutes / 60);
+    if ( hours < 24 ) {
+      var x = minutes - 60*hours;
+      return hours + "h" + (x==0 ? "" : " " + x + "m");
+    }
+    var days = Math.floor(hours / 24);
+    if ( days < 7 ) {
+      var x = hours - 24*days;
+      return days + "d " + (x==0 ? "" : " " + x + "h");
+    }
+    var weeks = Math.floor(days / 7);
+    var x = days - 7*weeks;
+    return weeks + "w " + (x==0 ? "" : " " + x + "d");
+  }
+}

Propchange: incubator/ambari/branches/branch-1.4.0/ambari-web/app/utils/app_graph.js
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: incubator/ambari/branches/branch-1.4.0/ambari-web/app/views.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.4.0/ambari-web/app/views.js?rev=1492013&r1=1492012&r2=1492013&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.4.0/ambari-web/app/views.js (original)
+++ incubator/ambari/branches/branch-1.4.0/ambari-web/app/views.js Tue Jun 11 23:56:21 2013
@@ -133,6 +133,7 @@ require('views/main/apps_view');
 require('views/main/apps/item_view');
 require('views/main/apps/item/bar_view');
 require('views/main/apps/item/dag_view');
+require('views/main/apps/item/app_view');
 require('views/main/mirroring_view');
 require('views/main/mirroring/dropdown_view');
 require('views/main/mirroring/dataset_view');