Skip to content
Merged
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
293 changes: 293 additions & 0 deletions tools/admin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,293 @@
# Site Admin Tool

Comprehensive administration console for managing DA.live sites - library setup, integrations, and site configuration.

## Features

### Library Management
- **Blocks** - Discover, document, and manage block components
- **Templates** - Create and manage page templates
- **Icons** - Manage SVG icons for your site
- **Placeholders** - Define reusable text placeholders/tokens

### Integrations
- **AEM Assets** - Connect AEM as a Cloud Service assets repository
- **Translation** - Configure translation services and behavior
- **Universal Editor** - Set up WYSIWYG content authoring

## Installation

**Important:** Run these commands from your project root (where the `tools/` folder should be created or updated).

### Option 1: Using npx (Recommended)

```bash
npx degit kmurugulla/brightpath/tools/admin tools/admin
```

### Option 2: Using curl

```bash
curl -L https://github.com/kmurugulla/brightpath/archive/refs/heads/main.tar.gz | \
tar -xz --strip=3 "brightpath-main/tools/admin" && \
mv admin tools/
```

### Option 3: Manual Copy

Copy the entire `tools/admin` directory into your project's `tools/` folder.

## Getting Started

### Access the Tool

Run your local development server:
```bash
aem up
```

Then access the admin tool via:
```
https://da.live/app/{org}/{site}/tools/admin/siteadmin?ref=local
```

Replace `{org}` and `{site}` with your DA.live organization and site names.

**Query Parameters:**
- `ref=local` - Points to your local development server (default port 3000)
- `ref=main` - Points to your production site

## Usage Guide

### Library Setup - Initial Mode

Create a new block library from scratch or add blocks to an existing library:

**Steps:**
1. **Enter GitHub Repository URL** - Provide the URL to your GitHub repository containing blocks
- Public repositories work immediately
- Private repositories require a GitHub token (will be prompted)
- Token can be saved securely for future use

2. **Block Discovery** - Automatically discovers all blocks in your repository
- Searches for blocks at any level (supports nested structures)
- Detects new blocks not yet in your library (marked with "New" badge)
- Use "Select New Only" to quickly add just new blocks
- Use "Select All" / "Deselect All" for bulk operations

3. **Block Analysis** - Each block is analyzed for:
- Structure and variants
- CSS classes and features
- Required vs. optional content
- Intelligent placeholder documentation generated

4. **Sample Pages (Optional)** - Select pages to extract real content examples
- Browse your DA.live content via page picker
- Extract actual block usage from live pages
- Enriches documentation with real examples

5. **Create Library** - Click "Set Up Library" to:
- Generate block documentation
- Create/update `blocks.json` configuration
- Register library in site configuration
- Automatically version existing docs before overwriting

### Library Setup - Update Examples Mode

Update existing block documentation with new content examples:

**Steps:**
1. **Switch to "Update Examples" mode** using the toggle
2. **Enter Organization and Site** - Your existing DA.live site details
3. **Select Blocks** - Choose which blocks to refresh
4. **Add Sample Pages** - Select pages containing updated block examples
5. **Update** - Click "Update Examples" to:
- Create version snapshots of existing docs
- Extract content from selected pages
- Update only the blocks found in those pages
- Preserve all other existing blocks

### Managing Templates

**Add Templates:**
1. Navigate to "Templates" tab
2. Enter template name (e.g., "Blog Post")
3. Click "Select Page" to choose a source page
4. Click "+ Add" to add to the list
5. Click "Set Up Library" to save

**Edit/Remove:**
- Use "Edit" button on existing templates to modify
- Use "Remove" button to delete from library

### Managing Icons

**Add Icons:**
1. Navigate to "Icons" tab
2. Enter icon name (e.g., "search", "menu")
3. Click "Select Page" to choose an SVG file
4. Click "+ Add" to add to the list
5. Click "Set Up Library" to save

**SVG Requirements:**
- Must be valid SVG format
- Recommended size: 24x24px
- Clean, optimized paths

### Managing Placeholders

**Add Placeholders:**
1. Navigate to "Placeholders" tab
2. Enter a key (e.g., "copyright")
3. Enter a value (e.g., "© 2024 Company Name")
4. Click "+ Add"
5. Click "Set Up Library" to save

**Use Cases:**
- Legal disclaimers
- Copyright notices
- Repeated text snippets
- Dynamic content tokens

### Integration Setup

#### AEM Assets Integration

Connect your AEM as a Cloud Service assets repository:

1. Navigate to "AEM Assets" tab
2. Enter **Repository ID** - Your AEM assets repository identifier
3. Enter **Production Origin** - Your AEM production URL
4. Click "Verify URL" to test the connection
5. Select desired options:
- **Image Type** - Enable image type selection
- **Renditions Select** - Allow rendition selection
- **DM Delivery** - Dynamic Media delivery
- **Smart Crop Select** - Smart crop selection
6. Click "Save Configuration"

#### Translation Configuration

Configure how translation services handle content:

1. Navigate to "Translation" tab
2. Configure settings:
- **Translate Behavior** - How to handle existing content (overwrite/skip)
- **Translate Staging** - Enable/disable staging
- **Rollout Behavior** - How to handle rollout (overwrite/skip)
3. Click "Save Configuration"

#### Universal Editor Setup

Enable WYSIWYG content authoring:

1. Navigate to "Universal Editor" tab
2. Enter **Editor Path** - Path to your Universal Editor configuration
3. Click "Save Configuration"

## Architecture

### File Structure
```
tools/admin/
├── app/
│ ├── handlers/ # Event handlers
│ ├── main.js # Main application logic
│ ├── router.js # Client-side routing
│ ├── state.js # Application state
│ └── templates.js # HTML templates
├── operations/ # Business logic
├── utils/ # Utility functions
├── styles/ # CSS files
│ ├── admin.css # Core styles (base, layout, nav)
│ ├── blocks-section.css
│ ├── library-items-section.css
│ ├── integrations.css
│ ├── progress.css
│ ├── error-modal.css
│ ├── page-picker.css
│ └── github-section.css
├── config.js # Configuration constants
├── siteadmin.html # Entry point
└── README.md
```

### Key Components

- **Handlers** - Factory pattern for library items (templates, icons, placeholders)
- **Operations** - GitHub API, DA.live API, library operations
- **Utils** - Block analysis, content extraction, document generation
- **State Management** - Centralized application state
- **Router** - Hash-based client-side routing

## Requirements

### Access
- Must be run from within DA.live for authentication
- Write access to CONFIG for your organization
- [See permissions guide](https://docs.da.live/administrators/guides/permissions)

### GitHub Integration
- GitHub token needed **only** for private repositories
- Token can be saved securely in browser for future use
- Public repositories work without authentication

### Optional
- Sample pages for extracting real content examples
- Tool generates intelligent placeholders without them

## Troubleshooting

### Authentication Issues
- **Problem**: "DA.live authentication required"
- **Solution**: Ensure you're accessing the tool from within DA.live, not directly via localhost

### GitHub Rate Limiting
- **Problem**: "GitHub API rate limit exceeded"
- **Solution**: Add a GitHub token (increases rate limit from 60 to 5000 requests/hour)

### Library Not Found
- **Problem**: "No library found at this location"
- **Solution**: Run "Library Setup" first in setup mode to create the library structure

### Permission Errors
- **Problem**: "Unable to update site configuration"
- **Solution**: Ensure you have CONFIG write permissions for your organization

## Development

### Making Changes

The tool is designed to be customized for your project:

1. Edit files in `tools/admin/`
2. Changes are reflected immediately with `ref=local`
3. Test thoroughly before committing
4. Run linting: `npm run lint`

### Code Style

- JavaScript: ES6+ with Airbnb ESLint configuration
- CSS: Modern CSS with nesting, custom properties
- No build step required - vanilla JavaScript

### Contributing

When modifying the tool:
1. Follow existing code patterns
2. Use the handler factory for new library item types
3. Maintain CSS custom properties in `admin.css`
4. Test all views and interactions
5. Ensure linting passes

## Support

For issues or questions:
- Check DA.live documentation: https://docs.da.live
- Review this README
- Check browser console for errors
- Verify permissions and authentication

## License

MIT
103 changes: 103 additions & 0 deletions tools/admin/app/handlers/aem-assets-handlers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
export function attachAemAssetsListeners(app, state) {
const repositoryIdInput = document.getElementById('aem-repository-id');
const prodOriginInput = document.getElementById('aem-prod-origin');
const verifyUrlBtn = document.getElementById('verify-aem-url');
const saveConfigBtn = document.getElementById('save-aem-config');

if (repositoryIdInput) {
repositoryIdInput.addEventListener('input', (e) => {
state.aemAssetsConfig.repositoryId = e.target.value.trim();
});
}

if (prodOriginInput) {
prodOriginInput.addEventListener('input', (e) => {
state.aemAssetsConfig.prodOrigin = e.target.value.trim();
});
}

if (verifyUrlBtn) {
verifyUrlBtn.addEventListener('click', () => app.handleVerifyAemUrl());
}

const checkboxes = [
{ id: 'aem-image-type', key: 'imageType' },
{ id: 'aem-renditions-select', key: 'renditionsSelect' },
{ id: 'aem-dm-delivery', key: 'dmDelivery' },
{ id: 'aem-smartcrop-select', key: 'smartCropSelect' },
];

checkboxes.forEach(({ id, key }) => {
const checkbox = document.getElementById(id);
if (checkbox) {
checkbox.addEventListener('change', (e) => {
state.aemAssetsConfig[key] = e.target.checked;
});
}
});

if (saveConfigBtn) {
saveConfigBtn.addEventListener('click', () => app.handleSaveAemConfig());
}
}

export async function handleSaveAemConfig(state, render, daApi) {
const { repositoryId } = state.aemAssetsConfig;

if (!repositoryId) {
state.errors.aemAssets = 'Repository ID is required';
render();
return;
}

if (!repositoryId.startsWith('author-') && !repositoryId.startsWith('delivery-')) {
state.errors.aemAssets = 'Repository ID must start with "author-" or "delivery-"';
render();
return;
}

state.errors.aemAssets = '';
render();

try {
const result = await daApi.updateAemAssetsConfig(
state.org,
state.site,
state.aemAssetsConfig,
);

if (result.success) {
state.errors.aemAssets = '✓ Configuration saved successfully!';
} else {
state.errors.aemAssets = `Error saving configuration: ${result.error}`;
}
render();
} catch (error) {
state.errors.aemAssets = `Error saving configuration: ${error.message}`;
render();
}
}

export async function handleVerifyAemUrl(state, render) {
if (!state.aemAssetsConfig.prodOrigin) {
return;
}

state.validatingAemUrl = true;
state.errors.aemAssets = '';
render();

try {
await fetch(state.aemAssetsConfig.prodOrigin, {
method: 'HEAD',
mode: 'no-cors',
});
state.validatingAemUrl = false;
state.errors.aemAssets = '✓ URL verified successfully!';
render();
} catch (error) {
state.validatingAemUrl = false;
state.errors.aemAssets = `Unable to verify URL: ${error.message}`;
render();
}
}
Loading
Loading