Skip to content
Draft
Show file tree
Hide file tree
Changes from 6 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
57 changes: 57 additions & 0 deletions events/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# 📨 Events App

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as discussed can we have two separate app. event generator app. event consumer app please

Copy link
Member

@inishchith inishchith Jun 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't think that'll be ideal - we can demonstrate the concept under events directory itself under single app via two workflows - One workflow triggers another. Add more in the readme around use-cases that this can power via mermaid diagrams (ex: app to app, app to workflow, workflow to workflow and more).

@SanilK2108

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey folks, updated the flow here -

Added a UI, user can go to the UI to start a workflow - WorkflowTriggeredByUI.

When this workflow ends, another workflow WorkflowTriggeredByEvent starts automatically

A simple application demonstrating how to build apps with the Atlan Application SDK using events.

<img width="1505" alt="Screenshot 2025-06-18 at 1 42 09 PM" src="https://github.com/user-attachments/assets/e6bffb58-b305-4212-963c-d29d495c795b" />

## Features
- Simulates event-driven workflows
- Real-time workflow status tracking
- Integration with Temporal for workflow management
- Demonstrates async and sync activities in a workflow
- Example of basic workflow implementation

## Usage

> [!NOTE]
> To run, first see the [main project README](../README.md) for prerequisites.

### Run the Events Application

```bash
uv run main.py
```

### Access the Application

Once the application is running:

- **Temporal UI**: Access the Temporal Web UI at `http://localhost:8233` (or your Temporal UI address) to monitor workflow executions.
- **Frontend**: Access the Frontend UI at `http://localhost:8000`

To see the events flow -
1. Click "Start Workflow" on the frontend UI at `http://localhost:8000`
2. Go to the temporal dashboard to see that a new workflow of the type `WorkflowTriggeredByUI` has started
3. Wait for this workflow to finish, once finished, a new workflow will be triggered by the `workflow_end` event of this workflow of type `WorkflowTriggeredByEvent`

![swimlanes-028e52a813253d7f59311fe0fb8b4af1](https://github.com/user-attachments/assets/3eb43edb-0b5a-4f0a-99e9-baab9ef111e1)

## Development

### Project Structure
```
.
├── activities.py # Workflow activities
├── main.py # Application entry point
├── workflows.py # Workflow definitions
├── subscriber_manifest.json # Subscriber manifest
└── README.md # This file
```

## Learning Resources
- [Temporal Documentation](https://docs.temporal.io/)
- [Atlan Application SDK Documentation](https://github.com/atlanhq/application-sdk/tree/main/docs)
- [Python FastAPI Documentation](https://fastapi.tiangolo.com/)

## Contributing
We welcome contributions! Please feel free to submit a Pull Request.
Empty file added events/__init__.py
Empty file.
28 changes: 28 additions & 0 deletions events/activities.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import asyncio

from application_sdk.activities import ActivitiesInterface
from application_sdk.observability.logger_adaptor import get_logger
from temporalio import activity


logger = get_logger(__name__)
activity.logger = logger


class SampleActivities(ActivitiesInterface):
@activity.defn
async def activity_1(self):
logger.info("Activity 1")

await asyncio.sleep(5)

return

@activity.defn
async def activity_2(self):
logger.info("Activity 2")

await asyncio.sleep(5)

return

199 changes: 199 additions & 0 deletions events/frontend/static/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
:root {
--primary-color: #FFD43B;
--primary-hover: #FCC419;
--background: #1E2124;
--card-bg: #2D3135;
--text-primary: #FFFFFF;
--text-secondary: #A1A1AA;
--border-color: #3F3F46;
--input-bg: #18191C;
--shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.1);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 10px 25px rgba(0, 0, 0, 0.2);
--transition: all 0.2s ease;
}

/* Base styles */
body {
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
background-color: var(--background);
margin: 0;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
color: var(--text-primary);
}

/* Layout components */
.container {
background-color: var(--card-bg);
max-width: 600px;
width: 90%;
margin: 40px auto;
padding: 2.5rem;
border-radius: 24px;
box-shadow: var(--shadow-lg);
}

.header {
text-align: center;
margin-bottom: 2.5rem;
}

/* Typography */
h1 {
color: var(--primary-color);
font-size: 3rem;
margin-bottom: 0.5rem;
text-shadow: var(--shadow-sm);
}

.subtitle {
color: var(--text-secondary);
font-size: 1.2rem;
margin-bottom: 2rem;
}

/* Form elements */
.form-group {
margin-bottom: 2rem;
}

label {
display: block;
margin-bottom: 0.75rem;
font-weight: 600;
color: var(--text-primary);
font-size: 1.1rem;
}

input[type="text"] {
width: 100%;
padding: 1rem;
border: 2px solid var(--border-color);
border-radius: 12px;
font-size: 1rem;
transition: var(--transition);
background-color: var(--input-bg);
color: var(--text-primary);
}

input[type="text"]:focus {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 4px rgba(255, 212, 59, 0.1);
}

.helper-text {
font-size: 0.9rem;
color: var(--text-secondary);
margin-top: 0.5rem;
}

button {
background-color: var(--primary-color);
color: var(--background);
border: none;
padding: 1rem 2rem;
border-radius: 12px;
cursor: pointer;
font-size: 1.1rem;
font-weight: 600;
width: 100%;
transition: var(--transition);
}

button:hover {
background-color: var(--primary-hover);
transform: translateY(-2px);
box-shadow: var(--shadow-md);
}

button:disabled {
opacity: 0.7;
cursor: not-allowed;
}

/* Modal */
.modal {
display: none;
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(5px);
z-index: 1000;
justify-content: center;
align-items: center;
}

.modal.show {
display: flex;
}

.modal-content {
background: #2D3135;
padding: 2.5rem;
border-radius: 16px;
text-align: center;
max-width: 360px;
width: 90%;
}

.success-icon {
background-color: var(--primary-color);
width: 48px;
height: 48px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 1.5rem;
}

.success-icon svg {
width: 24px;
height: 24px;
color: var(--background);
}

.modal h2 {
color: var(--text-primary);
font-size: 1.5rem;
margin: 0 0 0.5rem;
font-weight: 600;
}

.modal p {
color: var(--text-secondary);
font-size: 1rem;
margin: 0 0 1.5rem;
}

.view-status-link {
color: #A78BFA; /* Light purple color */
text-decoration: none;
font-size: 0.95rem;
font-weight: 500;
padding: 0.5rem 1rem;
border-radius: 8px;
transition: all 0.2s ease;
display: inline-flex;
align-items: center;
gap: 6px;
}

.view-status-link:hover {
background: rgba(167, 139, 250, 0.1);
transform: translateY(-1px);
}

.sparkle-icon {
font-size: 1.1em;
margin-left: 2px;
}

.btn-primary {
display: inline-block;
text-decoration: none;
}
65 changes: 65 additions & 0 deletions events/frontend/templates/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Trigger Workflow</title>
<style>
body {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
margin: 0;
background: #f7f9fb;
font-family: Arial, sans-serif;
}
h1 {
font-size: 2rem;
margin-bottom: 2rem;
color: #222;
}
.big-blue-btn {
padding: 1.2rem 3rem;
font-size: 1.3rem;
background: #2563eb;
color: #fff;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background 0.2s;
box-shadow: 0 2px 8px rgba(37,99,235,0.08);
}
.big-blue-btn:hover {
background: #1d4ed8;
}
</style>
</head>
<body>
<h1>Start a workflow to trigger another one</h1>
<button class="big-blue-btn" onclick="startWorkflow()">Start Workflow</button>
<script>
function startWorkflow() {
fetch("/workflows/v1/start", {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
search_term: 'test',
recipients: 'test'
})
})
.then(response => {
if (response.ok) {
alert('Workflow started!');
} else {
alert('Failed to start workflow.');
}
})
.catch(() => alert('Failed to start workflow.'));
}
</script>
</body>
</html>
Loading