Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/sync-docs-to-site.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ on:
- main
paths:
- 'docs/**'
# Build tooling, not website content.
- '!docs/operator-demo-videos/**'
workflow_dispatch:

# Run one sync at a time.
Expand Down Expand Up @@ -96,11 +98,16 @@ jobs:
source_rels = set()
created = updated = deleted = 0

# Build tooling, not website content; never mirrored.
excluded_dirs = ("operator-demo-videos",)

# Mirror every file: .md keeps the target front matter, others copied as-is.
for sfile in sorted(source.rglob("*")):
if sfile.is_dir():
continue
rel = sfile.relative_to(source)
if rel.parts and rel.parts[0] in excluded_dirs:
continue
source_rels.add(rel)
tfile = target / rel
existed = tfile.exists()
Expand Down
6 changes: 5 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@
Test / forkOptions := (Test / forkOptions).value
.withWorkingDirectory((ThisBuild / baseDirectory).value),
Test / testGrouping := (Test / definedTests).value.map { suite =>
Tests.Group(suite.name, Seq(suite), Tests.SubProcess((Test / forkOptions).value))

Check warning on line 231 in build.sbt

View workflow job for this annotation

GitHub Actions / Bench

The evaluation of `/` inside an anonymous function is prohibited.

Check warning on line 231 in build.sbt

View workflow job for this annotation

GitHub Actions / Bench

The evaluation of `/` inside an anonymous function is prohibited.

Check warning on line 231 in build.sbt

View workflow job for this annotation

GitHub Actions / build / amber (ubuntu-latest, 17)

The evaluation of `/` inside an anonymous function is prohibited.

Check warning on line 231 in build.sbt

View workflow job for this annotation

GitHub Actions / build / amber-integration (macos-latest, 17)

The evaluation of `/` inside an anonymous function is prohibited.

Check warning on line 231 in build.sbt

View workflow job for this annotation

GitHub Actions / build / amber-integration (ubuntu-latest, 17)

The evaluation of `/` inside an anonymous function is prohibited.

Check warning on line 231 in build.sbt

View workflow job for this annotation

GitHub Actions / build / platform (file-service)

The evaluation of `/` inside an anonymous function is prohibited.

Check warning on line 231 in build.sbt

View workflow job for this annotation

GitHub Actions / build / platform (access-control-service)

The evaluation of `/` inside an anonymous function is prohibited.

Check warning on line 231 in build.sbt

View workflow job for this annotation

GitHub Actions / build / platform (notebook-migration-service)

The evaluation of `/` inside an anonymous function is prohibited.

Check warning on line 231 in build.sbt

View workflow job for this annotation

GitHub Actions / build / platform (config-service)

The evaluation of `/` inside an anonymous function is prohibited.

Check warning on line 231 in build.sbt

View workflow job for this annotation

GitHub Actions / build / platform (computing-unit-managing-service)

The evaluation of `/` inside an anonymous function is prohibited.

Check warning on line 231 in build.sbt

View workflow job for this annotation

GitHub Actions / build / platform-integration (workflow-compiling-service)

The evaluation of `/` inside an anonymous function is prohibited.

Check warning on line 231 in build.sbt

View workflow job for this annotation

GitHub Actions / build / platform-integration (file-service)

The evaluation of `/` inside an anonymous function is prohibited.

Check warning on line 231 in build.sbt

View workflow job for this annotation

GitHub Actions / build / platform (workflow-compiling-service)

The evaluation of `/` inside an anonymous function is prohibited.

Check warning on line 231 in build.sbt

View workflow job for this annotation

GitHub Actions / build / platform-integration (notebook-migration-service)

The evaluation of `/` inside an anonymous function is prohibited.

Check warning on line 231 in build.sbt

View workflow job for this annotation

GitHub Actions / build / platform-integration (access-control-service)

The evaluation of `/` inside an anonymous function is prohibited.

Check warning on line 231 in build.sbt

View workflow job for this annotation

GitHub Actions / build / platform-integration (config-service)

The evaluation of `/` inside an anonymous function is prohibited.

Check warning on line 231 in build.sbt

View workflow job for this annotation

GitHub Actions / build / platform-integration (computing-unit-managing-service)

The evaluation of `/` inside an anonymous function is prohibited.
}
)

Expand Down Expand Up @@ -279,6 +279,9 @@
)
.dependsOn(DAO % "test->test") // test scope dependency

// Playwright automation recording the per-operator demo videos linked from docs/reference/operators/.
lazy val DemoVideoGenerator = (project in file("docs/operator-demo-videos"))

// root project definition
lazy val TexeraProject = (project in file("."))
.aggregate(
Expand All @@ -299,7 +302,8 @@
FileService,
WorkflowCompilingService,
WorkflowExecutionService,
NotebookMigrationService
NotebookMigrationService,
DemoVideoGenerator
)
.settings(
name := "texera",
Expand Down
52 changes: 52 additions & 0 deletions docs/operator-demo-videos/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// 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.

import scala.collection.Seq

/////////////////////////////////////////////////////////////////////////////
// Project Settings
/////////////////////////////////////////////////////////////////////////////

name := "operator-demo-videos"

// Enable semanticdb for Scalafix
ThisBuild / semanticdbEnabled := true
ThisBuild / semanticdbVersion := scalafixSemanticdb.revision

// Restrict parallel execution of tests to avoid conflicts
Global / concurrentRestrictions += Tags.limit(Tags.Test, 1)

/////////////////////////////////////////////////////////////////////////////
// Compiler Options
/////////////////////////////////////////////////////////////////////////////

Compile / scalacOptions ++= Seq(
"-Xelide-below", "WARNING", // Turn on optimizations with "WARNING" as the threshold
"-feature", // Check feature warnings
"-deprecation", // Check deprecation warnings
"-Ywarn-unused:imports" // Check for unused imports
)

/////////////////////////////////////////////////////////////////////////////
// Dependencies
/////////////////////////////////////////////////////////////////////////////

libraryDependencies ++= Seq(
// Drives a real browser to record the operator demos.
"com.microsoft.playwright" % "playwright" % "1.57.0",
"org.scalatest" %% "scalatest" % "3.2.20" % Test
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* 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.texera.demovideos.config

case class UiConfig(
recordWidth: Int,
recordHeight: Int,
slowMo: Int,
resultPanelHoldMs: Int,
propertyPanelResizeHeight: Double,
operatorPosX: Double,
operatorPosY: Double
)

object TestDataConfig {
val baseUrl = "http://localhost:4200"

val uiConfig = UiConfig(
// 1080p: the canvas, the left operator panel, and the property panel all have to be
// usable at once. Below this the operator list needs scrolling before an item can be
// dragged, and the recording is cramped to watch.
recordWidth = 1920,
recordHeight = 1080,
slowMo = 400,
resultPanelHoldMs = 5000,
propertyPanelResizeHeight = 300.0,
operatorPosX = 0.33,
operatorPosY = 0.4
)

val videoOutputDir = "docs/operator-demo-videos/generated"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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.texera.demovideos.controllers

// Timing constants shared by the controllers; tuned against the real UI.
// Later controllers extend these objects as they need more tiers.

/** Semantic wait tiers for `page.waitForTimeout(...)`, named by what is being waited on. */
private[controllers] object Delays {
val Long: Int = 300 // major UI transition: panel collapse, page settling
val Network: Int = 700 // backend round trip: upload, login submission
}

/** Upper bounds for `Locator.waitFor(...)` and similar. */
private[controllers] object Timeouts {
val Medium: Int = 5000 // navigation, or a dialog that has to open
val Long: Int = 20000 // page load with heavy assets
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* 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.texera.demovideos.controllers

import com.microsoft.playwright.Page
import scala.collection.mutable.ArrayBuffer

/**
* Shared context wrapping Playwright Page, passed through all builders.
*/
class ControllerContext(val page: Page) {
private var _fakeCursorInstalled: Boolean = false

def ensureFakeCursor(): Unit = {
if (!_fakeCursorInstalled) {
Utils.installFakeCursor(page)
_fakeCursorInstalled = true
}
}
}

/** A single named step that runs against a ControllerContext. */
trait ControllerStep {
def name: String
def run(ctx: ControllerContext): Unit
}

object ControllerStep {
def apply(stepName: String)(action: ControllerContext => Unit): ControllerStep =
new ControllerStep {
override def name: String = stepName
override def run(ctx: ControllerContext): Unit = action(ctx)
}
}

/**
* Base builder — subclasses accumulate steps via fluent API, then execute().
*
* Usage:
* new LoginControllerBuilder(ctx).login("u","p").execute()
*/
abstract class ControllerBuilder(protected val context: ControllerContext) {
private val steps: ArrayBuffer[ControllerStep] = ArrayBuffer.empty

protected def addStep(step: ControllerStep): this.type = {
steps += step
this
}

def execute(): Unit = {
steps.foreach { step =>
println(s"[${step.name}] Executing...")
step.run(context)
println(s"[${step.name}] Done")
}
}
}
Loading
Loading