Skip to content
Draft
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ and this project adheres to

### Fixed

- Restore "Create workflow" flow
[#4266](https://github.com/OpenFn/lightning/issues/4266)
- Allow users to add collaborators with long email domains
[#4185](https://github.com/OpenFn/lightning/issues/4185)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { cn } from '#/utils/cn';

interface BadgeProps {
onClose: () => void;
onClose?: () => void;
className?: string;
variant?: 'default' | 'warning';
}
Expand All @@ -23,19 +23,21 @@ const Badge: React.FC<React.PropsWithChildren<BadgeProps>> = ({
)}
>
<span className="flex items-center">{children}</span>
<button
onClick={onClose}
className={cn(
'group relative -mr-1 flex items-center justify-center h-3.5 w-3.5 rounded-sm',
variant === 'default' && 'hover:bg-blue-600/20',
variant === 'warning' && 'hover:bg-yellow-700/20'
)}
aria-label="Remove"
title="Remove"
>
<span className="sr-only">Remove</span>
<span className="hero-x-mark h-3.5 w-3.5" />
</button>
{onClose && (
<button
onClick={onClose}
className={cn(
'group relative -mr-1 flex items-center justify-center h-3.5 w-3.5 rounded-sm',
variant === 'default' && 'hover:bg-blue-600/20',
variant === 'warning' && 'hover:bg-yellow-700/20'
)}
aria-label="Remove"
title="Remove"
>
<span className="sr-only">Remove</span>
<span className="hero-x-mark h-3.5 w-3.5" />
</button>
)}
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
* - IDE FullScreenIDE (run selection indicator)
*/

import Badge from '#/manual-run-panel/Badge';
import Badge from './Badge';

interface RunBadgeProps {
runId: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { cn } from '#/utils/cn';

import type { Template } from '../../types/template';
import Badge from '../common/Badge';

interface TemplateCardProps {
template: Template;
Expand Down Expand Up @@ -57,12 +58,22 @@ export function TemplateCard({
</div>
</div>

<h3 className="text-sm font-medium text-gray-900 mb-1 pr-6 truncate">
{template.name}
</h3>
<p className="text-sm text-gray-600 line-clamp-2">
{template.description || 'No description provided'}
</p>
<div
className={cn(
'flex items-center gap-2 pr-6',
!('isBase' in template && template.isBase) && 'mb-1'
)}
>
<h3 className="text-sm font-medium text-gray-900 truncate">
{template.name}
</h3>
{'isBase' in template && template.isBase && <Badge>base</Badge>}
</div>
{'isBase' in template && template.isBase ? null : (
<p className="text-sm text-gray-600 line-clamp-2">
{template.description || 'No description provided'}
</p>
)}
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,21 +72,22 @@ export function TemplatePanel({ onImportClick, onImport }: TemplatePanelProps) {
}, [channel, uiStore]);

const allTemplates: Template[] = useMemo(() => {
const combined = [...BASE_TEMPLATES, ...templates];

if (!searchQuery.trim()) {
return combined;
return [...BASE_TEMPLATES, ...templates];
}

const query = searchQuery.toLowerCase();
return combined.filter(template => {
const filteredUserTemplates = templates.filter(template => {
const matchName = template.name.toLowerCase().includes(query);
const matchDesc = template.description?.toLowerCase().includes(query);
const matchTags = template.tags.some(tag =>
tag.toLowerCase().includes(query)
);
return matchName || matchDesc || matchTags;
});

// Always show base templates, regardless of search query
return [...BASE_TEMPLATES, ...filteredUserTemplates];
}, [templates, searchQuery]);

const handleSelectTemplate = useCallback(
Expand Down Expand Up @@ -117,8 +118,8 @@ export function TemplatePanel({ onImportClick, onImport }: TemplatePanelProps) {
};

const handleBuildWithAI = useCallback(() => {
// Only trigger if there are no matching templates and there's a search query
if (allTemplates.length === 0 && searchQuery) {
// Only trigger if no user templates matched and there's a search query
if (allTemplates.length === BASE_TEMPLATES.length && searchQuery) {
// Clear any existing AI session and disconnect
aiStore.disconnect();
aiStore.clearSession();
Expand All @@ -141,7 +142,7 @@ export function TemplatePanel({ onImportClick, onImport }: TemplatePanelProps) {
<div className="shrink-0 px-4 py-4 border-b border-gray-200">
<div className="flex items-center justify-between mb-3">
<h2 className="text-lg font-semibold text-gray-900">
Browse templates
Create a new workflow
</h2>
<button
type="button"
Expand All @@ -156,7 +157,7 @@ export function TemplatePanel({ onImportClick, onImport }: TemplatePanelProps) {
value={searchQuery}
onChange={handleSearchChange}
onEnter={handleBuildWithAI}
placeholder="Search templates by name, description, or tags..."
placeholder="Describe your workflow..."
focusOnMount
/>
</div>
Expand Down Expand Up @@ -214,21 +215,19 @@ export function TemplatePanel({ onImportClick, onImport }: TemplatePanelProps) {
/>
))}

{allTemplates.length === 0 && searchQuery && (
{allTemplates.length === BASE_TEMPLATES.length && searchQuery && (
<div className="col-span-full flex items-center justify-center h-64">
<div className="text-center max-w-md">
<div className="inline-flex items-center justify-center w-14 h-14 rounded-full bg-gray-100 mb-5">
<span className="hero-magnifying-glass h-7 w-7 text-gray-400" />
<span className="hero-question-mark-circle h-7 w-7 text-gray-400" />
</div>
<h3 className="text-base font-medium text-gray-900 mb-2">
No matching templates
</h3>
<p className="text-sm text-gray-600 mb-6">
We couldn't find any templates for "
We couldn't find any matches for "
<span className="font-medium text-gray-900">
{searchQuery}
</span>
"
". Start from scratch with one of these base templates or
click below to generate this workflow with AI.
</p>
<button
type="button"
Expand Down
29 changes: 13 additions & 16 deletions assets/js/collaborative-editor/constants/baseTemplates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,23 @@ export const BASE_TEMPLATES: BaseTemplate[] = [
isBase: true,
code: `name: "Event-based workflow"
jobs:
My-job:
name: My job
Transform-data:
name: Transform data
adaptor: "@openfn/language-common@latest"
body: |
// Start writing your job code here
// Validate and transform the data you've received...
fn(state => {
console.log("Triggered by webhook");
console.log("Do some data transformation here");
return state;
})
triggers:
webhook:
type: webhook
enabled: true
edges:
webhook->My-job:
webhook->Transform-data:
source_trigger: webhook
target_job: My-job
target_job: Transform-data
condition_type: always
enabled: true`,
},
Expand All @@ -37,24 +37,21 @@ edges:
isBase: true,
code: `name: "Scheduled workflow"
jobs:
My-job:
name: My job
adaptor: "@openfn/language-common@latest"
Get-data:
name: Get data
adaptor: "@openfn/language-http@latest"
body: |
// Start writing your job code here
fn(state => {
console.log("Running on schedule");
return state;
})
// Get some data from an API...
get('https://www.example.com');
triggers:
cron:
type: cron
cron_expression: "0 0 * * *"
enabled: true
edges:
cron->My-job:
cron->Get-data:
source_trigger: cron
target_job: My-job
target_job: Get-data
condition_type: always
enabled: true`,
},
Expand Down
2 changes: 1 addition & 1 deletion assets/js/manual-run-panel/views/ExistingView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { cn } from '#/utils/cn';
import formatDate from '#/utils/formatDate';
import truncateUid from '#/utils/truncateUID';

import Pill from '../Badge';
import Pill from '#/collaborative-editor/components/common/Badge';
import DataclipTypePill from '../DataclipTypePill';
import {
DataclipTypeNames,
Expand Down
2 changes: 1 addition & 1 deletion assets/js/manual-run-panel/views/SelectedClipView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React from 'react';

import { DataclipViewer } from '../../react/components/DataclipViewer';
import formatDate from '../../utils/formatDate';
import Pill from '../Badge';
import Pill from '#/collaborative-editor/components/common/Badge';
import DataclipTypePill from '../DataclipTypePill';
import type { Dataclip } from '../types';

Expand Down
13 changes: 8 additions & 5 deletions assets/js/utils/editorUrlConversion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,15 +224,18 @@ export function buildCollaborativeEditorUrl(options: {
const collaborativeParams = classicalToCollaborativeParams(searchParams, {
selectedType,
});
const queryString =
collaborativeParams.toString().length > 0
? `?${collaborativeParams.toString()}`
: '';

const basePath = isNewWorkflow
? `/projects/${projectId}/w/new/collaborate`
? `/projects/${projectId}/w/new/collaborate?method=template`
: `/projects/${projectId}/w/${workflowId}/collaborate`;

// If base URL already has query params, use & instead of ?
const hasExistingParams = basePath.includes('?');
const queryString =
collaborativeParams.toString().length > 0
? `${hasExistingParams ? '&' : '?'}${collaborativeParams.toString()}`
: '';

return `${basePath}${queryString}`;
}

Expand Down
Loading