add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
$hasAllowedProfile = !empty($allowedProfileOptions);
|
|
|
|
|
|
|
|
|
|
$renderErrorTable = static function (array $rows): void {
|
|
|
|
|
if (!$rows) {
|
|
|
|
|
?>
|
|
|
|
|
<div class="notice" data-variant="success"><?php e(t('No row errors found')); ?></div>
|
|
|
|
|
<?php
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
?>
|
|
|
|
|
<div class="app-list-table">
|
|
|
|
|
<table>
|
|
|
|
|
<thead>
|
|
|
|
|
<tr>
|
|
|
|
|
<th><?php e(t('Row')); ?></th>
|
|
|
|
|
<th><?php e(t('Reference')); ?></th>
|
|
|
|
|
<th><?php e(t('Code')); ?></th>
|
|
|
|
|
<th><?php e(t('Message')); ?></th>
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
<?php foreach ($rows as $row): ?>
|
|
|
|
|
<tr>
|
|
|
|
|
<td><?php e((string) ($row['row_number'] ?? '')); ?></td>
|
|
|
|
|
<td><?php e((string) ($row['identifier'] ?? '')); ?></td>
|
|
|
|
|
<td><span class="badge" data-variant="neutral"><?php e((string) ($row['code'] ?? '')); ?></span></td>
|
|
|
|
|
<td><?php e((string) ($row['message'] ?? '')); ?></td>
|
|
|
|
|
</tr>
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
<?php
|
|
|
|
|
};
|
|
|
|
|
?>
|
|
|
|
|
|
|
|
|
|
<div class="app-details-container">
|
|
|
|
|
<section>
|
2026-03-04 15:56:58 +01:00
|
|
|
<div class="app-details-titlebar" data-detail-unsaved-message="<?php e(t('You have unsaved changes. Leave without saving?')); ?>">
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
<h1><?php e(t('Imports')); ?></h1>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<?php if (!empty($errors)): ?>
|
|
|
|
|
<div class="notice" data-variant="error">
|
|
|
|
|
<ul>
|
|
|
|
|
<?php foreach ($errors as $error): ?>
|
|
|
|
|
<li><?php e($error); ?></li>
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
|
|
|
|
|
<?php if ($hasAllowedProfile): ?>
|
|
|
|
|
<div class="app-tabs">
|
|
|
|
|
<div class="app-tabs-nav">
|
|
|
|
|
<?php foreach ($allowedProfileOptions as $option): ?>
|
|
|
|
|
<?php
|
|
|
|
|
$tabType = (string) ($option['key'] ?? '');
|
|
|
|
|
$tabLabel = (string) ($option['label'] ?? $tabType);
|
|
|
|
|
$isActiveTab = $selectedType === $tabType ? 'is-active' : '';
|
|
|
|
|
?>
|
|
|
|
|
<a href="<?php e('admin/imports?type=' . urlencode($tabType)); ?>" class="<?php e($isActiveTab); ?>">
|
|
|
|
|
<?php e($tabLabel); ?>
|
|
|
|
|
</a>
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
|
|
|
|
|
<?php if (!$hasAllowedProfile): ?>
|
|
|
|
|
<div class="notice" data-variant="warning">
|
|
|
|
|
<?php e(t('You do not have permission to run imports.')); ?>
|
|
|
|
|
</div>
|
|
|
|
|
<?php elseif ($step === 'upload'): ?>
|
|
|
|
|
<div>
|
|
|
|
|
<?php if ($selectedType !== ''): ?>
|
|
|
|
|
<blockquote data-variant="info">
|
|
|
|
|
<p><?php e(t('Here is a CSV template for this import profile.')); ?></p>
|
|
|
|
|
<a class="primary" href="<?php e('admin/imports/sample/' . urlencode($selectedType)); ?>">
|
|
|
|
|
<?php e(t('Download sample CSV')); ?>
|
|
|
|
|
</a>
|
|
|
|
|
</blockquote>
|
|
|
|
|
<?php endif; ?>
|
2026-04-05 16:32:34 +02:00
|
|
|
<form id="imports-upload-form" method="post" enctype="multipart/form-data" data-standard-detail-form="1">
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
<input type="hidden" name="<?php e($csrfKey); ?>" value="<?php e($csrfToken); ?>">
|
|
|
|
|
<input type="hidden" name="stage" value="analyze">
|
|
|
|
|
<input type="hidden" name="type" value="<?php e($selectedType); ?>">
|
|
|
|
|
<div class="grid">
|
|
|
|
|
<label>
|
|
|
|
|
<span><?php e(t('CSV file')); ?></span>
|
|
|
|
|
<input type="file" name="csv_file" accept=".csv,.txt,text/csv" required>
|
|
|
|
|
<small><?php e(t('Max size 10MB, max 20000 rows')); ?></small>
|
|
|
|
|
</label>
|
|
|
|
|
</div>
|
|
|
|
|
<button type="submit"><?php e(t('Analyze file')); ?></button>
|
|
|
|
|
</form>
|
|
|
|
|
</div>
|
|
|
|
|
<?php elseif ($step === 'mapping'): ?>
|
2026-04-05 16:32:34 +02:00
|
|
|
<form id="imports-mapping-form" method="post" data-standard-detail-form="1">
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
<input type="hidden" name="<?php e($csrfKey); ?>" value="<?php e($csrfToken); ?>">
|
|
|
|
|
<input type="hidden" name="stage" value="preview">
|
|
|
|
|
<input type="hidden" name="type" value="<?php e($selectedType); ?>">
|
|
|
|
|
<input type="hidden" name="token" value="<?php e($token !== '' ? $token : (string) ($state['token'] ?? '')); ?>">
|
|
|
|
|
|
|
|
|
|
<blockquote data-variant="info">
|
|
|
|
|
<p class="muted"><?php e(t('Required fields') . ': ' . $requiredTargetsHint); ?></p>
|
|
|
|
|
</blockquote>
|
|
|
|
|
<div class="app-list-table">
|
|
|
|
|
<table>
|
|
|
|
|
<thead>
|
|
|
|
|
<tr>
|
|
|
|
|
<th><?php e(t('CSV header')); ?></th>
|
|
|
|
|
<th><?php e(t('Target field')); ?></th>
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
<?php foreach ($headers as $header): ?>
|
|
|
|
|
<?php $currentTarget = (string) ($mapping[$header] ?? ''); ?>
|
|
|
|
|
<tr>
|
|
|
|
|
<td><?php e((string) $header); ?></td>
|
|
|
|
|
<td>
|
|
|
|
|
<select style="margin:0;" name="mapping[<?php e((string) $header); ?>]">
|
|
|
|
|
<option value=""><?php e(t('Ignore column')); ?></option>
|
|
|
|
|
<?php foreach ($allowedTargets as $target => $label): ?>
|
|
|
|
|
<option value="<?php e($target); ?>" <?php if ($currentTarget === $target) { ?>selected<?php } ?>>
|
|
|
|
|
<?php e($label); ?><?php if (in_array($target, $requiredTargets, true)) { ?> *<?php } ?>
|
|
|
|
|
</option>
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
</select>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
<hr>
|
|
|
|
|
<div class="app-list-titlebar-actions">
|
|
|
|
|
<a class="outline secondary" role="button" href="admin/imports"><?php e(t('Back')); ?></a>
|
|
|
|
|
<button type="submit"><?php e(t('Run preview')); ?></button>
|
|
|
|
|
</div>
|
|
|
|
|
</form>
|
|
|
|
|
<?php elseif ($step === 'preview' && is_array($preview)): ?>
|
|
|
|
|
<div>
|
|
|
|
|
<blockquote data-variant="info">
|
|
|
|
|
<p><?php e(t('Preview')); ?></p>
|
|
|
|
|
</blockquote>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="grid">
|
|
|
|
|
<label>
|
|
|
|
|
<span><?php e(t('Rows total')); ?></span>
|
|
|
|
|
<input type="text" value="<?php e((string) ($preview['rows_total'] ?? 0)); ?>" readonly>
|
|
|
|
|
</label>
|
|
|
|
|
<label>
|
|
|
|
|
<span><?php e(t('Valid rows')); ?></span>
|
|
|
|
|
<input type="text" value="<?php e((string) ($preview['valid_rows'] ?? 0)); ?>" readonly>
|
|
|
|
|
</label>
|
|
|
|
|
<label>
|
|
|
|
|
<span><?php e(t('Would create')); ?></span>
|
|
|
|
|
<input type="text" value="<?php e((string) ($preview['would_create'] ?? 0)); ?>" readonly>
|
|
|
|
|
</label>
|
|
|
|
|
<label>
|
|
|
|
|
<span><?php e(t('Would skip')); ?></span>
|
|
|
|
|
<input type="text" value="<?php e((string) ($preview['would_skip'] ?? 0)); ?>" readonly>
|
|
|
|
|
</label>
|
|
|
|
|
<label>
|
|
|
|
|
<span><?php e(t('Would fail')); ?></span>
|
|
|
|
|
<input type="text" value="<?php e((string) ($preview['would_fail'] ?? 0)); ?>" readonly>
|
|
|
|
|
</label>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<h3><?php e(t('Row issues')); ?></h3>
|
|
|
|
|
<?php $renderErrorTable(is_array($preview['errors'] ?? null) ? $preview['errors'] : []); ?>
|
|
|
|
|
<hr>
|
2026-04-05 16:32:34 +02:00
|
|
|
<form id="imports-commit-form" method="post" data-standard-detail-form="1">
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
<input type="hidden" name="<?php e($csrfKey); ?>" value="<?php e($csrfToken); ?>">
|
|
|
|
|
<input type="hidden" name="stage" value="commit">
|
|
|
|
|
<input type="hidden" name="type" value="<?php e($selectedType); ?>">
|
|
|
|
|
<input type="hidden" name="token" value="<?php e($token); ?>">
|
|
|
|
|
<?php foreach ($mapping as $header => $target): ?>
|
|
|
|
|
<input type="hidden" name="mapping[<?php e((string) $header); ?>]" value="<?php e((string) $target); ?>">
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
<div class="app-list-titlebar-actions">
|
|
|
|
|
<a class="outline secondary" role="button" href="admin/imports"><?php e(t('Cancel')); ?></a>
|
|
|
|
|
<button type="submit"><?php e(t('Start import')); ?></button>
|
|
|
|
|
</div>
|
|
|
|
|
</form>
|
|
|
|
|
</div>
|
|
|
|
|
<?php elseif ($step === 'result' && is_array($result)): ?>
|
|
|
|
|
<div>
|
|
|
|
|
<blockquote data-variant="info">
|
|
|
|
|
<p><?php e(t('Import finished')); ?></p>
|
|
|
|
|
</blockquote>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="grid">
|
|
|
|
|
<label>
|
|
|
|
|
<span><?php e(t('Processed')); ?></span>
|
|
|
|
|
<input type="text" value="<?php e((string) ($result['processed'] ?? 0)); ?>" readonly>
|
|
|
|
|
</label>
|
|
|
|
|
<label>
|
|
|
|
|
<span><?php e(t('Created')); ?></span>
|
|
|
|
|
<input type="text" value="<?php e((string) ($result['created'] ?? 0)); ?>" readonly>
|
|
|
|
|
</label>
|
|
|
|
|
<label>
|
|
|
|
|
<span><?php e(t('Skipped')); ?></span>
|
|
|
|
|
<input type="text" value="<?php e((string) ($result['skipped'] ?? 0)); ?>" readonly>
|
|
|
|
|
</label>
|
|
|
|
|
<label>
|
|
|
|
|
<span><?php e(t('Failed')); ?></span>
|
|
|
|
|
<input type="text" value="<?php e((string) ($result['failed'] ?? 0)); ?>" readonly>
|
|
|
|
|
</label>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<h3><?php e(t('Row issues')); ?></h3>
|
|
|
|
|
<?php $renderErrorTable(is_array($result['errors'] ?? null) ? $result['errors'] : []); ?>
|
|
|
|
|
<hr>
|
|
|
|
|
<p>
|
|
|
|
|
<a class="outline secondary" role="button" href="admin/imports"><?php e(t('Import another file')); ?></a>
|
|
|
|
|
</p>
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<aside id="app-details-aside-section">
|
|
|
|
|
<div class="app-details-aside-section">
|
|
|
|
|
<hgroup>
|
|
|
|
|
<h2><?php e($selectedProfileLabel); ?></h2>
|
|
|
|
|
<p><small><?php e(t('Import')); ?></small></p>
|
|
|
|
|
</hgroup>
|
|
|
|
|
<hr>
|
|
|
|
|
<details open data-details-always-open>
|
|
|
|
|
<summary><?php e(t('How the import works')); ?></summary>
|
|
|
|
|
<hr>
|
|
|
|
|
<p><?php e(t('1. Upload CSV and click analyze')); ?></p>
|
|
|
|
|
<p><?php e(t('2. Map your CSV columns to system fields')); ?></p>
|
|
|
|
|
<p><?php e(t('3. Review preview counters and row errors')); ?></p>
|
|
|
|
|
<p><?php e(t('4. Start import for valid rows')); ?></p>
|
|
|
|
|
</details>
|
|
|
|
|
<hr>
|
|
|
|
|
<details open data-details-always-open>
|
|
|
|
|
<summary><?php e(t('Rules')); ?></summary>
|
|
|
|
|
<hr>
|
|
|
|
|
<p><?php e(t('Create-only: existing entries are skipped')); ?></p>
|
|
|
|
|
<p><?php e(t('Required fields') . ': ' . $requiredTargetsHint); ?></p>
|
|
|
|
|
<?php if (!empty($showAssignmentPermissionHint)): ?>
|
|
|
|
|
<p><?php e(t('Assignment columns require additional permission.')); ?></p>
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
<p><?php e(t('Max size 10MB, max 20000 rows')); ?></p>
|
|
|
|
|
</details>
|
|
|
|
|
</div>
|
|
|
|
|
</aside>
|
|
|
|
|
</div>
|