feat: Add plugin configuration editing with template variable parsing
## Backend Changes:
- Enhanced PluginTemplate.save() to auto-parse template variables from plugin code
- Updated PluginInstallationSerializer to expose template metadata (description, category, version, author, logo, template_variables)
- Fixed template variable parser to handle nested {{ }} braces in default values
- Added brace-counting algorithm to properly extract variables with insertion codes
- Fixed explicit type parameter detection (textarea, text, email, etc.)
- Made scheduled_task optional on PluginInstallation model
- Added EventPlugin through model for event-plugin relationships
- Added Event.execute_plugins() method for plugin automation
## Frontend Changes:
- Created Tasks.tsx page for managing scheduled tasks
- Enhanced MyPlugins page with clickable plugin cards
- Added edit configuration modal with dynamic form generation
- Implemented escape sequence handling (convert \n, \', etc. for display)
- Added plugin logos to My Plugins page
- Updated type definitions for PluginInstallation interface
- Added insertion code documentation to Plugin Docs
## Plugin System:
- All platform plugins now have editable email templates with textarea support
- Template variables properly parsed with full default values
- Insertion codes ({{CUSTOMER_NAME}}, {{BUSINESS_NAME}}, etc.) documented
- Plugin logos displayed in marketplace and My Plugins
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
112
frontend/public/plugin-logos/generate_with_gemini_sdk.py
Normal file
112
frontend/public/plugin-logos/generate_with_gemini_sdk.py
Normal file
@@ -0,0 +1,112 @@
|
||||
#!/usr/bin/env python3
|
||||
import google.generativeai as genai
|
||||
import os
|
||||
from PIL import Image
|
||||
import io
|
||||
|
||||
# Configure API Key
|
||||
genai.configure(api_key="AIzaSyB-nR0nkeftKrd42NrNIDcFCj3yFP8JLtw")
|
||||
|
||||
OUTPUT_DIR = "/home/poduck/Desktop/smoothschedule2/frontend/public/plugin-logos"
|
||||
|
||||
# Plugin configurations
|
||||
plugins = [
|
||||
{
|
||||
'filename': 'daily-appointment-summary.png',
|
||||
'prompt': '''Create a modern, minimalist app icon in a square format with rounded corners.
|
||||
Design: Indigo blue gradient background (#4f46e5). White simple envelope icon combined with a small calendar symbol.
|
||||
Style: Flat design, clean geometric shapes, professional SaaS application aesthetic.
|
||||
The icon should be instantly recognizable at 48x48 pixels.'''
|
||||
},
|
||||
{
|
||||
'filename': 'no-show-tracker.png',
|
||||
'prompt': '''Create a modern, minimalist app icon in a square format with rounded corners.
|
||||
Design: Red gradient background (#dc2626). White simple person silhouette with a bold X or cancel symbol overlay.
|
||||
Style: Flat design, clean geometric shapes, professional SaaS application aesthetic.
|
||||
The icon should clearly convey "missed appointment" at small sizes.'''
|
||||
},
|
||||
{
|
||||
'filename': 'birthday-greetings.png',
|
||||
'prompt': '''Create a modern, minimalist app icon in a square format with rounded corners.
|
||||
Design: Pink gradient background (#ec4899). White simple birthday cake with candles or gift box with bow.
|
||||
Style: Flat design, clean geometric shapes, cheerful yet professional aesthetic.
|
||||
The icon should feel celebratory and friendly at small sizes.'''
|
||||
},
|
||||
{
|
||||
'filename': 'monthly-revenue-report.png',
|
||||
'prompt': '''Create a modern, minimalist app icon in a square format with rounded corners.
|
||||
Design: Green gradient background (#10b981). White simple upward trending line chart or bar graph showing growth.
|
||||
Style: Flat design, clean geometric shapes, professional business analytics aesthetic.
|
||||
The icon should convey success and growth at small sizes.'''
|
||||
},
|
||||
{
|
||||
'filename': 'appointment-reminder-24hr.png',
|
||||
'prompt': '''Create a modern, minimalist app icon in a square format with rounded corners.
|
||||
Design: Amber/orange gradient background (#f59e0b). White simple notification bell with a small red alert dot or badge.
|
||||
Style: Flat design, clean geometric shapes, attention-grabbing yet professional aesthetic.
|
||||
The icon should clearly indicate alerts and reminders at small sizes.'''
|
||||
},
|
||||
{
|
||||
'filename': 'inactive-customer-reengagement.png',
|
||||
'prompt': '''Create a modern, minimalist app icon in a square format with rounded corners.
|
||||
Design: Purple gradient background (#8b5cf6). White simple heart symbol with a circular refresh/return arrow around it.
|
||||
Style: Flat design, clean geometric shapes, warm and welcoming professional aesthetic.
|
||||
The icon should convey customer care and comeback at small sizes.'''
|
||||
}
|
||||
]
|
||||
|
||||
def generate_image(prompt, filename):
|
||||
"""Generate an image using Gemini 2.0 Flash Image Generation"""
|
||||
print(f"\nGenerating {filename}...")
|
||||
|
||||
try:
|
||||
# Use the image generation model
|
||||
model = genai.GenerativeModel('gemini-2.0-flash-exp-image-generation')
|
||||
|
||||
# Generate the image
|
||||
response = model.generate_content(prompt)
|
||||
|
||||
# Check for generated image
|
||||
if hasattr(response, 'parts') and response.parts:
|
||||
for part in response.parts:
|
||||
if hasattr(part, 'inline_data') and part.inline_data:
|
||||
# Extract image data
|
||||
image_data = part.inline_data.data
|
||||
|
||||
# Save the image
|
||||
output_path = os.path.join(OUTPUT_DIR, filename)
|
||||
with open(output_path, 'wb') as f:
|
||||
f.write(image_data)
|
||||
|
||||
print(f"✓ Saved: {output_path} ({len(image_data)} bytes)")
|
||||
return True
|
||||
|
||||
# If no image data found, check if there's text response
|
||||
if hasattr(response, 'text'):
|
||||
print(f"✗ No image generated. Response text: {response.text[:200]}")
|
||||
else:
|
||||
print(f"✗ No image generated. Response: {response}")
|
||||
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ Error: {type(e).__name__}: {str(e)}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
# Create output directory
|
||||
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||
|
||||
print("Starting logo generation with Gemini 2.0 Flash Image Generation...")
|
||||
print("=" * 60)
|
||||
|
||||
success_count = 0
|
||||
for plugin in plugins:
|
||||
if generate_image(plugin['prompt'], plugin['filename']):
|
||||
success_count += 1
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print(f"Generation complete: {success_count}/{len(plugins)} successful")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user