diff --git a/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/hub/workflow/HubWorkflowResource.scala b/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/hub/workflow/HubWorkflowResource.scala index 3cbf69df685..03608654518 100644 --- a/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/hub/workflow/HubWorkflowResource.scala +++ b/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/hub/workflow/HubWorkflowResource.scala @@ -6,15 +6,21 @@ import edu.uci.ics.texera.web.model.jooq.generated.Tables._ import edu.uci.ics.texera.web.model.jooq.generated.enums.UserRole import edu.uci.ics.texera.web.model.jooq.generated.tables.daos.WorkflowDao import edu.uci.ics.texera.web.model.jooq.generated.tables.pojos.{User, Workflow} +import edu.uci.ics.texera.web.resource.dashboard.hub.workflow.HubWorkflowResource.fetchDashboardWorkflowsByWids import edu.uci.ics.texera.web.resource.dashboard.hub.workflow.HubWorkflowResource.recordUserActivity import edu.uci.ics.texera.web.resource.dashboard.user.workflow.WorkflowAccessResource -import edu.uci.ics.texera.web.resource.dashboard.user.workflow.WorkflowResource.WorkflowWithPrivilege +import edu.uci.ics.texera.web.resource.dashboard.user.workflow.WorkflowResource.{ + DashboardWorkflow, + WorkflowWithPrivilege +} +import org.jooq.impl.DSL +import scala.jdk.CollectionConverters._ import java.util import javax.ws.rs._ import javax.ws.rs.core.MediaType import org.jooq.types.UInteger - +import java.util.Collections import java.util.regex.Pattern import javax.servlet.http.HttpServletRequest import javax.ws.rs.core.Context @@ -26,6 +32,53 @@ object HubWorkflowResource { "^([0-9]{1,3}\\.){3}[0-9]{1,3}$" ) + def fetchDashboardWorkflowsByWids(wids: Seq[UInteger]): util.List[DashboardWorkflow] = { + if (wids.nonEmpty) { + context + .select( + WORKFLOW.NAME, + WORKFLOW.DESCRIPTION, + WORKFLOW.WID, + WORKFLOW.CREATION_TIME, + WORKFLOW.LAST_MODIFIED_TIME, + USER.NAME.as("ownerName"), + WORKFLOW_OF_USER.UID.as("ownerId") + ) + .from(WORKFLOW) + .join(WORKFLOW_OF_USER) + .on(WORKFLOW.WID.eq(WORKFLOW_OF_USER.WID)) + .join(USER) + .on(WORKFLOW_OF_USER.UID.eq(USER.UID)) + .where(WORKFLOW.WID.in(wids: _*)) + .fetch() + .asScala + .map(record => { + val workflow = new Workflow( + record.get(WORKFLOW.NAME), + record.get(WORKFLOW.DESCRIPTION), + record.get(WORKFLOW.WID), + null, + record.get(WORKFLOW.CREATION_TIME), + record.get(WORKFLOW.LAST_MODIFIED_TIME), + null + ) + + DashboardWorkflow( + isOwner = false, + accessLevel = "", + ownerName = record.get("ownerName", classOf[String]), + workflow = workflow, + projectIDs = List(), + ownerId = record.get("ownerId", classOf[UInteger]) + ) + }) + .toList + .asJava + } else { + Collections.emptyList[DashboardWorkflow]() + } + } + def recordUserActivity( request: HttpServletRequest, userId: UInteger = UInteger.valueOf(0), @@ -71,9 +124,10 @@ class HubWorkflowResource { @GET @Path("/count") - def getWorkflowCount: Integer = { + def getPublishedWorkflowCount: Integer = { context.selectCount .from(WORKFLOW) + .where(WORKFLOW.IS_PUBLISHED.eq(1.toByte)) .fetchOne(0, classOf[Integer]) } @@ -264,6 +318,44 @@ class HubWorkflowResource { cloneCount } + @GET + @Path("/topLovedWorkflows") + @Produces(Array(MediaType.APPLICATION_JSON)) + def getTopLovedWorkflows: util.List[DashboardWorkflow] = { + val topLovedWorkflowsWids = context + .select(WORKFLOW_USER_LIKES.WID) + .from(WORKFLOW_USER_LIKES) + .groupBy(WORKFLOW_USER_LIKES.WID) + .orderBy(DSL.count(WORKFLOW_USER_LIKES.WID).desc()) + .limit(8) + .fetchInto(classOf[UInteger]) + .asScala + .toSeq + + println(fetchDashboardWorkflowsByWids(topLovedWorkflowsWids)) + + fetchDashboardWorkflowsByWids(topLovedWorkflowsWids) + } + + @GET + @Path("/topClonedWorkflows") + @Produces(Array(MediaType.APPLICATION_JSON)) + def getTopClonedWorkflows: util.List[DashboardWorkflow] = { + val topClonedWorkflowsWids = context + .select(WORKFLOW_USER_CLONES.WID) + .from(WORKFLOW_USER_CLONES) + .groupBy(WORKFLOW_USER_CLONES.WID) + .orderBy(DSL.count(WORKFLOW_USER_CLONES.WID).desc()) + .limit(8) + .fetchInto(classOf[UInteger]) + .asScala + .toSeq + + println(fetchDashboardWorkflowsByWids(topClonedWorkflowsWids)) + + fetchDashboardWorkflowsByWids(topClonedWorkflowsWids) + } + @POST @Path("/view") @Consumes(Array(MediaType.APPLICATION_JSON)) diff --git a/core/gui/src/app/app-routing.module.ts b/core/gui/src/app/app-routing.module.ts index f2bcb552995..d9621e8fe80 100644 --- a/core/gui/src/app/app-routing.module.ts +++ b/core/gui/src/app/app-routing.module.ts @@ -18,9 +18,9 @@ import { AdminGmailComponent } from "./dashboard/component/admin/gmail/admin-gma import { UserDatasetExplorerComponent } from "./dashboard/component/user/user-dataset/user-dataset-explorer/user-dataset-explorer.component"; import { UserDatasetComponent } from "./dashboard/component/user/user-dataset/user-dataset.component"; import { HubWorkflowSearchComponent } from "./hub/component/workflow/search/hub-workflow-search.component"; -import { HubWorkflowResultComponent } from "./hub/component/workflow/result/hub-workflow-result.component"; import { HubWorkflowComponent } from "./hub/component/workflow/hub-workflow.component"; import { HubWorkflowDetailComponent } from "./hub/component/workflow/detail/hub-workflow-detail.component"; +import { LandingPageComponent } from "./hub/component/landing-page/landing-page.component"; const routes: Routes = []; @@ -31,6 +31,10 @@ if (environment.userSystemEnabled) { children: [ { path: "home", + component: LandingPageComponent, + }, + { + path: "about", component: HomeComponent, }, { @@ -41,15 +45,11 @@ if (environment.userSystemEnabled) { component: HubWorkflowComponent, children: [ { - path: "search", + path: "result", component: HubWorkflowSearchComponent, }, { - path: "search/result", - component: HubWorkflowResultComponent, - }, - { - path: "search/result/detail/:id", + path: "result/detail/:id", component: HubWorkflowDetailComponent, }, ], diff --git a/core/gui/src/app/app.module.ts b/core/gui/src/app/app.module.ts index f1c683f9f58..f0eac77a97c 100644 --- a/core/gui/src/app/app.module.ts +++ b/core/gui/src/app/app.module.ts @@ -134,10 +134,10 @@ import { ListItemComponent } from "./dashboard/component/user/list-item/list-ite import { HubComponent } from "./hub/component/hub.component"; import { HubWorkflowSearchComponent } from "./hub/component/workflow/search/hub-workflow-search.component"; import { GoogleLoginComponent } from "./dashboard/component/user/google-login/google-login.component"; -import { HubWorkflowResultComponent } from "./hub/component/workflow/result/hub-workflow-result.component"; import { HubWorkflowComponent } from "./hub/component/workflow/hub-workflow.component"; -import { HubWorkflowSearchBarComponent } from "./hub/component/workflow/search-bar/hub-workflow-search-bar.component"; import { HubWorkflowDetailComponent } from "./hub/component/workflow/detail/hub-workflow-detail.component"; +import { LandingPageComponent } from "./hub/component/landing-page/landing-page.component"; +import { BrowseSectionComponent } from "./hub/component/browse-section/browse-section.component"; import { BreakpointConditionInputComponent } from "./workspace/component/code-editor-dialog/breakpoint-condition-input/breakpoint-condition-input.component"; import { CodeDebuggerComponent } from "./workspace/component/code-editor-dialog/code-debugger.component"; @@ -224,10 +224,10 @@ registerLocaleData(en); HubComponent, HubWorkflowComponent, HubWorkflowSearchComponent, - HubWorkflowSearchBarComponent, HubWorkflowDetailComponent, - HubWorkflowResultComponent, GoogleLoginComponent, + LandingPageComponent, + BrowseSectionComponent, BreakpointConditionInputComponent, CodeDebuggerComponent, ], diff --git a/core/gui/src/app/dashboard/component/dashboard.component.html b/core/gui/src/app/dashboard/component/dashboard.component.html index d8281f671cc..801d0af2819 100644 --- a/core/gui/src/app/dashboard/component/dashboard.component.html +++ b/core/gui/src/app/dashboard/component/dashboard.component.html @@ -142,21 +142,27 @@