Enhance Activepieces automation flows with restore UI and publishing

- Add "Restore Defaults" dropdown to Automations page with confirmation
- Create flows in "Defaults" folder for organization
- Pre-populate trigger sample data when creating/restoring flows
- Auto-publish flows (lock and enable) after creation
- Fix email template context variables to match template tags
- Fix dark mode logo switching in Activepieces iframe
- Add iframe refresh on flow restore
- Auto-populate business context (name, email, phone, address) in emails

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
poduck
2025-12-21 23:38:10 -05:00
parent ac3115a5a1
commit 7b380fa903
14 changed files with 786 additions and 149 deletions

View File

@@ -9,7 +9,6 @@ import { listCustomersAction } from './lib/actions/list-customers';
import { sendEmailAction } from './lib/actions/send-email';
import { listEmailTemplatesAction } from './lib/actions/list-email-templates';
import { eventCreatedTrigger, eventUpdatedTrigger, eventCancelledTrigger, eventStatusChangedTrigger, paymentReceivedTrigger, upcomingEventsTrigger } from './lib/triggers';
import { API_URL } from './lib/common';
/**
* SmoothSchedule Authentication

View File

@@ -38,6 +38,39 @@ interface PaymentData {
} | null;
}
const SAMPLE_PAYMENT_DATA: PaymentData = {
id: 12345,
payment_intent_id: 'pi_3QDEr5GvIfP3a7s90bcd1234',
amount: '50.00',
currency: 'usd',
type: 'deposit',
status: 'SUCCEEDED',
created_at: '2024-12-01T10:00:00Z',
completed_at: '2024-12-01T10:00:05Z',
event: {
id: 100,
title: 'Consultation with John Doe',
start_time: '2024-12-15T14:00:00Z',
end_time: '2024-12-15T15:00:00Z',
status: 'SCHEDULED',
deposit_amount: '50.00',
final_price: '200.00',
remaining_balance: '150.00',
},
service: {
id: 1,
name: 'Consultation',
price: '200.00',
},
customer: {
id: 50,
first_name: 'John',
last_name: 'Doe',
email: 'john.doe@example.com',
phone: '+1-555-0100',
},
};
export const paymentReceivedTrigger = createTrigger({
auth: smoothScheduleAuth,
name: 'payment_received',
@@ -78,15 +111,26 @@ export const paymentReceivedTrigger = createTrigger({
queryParams['type'] = paymentType;
}
const payments = await makeRequest<PaymentData[]>(
auth,
HttpMethod.GET,
'/payments/',
undefined,
queryParams
);
try {
const payments = await makeRequest<PaymentData[]>(
auth,
HttpMethod.GET,
'/payments/',
undefined,
queryParams
);
return payments;
// Return real data if available, otherwise return sample data
if (payments && payments.length > 0) {
return payments;
}
} catch (error) {
// Fall through to sample data on error
console.error('Error fetching payments for sample data:', error);
}
// Return static sample data if no real payments exist
return [SAMPLE_PAYMENT_DATA];
},
async run(context) {
const auth = context.auth as SmoothScheduleAuth;
@@ -121,36 +165,5 @@ export const paymentReceivedTrigger = createTrigger({
return payments;
},
sampleData: {
id: 12345,
payment_intent_id: 'pi_3QDEr5GvIfP3a7s90bcd1234',
amount: '50.00',
currency: 'usd',
type: 'deposit',
status: 'SUCCEEDED',
created_at: '2024-12-01T10:00:00Z',
completed_at: '2024-12-01T10:00:05Z',
event: {
id: 100,
title: 'Consultation with John Doe',
start_time: '2024-12-15T14:00:00Z',
end_time: '2024-12-15T15:00:00Z',
status: 'SCHEDULED',
deposit_amount: '50.00',
final_price: '200.00',
remaining_balance: '150.00',
},
service: {
id: 1,
name: 'Consultation',
price: '200.00',
},
customer: {
id: 50,
first_name: 'John',
last_name: 'Doe',
email: 'john.doe@example.com',
phone: '+1-555-0100',
},
},
sampleData: SAMPLE_PAYMENT_DATA,
});

View File

@@ -1,15 +1,64 @@
import { t } from 'i18next';
import { useEffect, useState } from 'react';
import { flagsHooks } from '@/hooks/flags-hooks';
import { useTheme } from '@/components/theme-provider';
const FullLogo = () => {
const branding = flagsHooks.useWebsiteBranding();
const { theme } = useTheme();
// Track resolved theme from DOM (handles 'system' theme correctly)
const [isDark, setIsDark] = useState(() =>
document.documentElement.classList.contains('dark')
);
useEffect(() => {
// Update when theme changes - check the actual applied class
const checkDark = () => {
setIsDark(document.documentElement.classList.contains('dark'));
};
checkDark();
// Observe class changes on documentElement
const observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
if (mutation.attributeName === 'class') {
checkDark();
}
}
});
observer.observe(document.documentElement, { attributes: true });
return () => observer.disconnect();
}, [theme]);
// Support dark mode by switching logo URLs
// Light logo (dark text) for light mode, dark logo (light text) for dark mode
const baseLogoUrl = branding.logos.fullLogoUrl;
// Compute the appropriate logo URL based on theme
let logoUrl = baseLogoUrl;
if (isDark) {
// Need dark logo (light text for dark background)
if (baseLogoUrl.includes('-light.svg')) {
logoUrl = baseLogoUrl.replace('-light.svg', '-dark.svg');
} else if (!baseLogoUrl.includes('-dark.svg')) {
logoUrl = baseLogoUrl.replace(/\.svg$/, '-dark.svg');
}
} else {
// Need light logo (dark text for light background)
if (baseLogoUrl.includes('-dark.svg')) {
logoUrl = baseLogoUrl.replace('-dark.svg', '-light.svg');
}
// Otherwise use base URL as-is (assumed to be light version)
}
return (
<div className="h-[60px]">
<img
className="h-full"
src={branding.logos.fullLogoUrl}
src={logoUrl}
alt={t('logo')}
/>
</div>

View File

@@ -65,8 +65,8 @@ export function generateTheme({
export const defaultTheme = generateTheme({
primaryColor: '#6e41e2',
websiteName: 'Activepieces',
fullLogoUrl: 'https://cdn.activepieces.com/brand/full-logo.png',
websiteName: 'Automation Builder',
fullLogoUrl: 'https://smoothschedule.nyc3.digitaloceanspaces.com/static/images/automation-builder-logo-light.svg',
favIconUrl: 'https://cdn.activepieces.com/brand/favicon.ico',
logoIconUrl: 'https://cdn.activepieces.com/brand/logo.svg',
})