Skip to content
Draft
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
18 changes: 14 additions & 4 deletions app/Actions/Coconut/SearchMolecule.php
Original file line number Diff line number Diff line change
Expand Up @@ -285,13 +285,23 @@
private function buildTagsStatement($offset)
{
if ($this->tagType == 'dataSource') {
$this->collection = Collection::where('title', $this->query)->first();
if ($this->collection) {
$query = $this->collection->molecules()
$matched = Collection::query()
->where('title', $this->query)
->where('is_latest', true)
->first()
?? Collection::where('title', $this->query)->first();
if ($matched) {
$latest = $matched->is_latest
? $matched
: ($matched->lineageVersionsQuery()->where('is_latest', true)->first() ?? $matched);

$this->collection = $latest;

$query = $latest->molecules()
->whereIn('molecules.id', function ($query) {
$query->select('molecule_id')
->from('entries')
->where('collection_id', $this->collection->id)
->where('collection_id', $latest->id)

Check failure on line 304 in app/Actions/Coconut/SearchMolecule.php

View workflow job for this annotation

GitHub Actions / PHPStan Analysis / PHPStan Analysis (Level 5)

Undefined variable: $latest
->distinct();
});

Expand Down
1 change: 1 addition & 0 deletions app/Console/Commands/DashWidgetsRefresh.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public function handle()
return DB::table('collections')
->selectRaw('count(*) as count')
->where('status', 'PUBLISHED')
->where('is_latest', true)
->get()[0]->count;
});
$this->info('Cache for collections refreshed.');
Expand Down
36 changes: 36 additions & 0 deletions app/Console/Commands/ImportCollectionVersion.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace App\Console\Commands;

use App\Models\Collection;
use App\Services\CollectionVersioning\CollectionVersionImporter;
use Illuminate\Console\Command;

class ImportCollectionVersion extends Command
{
protected $signature = 'coconut:import-collection-version {new_collection_id : The new version collection ID}';

protected $description = 'Run the full collection version migration pipeline';

public function handle(CollectionVersionImporter $importer): int
{
$collection = Collection::query()->find($this->argument('new_collection_id'));
if (! $collection) {
$this->error('Collection not found.');

return self::FAILURE;
}

try {
$result = $importer->import($collection);
$this->info('Collection version migration completed.');
$this->table(array_keys($result), [array_values($result)]);

return self::SUCCESS;
} catch (\Throwable $e) {
$this->error($e->getMessage());

return self::FAILURE;
}
}
}
7 changes: 5 additions & 2 deletions app/Console/Commands/ImportEntries.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,12 @@ public function handle()
$collection_id = $this->argument('collection_id');

if (! is_null($collection_id)) {
$collections = Collection::where('id', $collection_id)->get();
$collections = Collection::query()->where('id', $collection_id)->eligibleForLegacyPipeline()->get();
} else {
$collections = Collection::where('status', 'DRAFT')->get();
$collections = Collection::query()
->where('status', 'DRAFT')
->eligibleForLegacyPipeline()
->get();
}

foreach ($collections as $collection) {
Expand Down
35 changes: 35 additions & 0 deletions app/Console/Commands/PreviewCollectionVersion.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace App\Console\Commands;

use App\Models\Collection;
use App\Services\CollectionVersioning\CollectionVersionImporter;
use Illuminate\Console\Command;

class PreviewCollectionVersion extends Command
{
protected $signature = 'coconut:preview-collection-version {new_collection_id : The new version collection ID}';

protected $description = 'Preview SMILES diff counts for a collection version migration';

public function handle(CollectionVersionImporter $importer): int
{
$collection = Collection::query()->find($this->argument('new_collection_id'));
if (! $collection) {
$this->error('Collection not found.');

return self::FAILURE;
}

try {
$preview = $importer->preview($collection);
$this->table(array_keys($preview), [array_values($preview)]);

return self::SUCCESS;
} catch (\Throwable $e) {
$this->error($e->getMessage());

return self::FAILURE;
}
}
}
3 changes: 3 additions & 0 deletions app/Console/Commands/ProcessEntries.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ public function handle()
$i = 0;

$collection = Collection::whereId($collectionId['collection_id'])->first();
if (! $collection || $collection->isVersionMigrationActive()) {
continue;
}
$collection->jobs_status = 'PROCESSING';
$collection->job_info = 'Processing entries using ChEMBL Pipeline.';
$collection->save();
Expand Down
13 changes: 13 additions & 0 deletions app/Filament/Dashboard/Resources/CollectionResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,18 @@ public static function infolist(Schema $schema): Schema
TextEntry::make('identifier')
->label('Identifier')
->placeholder('No identifier'),
TextEntry::make('version')
->label('Version'),
TextEntry::make('is_latest')
->label('Latest')
->formatStateUsing(fn ($state) => $state ? 'Yes' : 'No'),
TextEntry::make('doi')
->label('Version DOI')
->placeholder('Not minted'),
TextEntry::make('doi_base')
->label('Base DOI (latest)')
->state(fn (Collection $record) => $record->lineageRoot()->doi_base)
->placeholder('Not minted'),
])
->columns(2),
Section::make('Display Image')
Expand Down Expand Up @@ -217,6 +229,7 @@ public static function table(Table $table): Table
'EMBARGO' => 'warning',
'PUBLISHED' => 'success',
'REJECTED' => 'danger',
'SUPERSEDED' => 'gray',
default => 'gray',
}),
])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@

use App\Filament\Dashboard\Resources\CollectionResource;
use App\Filament\Dashboard\Resources\CollectionResource\Widgets\CollectionStats;
use App\Models\Collection;
use App\Services\CollectionVersioning\CollectionVersionCreator;
use App\Services\CollectionVersioning\CollectionVersionImporter;
use Filament\Actions\Action;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\ViewRecord;

class ViewCollection extends ViewRecord
Expand All @@ -16,4 +21,80 @@ protected function getHeaderWidgets(): array
CollectionStats::class,
];
}

protected function getHeaderActions(): array
{
return [
Action::make('createNewVersion')
->label('Create new version')
->icon('heroicon-o-document-duplicate')
->visible(fn (Collection $record) => $record->is_latest
&& $record->status === 'PUBLISHED'
&& ! $record->isVersionMigrationActive())
->requiresConfirmation()
->modalHeading('Create new collection version')
->modalDescription('This clones metadata into a new DRAFT version with the same CNPC identifier. Import CSV entries, then use Preview and Process new version.')
->action(function (Collection $record, CollectionVersionCreator $creator) {
$new = $creator->createFrom($record);
Notification::make()
->title('New version created')
->body("Version {$new->version} is ready for CSV import.")
->success()
->send();

$this->redirect(CollectionResource::getUrl('view', ['record' => $new]));
}),
Action::make('previewVersionMigration')
->label('Preview migration')
->icon('heroicon-o-eye')
->visible(fn (Collection $record) => $record->version_migration_status === Collection::VERSION_MIGRATION_PENDING)
->action(function (Collection $record, CollectionVersionImporter $importer) {
try {
$preview = $importer->preview($record);
Notification::make()
->title('Migration preview')
->body(sprintf(
'Dropped: %d | Retained: %d | New: %d | Revoke candidates: %d',
$preview['old_only_count'],
$preview['retained_count'],
$preview['new_only_count'],
$preview['revoke_candidate_count'],
))
->info()
->send();
} catch (\Throwable $e) {
Notification::make()->title('Preview failed')->body($e->getMessage())->danger()->send();
}
}),
Action::make('processNewVersion')
->label('Process new version')
->icon('heroicon-o-play')
->color('success')
->visible(fn (Collection $record) => in_array($record->version_migration_status, [
Collection::VERSION_MIGRATION_PENDING,
Collection::VERSION_MIGRATION_PROCESSING,
], true))
->requiresConfirmation()
->modalHeading('Process collection version migration')
->modalDescription('This validates entries, diffs by standardized SMILES, migrates live data, revokes dropped exclusive molecules, and archives the previous version.')
->action(function (Collection $record, CollectionVersionImporter $importer) {
try {
$result = $importer->import($record);
Notification::make()
->title('Version migration completed')
->body(sprintf(
'Revoked: %d | Retained: %d | New: %d',
$result['revoked'],
$result['retained'],
$result['new_only'],
))
->success()
->send();
$this->redirect(CollectionResource::getUrl('view', ['record' => $record->fresh()]));
} catch (\Throwable $e) {
Notification::make()->title('Migration failed')->body($e->getMessage())->danger()->send();
}
}),
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@ public function table(Table $table): Table
->label('Reference ID')
->searchable(),
TextColumn::make('status'),
TextColumn::make('is_archived')
->label('Archived')
->badge()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
SelectFilter::make('status')
Expand All @@ -165,11 +169,16 @@ public function table(Table $table): Table
->headerActions([
ImportAction::make()
->importer(EntryImporter::class)
->hidden(fn () => $this->ownerRecord->status === 'SUPERSEDED')
->options([
'collection_id' => $this->ownerRecord->id,
]),
Action::make('process')
->hidden(function () {
if ($this->ownerRecord->isVersionMigrationActive()) {
return true;
}

return $this->ownerRecord->entries()->where('status', 'SUBMITTED')->count() < 1;
})
->action(function () {
Expand All @@ -190,9 +199,11 @@ public function table(Table $table): Table
ViewAction::make()
->iconButton(),
EditAction::make()
->iconButton(),
->iconButton()
->hidden(fn () => $this->ownerRecord->status === 'SUPERSEDED'),
DeleteAction::make()
->iconButton(),
->iconButton()
->hidden(fn () => $this->ownerRecord->status === 'SUPERSEDED'),
])
->toolbarActions([
BulkActionGroup::make([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,17 @@
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Model;

class MoleculesRelationManager extends RelationManager
{
protected static string $relationship = 'molecules';

public static function canViewForRecord(Model $ownerRecord, string $pageClass): bool
{
return $ownerRecord->status !== 'SUPERSEDED';
}

public function form(Schema $schema): Schema
{
return $schema
Expand Down
2 changes: 1 addition & 1 deletion app/Filament/Dashboard/Widgets/DashboardStats.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ protected function getStats(): array
});

$totalCollections = Cache::flexible('stats.collections', [172800, 259200], function () {
return DB::table('collections')->selectRaw('count(*)')->whereRaw("status = 'PUBLISHED'")->get()[0]->count;
return DB::table('collections')->selectRaw('count(*)')->whereRaw("status = 'PUBLISHED'")->where('is_latest', true)->get()[0]->count;
});

$uniqueOrganisms = Cache::flexible('stats.organisms', [172800, 259200], function () {
Expand Down
1 change: 1 addition & 0 deletions app/Helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ function getCollectionStatuses()
'EMBARGO' => 'Embargo',
'PUBLISHED' => 'Published',
'REJECTED' => 'Rejected',
'SUPERSEDED' => 'Superseded',
];
}

Expand Down
18 changes: 16 additions & 2 deletions app/Http/Controllers/CollectionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,33 @@ public function __invoke(Request $request, $id)
}

$collection = Cache::flexible('collections.'.$id, [172800, 259200], function () use ($id) {
return Collection::where('identifier', $id)->first();
return Collection::query()
->where('identifier', $id)
->orderByDesc('is_latest')
->orderByDesc('version')
->first();
});

if (! $collection) {
abort(404);
}

$latest = $collection->is_latest
? $collection
: ($collection->lineageVersionsQuery()->where('is_latest', true)->first() ?? $collection);

$query = [
'type' => 'tags',
'q' => str_replace(' ', '+', $collection->title),
'q' => str_replace(' ', '+', $latest->title),
'tagType' => 'dataSource',
];

if ($request->has('version')) {
$query['version'] = (int) $request->query('version');
} elseif (! $collection->is_latest) {
$query['version'] = $collection->version;
}

$baseUrl = config('app.url');

return redirect()->to($baseUrl.'/search?'.http_build_query($query));
Expand Down
1 change: 1 addition & 0 deletions app/Livewire/CollectionList.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public function render()
// $search = strtolower($this->query ?? '');
$query = Collection::query()
->where('status', 'PUBLISHED')
->where('is_latest', true)
->where(function ($query) use ($search) {
$query->whereRaw('LOWER(title) ILIKE ?', ['%'.$search.'%'])
->orWhereRaw('LOWER(description) ILIKE ?', ['%'.$search.'%']);
Expand Down
Loading
Loading