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
16 changes: 7 additions & 9 deletions .lagoon.env
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,16 @@ QUEUE_CONNECTION=redis
# No environment vars

# Freedom Tech PHP Lagoon Client Settings
FTLAGOON_PRIVATE_KEY_FILE=storage/ftlagoon/.ssh/id_rsa
FTLAGOON_TOKEN_CACHE_DIR=storage/ftlagoon/.tokencache/
FTLAGOON_PRIVATE_KEY_FILE=/app/storage/ftlagoon/.ssh/polydock
FTLAGOON_TOKEN_CACHE_DIR=/app/storage/ftlagoon/.tokencache/

FTLAGOON_ENDPOINT=https://api.main.lagoon-core.test6.amazee.io/graphql
FTLAGOON_SSH_USER=lagoon
FTLAGOON_SSH_PORT=22
FTLAGOON_SSH_SERVER=ssh.main.lagoon-core.test6.amazee.io
FTLAGOON_SSH_PRIVATE_KEY_FILE=/home/bryan/.ssh/id_rsa
# FTLAGOON_ENDPOINT=https://api.main.lagoon-core.test6.amazee.io/graphql
# FTLAGOON_SSH_USER=lagoon
# FTLAGOON_SSH_PORT=22
# FTLAGOON_SSH_SERVER=ssh.main.lagoon-core.test6.amazee.io

# FTLAGOON_PRIVATE_KEY_FILE=storage/ftlagoon/.ssh/polydock
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The FTLAGOON_PRIVATE_KEY_FILE paths have changed from relative paths (storage/ftlagoon/.ssh/id_rsa) to absolute paths (/app/storage/ftlagoon/.ssh/polydock). Also, the key filename changed from 'id_rsa' to 'polydock'. Ensure that:

  1. The new absolute paths are correct for the deployment environment
  2. The key file 'polydock' exists at the specified location
  3. Any deployment scripts or documentation are updated to reflect this change
  4. The commented-out sections with the old paths are intentionally kept for reference or should be removed
Suggested change
# FTLAGOON_PRIVATE_KEY_FILE=storage/ftlagoon/.ssh/polydock

Copilot uses AI. Check for mistakes.
# FTLAGOON_ENDPOINT=https://api.lagoon.amazeeio.cloud/graphql
# FTLAGOON_SSH_USER=lagoon
# FTLAGOON_SSH_PORT=32222
# FTLAGOON_SSH_SERVER=ssh.lagoon.amazeeio.cloud
# FTLAGOON_SSH_PRIVATE_KEY_FILE=/home/bryan/.ssh/id_rsa

19 changes: 18 additions & 1 deletion app/Console/Commands/CreateStoreApp.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use App\Enums\PolydockStoreAppStatusEnum;
use App\Models\PolydockStore;
use App\Models\PolydockStoreApp;
use App\Services\PolydockAppClassDiscovery;
use Illuminate\Console\Command;

class CreateStoreApp extends Command
Expand Down Expand Up @@ -72,7 +73,23 @@ public function handle(): int

// Gather app information
$name = $this->option('name') ?? $this->ask('App name');
$appClass = $this->option('app-class') ?? $this->ask('Polydock app class');
$discovery = app(PolydockAppClassDiscovery::class);
$availableClasses = $discovery->getAvailableAppClasses();
$appClass = $this->option('app-class');
if ($appClass) {
if (! $discovery->isValidAppClass($appClass)) {
$this->error("Invalid app class: {$appClass}. Must be a concrete PolydockAppInterface implementation.");

return 1;
}
} else {
if (empty($availableClasses)) {
$this->error('No Polydock app classes found. Ensure packages are installed correctly.');

return 1;
}
$appClass = $this->choice('Select Polydock app class', array_keys($availableClasses));
}
$description = $this->option('description') ?? $this->ask('App description');
$author = $this->option('author') ?? $this->ask('Author');
$website = $this->option('website') ?? $this->ask('Author website');
Expand Down
122 changes: 110 additions & 12 deletions app/Filament/Admin/Resources/PolydockAppInstanceResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use App\Models\PolydockAppInstance;
use App\PolydockEngine\Helpers\AmazeeAiBackendHelper;
use App\PolydockEngine\Helpers\LagoonHelper;
use App\Services\PolydockAppClassDiscovery;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Infolists\Infolist;
Expand All @@ -17,6 +18,7 @@
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use FreedomtechHosting\PolydockApp\Attributes\PolydockAppInstanceFields;
use FreedomtechHosting\PolydockApp\Enums\PolydockAppInstanceStatus;

class PolydockAppInstanceResource extends Resource
Expand Down Expand Up @@ -70,20 +72,28 @@ public static function table(Table $table): Table
TextColumn::make('send_midtrial_email_at')
->label('Midtrial Email')
->description(fn ($record) => $record->midtrial_email_sent ? 'Sent' : 'Pending')
->state(fn ($record) => $record->send_midtrial_email_at ? $record->send_midtrial_email_at->format('Y-m-d H:i:s') : ''),
->state(fn ($record) => $record->send_midtrial_email_at
? $record->send_midtrial_email_at->format('Y-m-d H:i:s')
: ''),
TextColumn::make('send_one_day_left_email_at')
->label('1D Left Email')
->description(fn ($record) => $record->one_day_left_email_sent ? 'Sent' : 'Pending')
->state(fn ($record) => $record->send_one_day_left_email_at ? $record->send_one_day_left_email_at->format('Y-m-d H:i:s') : ''),
->state(fn ($record) => $record->send_one_day_left_email_at
? $record->send_one_day_left_email_at->format('Y-m-d H:i:s')
: ''),
TextColumn::make('trial_complete_email_sent')
->label('Trial Complete Email')
->state(fn ($record) => ($record->is_trial && $record->trial_complete_email_sent) ? 'Sent' : ($record->is_trial ? 'Pending' : '')),
->state(fn ($record) => $record->is_trial && $record->trial_complete_email_sent
? 'Sent'
: ($record->is_trial ? 'Pending' : '')),
])
->filters([
SelectFilter::make('status')
->options(collect(PolydockAppInstanceStatus::cases())
->mapWithKeys(fn ($status) => [$status->value => $status->getLabel()])
->toArray())
->options(
collect(PolydockAppInstanceStatus::cases())
->mapWithKeys(fn ($status) => [$status->value => $status->getLabel()])
->toArray(),
)
->multiple()
->label('Instance Status')
->indicator('Status'),
Expand Down Expand Up @@ -165,7 +175,8 @@ public static function table(Table $table): Table
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])->headerActions([
])
->headerActions([
ExportAction::make()
->label('Export registrations')
->exporter(UserRemoteRegistrationExporter::class),
Expand Down Expand Up @@ -205,10 +216,19 @@ public static function infolist(Infolist $infolist): Infolist
->schema([
\Filament\Infolists\Components\TextEntry::make('storeApp.lagoon_deploy_region_id_ext')
->label('Deploy Region')
->formatStateUsing(fn ($state) => LagoonHelper::getLagoonCodeDataValueForRegion($state, 'name')),
\Filament\Infolists\Components\TextEntry::make('storeApp.amazee_ai_backend_region_id_ext')
->formatStateUsing(
fn ($state) => LagoonHelper::getLagoonCodeDataValueForRegion($state, 'name'),
),
\Filament\Infolists\Components\TextEntry::make(
'storeApp.amazee_ai_backend_region_id_ext',
)
->label('AI Backend Region')
->formatStateUsing(fn ($state) => AmazeeAiBackendHelper::getAmazeeAiBackendCodeDataValueForRegion($state, 'name')),
->formatStateUsing(
fn ($state) => AmazeeAiBackendHelper::getAmazeeAiBackendCodeDataValueForRegion(
$state,
'name',
),
),
]),
])
->columnSpan(2),
Expand All @@ -229,6 +249,13 @@ public static function infolist(Infolist $infolist): Infolist
])
->columnSpan(1),

\Filament\Infolists\Components\Section::make('Instance Configuration')
->description('Instance-specific settings configured at creation.')
->schema(fn ($record) => self::getRenderedInstanceConfigForRecord($record))
->visible(fn ($record) => self::hasInstanceConfigFields($record))
->columnSpan(3)
->collapsible(),

\Filament\Infolists\Components\Section::make('Instance Data')
->description('Safe data that can be shared with webhooks')
->schema(fn ($record) => self::getRenderedSafeDataForRecord($record))
Expand All @@ -249,7 +276,7 @@ public static function getRenderedSafeDataForRecord(PolydockAppInstance $record)
}

if ($value === null) {
$value = '';
$value = 'N/A';
}

$renderKey = 'webhook_data_'.$key;
Expand All @@ -271,6 +298,76 @@ public static function getRenderedSafeDataForRecord(PolydockAppInstance $record)
return $renderedArray;
}

/**
* Check if the record's app class defines instance configuration fields.
*/
public static function hasInstanceConfigFields(PolydockAppInstance $record): bool
{
$storeApp = $record->storeApp;
if (! $storeApp || empty($storeApp->polydock_app_class)) {
return false;
}

$discovery = app(PolydockAppClassDiscovery::class);

return ! empty($discovery->getAppInstanceInfolistSchema($storeApp->polydock_app_class));
}

/**
* Get rendered infolist components for instance configuration fields.
*
* Values are loaded from PolydockVariables associated with the app instance.
*/
public static function getRenderedInstanceConfigForRecord(PolydockAppInstance $record): array
{
$storeApp = $record->storeApp;
if (! $storeApp || empty($storeApp->polydock_app_class)) {
return [];
}

$discovery = app(PolydockAppClassDiscovery::class);
$fieldNames = $discovery->getAppInstanceFormFieldNames($storeApp->polydock_app_class);

if (empty($fieldNames)) {
return [];
}

// Build a simple display of instance config values from PolydockVariables
$renderedArray = [];
$instanceConfigPrefix = PolydockAppInstanceFields::FIELD_PREFIX;

foreach ($fieldNames as $fieldName) {
$value = $record->getPolydockVariableValue($fieldName);

// Create a human-readable label from the field name
// e.g., "instance_config_ai_model_override" -> "Ai Model Override"
$labelName = str_replace($instanceConfigPrefix, '', $fieldName);
$labelName = str_replace('_', ' ', $labelName);
$labelName = ucwords($labelName);

// Check if value should be masked (for encrypted fields)
$isEncrypted = $record->isPolydockVariableEncrypted($fieldName);

$renderedItem = \Filament\Infolists\Components\TextEntry::make('instance_config_display_'.$fieldName)
->label($labelName);

if ($isEncrypted && $value !== null && $value !== '') {
// Mask encrypted values
$renderedItem->state('********');
} elseif ($value === null || $value === '') {
$renderedItem->state('Not configured')
->color('gray');
} else {
$renderedItem->state($value);
}

$renderedArray[] = $renderedItem;
}

return $renderedArray;
}

#[\Override]
public static function getRelations(): array
{
return [
Expand All @@ -281,14 +378,15 @@ public static function getRelations(): array
#[\Override]
public static function canCreate(): bool
{
return false;
return true;
}

#[\Override]
public static function getPages(): array
{
return [
'index' => Pages\ListPolydockAppInstances::route('/'),
'create' => Pages\CreatePolydockAppInstance::route('/create'),
'view' => Pages\ViewPolydockAppInstance::route('/{record}'),
'edit' => Pages\EditPolydockAppInstance::route('/{record}/edit'),
];
Expand Down
Loading