From 2a5c5f5f2e51d14515292da0a0ff91348d5fee0f Mon Sep 17 00:00:00 2001 From: Sagar Date: Wed, 18 Sep 2024 02:00:13 +0200 Subject: [PATCH 01/47] wip: suggested changes are now stored in the reports table. SQL queries need to be built at the time of approving the report --- app/Actions/Coconut/SearchMolecule.php | 1 - .../Commands/OrganismDedupeOptions.php | 2 - .../Dashboard/Resources/CitationResource.php | 88 +------ .../Resources/CollectionResource.php | 3 - .../Resources/GeoLocationResource.php | 7 +- .../Dashboard/Resources/OrganismResource.php | 99 +------- .../MoleculesRelationManager.php | 45 +++- .../Dashboard/Resources/ReportResource.php | 232 +++++++++++++++++- .../ReportResource/Pages/CreateReport.php | 9 + app/Http/Controllers/API/SearchController.php | 4 - app/Models/Citation.php | 96 ++++++++ app/Models/GeoLocation.php | 15 ++ app/Models/Organism.php | 105 ++++++++ app/Models/Report.php | 7 +- docs/.vitepress/config.mts | 42 ++-- docs/analysis.md | 3 - docs/curation.md | 27 ++ docs/data-contributors.md | 18 ++ docs/developers.md | 9 + docs/steering-committee.md | 45 ++++ 20 files changed, 621 insertions(+), 236 deletions(-) create mode 100644 docs/data-contributors.md create mode 100644 docs/developers.md create mode 100644 docs/steering-committee.md diff --git a/app/Actions/Coconut/SearchMolecule.php b/app/Actions/Coconut/SearchMolecule.php index 9198fb21..c5ee90ad 100644 --- a/app/Actions/Coconut/SearchMolecule.php +++ b/app/Actions/Coconut/SearchMolecule.php @@ -350,7 +350,6 @@ private function executeQuery($statement) $ids_array = collect($hits)->pluck('id')->toArray(); $ids = implode(',', $ids_array); - // dd($ids); if ($ids != '') { diff --git a/app/Console/Commands/OrganismDedupeOptions.php b/app/Console/Commands/OrganismDedupeOptions.php index 1abe945c..ce32649d 100644 --- a/app/Console/Commands/OrganismDedupeOptions.php +++ b/app/Console/Commands/OrganismDedupeOptions.php @@ -74,8 +74,6 @@ public function handle() array_unshift($choices, 'Skip'); - // dd($choices); - $retainValue = select( 'Select the record you want to retain:', $choices diff --git a/app/Filament/Dashboard/Resources/CitationResource.php b/app/Filament/Dashboard/Resources/CitationResource.php index 00776312..28ee9b40 100644 --- a/app/Filament/Dashboard/Resources/CitationResource.php +++ b/app/Filament/Dashboard/Resources/CitationResource.php @@ -6,18 +6,12 @@ use App\Filament\Dashboard\Resources\CitationResource\RelationManagers\CollectionRelationManager; use App\Filament\Dashboard\Resources\CitationResource\RelationManagers\MoleculeRelationManager; use App\Models\Citation; -use Closure; -use Filament\Forms\Components\Section; -use Filament\Forms\Components\Textarea; -use Filament\Forms\Components\TextInput; use Filament\Forms\Form; -use Filament\Forms\Get; use Filament\Resources\Resource; use Filament\Tables; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Table; use Illuminate\Support\Facades\Cache; -use Illuminate\Support\HtmlString; use Tapp\FilamentAuditing\RelationManagers\AuditsRelationManager; class CitationResource extends Resource @@ -35,87 +29,7 @@ class CitationResource extends Resource public static function form(Form $form): Form { return $form - ->schema([ - Section::make() - ->schema([ - TextInput::make('failMessage') - ->default('') - ->hidden() - ->disabled(), - TextInput::make('doi') - ->label('DOI') - ->live(onBlur: true) - ->afterStateUpdated(function ($set, $state) { - if (doiRegxMatch($state)) { - $citationDetails = fetchDOICitation($state); - if ($citationDetails) { - $set('title', $citationDetails['title']); - $set('authors', $citationDetails['authors']); - $set('citation_text', $citationDetails['citation_text']); - $set('failMessage', 'Success'); - } else { - $set('failMessage', 'No citation found. Please fill in the details manually'); - } - } else { - $set('failMessage', 'Invalid DOI'); - } - }) - ->helperText(function ($get) { - - if ($get('failMessage') == 'Fetching') { - return new HtmlString(' - - - '); - } elseif ($get('failMessage') != 'Success') { - return new HtmlString(''.$get('failMessage').''); - } else { - return null; - } - }) - ->required() - ->unique() - ->rules([ - fn (Get $get): Closure => function (string $attribute, $value, Closure $fail) use ($get) { - if ($get('failMessage') != 'No citation found. Please fill in the details manually') { - $fail($get('failMessage')); - } - }, - ]) - ->validationMessages([ - 'unique' => 'The DOI already exists.', - ]), - ]), - - Section::make() - ->schema([ - TextInput::make('title') - ->disabled(function ($get, string $operation) { - if ($operation = 'edit' || $get('failMessage') == 'No citation found. Please fill in the details manually') { - return false; - } else { - return true; - } - }), - TextInput::make('authors') - ->disabled(function ($get, string $operation) { - if ($operation = 'edit' || $get('failMessage') == 'No citation found. Please fill in the details manually') { - return false; - } else { - return true; - } - }), - Textarea::make('citation_text') - ->label('Citation text / URL') - ->disabled(function ($get, string $operation) { - if ($operation = 'edit' || $get('failMessage') == 'No citation found. Please fill in the details manually') { - return false; - } else { - return true; - } - }), - ])->columns(1), - ]); + ->schema(Citation::getForm()); } public static function table(Table $table): Table diff --git a/app/Filament/Dashboard/Resources/CollectionResource.php b/app/Filament/Dashboard/Resources/CollectionResource.php index 500fe6cb..72d72403 100644 --- a/app/Filament/Dashboard/Resources/CollectionResource.php +++ b/app/Filament/Dashboard/Resources/CollectionResource.php @@ -131,9 +131,6 @@ public static function table(Table $table): Table public static function getRelations(): array { - // $record = static::getOwner(); - // dd(static::getOwner()); - // dd(static::$model::molecules()->get()); $arr = [ EntriesRelationManager::class, CitationsRelationManager::class, diff --git a/app/Filament/Dashboard/Resources/GeoLocationResource.php b/app/Filament/Dashboard/Resources/GeoLocationResource.php index 9288ff9c..2e96fcb7 100644 --- a/app/Filament/Dashboard/Resources/GeoLocationResource.php +++ b/app/Filament/Dashboard/Resources/GeoLocationResource.php @@ -5,7 +5,6 @@ use App\Filament\Dashboard\Resources\GeoLocationResource\Pages; use App\Filament\Dashboard\Resources\GeoLocationResource\Widgets\GeoLocationStats; use App\Models\GeoLocation; -use Filament\Forms\Components\TextInput; use Filament\Forms\Form; use Filament\Resources\Resource; use Filament\Tables; @@ -26,11 +25,7 @@ class GeoLocationResource extends Resource public static function form(Form $form): Form { return $form - ->schema([ - TextInput::make('name') - ->required() - ->maxLength(255), - ]); + ->schema(GeoLocation::getForm()); } public static function table(Table $table): Table diff --git a/app/Filament/Dashboard/Resources/OrganismResource.php b/app/Filament/Dashboard/Resources/OrganismResource.php index 2f162e54..9624a38e 100644 --- a/app/Filament/Dashboard/Resources/OrganismResource.php +++ b/app/Filament/Dashboard/Resources/OrganismResource.php @@ -9,8 +9,6 @@ use App\Forms\Components\OrganismsTable; use App\Models\Organism; use Archilex\AdvancedTables\Filters\AdvancedFilter; -use Filament\Forms; -use Filament\Forms\Components\Actions\Action; use Filament\Forms\Components\Grid; use Filament\Forms\Components\Group; use Filament\Forms\Components\Section; @@ -43,102 +41,9 @@ public static function form(Form $form): Form Group::make() ->schema([ Section::make('') - ->schema([ - Forms\Components\TextInput::make('name') - ->required() - ->unique() - ->maxLength(255) - ->suffixAction( - Action::make('infoFromSources') - ->icon('heroicon-m-clipboard') - // ->fillForm(function ($record, callable $get): array { - // $entered_name = $get('name'); - // $name = ucfirst(trim($entered_name)); - // $data = null; - // $iri = null; - // $organism = null; - // $rank = null; - - // if ($name && $name != '') { - // $data = Self::getOLSIRI($name, 'species'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'species'); - // Self::info("Mapped and updated: $name"); - // } else { - // $data = Self::getOLSIRI(explode(' ', $name)[0], 'genus'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'genus'); - // Self::info("Mapped and updated: $name"); - // } else { - // $data = Self::getOLSIRI(explode(' ', $name)[0], 'family'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'genus'); - // Self::info("Mapped and updated: $name"); - // } else { - // [$name, $iri, $organism, $rank] = Self::getGNFMatches($name, $record); - // } - // } - // } - // } - // return [ - // 'name' => $name, - // 'iri' => $iri, - // 'rank' => $rank, - // ]; - // }) - // ->form([ - // Forms\Components\TextInput::make('name')->readOnly(), - // Forms\Components\TextInput::make('iri')->readOnly(), - // Forms\Components\TextInput::make('rank')->readOnly(), - // ]) - // ->action(fn ( $record) => $record->advance()) - ->modalContent(function ($record, $get): View { - $name = ucfirst(trim($get('name'))); - $data = null; - // $iri = null; - // $organism = null; - // $rank = null; - - if ($name && $name != '') { - $data = self::getOLSIRI($name, 'species'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'species'); - // } else { - // $data = Self::getOLSIRI(explode(' ', $name)[0], 'genus'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'genus'); - // } else { - // $data = Self::getOLSIRI(explode(' ', $name)[0], 'family'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'genus'); - // } else { - // [$name, $iri, $organism, $rank] = Self::getGNFMatches($name, $record); - // } - // } - // } - } - - return view( - 'forms.components.organism-info', - [ - 'data' => $data, - ], - ); - }) - ->action(function (array $data, Organism $record): void { - // Self::updateOrganismModel($data['name'], $data['iri'], $record, $data['rank']); - }) - ->slideOver() - ), - Forms\Components\TextInput::make('iri') - ->label('IRI') - ->maxLength(255), - Forms\Components\TextInput::make('rank') - ->maxLength(255), - ]), + ->schema(Organism::getForm()), ]) ->columnSpan(1), - Group::make() ->schema([ Section::make('') @@ -254,7 +159,6 @@ protected static function getGNFMatches($name, $organism) $responseBody = json_decode($response->getBody(), true); return $responseBody; - // dd($responseBody); // if (isset($responseBody['names']) && count($responseBody['names']) > 0) { // $r_name = $responseBody['names'][0]; @@ -293,7 +197,6 @@ protected static function getGNFMatches($name, $organism) protected static function updateOrganismModel($name, $iri, $organism = null, $rank = null) { - // dd($name, $iri, $organism, $rank); if (! $organism) { $organism = Organism::where('name', $name)->first(); } diff --git a/app/Filament/Dashboard/Resources/OrganismResource/RelationManagers/MoleculesRelationManager.php b/app/Filament/Dashboard/Resources/OrganismResource/RelationManagers/MoleculesRelationManager.php index fc5845e8..c754721f 100644 --- a/app/Filament/Dashboard/Resources/OrganismResource/RelationManagers/MoleculesRelationManager.php +++ b/app/Filament/Dashboard/Resources/OrganismResource/RelationManagers/MoleculesRelationManager.php @@ -160,13 +160,48 @@ public function table(Table $table): Table } $newOrganism = Organism::findOrFail($data['org_id']); - $locations = $livewire->mountedTableBulkActionData['locations']; - if ($locations) { - $sampleLocations = SampleLocation::findOrFail($locations); - foreach ($sampleLocations as $location) { - $location->auditSyncWithoutDetaching('molecules', $moleculeIds); + // Get the NEW sample locations + $new_form_sample_locations = $livewire->mountedTableBulkActionData['locations']; + if ($new_form_sample_locations) { + $new_sample_locations = SampleLocation::findOrFail($new_form_sample_locations); + } + + // Get the CURRENT organism + $currentOrganism = $this->getOwnerRecord(); + + // Handling Molecules with only ONE location + // Detach Molecules with only ONE location from CURRENT Organism + if ($molecule_ids_with_one_location) { + $molecule_with_one_location = $records->whereIn('id', $molecule_ids_with_one_location); + $currentOrganism->auditDetach('molecules', $molecule_ids_with_one_location); + + // Detach molecules with only ONE location from CURRENT Sample Locations + foreach ($molecule_with_one_location as $record) { + $current_sample_locations = $record->sampleLocations()->where('organism_id', $this->getOwnerRecord()->id)->get(); + foreach ($current_sample_locations as $location) { + $location->auditDetach('molecules', $record->id); + } } } + + // Handling Molecules with MULTIPLE locations + // Detach molecules from Sample Locations + foreach ($molecues_with_muliple_locations as $molecule) { + $current_sample_locations_subset = SampleLocation::findOrFail($molecule['sampleLocations']); + $current_sample_locations_multiple = $records->where('id', $molecule['id'])[0]->sampleLocations()->where('organism_id', $this->getOwnerRecord()->id)->get(); + if ($current_sample_locations_multiple->pluck('id') == $current_sample_locations_subset->pluck('id')) { + $currentOrganism->auditDetach('molecules', $molecule['id']); + } + foreach ($current_sample_locations_subset as $location) { + $location->auditDetach('molecules', $molecule['id']); + customAuditLog('re-assign', [$records->find($molecule['id'])], 'sampleLocations', $current_sample_locations_subset, $new_sample_locations); + } + } + + foreach ($new_sample_locations as $location) { + $location->auditSyncWithoutDetaching('molecules', $moleculeIds); + // customAuditLog('cust_sync', $records, 'sampleLocations', [], $location); + } $newOrganism->auditSyncWithoutDetaching('molecules', $moleculeIds); $currentOrganism->refresh(); diff --git a/app/Filament/Dashboard/Resources/ReportResource.php b/app/Filament/Dashboard/Resources/ReportResource.php index a26e7ad1..97997f4e 100644 --- a/app/Filament/Dashboard/Resources/ReportResource.php +++ b/app/Filament/Dashboard/Resources/ReportResource.php @@ -5,15 +5,20 @@ use App\Filament\Dashboard\Resources\ReportResource\Pages; use App\Filament\Dashboard\Resources\ReportResource\RelationManagers; use App\Models\Citation; +use App\Models\GeoLocation; use App\Models\Molecule; +use App\Models\Organism; use App\Models\Report; use Archilex\AdvancedTables\Filters\AdvancedFilter; use Filament\Forms\Components\Actions; use Filament\Forms\Components\Actions\Action; use Filament\Forms\Components\Grid; use Filament\Forms\Components\KeyValue; +use Filament\Forms\Components\Repeater; use Filament\Forms\Components\Select; use Filament\Forms\Components\SpatieTagsInput; +use Filament\Forms\Components\Tabs; +use Filament\Forms\Components\TagsInput; use Filament\Forms\Components\Textarea; use Filament\Forms\Components\TextInput; use Filament\Forms\Components\ToggleButtons; @@ -125,11 +130,228 @@ public static function form(Form $form): Form ->hidden(function (Get $get) { return $get('is_change'); }), - KeyValue::make('suggested_changes') - ->hintIcon('heroicon-m-question-mark-circle', tooltip: 'Enter the property (in the left column) and suggested change (in the right column)') - ->addActionLabel('Add property') - ->keyLabel('Property') - ->valueLabel('Suggested change') + // KeyValue::make('suggested_changes') + // ->hintIcon('heroicon-m-question-mark-circle', tooltip: 'Enter the property (in the left column) and suggested change (in the right column)') + // ->addActionLabel('Add property') + // ->keyLabel('Property') + // ->valueLabel('Suggested change') + // ->hidden(function (Get $get) { + // return ! $get('is_change'); + // }), + Tabs::make('Tabs') + ->tabs([ + Tabs\Tab::make('organisms_changes') + ->label('Organisms') + ->schema([ + Repeater::make('organisms_changes') + ->schema([ + Select::make('operation') + ->options([ + 'update' => 'Update', + 'remove' => 'Remove', + 'add' => 'Add', + ]) + ->default('update') + ->live(), + Select::make('organisms') + ->label('Organism') + ->searchable() + ->searchDebounce(500) + ->getSearchResultsUsing(function (string $search, Get $get): array { + return Molecule::where('identifier', $get('../../mol_id_csv'))->get()[0]->organisms()->where('name', 'ilike', "%{$search}%")->limit(10)->pluck('organisms.name', 'organisms.id')->toArray() ?? []; + }) + ->getOptionLabelUsing(fn ($value): ?string => Organism::find($value)?->name) + ->hidden(function (Get $get) { + return $get('operation') == 'add'; + }), + TextInput::make('name') + ->label('Change to') + ->hidden(function (Get $get) { + return $get('operation') != 'update'; + }), + Grid::make('new_organism_details') + ->schema(Organism::getForm())->columns(3) + ->hidden(function (Get $get) { + return $get('operation') != 'add'; + }) + ->columnStart(2), + ]) + ->reorderable(false) + ->columns(4), + + ]), + Tabs\Tab::make('geo_locations_changes') + ->label('Geo Locations') + ->schema([ + Repeater::make('geo_locations_changes') + ->schema([ + Select::make('operation') + ->options([ + 'update' => 'Update', + 'remove' => 'Remove', + 'add' => 'Add', + ]) + ->default('update') + ->live(), + Select::make('geo_locations') + ->label('Geo Location') + ->searchable() + ->searchDebounce(500) + ->getSearchResultsUsing(function (string $search, Get $get): array { + return Molecule::where('identifier', $get('../../mol_id_csv'))->get()[0]->geo_locations()->where('name', 'ilike', "%{$search}%")->limit(10)->pluck('geo_locations.name', 'geo_locations.id')->toArray(); + }) + ->getOptionLabelUsing(fn ($value): ?string => GeoLocation::find($value)?->name) + ->hidden(function (Get $get) { + return $get('operation') == 'add'; + }), + TextInput::make('name') + ->label('Change to') + ->hidden(function (Get $get) { + return $get('operation') != 'update'; + }), + Grid::make('new_geo_locations_details') + ->schema(GeoLocation::getForm())->columns(3) + ->hidden(function (Get $get) { + return $get('operation') != 'add'; + }) + ->columnStart(2), + ]) + ->reorderable(false) + ->columns(4), + ]), + Tabs\Tab::make('synonyms') + ->label('Synonyms') + ->schema([ + Repeater::make('synonyms_changes') + ->schema([ + Select::make('operation') + ->options([ + 'update' => 'Update', + 'remove' => 'Remove', + 'add' => 'Add', + ]) + ->default('update') + ->live(), + Select::make('synonyms') + ->label('Synonym') + ->searchable() + ->searchDebounce(500) + ->getSearchResultsUsing(function (string $search, Get $get): array { + $synonyms = Molecule::select('synonyms')->where('identifier', $get('../../mol_id_csv'))->get()[0]['synonyms']; + $matched_synonyms = []; + foreach ($synonyms as $synonym) { + str_contains(strtolower($synonym), strtolower($search)) ? array_push($matched_synonyms, $synonym) : null; + } + + return $matched_synonyms; + }) + ->hidden(function (Get $get) { + return $get('operation') == 'add'; + }), + TextInput::make('name') + ->label('Change to') + ->hidden(function (Get $get) { + return $get('operation') != 'update'; + }), + Grid::make('new_synonym_details') + ->schema([ + TagsInput::make('new_synonym') + ->label('New Synonym') + ->separator(',') + ->splitKeys([',']), + ])->columns(3) + ->hidden(function (Get $get) { + return $get('operation') != 'add'; + }) + ->columnStart(2), + ]) + ->reorderable(false) + ->columns(4), + ]), + Tabs\Tab::make('identifiers') + ->label('Identifiers') + ->schema([ + Repeater::make('identifiers_changes') + ->schema([ + Select::make('identifer_to_change') + ->options([ + 'name' => 'Name', + 'cas' => 'CAS', + ]) + ->default('name') + ->live(), + Select::make('current_Name') + ->options(function (Get $get): array { + return [Molecule::where('identifier', $get('../../mol_id_csv'))->get()[0]->name ?? '']; + }) + ->default(0) + ->disabled() + ->hidden(function (Get $get) { + return $get('identifer_to_change') == 'cas'; + }), + Select::make('current_CAS') + ->options(function (Get $get): array { + return [Molecule::where('identifier', $get('../../mol_id_csv'))->get()[0]->cas]; + }) + ->default(0) + ->disabled() + ->hidden(function (Get $get) { + return $get('identifer_to_change') == 'name'; + }), + TextInput::make('new_name') + ->label(function (Get $get) { + return $get('identifer_to_change') == 'name' ? 'New Name' : 'New CAS'; + }), + ]) + ->reorderable(false) + ->columns(4), + ]), + Tabs\Tab::make('citations') + ->label('Citations') + ->schema([ + Repeater::make('citations_changes') + ->schema([ + Select::make('operation') + ->options([ + 'update' => 'Update', + 'remove' => 'Remove', + 'add' => 'Add', + ]) + ->default('update') + ->live(), + Select::make('citations') + ->label('Citation') + ->searchable() + ->searchDebounce(500) + ->getSearchResultsUsing(function (string $search, Get $get): array { + return Molecule::where('identifier', $get('../../mol_id_csv'))->get()[0]->citations()->where('title', 'ilike', "%{$search}%")->limit(10)->pluck('citations.title', 'citations.id')->toArray(); + }) + ->getOptionLabelUsing(fn ($value): ?string => Citation::find($value)?->name) + ->hidden(function (Get $get) { + return $get('operation') == 'add'; + }), + TextInput::make('name') + ->label('Change to') + ->hidden(function (Get $get) { + return $get('operation') != 'update'; + }), + Grid::make('new_citation_details') + ->schema(Citation::getForm())->columns(3) + ->hidden(function (Get $get) { + return $get('operation') != 'add'; + }) + ->columnStart(2), + ]) + ->reorderable(false) + ->columns(4), + + ]), + + Tabs\Tab::make('Chemical Classifications') + ->schema([ + // ... + ]), + ]) ->hidden(function (Get $get) { return ! $get('is_change'); }), diff --git a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php index 937c3131..2878f2c6 100644 --- a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php +++ b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php @@ -67,6 +67,15 @@ protected function mutateFormDataBeforeCreate(array $data): array $data['user_id'] = auth()->id(); $data['status'] = 'submitted'; + $suggested_changes = []; + $suggested_changes['organisms_changes'] = $data['organisms_changes']; + $suggested_changes['geo_locations_changes'] = $data['geo_locations_changes']; + $suggested_changes['synonyms_changes'] = $data['synonyms_changes']; + $suggested_changes['identifiers_changes'] = $data['identifiers_changes']; + $suggested_changes['citations_changes'] = $data['citations_changes']; + + $data['suggested_changes'] = $suggested_changes; + return $data; } diff --git a/app/Http/Controllers/API/SearchController.php b/app/Http/Controllers/API/SearchController.php index 8cd31eb8..2a21f544 100644 --- a/app/Http/Controllers/API/SearchController.php +++ b/app/Http/Controllers/API/SearchController.php @@ -19,8 +19,6 @@ public function search(Request $request) $queryType = 'text'; $results = []; - //dd($request); - $limit = $request->query('limit'); $sort = $request->query('sort'); $limit = $limit ? $limit : 24; @@ -218,7 +216,6 @@ public function search(Request $request) $statement = $statement.')'; } $statement = $statement.' LIMIT '.$limit; - // dd($statement ); } else { if ($query) { $query = str_replace("'", "''", $query); @@ -289,7 +286,6 @@ public function search(Request $request) $page ); - //dd($pagination); return $pagination; } catch (QueryException $exception) { $message = $exception->getMessage(); diff --git a/app/Models/Citation.php b/app/Models/Citation.php index 8ee2f9ff..94542b75 100644 --- a/app/Models/Citation.php +++ b/app/Models/Citation.php @@ -2,9 +2,15 @@ namespace App\Models; +use Closure; +use Filament\Forms\Components\Section; +use Filament\Forms\Components\Textarea; +use Filament\Forms\Components\TextInput; +use Filament\Forms\Get; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphToMany; +use Illuminate\Support\HtmlString; use OwenIt\Auditing\Contracts\Auditable; class Citation extends Model implements Auditable @@ -47,4 +53,94 @@ public function reports(): MorphToMany { return $this->morphToMany(Report::class, 'reportable'); } + + public function transformAudit(array $data): array + { + return changeAudit($data); + } + + public static function getForm() + { + return [ + Section::make() + ->schema([ + TextInput::make('failMessage') + ->default('') + ->hidden() + ->disabled(), + TextInput::make('doi') + ->label('DOI') + ->live(onBlur: true) + ->afterStateUpdated(function ($set, $state) { + if (doiRegxMatch($state)) { + $citationDetails = fetchDOICitation($state); + if ($citationDetails) { + $set('title', $citationDetails['title']); + $set('authors', $citationDetails['authors']); + $set('citation_text', $citationDetails['citation_text']); + $set('failMessage', 'Success'); + } else { + $set('failMessage', 'No citation found. Please fill in the details manually'); + } + } else { + $set('failMessage', 'Invalid DOI'); + } + }) + ->helperText(function ($get) { + + if ($get('failMessage') == 'Fetching') { + return new HtmlString(' + + + '); + } elseif ($get('failMessage') != 'Success') { + return new HtmlString(''.$get('failMessage').''); + } else { + return null; + } + }) + ->required() + ->unique() + ->rules([ + fn (Get $get): Closure => function (string $attribute, $value, Closure $fail) use ($get) { + if ($get('failMessage') != 'No citation found. Please fill in the details manually') { + $fail($get('failMessage')); + } + }, + ]) + ->validationMessages([ + 'unique' => 'The DOI already exists.', + ]), + ]), + + Section::make() + ->schema([ + TextInput::make('title') + ->disabled(function ($get, string $operation) { + if ($operation = 'edit' || $get('failMessage') == 'No citation found. Please fill in the details manually') { + return false; + } else { + return true; + } + }), + TextInput::make('authors') + ->disabled(function ($get, string $operation) { + if ($operation = 'edit' || $get('failMessage') == 'No citation found. Please fill in the details manually') { + return false; + } else { + return true; + } + }), + Textarea::make('citation_text') + ->label('Citation text / URL') + ->disabled(function ($get, string $operation) { + if ($operation = 'edit' || $get('failMessage') == 'No citation found. Please fill in the details manually') { + return false; + } else { + return true; + } + }), + ])->columns(1), + ]; + } } diff --git a/app/Models/GeoLocation.php b/app/Models/GeoLocation.php index 3686a8d0..28bcd5ef 100644 --- a/app/Models/GeoLocation.php +++ b/app/Models/GeoLocation.php @@ -2,6 +2,7 @@ namespace App\Models; +use Filament\Forms\Components\TextInput; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use OwenIt\Auditing\Contracts\Auditable; @@ -24,4 +25,18 @@ public function molecules() { return $this->belongsToMany(Molecule::class)->withPivot('locations')->withTimestamps(); } + + public function transformAudit(array $data): array + { + return changeAudit($data); + } + + public static function getForm(): array + { + return [ + TextInput::make('name') + ->required() + ->maxLength(255), + ]; + } } diff --git a/app/Models/Organism.php b/app/Models/Organism.php index c2fb8c48..ad4c09ab 100644 --- a/app/Models/Organism.php +++ b/app/Models/Organism.php @@ -2,6 +2,9 @@ namespace App\Models; +use Filament\Forms; +use Filament\Forms\Components\Actions\Action; +use Illuminate\Contracts\View\View; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsToMany; @@ -46,4 +49,106 @@ public function getIriAttribute($value) { return urldecode($value); } + + public function transformAudit(array $data): array + { + return changeAudit($data); + } + + public static function getForm(): array + { + return [ + Forms\Components\TextInput::make('name') + ->required() + ->unique(Organism::class, 'name') + ->maxLength(255) + ->suffixAction( + Action::make('infoFromSources') + ->icon('heroicon-m-clipboard') + // ->fillForm(function ($record, callable $get): array { + // $entered_name = $get('name'); + // $name = ucfirst(trim($entered_name)); + // $data = null; + // $iri = null; + // $organism = null; + // $rank = null; + + // if ($name && $name != '') { + // $data = Self::getOLSIRI($name, 'species'); + // if ($data) { + // Self::updateOrganismModel($name, $data, $record, 'species'); + // Self::info("Mapped and updated: $name"); + // } else { + // $data = Self::getOLSIRI(explode(' ', $name)[0], 'genus'); + // if ($data) { + // Self::updateOrganismModel($name, $data, $record, 'genus'); + // Self::info("Mapped and updated: $name"); + // } else { + // $data = Self::getOLSIRI(explode(' ', $name)[0], 'family'); + // if ($data) { + // Self::updateOrganismModel($name, $data, $record, 'genus'); + // Self::info("Mapped and updated: $name"); + // } else { + // [$name, $iri, $organism, $rank] = Self::getGNFMatches($name, $record); + // } + // } + // } + // } + // return [ + // 'name' => $name, + // 'iri' => $iri, + // 'rank' => $rank, + // ]; + // }) + // ->form([ + // Forms\Components\TextInput::make('name')->readOnly(), + // Forms\Components\TextInput::make('iri')->readOnly(), + // Forms\Components\TextInput::make('rank')->readOnly(), + // ]) + // ->action(fn ( $record) => $record->advance()) + ->modalContent(function ($record, $get): View { + $name = ucfirst(trim($get('name'))); + $data = null; + // $iri = null; + // $organism = null; + // $rank = null; + + if ($name && $name != '') { + $data = self::getOLSIRI($name, 'species'); + // if ($data) { + // Self::updateOrganismModel($name, $data, $record, 'species'); + // } else { + // $data = Self::getOLSIRI(explode(' ', $name)[0], 'genus'); + // if ($data) { + // Self::updateOrganismModel($name, $data, $record, 'genus'); + // } else { + // $data = Self::getOLSIRI(explode(' ', $name)[0], 'family'); + // if ($data) { + // Self::updateOrganismModel($name, $data, $record, 'genus'); + // } else { + // [$name, $iri, $organism, $rank] = Self::getGNFMatches($name, $record); + // } + // } + // } + } + + return view( + 'forms.components.organism-info', + [ + 'data' => $data, + ], + ); + }) + ->action(function (array $data, Organism $record): void { + // Self::updateOrganismModel($data['name'], $data['iri'], $record, $data['rank']); + }) + ->slideOver() + ), + Forms\Components\TextInput::make('iri') + ->label('IRI') + ->maxLength(255), + Forms\Components\TextInput::make('rank') + ->maxLength(255), + ]; + } } diff --git a/app/Models/Report.php b/app/Models/Report.php index e4c4cfb9..f2c574af 100644 --- a/app/Models/Report.php +++ b/app/Models/Report.php @@ -2,7 +2,6 @@ namespace App\Models; -use App\States\Report\ReportState; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; @@ -38,7 +37,6 @@ class Report extends Model implements Auditable protected $casts = [ 'suggested_changes' => 'array', - // 'status' => ReportState::class, ]; /** @@ -70,6 +68,11 @@ public function organisms(): MorphToMany return $this->morphedByMany(Organism::class, 'reportable'); } + // public function geoLocations(): MorphToMany + // { + // return $this->morphedByMany(Organism::class, 'reportable'); + // } + /** * Get all of the users that are assigned this report. */ diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 432e8c6e..59068233 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -25,7 +25,7 @@ export default defineConfig({ nav: [ { text: 'Home', link: '/introduction' }, - { text: 'API', link: 'https://coconut.cheminf.studio/api-documentation' }, + // { text: 'API', link: 'https://coconut.cheminf.studio/api-documentation' }, { text: 'About', link: 'https://coconut.cheminf.studio/about' }, { text: 'Download', link: 'https://coconut.cheminf.studio/download' } ], @@ -47,19 +47,19 @@ export default defineConfig({ ] }, { - text: 'Curation', + text: 'Downloads', items: [ - { text: 'Analysis', link: '/analysis' }, - { text: 'Reporting', link: '/reporting' }, - { text: 'Audit Trail', link: '/audit-trail' } + { text: 'Data Base', link: '/data-base' }, + { text: 'Versions', link: '/versions' }, + { text: 'Use Cases', link: '/use-cases' }, ] }, { - text: 'Downloads', + text: 'Curation', items: [ - { text: 'Data Base', link: '/data-base' }, - { text: 'Use Cases', link: '/use-cases' }, - { text: 'Versions', link: '/versions' }, + // { text: 'Analysis', link: '/analysis' }, + { text: 'Reporting', link: '/reporting' }, + { text: 'Audit Trail', link: '/audit-trail' } ] }, { @@ -77,16 +77,16 @@ export default defineConfig({ // { text: 'Multiple Compound Submission', link: '/multi-submission' }, ] }, - { - text: 'API', - items: [ - { text: 'Auth', link: '/auth-api' }, - { text: 'Search', link: '/search-api' }, - { text: 'Schemas', link: '/schemas-api' }, - // { text: 'Download', link: '/download-api' }, - // { text: 'Submission', link: '/submission-api' } - ] - }, + // { + // text: 'API', + // items: [ + // { text: 'Auth', link: '/auth-api' }, + // { text: 'Search', link: '/search-api' }, + // { text: 'Schemas', link: '/schemas-api' }, + // { text: 'Download', link: '/download-api' }, + // { text: 'Submission', link: '/submission-api' } + // ] + // }, { text: 'Development', items: [ @@ -97,7 +97,9 @@ export default defineConfig({ { text: 'Contribution', items: [ - { text: 'Contributors and Steering Committee', link: '/contributors' } + { text: 'Steering Committee', link: '/steering-committee' }, + { text: 'Developers', link: '/developers' }, + // { text: 'Data Contributors', link: '/data-contributors' }, ], }, { diff --git a/docs/analysis.md b/docs/analysis.md index 2fc75169..f56140af 100644 --- a/docs/analysis.md +++ b/docs/analysis.md @@ -15,6 +15,3 @@ * Structures that cannot be parsed by the ChEMBL structure curation pipeline (113 in total) have been removed. * Duplicates have been merged into one entry and the highly annotated entry has been made the parent entry, and the remainder is now included in the parent entry. - ## Curation flow chart - - \ No newline at end of file diff --git a/docs/curation.md b/docs/curation.md index 107810b2..b83d3c53 100644 --- a/docs/curation.md +++ b/docs/curation.md @@ -1,5 +1,32 @@ # Curation of COCONUT DB +COCONUT has aggregated NPs data from 63 sources under open source licenses. This data ranged from supplimentary material from published papers to well curated databases under open licenses. It was decided by the Steering Committee that the focus of COCONUT Natural Products database was to provide reliable information on Molecules, Organisms and sample locations within the organisms where these molecules were reported from, and geo-locations where these organisms were reported to be found in literature. In order provide this complete set of information on a compound, wherever it was determined during the curation process that the required information was missing webscraping was utilised. Scraping was also used where source collection data was openly accessible but had no bulk download links. + +Following the above processes and principles, the Original 2021 version of COCONUT aggregated 53 openly accessible Collections. 2024 version of COCONUT expanded its database to include 10 more Collections bringing the total to 63. While gathering this data for the new version, the older 53 collection were revisited to ensure inclusion of updates from these sources. Where the Collections are no more accessible, the data that was used in the 2021 version of COCONUT was left as is. + +The process of aggregation invovled automated pipelines that minimises manual intervention and ensures the data is of highest quality. Initially data from each collection is passed through RDKit pipeline. Any molecules that failed to get parsed by RDKit were eliminated from further processing. The parsed molecules were then kept as CSV files with all the data provided by the sources. These CSV files are then loaded into COCONUT database preserving the data to trace it back the source. Now, to establish that the chemical structure are valid, ChEMBL pipeline (ChEMBL Structure Curation Pipeline Checker) was used. Any molecules marked with an error code of 6 or higer are marked as rejected and kept for future reference (COCONUT provides tools to make corrections at this stage to rectify any discrepancies that led to these errors and resubmit the molecules). The ones that are marked as passed are then imported into the tables accessible by the users on COCONUT. + + ## Curation flow chart + + + +## Curation tools +One of the features that distinguishes COCONUT 2024 from its predecessor is the Curation Tools. The research community's experience with 2021 version resulted in the realisation that not all the molecules from the Natural Products sources are organic in their origin. Hence rose the demand for ways to curate the molecules on COCONUT 2021. This was realised with the release of COCONUT 2024. + +### Reporting +The Curation process begins with Reporting. Any user on COCONUT has the ability to report on discrepancies in data displayed on the platform (Find more about reporting [here](/reporting)). Once a report is created, it stays in the **Draft** state. The user can still edit and make changes to the report at this stage. When the report is ready for submission, user can simply change the status to **Submittted**. This will now go into the Curation queue and gets examined by a Curator on the platform. + +::: info COCONUT Curators +Members of the COCONUT steering committee, also take up the role of curator on the platform. They can also confer this role to some selected users who are deemed knowledgable in the field of Natural Products. +::: + +If the Curator deems the report to be correct, the report gets approved and necessary action gets taken. For example, if a compound is reported to be synthetic in origin, after curator's enquiry, if is proven to be so, the compound gets deactivated along with a reason why it was deactivated. + +Users may also suggest changes to the details of a compound through reporting and the same curation process is followed. + +### Audit trails +To ensure transparency in the curation process and thereby impart authenticity to the data on the platform, COCONUT 2024 also provides for audit trails. Every change to the data displayed on the platform is captured. Who did what and where are tracked internally. Combined with the vetting process for curators, the audit trails prevent any misuse of the platform. Find more about auditing [here](/audit-trail). + diff --git a/docs/data-contributors.md b/docs/data-contributors.md new file mode 100644 index 00000000..84fd9071 --- /dev/null +++ b/docs/data-contributors.md @@ -0,0 +1,18 @@ +# Data Contributors to COCONUT +## + +::: info Original Dataset Maintainers +Their untiring efforts in making their data openly available +::: + +::: info Dr. Simon Saubern and Dr. Alex Shmaylov from the Commonwealth Scientific and Industrial Research Organisation (CSIRO), Australia + Australian Natural Product database to COCONUT +::: + +::: info Mr. Nikita Ionov and Prof. Dr. Vladimir Poroikov of the Russian Academy of Sciences, Russia + Phyto4Health data +::: + +::: info Prof. Dr. José L. Medina-Franco and Mr. Alejandro Gómez García of the National Autonomous University of Mexico, Mexico + Latin American dataset +::: diff --git a/docs/developers.md b/docs/developers.md new file mode 100644 index 00000000..899ca989 --- /dev/null +++ b/docs/developers.md @@ -0,0 +1,9 @@ +# Developers of COCONUT +## +- Sri Ram Sagar Kanakam (Sagar) +- Venkata chandrasekhar Nainala (Chandu) +- Dr. Kohulan Rajan +- Noura Rayya +- Dr. Jonas Schaub +- Nisha Sharma +- Viktor Weißenborn diff --git a/docs/steering-committee.md b/docs/steering-committee.md new file mode 100644 index 00000000..f923539b --- /dev/null +++ b/docs/steering-committee.md @@ -0,0 +1,45 @@ +# Steering committee of COCONUT +::: info Dr Pierre-Marie Allard + Université de Fribourg - Universität Freiburg,
+ Faculty of Science and Medicine +::: + +::: info Dr Peter Ertl + Ertl Molecular +::: + +::: info Prof. Dr Jose L. Medina-Franco + National Autonomous University of Mexico,
+ School of Chemistry +::: + +::: info Prof. Dr Guido F. Pauli + University of Illinois at Chicago,
+ Pharmacognosy Institute +::: + +::: info Prof. Dr. Christoph Steinbeck + Analytical Chemistry - Cheminformatics and Chemometrics,
+ Friedrich-Schiller-University +::: + + + From 2da1fcfdd08dc7e5ca7523b18ac51a0d2cacf81f Mon Sep 17 00:00:00 2001 From: Sagar Date: Tue, 24 Sep 2024 00:57:48 +0200 Subject: [PATCH 02/47] fix: key issue fixed --- app/Livewire/MoleculeHistoryTimeline.php | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/app/Livewire/MoleculeHistoryTimeline.php b/app/Livewire/MoleculeHistoryTimeline.php index f12a0364..2c79262f 100644 --- a/app/Livewire/MoleculeHistoryTimeline.php +++ b/app/Livewire/MoleculeHistoryTimeline.php @@ -18,18 +18,17 @@ public function getHistory() $audit_data[$index]['user_name'] = $audit->getMetadata()['user_name']; $audit_data[$index]['event'] = $audit->getMetadata()['audit_event']; $audit_data[$index]['created_at'] = date('Y/m/d', strtotime($audit->getMetadata()['audit_created_at'])); + // dd($audit->old_values, $audit->new_values); + // dd($audit->getModified()); - if (str_contains('.', array_keys($audit->old_values)[0])) { - $old_key = $audit->old_values ? explode('.', array_keys($audit->old_values)[0])[0] : null; - $new_key = $audit->new_values ? explode('.', array_keys($audit->new_values)[0])[0] : null; - - $old_key = $old_key ?: $new_key; - $new_key = $new_key ?: $old_key; - } else { - foreach ($audit->getModified() as $key => $value) { - $audit_data[$index]['affected_columns'][$key]['old_value'] = $value['old'] ?: null; - $audit_data[$index]['affected_columns'][$key]['new_value'] = $value['new'] ?: null; - } + $key = null; + $old_key = $audit->old_values ? explode('.', array_keys($audit->old_values)[0])[0] : null; + $new_key = $audit->new_values ? explode('.', array_keys($audit->new_values)[0])[0] : null; + $key = $old_key ?? $new_key; + + foreach ($audit->getModified() as $value) { + $audit_data[$index]['affected_columns'][$key]['old_value'] = array_key_exists('old', $value) ? $value['old'] : null; + $audit_data[$index]['affected_columns'][$key]['new_value'] = array_key_exists('new', $value) ? $value['new'] : null; } } From bef6b8dde8e06b76580dcb31eda1b748c844d7b6 Mon Sep 17 00:00:00 2001 From: Sagar Date: Tue, 24 Sep 2024 12:44:02 +0200 Subject: [PATCH 03/47] fix: disabled logging empty values and enabled handling of existing empty values in both old and new columns --- config/audit.php | 2 +- resources/views/livewire/molecule-history-timeline.blade.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/config/audit.php b/config/audit.php index df6dd561..bf34de57 100644 --- a/config/audit.php +++ b/config/audit.php @@ -101,7 +101,7 @@ | */ - 'empty_values' => true, + 'empty_values' => false, 'allowed_empty_values' => [ 'retrieved', ], diff --git a/resources/views/livewire/molecule-history-timeline.blade.php b/resources/views/livewire/molecule-history-timeline.blade.php index d283d5ff..27da7e88 100644 --- a/resources/views/livewire/molecule-history-timeline.blade.php +++ b/resources/views/livewire/molecule-history-timeline.blade.php @@ -10,6 +10,7 @@
    @foreach ($audit_data as $audit) + @if (array_key_exists('affected_columns', $audit))
  • @@ -66,6 +67,7 @@

  • + @endif @endforeach
From b6067a5b409fe46780ad87f28ec6cb48c8286e9d Mon Sep 17 00:00:00 2001 From: Sagar Date: Tue, 24 Sep 2024 12:49:29 +0200 Subject: [PATCH 04/47] fix: now the timestamps are auto managed for the pivot table molecule_sample_location --- app/Models/Molecule.php | 2 +- app/Models/SampleLocation.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Models/Molecule.php b/app/Models/Molecule.php index 707e5cb3..1387e7c0 100644 --- a/app/Models/Molecule.php +++ b/app/Models/Molecule.php @@ -129,7 +129,7 @@ public function geo_locations(): BelongsToMany public function sampleLocations(): BelongsToMany { - return $this->belongsToMany(SampleLocation::class); + return $this->belongsToMany(SampleLocation::class)->withTimestamps(); } /** diff --git a/app/Models/SampleLocation.php b/app/Models/SampleLocation.php index c7f64a54..c54ec90e 100644 --- a/app/Models/SampleLocation.php +++ b/app/Models/SampleLocation.php @@ -38,7 +38,7 @@ public function organisms(): HasOne public function molecules(): BelongsToMany { - return $this->belongsToMany(Molecule::class); + return $this->belongsToMany(Molecule::class)->withTimestamps(); } public function transformAudit(array $data): array From 5be9ccb64315a252e7bf5bae8e4c24bcc2494ae0 Mon Sep 17 00:00:00 2001 From: Sagar Date: Wed, 18 Sep 2024 02:00:13 +0200 Subject: [PATCH 05/47] wip: suggested changes are now stored in the reports table. SQL queries need to be built at the time of approving the report --- app/Actions/Coconut/SearchMolecule.php | 1 - .../Dashboard/Resources/CitationResource.php | 88 +------ .../Resources/CollectionResource.php | 3 - .../Resources/GeoLocationResource.php | 7 +- .../Dashboard/Resources/OrganismResource.php | 99 +------- .../Dashboard/Resources/ReportResource.php | 232 +++++++++++++++++- .../ReportResource/Pages/CreateReport.php | 9 + app/Http/Controllers/API/SearchController.php | 4 - app/Models/Citation.php | 91 +++++++ app/Models/GeoLocation.php | 10 + app/Models/Organism.php | 100 ++++++++ app/Models/Report.php | 7 +- 12 files changed, 445 insertions(+), 206 deletions(-) diff --git a/app/Actions/Coconut/SearchMolecule.php b/app/Actions/Coconut/SearchMolecule.php index 9198fb21..c5ee90ad 100644 --- a/app/Actions/Coconut/SearchMolecule.php +++ b/app/Actions/Coconut/SearchMolecule.php @@ -350,7 +350,6 @@ private function executeQuery($statement) $ids_array = collect($hits)->pluck('id')->toArray(); $ids = implode(',', $ids_array); - // dd($ids); if ($ids != '') { diff --git a/app/Filament/Dashboard/Resources/CitationResource.php b/app/Filament/Dashboard/Resources/CitationResource.php index 00776312..28ee9b40 100644 --- a/app/Filament/Dashboard/Resources/CitationResource.php +++ b/app/Filament/Dashboard/Resources/CitationResource.php @@ -6,18 +6,12 @@ use App\Filament\Dashboard\Resources\CitationResource\RelationManagers\CollectionRelationManager; use App\Filament\Dashboard\Resources\CitationResource\RelationManagers\MoleculeRelationManager; use App\Models\Citation; -use Closure; -use Filament\Forms\Components\Section; -use Filament\Forms\Components\Textarea; -use Filament\Forms\Components\TextInput; use Filament\Forms\Form; -use Filament\Forms\Get; use Filament\Resources\Resource; use Filament\Tables; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Table; use Illuminate\Support\Facades\Cache; -use Illuminate\Support\HtmlString; use Tapp\FilamentAuditing\RelationManagers\AuditsRelationManager; class CitationResource extends Resource @@ -35,87 +29,7 @@ class CitationResource extends Resource public static function form(Form $form): Form { return $form - ->schema([ - Section::make() - ->schema([ - TextInput::make('failMessage') - ->default('') - ->hidden() - ->disabled(), - TextInput::make('doi') - ->label('DOI') - ->live(onBlur: true) - ->afterStateUpdated(function ($set, $state) { - if (doiRegxMatch($state)) { - $citationDetails = fetchDOICitation($state); - if ($citationDetails) { - $set('title', $citationDetails['title']); - $set('authors', $citationDetails['authors']); - $set('citation_text', $citationDetails['citation_text']); - $set('failMessage', 'Success'); - } else { - $set('failMessage', 'No citation found. Please fill in the details manually'); - } - } else { - $set('failMessage', 'Invalid DOI'); - } - }) - ->helperText(function ($get) { - - if ($get('failMessage') == 'Fetching') { - return new HtmlString(' - - - '); - } elseif ($get('failMessage') != 'Success') { - return new HtmlString(''.$get('failMessage').''); - } else { - return null; - } - }) - ->required() - ->unique() - ->rules([ - fn (Get $get): Closure => function (string $attribute, $value, Closure $fail) use ($get) { - if ($get('failMessage') != 'No citation found. Please fill in the details manually') { - $fail($get('failMessage')); - } - }, - ]) - ->validationMessages([ - 'unique' => 'The DOI already exists.', - ]), - ]), - - Section::make() - ->schema([ - TextInput::make('title') - ->disabled(function ($get, string $operation) { - if ($operation = 'edit' || $get('failMessage') == 'No citation found. Please fill in the details manually') { - return false; - } else { - return true; - } - }), - TextInput::make('authors') - ->disabled(function ($get, string $operation) { - if ($operation = 'edit' || $get('failMessage') == 'No citation found. Please fill in the details manually') { - return false; - } else { - return true; - } - }), - Textarea::make('citation_text') - ->label('Citation text / URL') - ->disabled(function ($get, string $operation) { - if ($operation = 'edit' || $get('failMessage') == 'No citation found. Please fill in the details manually') { - return false; - } else { - return true; - } - }), - ])->columns(1), - ]); + ->schema(Citation::getForm()); } public static function table(Table $table): Table diff --git a/app/Filament/Dashboard/Resources/CollectionResource.php b/app/Filament/Dashboard/Resources/CollectionResource.php index 500fe6cb..72d72403 100644 --- a/app/Filament/Dashboard/Resources/CollectionResource.php +++ b/app/Filament/Dashboard/Resources/CollectionResource.php @@ -131,9 +131,6 @@ public static function table(Table $table): Table public static function getRelations(): array { - // $record = static::getOwner(); - // dd(static::getOwner()); - // dd(static::$model::molecules()->get()); $arr = [ EntriesRelationManager::class, CitationsRelationManager::class, diff --git a/app/Filament/Dashboard/Resources/GeoLocationResource.php b/app/Filament/Dashboard/Resources/GeoLocationResource.php index 9288ff9c..2e96fcb7 100644 --- a/app/Filament/Dashboard/Resources/GeoLocationResource.php +++ b/app/Filament/Dashboard/Resources/GeoLocationResource.php @@ -5,7 +5,6 @@ use App\Filament\Dashboard\Resources\GeoLocationResource\Pages; use App\Filament\Dashboard\Resources\GeoLocationResource\Widgets\GeoLocationStats; use App\Models\GeoLocation; -use Filament\Forms\Components\TextInput; use Filament\Forms\Form; use Filament\Resources\Resource; use Filament\Tables; @@ -26,11 +25,7 @@ class GeoLocationResource extends Resource public static function form(Form $form): Form { return $form - ->schema([ - TextInput::make('name') - ->required() - ->maxLength(255), - ]); + ->schema(GeoLocation::getForm()); } public static function table(Table $table): Table diff --git a/app/Filament/Dashboard/Resources/OrganismResource.php b/app/Filament/Dashboard/Resources/OrganismResource.php index 2f162e54..9624a38e 100644 --- a/app/Filament/Dashboard/Resources/OrganismResource.php +++ b/app/Filament/Dashboard/Resources/OrganismResource.php @@ -9,8 +9,6 @@ use App\Forms\Components\OrganismsTable; use App\Models\Organism; use Archilex\AdvancedTables\Filters\AdvancedFilter; -use Filament\Forms; -use Filament\Forms\Components\Actions\Action; use Filament\Forms\Components\Grid; use Filament\Forms\Components\Group; use Filament\Forms\Components\Section; @@ -43,102 +41,9 @@ public static function form(Form $form): Form Group::make() ->schema([ Section::make('') - ->schema([ - Forms\Components\TextInput::make('name') - ->required() - ->unique() - ->maxLength(255) - ->suffixAction( - Action::make('infoFromSources') - ->icon('heroicon-m-clipboard') - // ->fillForm(function ($record, callable $get): array { - // $entered_name = $get('name'); - // $name = ucfirst(trim($entered_name)); - // $data = null; - // $iri = null; - // $organism = null; - // $rank = null; - - // if ($name && $name != '') { - // $data = Self::getOLSIRI($name, 'species'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'species'); - // Self::info("Mapped and updated: $name"); - // } else { - // $data = Self::getOLSIRI(explode(' ', $name)[0], 'genus'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'genus'); - // Self::info("Mapped and updated: $name"); - // } else { - // $data = Self::getOLSIRI(explode(' ', $name)[0], 'family'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'genus'); - // Self::info("Mapped and updated: $name"); - // } else { - // [$name, $iri, $organism, $rank] = Self::getGNFMatches($name, $record); - // } - // } - // } - // } - // return [ - // 'name' => $name, - // 'iri' => $iri, - // 'rank' => $rank, - // ]; - // }) - // ->form([ - // Forms\Components\TextInput::make('name')->readOnly(), - // Forms\Components\TextInput::make('iri')->readOnly(), - // Forms\Components\TextInput::make('rank')->readOnly(), - // ]) - // ->action(fn ( $record) => $record->advance()) - ->modalContent(function ($record, $get): View { - $name = ucfirst(trim($get('name'))); - $data = null; - // $iri = null; - // $organism = null; - // $rank = null; - - if ($name && $name != '') { - $data = self::getOLSIRI($name, 'species'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'species'); - // } else { - // $data = Self::getOLSIRI(explode(' ', $name)[0], 'genus'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'genus'); - // } else { - // $data = Self::getOLSIRI(explode(' ', $name)[0], 'family'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'genus'); - // } else { - // [$name, $iri, $organism, $rank] = Self::getGNFMatches($name, $record); - // } - // } - // } - } - - return view( - 'forms.components.organism-info', - [ - 'data' => $data, - ], - ); - }) - ->action(function (array $data, Organism $record): void { - // Self::updateOrganismModel($data['name'], $data['iri'], $record, $data['rank']); - }) - ->slideOver() - ), - Forms\Components\TextInput::make('iri') - ->label('IRI') - ->maxLength(255), - Forms\Components\TextInput::make('rank') - ->maxLength(255), - ]), + ->schema(Organism::getForm()), ]) ->columnSpan(1), - Group::make() ->schema([ Section::make('') @@ -254,7 +159,6 @@ protected static function getGNFMatches($name, $organism) $responseBody = json_decode($response->getBody(), true); return $responseBody; - // dd($responseBody); // if (isset($responseBody['names']) && count($responseBody['names']) > 0) { // $r_name = $responseBody['names'][0]; @@ -293,7 +197,6 @@ protected static function getGNFMatches($name, $organism) protected static function updateOrganismModel($name, $iri, $organism = null, $rank = null) { - // dd($name, $iri, $organism, $rank); if (! $organism) { $organism = Organism::where('name', $name)->first(); } diff --git a/app/Filament/Dashboard/Resources/ReportResource.php b/app/Filament/Dashboard/Resources/ReportResource.php index a26e7ad1..97997f4e 100644 --- a/app/Filament/Dashboard/Resources/ReportResource.php +++ b/app/Filament/Dashboard/Resources/ReportResource.php @@ -5,15 +5,20 @@ use App\Filament\Dashboard\Resources\ReportResource\Pages; use App\Filament\Dashboard\Resources\ReportResource\RelationManagers; use App\Models\Citation; +use App\Models\GeoLocation; use App\Models\Molecule; +use App\Models\Organism; use App\Models\Report; use Archilex\AdvancedTables\Filters\AdvancedFilter; use Filament\Forms\Components\Actions; use Filament\Forms\Components\Actions\Action; use Filament\Forms\Components\Grid; use Filament\Forms\Components\KeyValue; +use Filament\Forms\Components\Repeater; use Filament\Forms\Components\Select; use Filament\Forms\Components\SpatieTagsInput; +use Filament\Forms\Components\Tabs; +use Filament\Forms\Components\TagsInput; use Filament\Forms\Components\Textarea; use Filament\Forms\Components\TextInput; use Filament\Forms\Components\ToggleButtons; @@ -125,11 +130,228 @@ public static function form(Form $form): Form ->hidden(function (Get $get) { return $get('is_change'); }), - KeyValue::make('suggested_changes') - ->hintIcon('heroicon-m-question-mark-circle', tooltip: 'Enter the property (in the left column) and suggested change (in the right column)') - ->addActionLabel('Add property') - ->keyLabel('Property') - ->valueLabel('Suggested change') + // KeyValue::make('suggested_changes') + // ->hintIcon('heroicon-m-question-mark-circle', tooltip: 'Enter the property (in the left column) and suggested change (in the right column)') + // ->addActionLabel('Add property') + // ->keyLabel('Property') + // ->valueLabel('Suggested change') + // ->hidden(function (Get $get) { + // return ! $get('is_change'); + // }), + Tabs::make('Tabs') + ->tabs([ + Tabs\Tab::make('organisms_changes') + ->label('Organisms') + ->schema([ + Repeater::make('organisms_changes') + ->schema([ + Select::make('operation') + ->options([ + 'update' => 'Update', + 'remove' => 'Remove', + 'add' => 'Add', + ]) + ->default('update') + ->live(), + Select::make('organisms') + ->label('Organism') + ->searchable() + ->searchDebounce(500) + ->getSearchResultsUsing(function (string $search, Get $get): array { + return Molecule::where('identifier', $get('../../mol_id_csv'))->get()[0]->organisms()->where('name', 'ilike', "%{$search}%")->limit(10)->pluck('organisms.name', 'organisms.id')->toArray() ?? []; + }) + ->getOptionLabelUsing(fn ($value): ?string => Organism::find($value)?->name) + ->hidden(function (Get $get) { + return $get('operation') == 'add'; + }), + TextInput::make('name') + ->label('Change to') + ->hidden(function (Get $get) { + return $get('operation') != 'update'; + }), + Grid::make('new_organism_details') + ->schema(Organism::getForm())->columns(3) + ->hidden(function (Get $get) { + return $get('operation') != 'add'; + }) + ->columnStart(2), + ]) + ->reorderable(false) + ->columns(4), + + ]), + Tabs\Tab::make('geo_locations_changes') + ->label('Geo Locations') + ->schema([ + Repeater::make('geo_locations_changes') + ->schema([ + Select::make('operation') + ->options([ + 'update' => 'Update', + 'remove' => 'Remove', + 'add' => 'Add', + ]) + ->default('update') + ->live(), + Select::make('geo_locations') + ->label('Geo Location') + ->searchable() + ->searchDebounce(500) + ->getSearchResultsUsing(function (string $search, Get $get): array { + return Molecule::where('identifier', $get('../../mol_id_csv'))->get()[0]->geo_locations()->where('name', 'ilike', "%{$search}%")->limit(10)->pluck('geo_locations.name', 'geo_locations.id')->toArray(); + }) + ->getOptionLabelUsing(fn ($value): ?string => GeoLocation::find($value)?->name) + ->hidden(function (Get $get) { + return $get('operation') == 'add'; + }), + TextInput::make('name') + ->label('Change to') + ->hidden(function (Get $get) { + return $get('operation') != 'update'; + }), + Grid::make('new_geo_locations_details') + ->schema(GeoLocation::getForm())->columns(3) + ->hidden(function (Get $get) { + return $get('operation') != 'add'; + }) + ->columnStart(2), + ]) + ->reorderable(false) + ->columns(4), + ]), + Tabs\Tab::make('synonyms') + ->label('Synonyms') + ->schema([ + Repeater::make('synonyms_changes') + ->schema([ + Select::make('operation') + ->options([ + 'update' => 'Update', + 'remove' => 'Remove', + 'add' => 'Add', + ]) + ->default('update') + ->live(), + Select::make('synonyms') + ->label('Synonym') + ->searchable() + ->searchDebounce(500) + ->getSearchResultsUsing(function (string $search, Get $get): array { + $synonyms = Molecule::select('synonyms')->where('identifier', $get('../../mol_id_csv'))->get()[0]['synonyms']; + $matched_synonyms = []; + foreach ($synonyms as $synonym) { + str_contains(strtolower($synonym), strtolower($search)) ? array_push($matched_synonyms, $synonym) : null; + } + + return $matched_synonyms; + }) + ->hidden(function (Get $get) { + return $get('operation') == 'add'; + }), + TextInput::make('name') + ->label('Change to') + ->hidden(function (Get $get) { + return $get('operation') != 'update'; + }), + Grid::make('new_synonym_details') + ->schema([ + TagsInput::make('new_synonym') + ->label('New Synonym') + ->separator(',') + ->splitKeys([',']), + ])->columns(3) + ->hidden(function (Get $get) { + return $get('operation') != 'add'; + }) + ->columnStart(2), + ]) + ->reorderable(false) + ->columns(4), + ]), + Tabs\Tab::make('identifiers') + ->label('Identifiers') + ->schema([ + Repeater::make('identifiers_changes') + ->schema([ + Select::make('identifer_to_change') + ->options([ + 'name' => 'Name', + 'cas' => 'CAS', + ]) + ->default('name') + ->live(), + Select::make('current_Name') + ->options(function (Get $get): array { + return [Molecule::where('identifier', $get('../../mol_id_csv'))->get()[0]->name ?? '']; + }) + ->default(0) + ->disabled() + ->hidden(function (Get $get) { + return $get('identifer_to_change') == 'cas'; + }), + Select::make('current_CAS') + ->options(function (Get $get): array { + return [Molecule::where('identifier', $get('../../mol_id_csv'))->get()[0]->cas]; + }) + ->default(0) + ->disabled() + ->hidden(function (Get $get) { + return $get('identifer_to_change') == 'name'; + }), + TextInput::make('new_name') + ->label(function (Get $get) { + return $get('identifer_to_change') == 'name' ? 'New Name' : 'New CAS'; + }), + ]) + ->reorderable(false) + ->columns(4), + ]), + Tabs\Tab::make('citations') + ->label('Citations') + ->schema([ + Repeater::make('citations_changes') + ->schema([ + Select::make('operation') + ->options([ + 'update' => 'Update', + 'remove' => 'Remove', + 'add' => 'Add', + ]) + ->default('update') + ->live(), + Select::make('citations') + ->label('Citation') + ->searchable() + ->searchDebounce(500) + ->getSearchResultsUsing(function (string $search, Get $get): array { + return Molecule::where('identifier', $get('../../mol_id_csv'))->get()[0]->citations()->where('title', 'ilike', "%{$search}%")->limit(10)->pluck('citations.title', 'citations.id')->toArray(); + }) + ->getOptionLabelUsing(fn ($value): ?string => Citation::find($value)?->name) + ->hidden(function (Get $get) { + return $get('operation') == 'add'; + }), + TextInput::make('name') + ->label('Change to') + ->hidden(function (Get $get) { + return $get('operation') != 'update'; + }), + Grid::make('new_citation_details') + ->schema(Citation::getForm())->columns(3) + ->hidden(function (Get $get) { + return $get('operation') != 'add'; + }) + ->columnStart(2), + ]) + ->reorderable(false) + ->columns(4), + + ]), + + Tabs\Tab::make('Chemical Classifications') + ->schema([ + // ... + ]), + ]) ->hidden(function (Get $get) { return ! $get('is_change'); }), diff --git a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php index 937c3131..2878f2c6 100644 --- a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php +++ b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php @@ -67,6 +67,15 @@ protected function mutateFormDataBeforeCreate(array $data): array $data['user_id'] = auth()->id(); $data['status'] = 'submitted'; + $suggested_changes = []; + $suggested_changes['organisms_changes'] = $data['organisms_changes']; + $suggested_changes['geo_locations_changes'] = $data['geo_locations_changes']; + $suggested_changes['synonyms_changes'] = $data['synonyms_changes']; + $suggested_changes['identifiers_changes'] = $data['identifiers_changes']; + $suggested_changes['citations_changes'] = $data['citations_changes']; + + $data['suggested_changes'] = $suggested_changes; + return $data; } diff --git a/app/Http/Controllers/API/SearchController.php b/app/Http/Controllers/API/SearchController.php index 8cd31eb8..2a21f544 100644 --- a/app/Http/Controllers/API/SearchController.php +++ b/app/Http/Controllers/API/SearchController.php @@ -19,8 +19,6 @@ public function search(Request $request) $queryType = 'text'; $results = []; - //dd($request); - $limit = $request->query('limit'); $sort = $request->query('sort'); $limit = $limit ? $limit : 24; @@ -218,7 +216,6 @@ public function search(Request $request) $statement = $statement.')'; } $statement = $statement.' LIMIT '.$limit; - // dd($statement ); } else { if ($query) { $query = str_replace("'", "''", $query); @@ -289,7 +286,6 @@ public function search(Request $request) $page ); - //dd($pagination); return $pagination; } catch (QueryException $exception) { $message = $exception->getMessage(); diff --git a/app/Models/Citation.php b/app/Models/Citation.php index 3cc86333..94542b75 100644 --- a/app/Models/Citation.php +++ b/app/Models/Citation.php @@ -2,9 +2,15 @@ namespace App\Models; +use Closure; +use Filament\Forms\Components\Section; +use Filament\Forms\Components\Textarea; +use Filament\Forms\Components\TextInput; +use Filament\Forms\Get; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphToMany; +use Illuminate\Support\HtmlString; use OwenIt\Auditing\Contracts\Auditable; class Citation extends Model implements Auditable @@ -52,4 +58,89 @@ public function transformAudit(array $data): array { return changeAudit($data); } + + public static function getForm() + { + return [ + Section::make() + ->schema([ + TextInput::make('failMessage') + ->default('') + ->hidden() + ->disabled(), + TextInput::make('doi') + ->label('DOI') + ->live(onBlur: true) + ->afterStateUpdated(function ($set, $state) { + if (doiRegxMatch($state)) { + $citationDetails = fetchDOICitation($state); + if ($citationDetails) { + $set('title', $citationDetails['title']); + $set('authors', $citationDetails['authors']); + $set('citation_text', $citationDetails['citation_text']); + $set('failMessage', 'Success'); + } else { + $set('failMessage', 'No citation found. Please fill in the details manually'); + } + } else { + $set('failMessage', 'Invalid DOI'); + } + }) + ->helperText(function ($get) { + + if ($get('failMessage') == 'Fetching') { + return new HtmlString(' + + + '); + } elseif ($get('failMessage') != 'Success') { + return new HtmlString(''.$get('failMessage').''); + } else { + return null; + } + }) + ->required() + ->unique() + ->rules([ + fn (Get $get): Closure => function (string $attribute, $value, Closure $fail) use ($get) { + if ($get('failMessage') != 'No citation found. Please fill in the details manually') { + $fail($get('failMessage')); + } + }, + ]) + ->validationMessages([ + 'unique' => 'The DOI already exists.', + ]), + ]), + + Section::make() + ->schema([ + TextInput::make('title') + ->disabled(function ($get, string $operation) { + if ($operation = 'edit' || $get('failMessage') == 'No citation found. Please fill in the details manually') { + return false; + } else { + return true; + } + }), + TextInput::make('authors') + ->disabled(function ($get, string $operation) { + if ($operation = 'edit' || $get('failMessage') == 'No citation found. Please fill in the details manually') { + return false; + } else { + return true; + } + }), + Textarea::make('citation_text') + ->label('Citation text / URL') + ->disabled(function ($get, string $operation) { + if ($operation = 'edit' || $get('failMessage') == 'No citation found. Please fill in the details manually') { + return false; + } else { + return true; + } + }), + ])->columns(1), + ]; + } } diff --git a/app/Models/GeoLocation.php b/app/Models/GeoLocation.php index 12ae9b35..28bcd5ef 100644 --- a/app/Models/GeoLocation.php +++ b/app/Models/GeoLocation.php @@ -2,6 +2,7 @@ namespace App\Models; +use Filament\Forms\Components\TextInput; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use OwenIt\Auditing\Contracts\Auditable; @@ -29,4 +30,13 @@ public function transformAudit(array $data): array { return changeAudit($data); } + + public static function getForm(): array + { + return [ + TextInput::make('name') + ->required() + ->maxLength(255), + ]; + } } diff --git a/app/Models/Organism.php b/app/Models/Organism.php index 52be6e4d..ad4c09ab 100644 --- a/app/Models/Organism.php +++ b/app/Models/Organism.php @@ -2,6 +2,9 @@ namespace App\Models; +use Filament\Forms; +use Filament\Forms\Components\Actions\Action; +use Illuminate\Contracts\View\View; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsToMany; @@ -51,4 +54,101 @@ public function transformAudit(array $data): array { return changeAudit($data); } + + public static function getForm(): array + { + return [ + Forms\Components\TextInput::make('name') + ->required() + ->unique(Organism::class, 'name') + ->maxLength(255) + ->suffixAction( + Action::make('infoFromSources') + ->icon('heroicon-m-clipboard') + // ->fillForm(function ($record, callable $get): array { + // $entered_name = $get('name'); + // $name = ucfirst(trim($entered_name)); + // $data = null; + // $iri = null; + // $organism = null; + // $rank = null; + + // if ($name && $name != '') { + // $data = Self::getOLSIRI($name, 'species'); + // if ($data) { + // Self::updateOrganismModel($name, $data, $record, 'species'); + // Self::info("Mapped and updated: $name"); + // } else { + // $data = Self::getOLSIRI(explode(' ', $name)[0], 'genus'); + // if ($data) { + // Self::updateOrganismModel($name, $data, $record, 'genus'); + // Self::info("Mapped and updated: $name"); + // } else { + // $data = Self::getOLSIRI(explode(' ', $name)[0], 'family'); + // if ($data) { + // Self::updateOrganismModel($name, $data, $record, 'genus'); + // Self::info("Mapped and updated: $name"); + // } else { + // [$name, $iri, $organism, $rank] = Self::getGNFMatches($name, $record); + // } + // } + // } + // } + // return [ + // 'name' => $name, + // 'iri' => $iri, + // 'rank' => $rank, + // ]; + // }) + // ->form([ + // Forms\Components\TextInput::make('name')->readOnly(), + // Forms\Components\TextInput::make('iri')->readOnly(), + // Forms\Components\TextInput::make('rank')->readOnly(), + // ]) + // ->action(fn ( $record) => $record->advance()) + ->modalContent(function ($record, $get): View { + $name = ucfirst(trim($get('name'))); + $data = null; + // $iri = null; + // $organism = null; + // $rank = null; + + if ($name && $name != '') { + $data = self::getOLSIRI($name, 'species'); + // if ($data) { + // Self::updateOrganismModel($name, $data, $record, 'species'); + // } else { + // $data = Self::getOLSIRI(explode(' ', $name)[0], 'genus'); + // if ($data) { + // Self::updateOrganismModel($name, $data, $record, 'genus'); + // } else { + // $data = Self::getOLSIRI(explode(' ', $name)[0], 'family'); + // if ($data) { + // Self::updateOrganismModel($name, $data, $record, 'genus'); + // } else { + // [$name, $iri, $organism, $rank] = Self::getGNFMatches($name, $record); + // } + // } + // } + } + + return view( + 'forms.components.organism-info', + [ + 'data' => $data, + ], + ); + }) + ->action(function (array $data, Organism $record): void { + // Self::updateOrganismModel($data['name'], $data['iri'], $record, $data['rank']); + }) + ->slideOver() + ), + Forms\Components\TextInput::make('iri') + ->label('IRI') + ->maxLength(255), + Forms\Components\TextInput::make('rank') + ->maxLength(255), + ]; + } } diff --git a/app/Models/Report.php b/app/Models/Report.php index f6e45e66..71793af8 100644 --- a/app/Models/Report.php +++ b/app/Models/Report.php @@ -2,7 +2,6 @@ namespace App\Models; -use App\States\Report\ReportState; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; @@ -38,7 +37,6 @@ class Report extends Model implements Auditable protected $casts = [ 'suggested_changes' => 'array', - // 'status' => ReportState::class, ]; /** @@ -70,6 +68,11 @@ public function organisms(): MorphToMany return $this->morphedByMany(Organism::class, 'reportable'); } + // public function geoLocations(): MorphToMany + // { + // return $this->morphedByMany(Organism::class, 'reportable'); + // } + /** * Get all of the users that are assigned this report. */ From 058d9421681f52a0cd3b54d37d287c99fba642f7 Mon Sep 17 00:00:00 2001 From: Sagar Date: Thu, 26 Sep 2024 17:33:11 +0200 Subject: [PATCH 06/47] feat: improved suggestions by replacing the old key value pairs with tabs that can be approved by curators --- .../Dashboard/Resources/ReportResource.php | 398 ++++++++++++++---- .../ReportResource/Pages/EditReport.php | 11 + .../ReportResource/Pages/ViewReport.php | 11 + ...09_150749_add_columns_on_reports_table.php | 2 +- 4 files changed, 334 insertions(+), 88 deletions(-) diff --git a/app/Filament/Dashboard/Resources/ReportResource.php b/app/Filament/Dashboard/Resources/ReportResource.php index 97997f4e..19ff713f 100644 --- a/app/Filament/Dashboard/Resources/ReportResource.php +++ b/app/Filament/Dashboard/Resources/ReportResource.php @@ -12,8 +12,8 @@ use Archilex\AdvancedTables\Filters\AdvancedFilter; use Filament\Forms\Components\Actions; use Filament\Forms\Components\Actions\Action; +use Filament\Forms\Components\Checkbox; use Filament\Forms\Components\Grid; -use Filament\Forms\Components\KeyValue; use Filament\Forms\Components\Repeater; use Filament\Forms\Components\Select; use Filament\Forms\Components\SpatieTagsInput; @@ -30,6 +30,7 @@ use Filament\Tables\Columns\TextColumn; use Filament\Tables\Table; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Support\Facades\DB; use Illuminate\Support\HtmlString; use Illuminate\Support\Str; use Tapp\FilamentAuditing\RelationManagers\AuditsRelationManager; @@ -62,46 +63,26 @@ public static function form(Form $form): Form ->columnSpan(2), Actions::make([ Action::make('approve') - ->hidden(function (Get $get, string $operation) { - return ! auth()->user()->roles()->exists() || $get('status') == 'rejected' || $get('status') == 'approved' || $operation == 'create'; - }) ->form([ Textarea::make('reason'), ]) - ->action(function (array $data, Report $record, Molecule $molecule, $set): void { - - $record['status'] = 'approved'; - $record['reason'] = $data['reason']; - $record->save(); - - $set('status', 'rejected'); - - if ($record['mol_id_csv'] && ! $record['is_change']) { - $molecule_ids = explode(',', $record['mol_id_csv']); - $molecule = Molecule::whereIn('id', $molecule_ids)->get(); - foreach ($molecule as $mol) { - $mol->active = false; - $mol->save(); - } - } + ->action(function (array $data, Report $record, Molecule $molecule, $set, $livewire): void { + self::approveReport($data, $record, $molecule, $livewire); + $set('status', 'approved'); }), Action::make('reject') ->color('danger') - ->hidden(function (Get $get, string $operation) { - return ! auth()->user()->roles()->exists() || $get('status') == 'rejected' || $get('status') == 'approved' || $operation == 'create'; - }) ->form([ Textarea::make('reason'), ]) ->action(function (array $data, Report $record, $set): void { - - $record['status'] = 'rejected'; - $record['reason'] = $data['reason']; - $record->save(); - + self::rejectReport($data, $record); $set('status', 'rejected'); }), ]) + ->hidden(function (Get $get, string $operation) { + return ! auth()->user()->roles()->exists() || $get('status') == 'rejected' || $get('status') == 'approved' || $operation != 'edit'; + }) ->verticalAlignment(VerticalAlignment::End) ->columnStart(4), ]) @@ -130,21 +111,19 @@ public static function form(Form $form): Form ->hidden(function (Get $get) { return $get('is_change'); }), - // KeyValue::make('suggested_changes') - // ->hintIcon('heroicon-m-question-mark-circle', tooltip: 'Enter the property (in the left column) and suggested change (in the right column)') - // ->addActionLabel('Add property') - // ->keyLabel('Property') - // ->valueLabel('Suggested change') - // ->hidden(function (Get $get) { - // return ! $get('is_change'); - // }), - Tabs::make('Tabs') + Tabs::make('suggested_changes') ->tabs([ Tabs\Tab::make('organisms_changes') ->label('Organisms') ->schema([ Repeater::make('organisms_changes') ->schema([ + Checkbox::make('approve') + ->inline(false) + ->hidden(function (string $operation) { + return ! auth()->user()->roles()->exists() || $operation == 'create'; + }) + ->disabled(false), Select::make('operation') ->options([ 'update' => 'Update', @@ -152,7 +131,8 @@ public static function form(Form $form): Form 'add' => 'Add', ]) ->default('update') - ->live(), + ->live() + ->columnSpan(2), Select::make('organisms') ->label('Organism') ->searchable() @@ -163,12 +143,14 @@ public static function form(Form $form): Form ->getOptionLabelUsing(fn ($value): ?string => Organism::find($value)?->name) ->hidden(function (Get $get) { return $get('operation') == 'add'; - }), + }) + ->columnSpan(2), TextInput::make('name') ->label('Change to') ->hidden(function (Get $get) { return $get('operation') != 'update'; - }), + }) + ->columnSpan(2), Grid::make('new_organism_details') ->schema(Organism::getForm())->columns(3) ->hidden(function (Get $get) { @@ -177,7 +159,7 @@ public static function form(Form $form): Form ->columnStart(2), ]) ->reorderable(false) - ->columns(4), + ->columns(7), ]), Tabs\Tab::make('geo_locations_changes') @@ -185,6 +167,11 @@ public static function form(Form $form): Form ->schema([ Repeater::make('geo_locations_changes') ->schema([ + Checkbox::make('approve') + ->inline(false) + ->hidden(function (string $operation) { + return ! auth()->user()->roles()->exists() || $operation == 'create'; + }), Select::make('operation') ->options([ 'update' => 'Update', @@ -192,7 +179,8 @@ public static function form(Form $form): Form 'add' => 'Add', ]) ->default('update') - ->live(), + ->live() + ->columnSpan(2), Select::make('geo_locations') ->label('Geo Location') ->searchable() @@ -203,12 +191,14 @@ public static function form(Form $form): Form ->getOptionLabelUsing(fn ($value): ?string => GeoLocation::find($value)?->name) ->hidden(function (Get $get) { return $get('operation') == 'add'; - }), + }) + ->columnSpan(2), TextInput::make('name') ->label('Change to') ->hidden(function (Get $get) { return $get('operation') != 'update'; - }), + }) + ->columnSpan(2), Grid::make('new_geo_locations_details') ->schema(GeoLocation::getForm())->columns(3) ->hidden(function (Get $get) { @@ -217,13 +207,18 @@ public static function form(Form $form): Form ->columnStart(2), ]) ->reorderable(false) - ->columns(4), + ->columns(7), ]), Tabs\Tab::make('synonyms') ->label('Synonyms') ->schema([ Repeater::make('synonyms_changes') ->schema([ + Checkbox::make('approve') + ->inline(false) + ->hidden(function (string $operation) { + return ! auth()->user()->roles()->exists() || $operation == 'create'; + }), Select::make('operation') ->options([ 'update' => 'Update', @@ -231,7 +226,8 @@ public static function form(Form $form): Form 'add' => 'Add', ]) ->default('update') - ->live(), + ->live() + ->columnSpan(2), Select::make('synonyms') ->label('Synonym') ->searchable() @@ -239,20 +235,26 @@ public static function form(Form $form): Form ->getSearchResultsUsing(function (string $search, Get $get): array { $synonyms = Molecule::select('synonyms')->where('identifier', $get('../../mol_id_csv'))->get()[0]['synonyms']; $matched_synonyms = []; + $associative_matched_synonyms = []; foreach ($synonyms as $synonym) { str_contains(strtolower($synonym), strtolower($search)) ? array_push($matched_synonyms, $synonym) : null; } + foreach ($matched_synonyms as $item) { + $associative_matched_synonyms[$item] = $item; + } - return $matched_synonyms; + return $associative_matched_synonyms; }) ->hidden(function (Get $get) { return $get('operation') == 'add'; - }), + }) + ->columnSpan(2), TextInput::make('name') ->label('Change to') ->hidden(function (Get $get) { return $get('operation') != 'update'; - }), + }) + ->columnSpan(2), Grid::make('new_synonym_details') ->schema([ TagsInput::make('new_synonym') @@ -266,14 +268,19 @@ public static function form(Form $form): Form ->columnStart(2), ]) ->reorderable(false) - ->columns(4), + ->columns(7), ]), Tabs\Tab::make('identifiers') ->label('Identifiers') ->schema([ Repeater::make('identifiers_changes') ->schema([ - Select::make('identifer_to_change') + Checkbox::make('approve') + ->inline(false) + ->hidden(function (string $operation) { + return ! auth()->user()->roles()->exists() || $operation == 'create'; + }), + Select::make('change') ->options([ 'name' => 'Name', 'cas' => 'CAS', @@ -282,35 +289,63 @@ public static function form(Form $form): Form ->live(), Select::make('current_Name') ->options(function (Get $get): array { - return [Molecule::where('identifier', $get('../../mol_id_csv'))->get()[0]->name ?? '']; + $name = Molecule::where('identifier', $get('../../mol_id_csv'))->first()->name ?? ''; + + return [$name => $name]; }) - ->default(0) - ->disabled() ->hidden(function (Get $get) { - return $get('identifer_to_change') == 'cas'; - }), - Select::make('current_CAS') + return $get('change') == 'cas'; + }) + ->columnSpan(2), + Select::make('operation') + ->options([ + 'update' => 'Update', + 'remove' => 'Remove', + 'add' => 'Add', + ]) + ->default('update') + ->hidden(function (Get $get) { + return $get('change') == 'name'; + }) + ->live() + ->columnSpan(2), + Select::make('current_cas') + ->label('Current CAS') ->options(function (Get $get): array { - return [Molecule::where('identifier', $get('../../mol_id_csv'))->get()[0]->cas]; + $cas_ids = Molecule::where('identifier', $get('../../mol_id_csv'))->first()->cas ?? ''; + $associative_cas_ids = []; + foreach ($cas_ids as $item) { + $associative_cas_ids[$item] = $item; + } + + return $associative_cas_ids; }) - ->default(0) - ->disabled() ->hidden(function (Get $get) { - return $get('identifer_to_change') == 'name'; - }), + return $get('change') == 'name' || $get('operation') == 'add'; + }) + ->columnSpan(2), TextInput::make('new_name') ->label(function (Get $get) { - return $get('identifer_to_change') == 'name' ? 'New Name' : 'New CAS'; - }), + return $get('change') == 'name' ? 'New Name' : 'New CAS'; + }) + ->hidden(function (Get $get) { + return $get('operation') == 'remove'; + }) + ->columnSpan(2), ]) ->reorderable(false) - ->columns(4), + ->columns(7), ]), Tabs\Tab::make('citations') ->label('Citations') ->schema([ Repeater::make('citations_changes') ->schema([ + Checkbox::make('approve') + ->inline(false) + ->hidden(function (string $operation) { + return ! auth()->user()->roles()->exists() || $operation == 'create'; + }), Select::make('operation') ->options([ 'update' => 'Update', @@ -318,7 +353,8 @@ public static function form(Form $form): Form 'add' => 'Add', ]) ->default('update') - ->live(), + ->live() + ->columnSpan(2), Select::make('citations') ->label('Citation') ->searchable() @@ -329,12 +365,14 @@ public static function form(Form $form): Form ->getOptionLabelUsing(fn ($value): ?string => Citation::find($value)?->name) ->hidden(function (Get $get) { return $get('operation') == 'add'; - }), + }) + ->columnSpan(2), TextInput::make('name') ->label('Change to') ->hidden(function (Get $get) { return $get('operation') != 'update'; - }), + }) + ->columnSpan(2), Grid::make('new_citation_details') ->schema(Citation::getForm())->columns(3) ->hidden(function (Get $get) { @@ -343,12 +381,17 @@ public static function form(Form $form): Form ->columnStart(2), ]) ->reorderable(false) - ->columns(4), + ->columns(7), ]), Tabs\Tab::make('Chemical Classifications') ->schema([ + Checkbox::make('approve') + ->inline(false) + ->hidden(function (string $operation) { + return ! auth()->user()->roles()->exists() || $operation == 'create'; + }), // ... ]), ]) @@ -452,6 +495,7 @@ public static function form(Form $form): Form return true; } }) + ->live() ->hidden(function (Get $get, string $operation) { if ($operation != 'create') { return true; @@ -509,20 +553,8 @@ public static function table(Table $table): Table ->form([ Textarea::make('reason'), ]) - ->action(function (array $data, Report $record, Molecule $molecule): void { - - $record['status'] = 'approved'; - $record['reason'] = $data['reason']; - $record->save(); - - if ($record['mol_id_csv'] && ! $record['is_change']) { - $molecule_ids = explode(',', $record['mol_id_csv']); - $molecule = Molecule::whereIn('id', $molecule_ids)->get(); - foreach ($molecule as $mol) { - $mol->active = false; - $mol->save(); - } - } + ->action(function (array $data, Report $record, Molecule $molecule, $livewire): void { + self::approveReport($data, $record, $molecule, $livewire); }), Tables\Actions\Action::make('reject') // ->button() @@ -535,10 +567,7 @@ public static function table(Table $table): Table ]) ->action(function (array $data, Report $record): void { - - $record['status'] = 'rejected'; - $record['reason'] = $data['reason']; - $record->save(); + self::rejectReport($data, $record); }), ]) ->bulkActions([ @@ -578,4 +607,199 @@ public static function getEloquentQuery(): Builder return parent::getEloquentQuery(); } + + public static function approveReport(array $data, Report $record, Molecule $molecule, $livewire): void + { + $record['status'] = 'approved'; + $record['comment'] = $data['reason']; + + // In case of reporting a synthetic molecule, Deactivate Molecules + if ($record['mol_id_csv'] && ! $record['is_change']) { + $molecule_ids = explode(',', $record['mol_id_csv']); + $molecule = Molecule::whereIn('id', $molecule_ids)->get(); + foreach ($molecule as $mol) { + $mol->active = false; + $mol->save(); + } + } + + // In case of Changes, run SQL queries for the approved changes + if ($record['is_change']) { + + // To remove null values from the arrays before we assign them below + // dd(array_map(function($subArray) { + // return array_filter($subArray, function($value) { + // return !is_null($value); + // }); + // }, $livewire->data['organisms_changes'])); + + $suggestedChanges = $record->suggested_changes; + $suggestedChanges['organisms_changes'] = $livewire->data['organisms_changes']; + $suggestedChanges['geo_locations_changes'] = $livewire->data['geo_locations_changes']; + $suggestedChanges['synonyms_changes'] = $livewire->data['synonyms_changes']; + $suggestedChanges['identifiers_changes'] = $livewire->data['identifiers_changes']; + $suggestedChanges['citations_changes'] = $livewire->data['citations_changes']; + $record->suggested_changes = $suggestedChanges; + } + + // Run SQL queries for the approved changes + self::runSQLQueries($record); + + // Save the report record in any case + $record->save(); + } + + public static function rejectReport(array $data, Report $record): void + { + $record['status'] = 'rejected'; + $record['comment'] = $data['reason']; + $record->save(); + } + + public static function runSQLQueries(Report $record): void + { + DB::transaction(function () use ($record) { + // Check if organisms_changes exists and process it + if (isset($record->suggested_changes['organisms_changes'])) { + foreach ($record->suggested_changes['organisms_changes'] as $organism) { + if ($organism['approve'] && $organism['operation'] === 'update' && ! is_null($organism['organisms'])) { + // Perform update only if organisms ID is not null + // --------check if the organism name already exists + // --------need to handle iri and other fields of Organism for authentication + $db_organism = Organism::find($organism['organisms']); + $db_organism->name = $organism['name']; + $db_organism->save(); + } elseif ($organism['approve'] && $organism['operation'] === 'remove' && ! is_null($organism['organisms'])) { + // Perform delete only if organisms ID is not null + $db_organism = Organism::find($organism['organisms']); + $db_organism->delete(); + } elseif ($organism['approve'] && $organism['operation'] === 'add' && ! is_null($organism['name'])) { + // Perform insert only if name is not null (and other required fields can be checked too) + Organism::create([ + 'name' => $organism['name'], + 'iri' => $organism['iri'], + 'rank' => $organism['rank'], + ]); + } + } + } + + // Check if geo_locations_changes exists and process it + if (isset($record->suggested_changes['geo_locations_changes'])) { + foreach ($record->suggested_changes['geo_locations_changes'] as $geo_location) { + if ($geo_location['approve'] && $geo_location['operation'] === 'update' && ! is_null($geo_location['geo_locations'])) { + // Perform update only if geo_locations ID is not null + $db_geo_location = GeoLocation::find($geo_location['geo_locations']); + $db_geo_location->name = $geo_location['name']; + $db_geo_location->save(); + } elseif ($geo_location['approve'] && $geo_location['operation'] === 'remove' && ! is_null($geo_location['geo_locations'])) { + // Perform delete only if geo_locations ID is not null + $db_geo_location = GeoLocation::find($geo_location['geo_locations']); + $db_geo_location->delete(); + } elseif ($geo_location['approve'] && $geo_location['operation'] === 'add' && ! is_null($geo_location['name'])) { + // Perform insert only if name is not null + GeoLocation::create(['name' => $geo_location['name']]); + } + } + } + + // Check if synonyms_changes exists and process it + if (isset($record->suggested_changes['synonyms_changes'])) { + foreach ($record->suggested_changes['synonyms_changes'] as $synonym) { + if ($synonym['approve'] && $synonym['operation'] === 'update' && ! is_null($synonym['synonyms'])) { + // Perform update only if synonym name is not null + $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); + $synonyms = $db_molecule->synonyms; + foreach (array_keys($synonyms, $synonym['synonyms']) as $key) { + $synonyms[$key] = $synonym['name']; + } + $db_molecule->synonyms = $synonyms; + $db_molecule->save(); + } elseif ($synonym['approve'] && $synonym['operation'] === 'remove' && ! is_null($synonym['synonyms'])) { + // Perform delete only if synonym name is not null + $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); + $synonyms = $db_molecule->synonyms; + foreach (array_keys($synonyms, $synonym['synonyms']) as $key) { + unset($synonyms[$key]); + } + $db_molecule->synonyms = $synonyms; + $db_molecule->save(); + } elseif ($synonym['approve'] && $synonym['operation'] === 'add' && ! empty($synonym['new_synonym'])) { + // Perform insert only if new_synonym is not empty + $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); + $synonyms = $db_molecule->synonyms; + $synonyms = array_merge($synonyms, $synonym['new_synonym']); + $db_molecule->synonyms = $synonyms; + $db_molecule->save(); + } + } + } + + // Check if identifiers_changes exists and process it + if (isset($record->suggested_changes['identifiers_changes'])) { + foreach ($record->suggested_changes['identifiers_changes'] as $identifier) { + if ($identifier['approve'] && $identifier['change'] === 'name' && ! is_null($identifier['current_Name']) && ! is_null($identifier['new_name'])) { + // Update name if current name and new name are not null + $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); + $db_molecule->name = $identifier['new_name']; + $db_molecule->save(); + } elseif ($identifier['change'] == 'cas') { + if ($identifier['approve'] && $identifier['operation'] === 'update' && ! is_null($identifier['current_cas']) && ! is_null($identifier['new_name'])) { + // Update CAS if the current CAS and new name is not null + $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); + $cas = $db_molecule->cas; + foreach (array_keys($cas, $identifier['current_cas']) as $key) { + $cas[$key] = $identifier['new_name']; + } + $db_molecule->cas = $cas; + $db_molecule->save(); + } elseif ($identifier['approve'] && $identifier['operation'] === 'remove' && ! is_null($identifier['current_cas'])) { + // Perform delete only if CAS is not null + $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); + $cas = $db_molecule->cas; + foreach (array_keys($cas, $identifier['current_cas']) as $key) { + unset($cas[$key]); + } + $db_molecule->cas = $cas; + $db_molecule->save(); + } elseif ($identifier['approve'] && $identifier['operation'] === 'add' && ! is_null($identifier['new_name'])) { + // Perform insert only if new_name (CAS) is not null + $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); + $cas = $db_molecule->cas; + $cas[] = $identifier['new_name']; + $db_molecule->cas = $cas; + $db_molecule->save(); + } + } + } + } + + // Check if citations_changes exists and process it + if (isset($record->suggested_changes['citations_changes'])) { + foreach ($record->suggested_changes['citations_changes'] as $citation) { + if ($citation['approve'] && $citation['operation'] === 'update' && ! is_null($citation['citations'])) { + // Perform update only if citation ID is not null + $db_citation = Citation::find($citation['citations']); + // $db_citation->doi = $citation['doi']; + $db_citation->title = $citation['name']; + // $db_citation->authors = $citation['authors']; + // $db_citation->citation_text = $citation['citation_text']; + $db_citation->save(); + } elseif ($citation['approve'] && $citation['operation'] === 'remove' && ! is_null($citation['citations'])) { + // Perform delete only if citation ID is not null + $db_citation = Citation::find($citation['citations']); + $db_citation->delete(); + } elseif ($citation['approve'] && $citation['operation'] === 'add' && ! is_null($citation['name'])) { + // Perform insert only if name (citation ID) is not null + $db_citation = new Citation; + $db_citation->doi = $citation['doi']; + $db_citation->title = $citation['title']; + $db_citation->authors = $citation['authors']; + $db_citation->citation_text = $citation['citation_text']; + $db_citation->save(); + } + } + } + }); + } } diff --git a/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php b/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php index faec4f41..5471d32c 100644 --- a/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php +++ b/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php @@ -10,6 +10,17 @@ class EditReport extends EditRecord { protected static string $resource = ReportResource::class; + protected function mutateFormDataBeforeFill(array $data): array + { + $data['organisms_changes'] = $data['suggested_changes']['organisms_changes']; + $data['geo_locations_changes'] = $data['suggested_changes']['geo_locations_changes']; + $data['synonyms_changes'] = $data['suggested_changes']['synonyms_changes']; + $data['identifiers_changes'] = $data['suggested_changes']['identifiers_changes']; + $data['citations_changes'] = $data['suggested_changes']['citations_changes']; + + return $data; + } + protected function getHeaderActions(): array { return [ diff --git a/app/Filament/Dashboard/Resources/ReportResource/Pages/ViewReport.php b/app/Filament/Dashboard/Resources/ReportResource/Pages/ViewReport.php index 379e42c1..6e3966f4 100644 --- a/app/Filament/Dashboard/Resources/ReportResource/Pages/ViewReport.php +++ b/app/Filament/Dashboard/Resources/ReportResource/Pages/ViewReport.php @@ -8,4 +8,15 @@ class ViewReport extends ViewRecord { protected static string $resource = ReportResource::class; + + protected function mutateFormDataBeforeFill(array $data): array + { + $data['organisms_changes'] = $data['suggested_changes']['organisms_changes']; + $data['geo_locations_changes'] = $data['suggested_changes']['geo_locations_changes']; + $data['synonyms_changes'] = $data['suggested_changes']['synonyms_changes']; + $data['identifiers_changes'] = $data['suggested_changes']['identifiers_changes']; + $data['citations_changes'] = $data['suggested_changes']['citations_changes']; + + return $data; + } } diff --git a/database/migrations/2024_09_09_150749_add_columns_on_reports_table.php b/database/migrations/2024_09_09_150749_add_columns_on_reports_table.php index 8ea2e3b4..db442525 100644 --- a/database/migrations/2024_09_09_150749_add_columns_on_reports_table.php +++ b/database/migrations/2024_09_09_150749_add_columns_on_reports_table.php @@ -24,7 +24,7 @@ public function up(): void public function down(): void { Schema::table('reports', function (Blueprint $table) { - $table->dropColumn([ 'query']); + $table->dropColumn(['query']); $table->renameColumn('doi', 'url'); }); } From 716fe435c89f0c67453a0534df6baf03463e2016 Mon Sep 17 00:00:00 2001 From: Sagar Date: Thu, 26 Sep 2024 17:34:17 +0200 Subject: [PATCH 07/47] fix: now the time line shows synonym and cas changes properly --- .../molecule-history-timeline.blade.php | 42 ++++++++++++++----- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/resources/views/livewire/molecule-history-timeline.blade.php b/resources/views/livewire/molecule-history-timeline.blade.php index 27da7e88..702cb219 100644 --- a/resources/views/livewire/molecule-history-timeline.blade.php +++ b/resources/views/livewire/molecule-history-timeline.blade.php @@ -34,26 +34,46 @@ @switch(explode('.',$column_name)[0]) @case('comment') - {{$column_values['new_value'][0]['comment'] ?? 'N/A'}} + {{$column_values['new_value'][0]['comment'] ?? 'N/A'}} @break @case('active') - @if ($column_values['new_value']) - Activated - @else - Deactivated - @endif + @if ($column_values['new_value']) + Activated + @else + Deactivated + @endif @break @case('created') - Initial creation of the compound on COCONUT + Initial creation of the compound on COCONUT @break @case('organisms') @case('sampleLocations') - Detached from:
{{$column_values['old_value']?:'N/A'}}
- Attached to:
{{$column_values['new_value']?:'N/A'}}
+ @if ($column_values['old_value']) + Detached from:
{{$column_values['old_value']?:'N/A'}}
+ @endif + @if ($column_values['new_value']) + Attached to:
{{$column_values['new_value']?:'N/A'}}
+ @endif + @break + @case('synonyms') + @if (array_diff($column_values['old_value'], $column_values['new_value'])) + Removed:
{{implode(', ',array_diff($column_values['old_value'], $column_values['new_value']))}}
+ @endif + @if (array_diff($column_values['new_value'], $column_values['old_value'])) + Added:
{{implode(', ',array_diff($column_values['new_value'], $column_values['old_value']))}}
+ @endif + @break + @case('cas') + @if (array_diff($column_values['old_value'], $column_values['new_value'])) + Removed:
{{implode(', ',array_diff($column_values['old_value'], $column_values['new_value']))}}
+ @endif + @if (array_diff($column_values['new_value'], $column_values['old_value'])) + Added:
{{implode(', ',array_diff($column_values['new_value'], $column_values['old_value']))}}
+ @endif @break @default - Old Value:
{{$column_values['old_value']??'N/A'}}
- New Value:
{{$column_values['new_value']??'N/A'}} + Old Value:
{{$column_values['old_value']??'N/A'}}
+ New Value:
{{$column_values['new_value']??'N/A'}} @endswitch
From d7dbc88fab69478eebc30a6128c795a8c8804f27 Mon Sep 17 00:00:00 2001 From: Sagar Date: Thu, 26 Sep 2024 17:35:19 +0200 Subject: [PATCH 08/47] chore: commented out the slide over (wip) --- app/Models/Organism.php | 159 ++++++++++++++++++++-------------------- 1 file changed, 80 insertions(+), 79 deletions(-) diff --git a/app/Models/Organism.php b/app/Models/Organism.php index ad4c09ab..489d5458 100644 --- a/app/Models/Organism.php +++ b/app/Models/Organism.php @@ -62,88 +62,89 @@ public static function getForm(): array ->required() ->unique(Organism::class, 'name') ->maxLength(255) - ->suffixAction( - Action::make('infoFromSources') - ->icon('heroicon-m-clipboard') - // ->fillForm(function ($record, callable $get): array { - // $entered_name = $get('name'); - // $name = ucfirst(trim($entered_name)); - // $data = null; - // $iri = null; - // $organism = null; - // $rank = null; + // ->suffixAction( + // Action::make('infoFromSources') + // ->icon('heroicon-m-clipboard') + // // ->fillForm(function ($record, callable $get): array { + // // $entered_name = $get('name'); + // // $name = ucfirst(trim($entered_name)); + // // $data = null; + // // $iri = null; + // // $organism = null; + // // $rank = null; - // if ($name && $name != '') { - // $data = Self::getOLSIRI($name, 'species'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'species'); - // Self::info("Mapped and updated: $name"); - // } else { - // $data = Self::getOLSIRI(explode(' ', $name)[0], 'genus'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'genus'); - // Self::info("Mapped and updated: $name"); - // } else { - // $data = Self::getOLSIRI(explode(' ', $name)[0], 'family'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'genus'); - // Self::info("Mapped and updated: $name"); - // } else { - // [$name, $iri, $organism, $rank] = Self::getGNFMatches($name, $record); - // } - // } - // } - // } - // return [ - // 'name' => $name, - // 'iri' => $iri, - // 'rank' => $rank, - // ]; - // }) - // ->form([ - // Forms\Components\TextInput::make('name')->readOnly(), - // Forms\Components\TextInput::make('iri')->readOnly(), - // Forms\Components\TextInput::make('rank')->readOnly(), - // ]) - // ->action(fn ( $record) => $record->advance()) - ->modalContent(function ($record, $get): View { - $name = ucfirst(trim($get('name'))); - $data = null; - // $iri = null; - // $organism = null; - // $rank = null; + // // if ($name && $name != '') { + // // $data = Self::getOLSIRI($name, 'species'); + // // if ($data) { + // // Self::updateOrganismModel($name, $data, $record, 'species'); + // // Self::info("Mapped and updated: $name"); + // // } else { + // // $data = Self::getOLSIRI(explode(' ', $name)[0], 'genus'); + // // if ($data) { + // // Self::updateOrganismModel($name, $data, $record, 'genus'); + // // Self::info("Mapped and updated: $name"); + // // } else { + // // $data = Self::getOLSIRI(explode(' ', $name)[0], 'family'); + // // if ($data) { + // // Self::updateOrganismModel($name, $data, $record, 'genus'); + // // Self::info("Mapped and updated: $name"); + // // } else { + // // [$name, $iri, $organism, $rank] = Self::getGNFMatches($name, $record); + // // } + // // } + // // } + // // } + // // return [ + // // 'name' => $name, + // // 'iri' => $iri, + // // 'rank' => $rank, + // // ]; + // // }) + // // ->form([ + // // Forms\Components\TextInput::make('name')->readOnly(), + // // Forms\Components\TextInput::make('iri')->readOnly(), + // // Forms\Components\TextInput::make('rank')->readOnly(), + // // ]) + // // ->action(fn ( $record) => $record->advance()) + // ->modalContent(function ($record, $get): View { + // $name = ucfirst(trim($get('name'))); + // $data = null; + // // $iri = null; + // // $organism = null; + // // $rank = null; - if ($name && $name != '') { - $data = self::getOLSIRI($name, 'species'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'species'); - // } else { - // $data = Self::getOLSIRI(explode(' ', $name)[0], 'genus'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'genus'); - // } else { - // $data = Self::getOLSIRI(explode(' ', $name)[0], 'family'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'genus'); - // } else { - // [$name, $iri, $organism, $rank] = Self::getGNFMatches($name, $record); - // } - // } - // } - } + // if ($name && $name != '') { + // $data = self::getOLSIRI($name, 'species'); + // // if ($data) { + // // Self::updateOrganismModel($name, $data, $record, 'species'); + // // } else { + // // $data = Self::getOLSIRI(explode(' ', $name)[0], 'genus'); + // // if ($data) { + // // Self::updateOrganismModel($name, $data, $record, 'genus'); + // // } else { + // // $data = Self::getOLSIRI(explode(' ', $name)[0], 'family'); + // // if ($data) { + // // Self::updateOrganismModel($name, $data, $record, 'genus'); + // // } else { + // // [$name, $iri, $organism, $rank] = Self::getGNFMatches($name, $record); + // // } + // // } + // // } + // } - return view( - 'forms.components.organism-info', - [ - 'data' => $data, - ], - ); - }) - ->action(function (array $data, Organism $record): void { - // Self::updateOrganismModel($data['name'], $data['iri'], $record, $data['rank']); - }) - ->slideOver() - ), + // return view( + // 'forms.components.organism-info', + // [ + // 'data' => $data, + // ], + // ); + // }) + // ->action(function (array $data, Organism $record): void { + // // Self::updateOrganismModel($data['name'], $data['iri'], $record, $data['rank']); + // }) + // ->slideOver() + // ) + , Forms\Components\TextInput::make('iri') ->label('IRI') ->maxLength(255), From ff4621b6f87bd0df7cee7dbddd60889aed928a54 Mon Sep 17 00:00:00 2001 From: Sagar Date: Thu, 26 Sep 2024 17:36:04 +0200 Subject: [PATCH 09/47] fix: minor fix related to creating citations --- app/Models/Citation.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Models/Citation.php b/app/Models/Citation.php index 94542b75..61f3d1c4 100644 --- a/app/Models/Citation.php +++ b/app/Models/Citation.php @@ -73,6 +73,7 @@ public static function getForm() ->live(onBlur: true) ->afterStateUpdated(function ($set, $state) { if (doiRegxMatch($state)) { + $set('failMessage', 'Fetching'); $citationDetails = fetchDOICitation($state); if ($citationDetails) { $set('title', $citationDetails['title']); @@ -103,7 +104,7 @@ public static function getForm() ->unique() ->rules([ fn (Get $get): Closure => function (string $attribute, $value, Closure $fail) use ($get) { - if ($get('failMessage') != 'No citation found. Please fill in the details manually') { + if ($get('failMessage') != 'Success') { $fail($get('failMessage')); } }, From 8fef4466365f7ee807d7ea1582a1a4cc10a39065 Mon Sep 17 00:00:00 2001 From: Sagar Date: Sun, 29 Sep 2024 20:04:11 +0200 Subject: [PATCH 10/47] feat: improved the user friendliness (wip) --- .../Dashboard/Resources/ReportResource.php | 47 ++++++++++--------- .../ReportResource/Pages/CreateReport.php | 12 +++++ 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/app/Filament/Dashboard/Resources/ReportResource.php b/app/Filament/Dashboard/Resources/ReportResource.php index 19ff713f..e717152b 100644 --- a/app/Filament/Dashboard/Resources/ReportResource.php +++ b/app/Filament/Dashboard/Resources/ReportResource.php @@ -60,12 +60,18 @@ public static function form(Form $form): Form true => 'Request Changes to Data', ]) ->inline() + ->hidden(function () { + return request()->has('type'); + }) ->columnSpan(2), Actions::make([ Action::make('approve') ->form([ Textarea::make('reason'), ]) + ->hidden(function (Get $get, string $operation) { + return ! auth()->user()->roles()->exists() || $get('status') == 'rejected' || $get('status') == 'approved' || $operation != 'edit'; + }) ->action(function (array $data, Report $record, Molecule $molecule, $set, $livewire): void { self::approveReport($data, $record, $molecule, $livewire); $set('status', 'approved'); @@ -75,14 +81,18 @@ public static function form(Form $form): Form ->form([ Textarea::make('reason'), ]) + ->hidden(function (Get $get, string $operation) { + return ! auth()->user()->roles()->exists() || $get('status') == 'rejected' || $get('status') == 'approved' || $operation != 'edit'; + }) ->action(function (array $data, Report $record, $set): void { self::rejectReport($data, $record); $set('status', 'rejected'); }), + Action::make('viewCompoundPage') + ->color('info') + ->url(fn (): string => env('APP_URL').'/compounds/'.request()->compound_id) + ->openUrlInNewTab(), ]) - ->hidden(function (Get $get, string $operation) { - return ! auth()->user()->roles()->exists() || $get('status') == 'rejected' || $get('status') == 'approved' || $operation != 'edit'; - }) ->verticalAlignment(VerticalAlignment::End) ->columnStart(4), ]) @@ -96,14 +106,15 @@ public static function form(Form $form): Form return getReportTypes(); }) ->hidden(function (string $operation) { - if ($operation == 'create') { - return false; - } else { - return true; - } + return $operation != 'create' || request()->has('type'); }), TextInput::make('title') ->hintIcon('heroicon-m-question-mark-circle', tooltip: 'Title of the report. This is required.') + ->default(function () { + if (request()->type == 'change' && request()->has('compound_id')) { + return 'Request changes'; + } + }) ->required(), Textarea::make('evidence') ->hintIcon('heroicon-m-question-mark-circle', tooltip: 'Please provide Evidence/Comment to support your claims in this report. This will help our Curators in reviewing your report.') @@ -384,16 +395,6 @@ public static function form(Form $form): Form ->columns(7), ]), - - Tabs\Tab::make('Chemical Classifications') - ->schema([ - Checkbox::make('approve') - ->inline(false) - ->hidden(function (string $operation) { - return ! auth()->user()->roles()->exists() || $operation == 'create'; - }), - // ... - ]), ]) ->hidden(function (Get $get) { return ! $get('is_change'); @@ -409,7 +410,10 @@ public static function form(Form $form): Form $state, shouldOpenInNewTab: true, ), - ), + ) + ->hidden(function () { + return request()->has('type') && request()->type == 'change'; + }), Select::make('collections') ->hintIcon('heroicon-m-question-mark-circle', tooltip: 'Select the Collections you want to report. This will help our Curators in reviewing your report.') ->relationship('collections', 'title') @@ -497,9 +501,10 @@ public static function form(Form $form): Form }) ->live() ->hidden(function (Get $get, string $operation) { - if ($operation != 'create') { + if ($operation != 'create' || request()->type == 'change') { return true; - } elseif (! request()->has('compound_id') && $get('report_type') != 'molecule') { + } + if (! request()->has('compound_id') && $get('report_type') != 'molecule') { return true; } }) diff --git a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php index 2878f2c6..f9e0b47d 100644 --- a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php +++ b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php @@ -14,6 +14,18 @@ class CreateReport extends CreateRecord { protected static string $resource = ReportResource::class; + public function getTitle(): string + { + $title = 'Create Report'; + request()->type == 'change' ? $title = 'Request Changes' : $title = 'Report '; + if (request()->has('compound_id')) { + $molecule = Molecule::where('identifier', request()->compound_id)->first(); + $title = $title.' - '.$molecule->name.' ('.$molecule->identifier.')'; + } + + return __($title); + } + protected function afterFill(): void { $request = request(); From 96b2dc80f3abbb0d76a0a911b5d16a49d9502a23 Mon Sep 17 00:00:00 2001 From: Sagar Date: Wed, 2 Oct 2024 01:14:01 +0200 Subject: [PATCH 11/47] feat: the report changes form is made user friendly with pre-filled fields Accordingly changed the actions and eloquent queries. Commented out the table actions for now since they do not allow for approval of changes. --- .../Dashboard/Resources/ReportResource.php | 716 ++++++++---------- 1 file changed, 322 insertions(+), 394 deletions(-) diff --git a/app/Filament/Dashboard/Resources/ReportResource.php b/app/Filament/Dashboard/Resources/ReportResource.php index e717152b..25f001ff 100644 --- a/app/Filament/Dashboard/Resources/ReportResource.php +++ b/app/Filament/Dashboard/Resources/ReportResource.php @@ -13,6 +13,7 @@ use Filament\Forms\Components\Actions; use Filament\Forms\Components\Actions\Action; use Filament\Forms\Components\Checkbox; +use Filament\Forms\Components\Fieldset; use Filament\Forms\Components\Grid; use Filament\Forms\Components\Repeater; use Filament\Forms\Components\Select; @@ -45,6 +46,17 @@ class ReportResource extends Resource protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack'; + protected static $molecule = null; + + protected static $approved_changes = null; + + protected static $overall_changes = null; + + public function __construct() + { + self::$molecule = request()->has('compound_id') ? Molecule::where('identifier', request()->compound_id)->first() : null; + } + public static function form(Form $form): Form { return $form @@ -60,15 +72,19 @@ public static function form(Form $form): Form true => 'Request Changes to Data', ]) ->inline() - ->hidden(function () { - return request()->has('type'); + ->hidden(function (string $operation, $record) { + return $operation == 'create' ? request()->has('type') : true; }) ->columnSpan(2), Actions::make([ Action::make('approve') - ->form([ - Textarea::make('reason'), - ]) + ->form(function ($record, $livewire) { + self::$approved_changes = self::prepareApprovedChanges($record, $livewire); + $key_value_fields = getChangesToDisplayModal(self::$approved_changes); + array_unshift($key_value_fields, Textarea::make('reason')); + + return $key_value_fields; + }) ->hidden(function (Get $get, string $operation) { return ! auth()->user()->roles()->exists() || $get('status') == 'rejected' || $get('status') == 'approved' || $operation != 'edit'; }) @@ -90,7 +106,7 @@ public static function form(Form $form): Form }), Action::make('viewCompoundPage') ->color('info') - ->url(fn (): string => env('APP_URL').'/compounds/'.request()->compound_id) + ->url(fn (string $operation, $record): string => $operation === 'create' ? env('APP_URL').'/compounds/'.request()->compound_id : env('APP_URL').'/compounds/'.$record->mol_id_csv) ->openUrlInNewTab(), ]) ->verticalAlignment(VerticalAlignment::End) @@ -112,7 +128,7 @@ public static function form(Form $form): Form ->hintIcon('heroicon-m-question-mark-circle', tooltip: 'Title of the report. This is required.') ->default(function () { if (request()->type == 'change' && request()->has('compound_id')) { - return 'Request changes'; + return 'Request changes to '.request()->compound_id; } }) ->required(), @@ -124,275 +140,192 @@ public static function form(Form $form): Form }), Tabs::make('suggested_changes') ->tabs([ - Tabs\Tab::make('organisms_changes') - ->label('Organisms') + Tabs\Tab::make('compound_info_changes') + ->label('Compound Info') ->schema([ - Repeater::make('organisms_changes') + Fieldset::make('Geo Locations') ->schema([ - Checkbox::make('approve') + Checkbox::make('approve_geo_locations') + ->label('Approve') ->inline(false) ->hidden(function (string $operation) { return ! auth()->user()->roles()->exists() || $operation == 'create'; }) - ->disabled(false), - Select::make('operation') - ->options([ - 'update' => 'Update', - 'remove' => 'Remove', - 'add' => 'Add', - ]) - ->default('update') - ->live() - ->columnSpan(2), - Select::make('organisms') - ->label('Organism') - ->searchable() - ->searchDebounce(500) - ->getSearchResultsUsing(function (string $search, Get $get): array { - return Molecule::where('identifier', $get('../../mol_id_csv'))->get()[0]->organisms()->where('name', 'ilike', "%{$search}%")->limit(10)->pluck('organisms.name', 'organisms.id')->toArray() ?? []; - }) - ->getOptionLabelUsing(fn ($value): ?string => Organism::find($value)?->name) - ->hidden(function (Get $get) { - return $get('operation') == 'add'; - }) - ->columnSpan(2), - TextInput::make('name') - ->label('Change to') - ->hidden(function (Get $get) { - return $get('operation') != 'update'; - }) - ->columnSpan(2), - Grid::make('new_organism_details') - ->schema(Organism::getForm())->columns(3) - ->hidden(function (Get $get) { - return $get('operation') != 'add'; + ->columnSpan(1), + Select::make('existing_geo_locations') + ->label('Existing') + ->multiple() + ->options(function (): array { + $geo_locations = []; + if (self::$molecule) { + $geo_locations = self::$molecule->geo_locations->pluck('name', 'id')->toArray(); + } + + return $geo_locations; }) - ->columnStart(2), + ->columnSpan(4), + TagsInput::make('new_geo_locations') + ->label('New') + ->separator(',') + ->splitKeys([',']) + ->columnSpan(4), ]) - ->reorderable(false) - ->columns(7), - - ]), - Tabs\Tab::make('geo_locations_changes') - ->label('Geo Locations') - ->schema([ - Repeater::make('geo_locations_changes') + ->columns(9), + Fieldset::make('Synonyms') ->schema([ - Checkbox::make('approve') + Checkbox::make('approve_synonyms') + ->label('Approve') ->inline(false) ->hidden(function (string $operation) { return ! auth()->user()->roles()->exists() || $operation == 'create'; - }), - Select::make('operation') - ->options([ - 'update' => 'Update', - 'remove' => 'Remove', - 'add' => 'Add', - ]) - ->default('update') - ->live() - ->columnSpan(2), - Select::make('geo_locations') - ->label('Geo Location') - ->searchable() - ->searchDebounce(500) - ->getSearchResultsUsing(function (string $search, Get $get): array { - return Molecule::where('identifier', $get('../../mol_id_csv'))->get()[0]->geo_locations()->where('name', 'ilike', "%{$search}%")->limit(10)->pluck('geo_locations.name', 'geo_locations.id')->toArray(); }) - ->getOptionLabelUsing(fn ($value): ?string => GeoLocation::find($value)?->name) - ->hidden(function (Get $get) { - return $get('operation') == 'add'; - }) - ->columnSpan(2), - TextInput::make('name') - ->label('Change to') - ->hidden(function (Get $get) { - return $get('operation') != 'update'; - }) - ->columnSpan(2), - Grid::make('new_geo_locations_details') - ->schema(GeoLocation::getForm())->columns(3) - ->hidden(function (Get $get) { - return $get('operation') != 'add'; + ->columnSpan(1), + Select::make('existing_synonyms') + ->label('Existing') + ->multiple() + ->options(function (): array { + $synonyms = []; + if (self::$molecule) { + $synonyms = self::$molecule->synonyms; + } + + return $synonyms; }) - ->columnStart(2), + ->columnSpan(4), + TagsInput::make('new_synonyms') + ->label('New') + ->separator(',') + ->splitKeys([',']) + ->columnSpan(4), ]) - ->reorderable(false) - ->columns(7), - ]), - Tabs\Tab::make('synonyms') - ->label('Synonyms') - ->schema([ - Repeater::make('synonyms_changes') + ->columns(9), + Fieldset::make('Name') ->schema([ - Checkbox::make('approve') + Checkbox::make('approve_name') + ->label('Approve') ->inline(false) ->hidden(function (string $operation) { return ! auth()->user()->roles()->exists() || $operation == 'create'; - }), - Select::make('operation') - ->options([ - 'update' => 'Update', - 'remove' => 'Remove', - 'add' => 'Add', - ]) - ->default('update') - ->live() - ->columnSpan(2), - Select::make('synonyms') - ->label('Synonym') - ->searchable() - ->searchDebounce(500) - ->getSearchResultsUsing(function (string $search, Get $get): array { - $synonyms = Molecule::select('synonyms')->where('identifier', $get('../../mol_id_csv'))->get()[0]['synonyms']; - $matched_synonyms = []; - $associative_matched_synonyms = []; - foreach ($synonyms as $synonym) { - str_contains(strtolower($synonym), strtolower($search)) ? array_push($matched_synonyms, $synonym) : null; - } - foreach ($matched_synonyms as $item) { - $associative_matched_synonyms[$item] = $item; - } - - return $associative_matched_synonyms; }) - ->hidden(function (Get $get) { - return $get('operation') == 'add'; + ->columnSpan(1), + Textarea::make('name') + ->default(function () { + if (self::$molecule) { + return self::$molecule->name; + } }) - ->columnSpan(2), - TextInput::make('name') - ->label('Change to') - ->hidden(function (Get $get) { - return $get('operation') != 'update'; + ->columnSpan(4), + ]) + ->columns(9), + Fieldset::make('CAS') + ->schema([ + Checkbox::make('approve_cas') + ->label('Approve') + ->inline(false) + ->hidden(function (string $operation) { + return ! auth()->user()->roles()->exists() || $operation == 'create'; }) - ->columnSpan(2), - Grid::make('new_synonym_details') - ->schema([ - TagsInput::make('new_synonym') - ->label('New Synonym') - ->separator(',') - ->splitKeys([',']), - ])->columns(3) - ->hidden(function (Get $get) { - return $get('operation') != 'add'; + ->columnSpan(1), + Select::make('existing_cas') + ->label('Existing') + ->multiple() + ->options(function () { + if (self::$molecule) { + return self::$molecule->cas; + } }) - ->columnStart(2), + ->columnSpan(4), + TagsInput::make('new_cas') + ->label('New') + ->separator(',') + ->splitKeys([',']) + ->columnSpan(4), ]) - ->reorderable(false) - ->columns(7), + ->columns(9), ]), - Tabs\Tab::make('identifiers') - ->label('Identifiers') + Tabs\Tab::make('organisms_changes') + ->label('Organisms') ->schema([ - Repeater::make('identifiers_changes') + Fieldset::make('Organisms') ->schema([ - Checkbox::make('approve') - ->inline(false) + Checkbox::make('approve_existing_organisms') + ->label('Approve') ->hidden(function (string $operation) { return ! auth()->user()->roles()->exists() || $operation == 'create'; - }), - Select::make('change') - ->options([ - 'name' => 'Name', - 'cas' => 'CAS', - ]) - ->default('name') - ->live(), - Select::make('current_Name') - ->options(function (Get $get): array { - $name = Molecule::where('identifier', $get('../../mol_id_csv'))->first()->name ?? ''; - - return [$name => $name]; }) - ->hidden(function (Get $get) { - return $get('change') == 'cas'; - }) - ->columnSpan(2), - Select::make('operation') - ->options([ - 'update' => 'Update', - 'remove' => 'Remove', - 'add' => 'Add', - ]) - ->default('update') - ->hidden(function (Get $get) { - return $get('change') == 'name'; - }) - ->live() - ->columnSpan(2), - Select::make('current_cas') - ->label('Current CAS') - ->options(function (Get $get): array { - $cas_ids = Molecule::where('identifier', $get('../../mol_id_csv'))->first()->cas ?? ''; - $associative_cas_ids = []; - foreach ($cas_ids as $item) { - $associative_cas_ids[$item] = $item; + ->columnSpanFull(), + Select::make('existing_organisms') + ->label('Existing') + ->multiple() + ->options(function () { + if (self::$molecule) { + return self::$molecule->organisms->pluck('name', 'id')->toArray(); } - - return $associative_cas_ids; }) ->hidden(function (Get $get) { - return $get('change') == 'name' || $get('operation') == 'add'; - }) - ->columnSpan(2), - TextInput::make('new_name') - ->label(function (Get $get) { - return $get('change') == 'name' ? 'New Name' : 'New CAS'; + return $get('operation') == 'add'; }) - ->hidden(function (Get $get) { - return $get('operation') == 'remove'; + ->columnSpan(9), + ]) + ->columns(9), + + Repeater::make('new_organisms') + ->label('') + ->schema([ + Checkbox::make('approve_new_organism') + ->label('Approve') + ->hidden(function (string $operation) { + return ! auth()->user()->roles()->exists() || $operation == 'create'; }) - ->columnSpan(2), + ->disabled(false) + ->columnSpanFull(), + Grid::make('new_organism') + ->schema(Organism::getForm())->columns(4), ]) ->reorderable(false) - ->columns(7), + ->addActionLabel('Add New Organism') + ->defaultItems(0) + ->columns(9), + ]), Tabs\Tab::make('citations') ->label('Citations') ->schema([ - Repeater::make('citations_changes') + Fieldset::make('Citations') ->schema([ - Checkbox::make('approve') - ->inline(false) + Checkbox::make('approve_existing_citations') + ->label('Approve') ->hidden(function (string $operation) { return ! auth()->user()->roles()->exists() || $operation == 'create'; - }), - Select::make('operation') - ->options([ - 'update' => 'Update', - 'remove' => 'Remove', - 'add' => 'Add', - ]) - ->default('update') - ->live() - ->columnSpan(2), - Select::make('citations') - ->label('Citation') - ->searchable() - ->searchDebounce(500) - ->getSearchResultsUsing(function (string $search, Get $get): array { - return Molecule::where('identifier', $get('../../mol_id_csv'))->get()[0]->citations()->where('title', 'ilike', "%{$search}%")->limit(10)->pluck('citations.title', 'citations.id')->toArray(); - }) - ->getOptionLabelUsing(fn ($value): ?string => Citation::find($value)?->name) - ->hidden(function (Get $get) { - return $get('operation') == 'add'; }) - ->columnSpan(2), - TextInput::make('name') - ->label('Change to') - ->hidden(function (Get $get) { - return $get('operation') != 'update'; + ->columnSpanFull(), + Select::make('existing_citations') + ->label('Existing') + ->multiple() + ->options(function () { + if (self::$molecule) { + return self::$molecule->citations->where('title', '!=', null)->pluck('title', 'id')->toArray(); + } }) - ->columnSpan(2), - Grid::make('new_citation_details') - ->schema(Citation::getForm())->columns(3) - ->hidden(function (Get $get) { - return $get('operation') != 'add'; + ->columnSpan(9), + ]) + ->columns(9), + Repeater::make('new_citations') + ->label('') + ->schema([ + Checkbox::make('approve_new_citation') + ->label('Approve') + ->hidden(function (string $operation) { + return ! auth()->user()->roles()->exists() || $operation == 'create'; }) - ->columnStart(2), + ->columnSpanFull(), + Grid::make('new_citation') + ->schema(Citation::getForm())->columns(4), ]) ->reorderable(false) - ->columns(7), + ->addActionLabel('Add New Citation') + ->defaultItems(0) + ->columns(9), ]), ]) @@ -411,8 +344,8 @@ public static function form(Form $form): Form shouldOpenInNewTab: true, ), ) - ->hidden(function () { - return request()->has('type') && request()->type == 'change'; + ->hidden(function (string $operation, $record) { + return $operation == 'create' ? request()->has('type') && request()->type == 'change' : $record->is_change; }), Select::make('collections') ->hintIcon('heroicon-m-question-mark-circle', tooltip: 'Select the Collections you want to report. This will help our Curators in reviewing your report.') @@ -550,30 +483,30 @@ public static function table(Table $table): Table ->visible(function ($record) { return auth()->user()->roles()->exists() && $record['status'] == 'submitted'; }), - Tables\Actions\Action::make('approve') - // ->button() - ->hidden(function (Report $record) { - return ! auth()->user()->roles()->exists() || $record['status'] == 'draft' || $record['status'] == 'rejected' || $record['status'] == 'approved'; - }) - ->form([ - Textarea::make('reason'), - ]) - ->action(function (array $data, Report $record, Molecule $molecule, $livewire): void { - self::approveReport($data, $record, $molecule, $livewire); - }), - Tables\Actions\Action::make('reject') - // ->button() - ->color('danger') - ->hidden(function (Report $record) { - return ! auth()->user()->roles()->exists() || $record['status'] == 'draft' || $record['status'] == 'rejected' || $record['status'] == 'approved'; - }) - ->form([ - Textarea::make('reason'), - - ]) - ->action(function (array $data, Report $record): void { - self::rejectReport($data, $record); - }), + // Tables\Actions\Action::make('approve') + // // ->button() + // ->hidden(function (Report $record) { + // return ! auth()->user()->roles()->exists() || $record['status'] == 'draft' || $record['status'] == 'rejected' || $record['status'] == 'approved'; + // }) + // ->form([ + // Textarea::make('reason'), + // ]) + // ->action(function (array $data, Report $record, Molecule $molecule, $livewire): void { + // self::approveReport($data, $record, $molecule, $livewire); + // }), + // Tables\Actions\Action::make('reject') + // // ->button() + // ->color('danger') + // ->hidden(function (Report $record) { + // return ! auth()->user()->roles()->exists() || $record['status'] == 'draft' || $record['status'] == 'rejected' || $record['status'] == 'approved'; + // }) + // ->form([ + // Textarea::make('reason'), + + // ]) + // ->action(function (array $data, Report $record): void { + // self::rejectReport($data, $record); + // }), ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ @@ -613,10 +546,9 @@ public static function getEloquentQuery(): Builder return parent::getEloquentQuery(); } - public static function approveReport(array $data, Report $record, Molecule $molecule, $livewire): void + public static function prepareApprovedChanges(Report $record, $livewire) { - $record['status'] = 'approved'; - $record['comment'] = $data['reason']; + $approved_changes = []; // In case of reporting a synthetic molecule, Deactivate Molecules if ($record['mol_id_csv'] && ! $record['is_change']) { @@ -629,27 +561,67 @@ public static function approveReport(array $data, Report $record, Molecule $mole } // In case of Changes, run SQL queries for the approved changes + $approved_changes['mol_id_csv'] = $record['mol_id_csv']; if ($record['is_change']) { - // To remove null values from the arrays before we assign them below - // dd(array_map(function($subArray) { - // return array_filter($subArray, function($value) { - // return !is_null($value); - // }); - // }, $livewire->data['organisms_changes'])); - - $suggestedChanges = $record->suggested_changes; - $suggestedChanges['organisms_changes'] = $livewire->data['organisms_changes']; - $suggestedChanges['geo_locations_changes'] = $livewire->data['geo_locations_changes']; - $suggestedChanges['synonyms_changes'] = $livewire->data['synonyms_changes']; - $suggestedChanges['identifiers_changes'] = $livewire->data['identifiers_changes']; - $suggestedChanges['citations_changes'] = $livewire->data['citations_changes']; - $record->suggested_changes = $suggestedChanges; + if ($livewire->data['approve_geo_locations']) { + $approved_changes['existing_geo_locations'] = $livewire->data['existing_geo_locations']; + $approved_changes['new_geo_locations'] = $livewire->data['new_geo_locations']; + } + + if ($livewire->data['approve_synonyms']) { + $approved_changes['existing_synonyms'] = $livewire->data['existing_synonyms']; + $approved_changes['new_synonyms'] = $livewire->data['new_synonyms']; + } + + if ($livewire->data['approve_name']) { + $approved_changes['name'] = $livewire->data['name']; + } + + if ($livewire->data['approve_cas']) { + $approved_changes['existing_cas'] = $livewire->data['existing_cas']; + $approved_changes['new_cas'] = $livewire->data['new_cas']; + } + + if ($livewire->data['approve_existing_organisms']) { + $approved_changes['existing_organisms'] = $livewire->data['existing_organisms']; + } + if (count($livewire->data['new_organisms']) > 0) { + foreach ($livewire->data['new_organisms'] as $key => $organism) { + if ($organism['approve_new_organism']) { + $approved_changes['new_organisms'][] = $organism; + } + } + } + + if ($livewire->data['approve_existing_citations']) { + $approved_changes['existing_citations'] = $livewire->data['existing_citations']; + } + if (count($livewire->data['new_citations']) > 0) { + foreach ($livewire->data['new_citations'] as $key => $citation) { + if ($citation['approve_new_citation']) { + $approved_changes['new_citations'][] = $citation; + } + } + } } + return $approved_changes; + } + + public static function approveReport(array $data, Report $record, Molecule $molecule, $livewire): void + { + // dd($data, $record, $molecule, $livewire); // Run SQL queries for the approved changes self::runSQLQueries($record); + $suggested_changes = $record['suggested_changes']; + + $suggested_changes['approved_changes'] = self::$overall_changes; + $record['suggested_changes'] = $suggested_changes; + $record['comment'] = $data['reason']; + $record['status'] = 'approved'; + // Save the report record in any case $record->save(); } @@ -664,147 +636,103 @@ public static function rejectReport(array $data, Report $record): void public static function runSQLQueries(Report $record): void { DB::transaction(function () use ($record) { - // Check if organisms_changes exists and process it - if (isset($record->suggested_changes['organisms_changes'])) { - foreach ($record->suggested_changes['organisms_changes'] as $organism) { - if ($organism['approve'] && $organism['operation'] === 'update' && ! is_null($organism['organisms'])) { - // Perform update only if organisms ID is not null - // --------check if the organism name already exists - // --------need to handle iri and other fields of Organism for authentication - $db_organism = Organism::find($organism['organisms']); - $db_organism->name = $organism['name']; - $db_organism->save(); - } elseif ($organism['approve'] && $organism['operation'] === 'remove' && ! is_null($organism['organisms'])) { - // Perform delete only if organisms ID is not null - $db_organism = Organism::find($organism['organisms']); - $db_organism->delete(); - } elseif ($organism['approve'] && $organism['operation'] === 'add' && ! is_null($organism['name'])) { - // Perform insert only if name is not null (and other required fields can be checked too) - Organism::create([ - 'name' => $organism['name'], - 'iri' => $organism['iri'], - 'rank' => $organism['rank'], - ]); + self::$overall_changes = getOverallChanges(self::$approved_changes); + // dd(self::$overall_changes); + + // Check if 'molecule_id' is provided or use a default molecule for association/dissociation + $molecule = Molecule::where('identifier', $record['mol_id_csv'])->first(); + + // Apply Geo Location Changes + if (array_key_exists('geo_location_changes', self::$overall_changes)) { + if (! empty(self::$overall_changes['geo_location_changes']['delete'])) { + $detachable_geo_locations_ids = GeoLocation::whereIn('name', self::$overall_changes['geo_location_changes']['delete'])->pluck('id')->toArray(); + $molecule->auditDetach('geo_locations', $detachable_geo_locations_ids); + } + if (! empty(self::$overall_changes['geo_location_changes']['add'])) { + $geoLocations = explode(',', self::$overall_changes['geo_location_changes']['add']); + foreach ($geoLocations as $newLocation) { + $geo_location = GeoLocation::firstOrCreate(['name' => $newLocation]); + $molecule->auditAttach('geo_locations', $geo_location); } } } - // Check if geo_locations_changes exists and process it - if (isset($record->suggested_changes['geo_locations_changes'])) { - foreach ($record->suggested_changes['geo_locations_changes'] as $geo_location) { - if ($geo_location['approve'] && $geo_location['operation'] === 'update' && ! is_null($geo_location['geo_locations'])) { - // Perform update only if geo_locations ID is not null - $db_geo_location = GeoLocation::find($geo_location['geo_locations']); - $db_geo_location->name = $geo_location['name']; - $db_geo_location->save(); - } elseif ($geo_location['approve'] && $geo_location['operation'] === 'remove' && ! is_null($geo_location['geo_locations'])) { - // Perform delete only if geo_locations ID is not null - $db_geo_location = GeoLocation::find($geo_location['geo_locations']); - $db_geo_location->delete(); - } elseif ($geo_location['approve'] && $geo_location['operation'] === 'add' && ! is_null($geo_location['name'])) { - // Perform insert only if name is not null - GeoLocation::create(['name' => $geo_location['name']]); - } + // Apply Synonym Changes + if (array_key_exists('synonym_changes', self::$overall_changes)) { + $db_synonyms = $molecule->synonyms; + if (! empty(self::$overall_changes['synonym_changes']['delete'])) { + $db_synonyms = array_diff($db_synonyms, self::$overall_changes['synonym_changes']['delete']); + $molecule->synonyms = $db_synonyms; + } + if (! empty(self::$overall_changes['synonym_changes']['add'])) { + $synonyms = explode(',', self::$overall_changes['synonym_changes']['add']); + $db_synonyms = array_merge($db_synonyms, $synonyms); + $molecule->synonyms = $db_synonyms; } } - // Check if synonyms_changes exists and process it - if (isset($record->suggested_changes['synonyms_changes'])) { - foreach ($record->suggested_changes['synonyms_changes'] as $synonym) { - if ($synonym['approve'] && $synonym['operation'] === 'update' && ! is_null($synonym['synonyms'])) { - // Perform update only if synonym name is not null - $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); - $synonyms = $db_molecule->synonyms; - foreach (array_keys($synonyms, $synonym['synonyms']) as $key) { - $synonyms[$key] = $synonym['name']; - } - $db_molecule->synonyms = $synonyms; - $db_molecule->save(); - } elseif ($synonym['approve'] && $synonym['operation'] === 'remove' && ! is_null($synonym['synonyms'])) { - // Perform delete only if synonym name is not null - $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); - $synonyms = $db_molecule->synonyms; - foreach (array_keys($synonyms, $synonym['synonyms']) as $key) { - unset($synonyms[$key]); - } - $db_molecule->synonyms = $synonyms; - $db_molecule->save(); - } elseif ($synonym['approve'] && $synonym['operation'] === 'add' && ! empty($synonym['new_synonym'])) { - // Perform insert only if new_synonym is not empty - $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); - $synonyms = $db_molecule->synonyms; - $synonyms = array_merge($synonyms, $synonym['new_synonym']); - $db_molecule->synonyms = $synonyms; - $db_molecule->save(); - } + // Apply Name Changes + if (array_key_exists('name_change', self::$overall_changes)) { + $molecule->name = self::$overall_changes['name_change']['new']; + $molecule->save(); + $molecule->refresh(); + } + + // Apply CAS Changes + if (array_key_exists('cas_changes', self::$overall_changes)) { + $db_cas = $molecule->cas; + if (! empty(self::$overall_changes['cas_changes']['delete'])) { + $db_cas = array_diff($db_cas, self::$overall_changes['cas_changes']['delete']); + $molecule->cas = $db_cas; + } + if (! empty(self::$overall_changes['cas_changes']['add'])) { + $cas = explode(',', self::$overall_changes['cas_changes']['add']); + $db_cas = array_merge($db_cas, $cas); + $molecule->cas = $db_cas; } } - // Check if identifiers_changes exists and process it - if (isset($record->suggested_changes['identifiers_changes'])) { - foreach ($record->suggested_changes['identifiers_changes'] as $identifier) { - if ($identifier['approve'] && $identifier['change'] === 'name' && ! is_null($identifier['current_Name']) && ! is_null($identifier['new_name'])) { - // Update name if current name and new name are not null - $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); - $db_molecule->name = $identifier['new_name']; - $db_molecule->save(); - } elseif ($identifier['change'] == 'cas') { - if ($identifier['approve'] && $identifier['operation'] === 'update' && ! is_null($identifier['current_cas']) && ! is_null($identifier['new_name'])) { - // Update CAS if the current CAS and new name is not null - $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); - $cas = $db_molecule->cas; - foreach (array_keys($cas, $identifier['current_cas']) as $key) { - $cas[$key] = $identifier['new_name']; - } - $db_molecule->cas = $cas; - $db_molecule->save(); - } elseif ($identifier['approve'] && $identifier['operation'] === 'remove' && ! is_null($identifier['current_cas'])) { - // Perform delete only if CAS is not null - $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); - $cas = $db_molecule->cas; - foreach (array_keys($cas, $identifier['current_cas']) as $key) { - unset($cas[$key]); - } - $db_molecule->cas = $cas; - $db_molecule->save(); - } elseif ($identifier['approve'] && $identifier['operation'] === 'add' && ! is_null($identifier['new_name'])) { - // Perform insert only if new_name (CAS) is not null - $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); - $cas = $db_molecule->cas; - $cas[] = $identifier['new_name']; - $db_molecule->cas = $cas; - $db_molecule->save(); - } + // Apply Organism Changes: Dissociate from Molecule + if (array_key_exists('organism_changes', self::$overall_changes)) { + if (! empty(self::$overall_changes['organism_changes']['delete'])) { + $organismIds = Organism::whereIn('name', self::$overall_changes['organism_changes']['delete'])->pluck('id')->toArray(); + $molecule->auditDetach('organisms', $organismIds); + } + if (! empty(self::$overall_changes['organism_changes']['add'])) { + foreach (self::$overall_changes['organism_changes']['add'] as $newOrganism) { + $organism = Organism::firstOrCreate([ + 'name' => $newOrganism['name'], + 'iri' => $newOrganism['iri'], + 'rank' => $newOrganism['rank'], + 'molecule_count' => 1, + 'slug' => Str::slug($newOrganism['name']), + ]); + $molecule->auditAttach('organisms', $organism); } } } - // Check if citations_changes exists and process it - if (isset($record->suggested_changes['citations_changes'])) { - foreach ($record->suggested_changes['citations_changes'] as $citation) { - if ($citation['approve'] && $citation['operation'] === 'update' && ! is_null($citation['citations'])) { - // Perform update only if citation ID is not null - $db_citation = Citation::find($citation['citations']); - // $db_citation->doi = $citation['doi']; - $db_citation->title = $citation['name']; - // $db_citation->authors = $citation['authors']; - // $db_citation->citation_text = $citation['citation_text']; - $db_citation->save(); - } elseif ($citation['approve'] && $citation['operation'] === 'remove' && ! is_null($citation['citations'])) { - // Perform delete only if citation ID is not null - $db_citation = Citation::find($citation['citations']); - $db_citation->delete(); - } elseif ($citation['approve'] && $citation['operation'] === 'add' && ! is_null($citation['name'])) { - // Perform insert only if name (citation ID) is not null - $db_citation = new Citation; - $db_citation->doi = $citation['doi']; - $db_citation->title = $citation['title']; - $db_citation->authors = $citation['authors']; - $db_citation->citation_text = $citation['citation_text']; - $db_citation->save(); + // Apply Citation Changes: Dissociate from Molecule + if (array_key_exists('citation_changes', self::$overall_changes)) { + if (! empty(self::$overall_changes['citation_changes']['delete'])) { + $citations = Citation::whereIn('title', self::$overall_changes['citation_changes']['delete'])->get(); + $citationIds = $citations->pluck('id')->toArray(); + $molecule->auditDetach('citations', $citationIds); + } + if (! empty(self::$overall_changes['citation_changes']['add'])) { + foreach (self::$overall_changes['citation_changes']['add'] as $newCitation) { + $citation = Citation::firstOrCreate([ + 'doi' => $newCitation['doi'], + 'title' => $newCitation['title'], + 'authors' => $newCitation['authors'], + 'citation_text' => $newCitation['citation_text'], + ]); + $molecule->auditAttach('citations', $citation); } } } + + $molecule->save(); }); } } From 2c1149ff90d1ee831b2a4e200eb2a52e06c9b353 Mon Sep 17 00:00:00 2001 From: Sagar Date: Wed, 2 Oct 2024 01:16:16 +0200 Subject: [PATCH 12/47] feat: enabled create time pop-up modal to display overall changes being requested The data structure of suggested changes is altered to suit the needs. --- .../ReportResource/Pages/CreateReport.php | 76 ++++++++++++++++--- 1 file changed, 67 insertions(+), 9 deletions(-) diff --git a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php index f9e0b47d..53cfb665 100644 --- a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php +++ b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php @@ -8,30 +8,46 @@ use App\Models\Collection; use App\Models\Molecule; use App\Models\Organism; +use Filament\Actions\Action; use Filament\Resources\Pages\CreateRecord; class CreateReport extends CreateRecord { protected static string $resource = ReportResource::class; + protected $molecule; + public function getTitle(): string { $title = 'Create Report'; request()->type == 'change' ? $title = 'Request Changes' : $title = 'Report '; if (request()->has('compound_id')) { - $molecule = Molecule::where('identifier', request()->compound_id)->first(); - $title = $title.' - '.$molecule->name.' ('.$molecule->identifier.')'; + $title = $title.' - '.$this->molecule->name.' ('.$this->molecule->identifier.')'; } return __($title); } + protected function beforeFill(): void + { + if (request()->has('compound_id')) { + $this->molecule = Molecule::where('identifier', request()->compound_id)->first(); + } + } + protected function afterFill(): void { $request = request(); + $this->data['compound_id'] = $request->compound_id; if ($request->type == 'change') { $this->data['is_change'] = true; + $this->data['existing_geo_locations'] = $this->molecule->geo_locations->pluck('name')->toArray(); + $this->data['existing_synonyms'] = $this->molecule->synonyms; + $this->data['existing_cas'] = array_values($this->molecule->cas); + $this->data['existing_organisms'] = $this->molecule->organisms->pluck('name')->toArray(); + $this->data['existing_citations'] = $this->molecule->citations->where('title', '!=', null)->pluck('title')->toArray(); } + if ($request->has('collection_uuid')) { $collection = Collection::where('uuid', $request->collection_uuid)->get(); $id = $collection[0]->id; @@ -79,14 +95,40 @@ protected function mutateFormDataBeforeCreate(array $data): array $data['user_id'] = auth()->id(); $data['status'] = 'submitted'; - $suggested_changes = []; - $suggested_changes['organisms_changes'] = $data['organisms_changes']; - $suggested_changes['geo_locations_changes'] = $data['geo_locations_changes']; - $suggested_changes['synonyms_changes'] = $data['synonyms_changes']; - $suggested_changes['identifiers_changes'] = $data['identifiers_changes']; - $suggested_changes['citations_changes'] = $data['citations_changes']; + if ($data['is_change'] == true) { + $suggested_changes = []; + $suggested_changes['existing_geo_locations'] = $data['existing_geo_locations']; + $suggested_changes['new_geo_locations'] = $data['new_geo_locations']; + $suggested_changes['approve_geo_locations'] = false; + + $suggested_changes['existing_synonyms'] = $data['existing_synonyms']; + $suggested_changes['new_synonyms'] = $data['new_synonyms']; + $suggested_changes['approve_synonyms'] = false; + + $suggested_changes['name'] = $data['name']; + $suggested_changes['approve_name'] = false; + + $suggested_changes['existing_cas'] = $data['existing_cas']; + $suggested_changes['new_cas'] = $data['new_cas']; + $suggested_changes['approve_cas'] = false; - $data['suggested_changes'] = $suggested_changes; + $suggested_changes['existing_organisms'] = $data['existing_organisms']; + $suggested_changes['approve_existing_organisms'] = false; + + $suggested_changes['new_organisms'] = $data['new_organisms']; + + $suggested_changes['existing_citations'] = $data['existing_citations']; + $suggested_changes['approve_existing_citations'] = false; + + $suggested_changes['new_citations'] = $data['new_citations']; + + $suggested_changes['overall_changes'] = getOverallChanges($data); + + // seperate copy for Curators + $suggested_changes['curator'] = $suggested_changes; + + $data['suggested_changes'] = $suggested_changes; + } return $data; } @@ -104,4 +146,20 @@ protected function afterCreate(): void ReportSubmitted::dispatch($this->record); } + + protected function getCreateFormAction(): Action + { + return parent::getCreateFormAction() + ->submit(null) + ->form(function () { + return getChangesToDisplayModal($this->data); + }) + ->modalHidden(function () { + return ! $this->data['is_change']; + }) + ->action(function () { + $this->closeActionModal(); + $this->create(); + }); + } } From 8f8113d004475837a1811e1582bb9e76fbd1ad76 Mon Sep 17 00:00:00 2001 From: Sagar Date: Wed, 2 Oct 2024 01:21:12 +0200 Subject: [PATCH 13/47] feat: altered the edit and view pages to load the new structure of the suggested changes View and edit pages now use a separate curator copy of suggested changes so as to allow further modifications. --- .../ReportResource/Pages/EditReport.php | 65 +++++++++++++++++-- .../ReportResource/Pages/ViewReport.php | 32 +++++++-- 2 files changed, 87 insertions(+), 10 deletions(-) diff --git a/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php b/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php index 5471d32c..e3a7475b 100644 --- a/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php +++ b/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php @@ -12,11 +12,66 @@ class EditReport extends EditRecord protected function mutateFormDataBeforeFill(array $data): array { - $data['organisms_changes'] = $data['suggested_changes']['organisms_changes']; - $data['geo_locations_changes'] = $data['suggested_changes']['geo_locations_changes']; - $data['synonyms_changes'] = $data['suggested_changes']['synonyms_changes']; - $data['identifiers_changes'] = $data['suggested_changes']['identifiers_changes']; - $data['citations_changes'] = $data['suggested_changes']['citations_changes']; + if ($data['is_change'] == true) { + $curators_copy_changes = $data['suggested_changes']['curator']; + $data['existing_geo_locations'] = $curators_copy_changes['existing_geo_locations']; + $data['new_geo_locations'] = $curators_copy_changes['new_geo_locations']; + $data['approve_geo_locations'] = $curators_copy_changes['approve_geo_locations']; + + $data['existing_synonyms'] = $curators_copy_changes['existing_synonyms']; + $data['new_synonyms'] = $curators_copy_changes['new_synonyms']; + $data['approve_synonyms'] = $curators_copy_changes['approve_synonyms']; + + $data['name'] = $curators_copy_changes['name']; + $data['approve_name'] = $curators_copy_changes['approve_name']; + + $data['existing_cas'] = $curators_copy_changes['existing_cas']; + $data['new_cas'] = $curators_copy_changes['new_cas']; + $data['approve_cas'] = $curators_copy_changes['approve_cas']; + + $data['existing_organisms'] = $curators_copy_changes['existing_organisms']; + $data['approve_existing_organisms'] = $curators_copy_changes['approve_existing_organisms']; + + $data['new_organisms'] = $curators_copy_changes['new_organisms']; + + $data['existing_citations'] = $curators_copy_changes['existing_citations']; + $data['approve_existing_citations'] = $curators_copy_changes['approve_existing_citations']; + + $data['new_citations'] = $curators_copy_changes['new_citations']; + } + + return $data; + } + + protected function mutateFormDataBeforeSave(array $data): array + { + if ($data['is_change'] == true) { + $data['suggested_changes']['curator']['existing_geo_locations'] = $data['existing_geo_locations']; + $data['suggested_changes']['curator']['new_geo_locations'] = $data['new_geo_locations']; + $data['suggested_changes']['curator']['approve_geo_locations'] = $data['approve_geo_locations']; + + $data['suggested_changes']['curator']['existing_synonyms'] = $data['existing_synonyms']; + $data['suggested_changes']['curator']['new_synonyms'] = $data['new_synonyms']; + $data['suggested_changes']['curator']['approve_synonyms'] = $data['approve_synonyms']; + + $data['suggested_changes']['curator']['name'] = $data['name']; + $data['suggested_changes']['curator']['approve_name'] = $data['approve_name']; + + $data['suggested_changes']['curator']['existing_cas'] = $data['existing_cas']; + $data['suggested_changes']['curator']['new_cas'] = $data['new_cas']; + $data['suggested_changes']['curator']['approve_cas'] = $data['approve_cas']; + + $data['suggested_changes']['curator']['existing_organisms'] = $data['existing_organisms']; + $data['suggested_changes']['curator']['approve_existing_organisms'] = $data['approve_existing_organisms']; + + $data['suggested_changes']['curator']['new_organisms'] = $data['new_organisms']; + + $data['suggested_changes']['curator']['existing_citations'] = $data['existing_citations']; + $data['suggested_changes']['curator']['approve_existing_citations'] = $data['approve_existing_citations']; + + $data['suggested_changes']['curator']['new_citations'] = $data['new_citations']; + + } return $data; } diff --git a/app/Filament/Dashboard/Resources/ReportResource/Pages/ViewReport.php b/app/Filament/Dashboard/Resources/ReportResource/Pages/ViewReport.php index 6e3966f4..fedf1343 100644 --- a/app/Filament/Dashboard/Resources/ReportResource/Pages/ViewReport.php +++ b/app/Filament/Dashboard/Resources/ReportResource/Pages/ViewReport.php @@ -11,11 +11,33 @@ class ViewReport extends ViewRecord protected function mutateFormDataBeforeFill(array $data): array { - $data['organisms_changes'] = $data['suggested_changes']['organisms_changes']; - $data['geo_locations_changes'] = $data['suggested_changes']['geo_locations_changes']; - $data['synonyms_changes'] = $data['suggested_changes']['synonyms_changes']; - $data['identifiers_changes'] = $data['suggested_changes']['identifiers_changes']; - $data['citations_changes'] = $data['suggested_changes']['citations_changes']; + if ($data['is_change'] == true) { + $curators_copy_changes = $data['suggested_changes']['curator']; + $data['existing_geo_locations'] = $curators_copy_changes['existing_geo_locations']; + $data['new_geo_locations'] = $curators_copy_changes['new_geo_locations']; + $data['approve_geo_locations'] = $curators_copy_changes['approve_geo_locations']; + + $data['existing_synonyms'] = $curators_copy_changes['existing_synonyms']; + $data['new_synonyms'] = $curators_copy_changes['new_synonyms']; + $data['approve_synonyms'] = $curators_copy_changes['approve_synonyms']; + + $data['name'] = $curators_copy_changes['name']; + $data['approve_name'] = $curators_copy_changes['approve_name']; + + $data['existing_cas'] = $curators_copy_changes['existing_cas']; + $data['new_cas'] = $curators_copy_changes['new_cas']; + $data['approve_cas'] = $curators_copy_changes['approve_cas']; + + $data['existing_organisms'] = $curators_copy_changes['existing_organisms']; + $data['approve_existing_organisms'] = $curators_copy_changes['approve_existing_organisms']; + + $data['new_organisms'] = $curators_copy_changes['new_organisms']; + + $data['existing_citations'] = $curators_copy_changes['existing_citations']; + $data['approve_existing_citations'] = $curators_copy_changes['approve_existing_citations']; + + $data['new_citations'] = $curators_copy_changes['new_citations']; + } return $data; } From bc36e7d1d8d90af60e6376986d7c0032204a1764 Mon Sep 17 00:00:00 2001 From: Sagar Date: Wed, 2 Oct 2024 01:23:01 +0200 Subject: [PATCH 14/47] feat: new helper functions and fixes to the old ones to accommodate report suggestions workflow. --- app/Helper.php | 150 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 149 insertions(+), 1 deletion(-) diff --git a/app/Helper.php b/app/Helper.php index 3c4d62f2..65b2508c 100644 --- a/app/Helper.php +++ b/app/Helper.php @@ -1,6 +1,8 @@ 'id', 'name' => 'name', + 'title' => 'title', // 'identifier' => 'identifier', ]; @@ -194,12 +197,15 @@ function changeAudit(array $data): array $data[$key_type][$changed_model] = []; foreach ($changed_data_values as $key => $value) { $value = is_array($value) ? $value : $value->toArray(); - if ($value) { + if (array_key_exists('name', $value)) { if (array_key_exists('identifier', $value)) { $value['name'] = $value['name'].' (ID: '.$value['id'].')'.' (COCONUT ID: '.$value['identifier'].')'; } else { + // ! array_key_exists('name', $value) ? dd($value) : ''; $value['name'] = $value['name'].' (ID: '.$value['id'].')'; } + } else { + $value['title'] = $value['title'].' (ID: '.$value['id'].')'; } $data[$key_type][$changed_model][$key] = array_intersect_key($value, $whitelist); } @@ -232,3 +238,145 @@ function flattenArray(array $array, $prefix = ''): array return $result; } + +function getChangesToDisplayModal($data) +{ + $key_values = []; + $overall_changes = getOverallChanges($data); + + foreach ($overall_changes as $key => $value) { + if (count($value['changes']) == 0) { + continue; + } + array_push($key_values, KeyValue::make($key) + ->addable(false) + ->deletable(false) + ->keyLabel($value['key']) + ->valueLabel($value['value']) + ->editableKeys(false) + ->editableValues(false) + ->default( + $value['changes'] + )); + } + + return $key_values; +} + +function getOverallChanges($data) +{ + $overall_changes = []; + $geo_location_changes = []; + $molecule = Molecule::where('identifier', $data['mol_id_csv'])->first(); + + $db_geo_locations = $molecule->geo_locations->pluck('name')->toArray(); + $deletable_locations = array_key_exists('existing_geo_locations', $data) ? array_diff($db_geo_locations, $data['existing_geo_locations']) : []; + $new_locations = array_key_exists('new_geo_locations', $data) ? (is_string($data['new_geo_locations']) ? $data['new_geo_locations'] : implode(',', $data['new_geo_locations'])) : null; + if (count($deletable_locations) > 0 || $new_locations) { + $key = implode(',', $deletable_locations) == '' ? ' ' : implode(',', $deletable_locations); + $geo_location_changes[$key] = $new_locations; + $overall_changes['geo_location_changes'] = [ + 'key' => 'Delete', + 'value' => 'Add', + 'changes' => $geo_location_changes, + 'delete' => $deletable_locations, + 'add' => $new_locations, + ]; + } + + $synonym_changes = []; + $db_synonyms = $molecule->synonyms; + $deletable_synonyms = array_key_exists('existing_synonyms', $data) ? array_diff($db_synonyms, $data['existing_synonyms']) : []; + $new_synonyms = array_key_exists('new_synonyms', $data) ? (is_string($data['new_synonyms']) ? $data['new_synonyms'] : implode(',', $data['new_synonyms'])) : null; + if (count($deletable_synonyms) > 0 || $new_synonyms) { + $key = implode(',', $deletable_synonyms) == '' ? ' ' : implode(',', $deletable_synonyms); + $synonym_changes[$key] = $new_synonyms; + $overall_changes['synonym_changes'] = [ + 'key' => 'Delete', + 'value' => 'Add', + 'changes' => $synonym_changes, + 'delete' => $deletable_synonyms, + 'add' => $new_synonyms, + ]; + } + + $name_change = []; + if (array_key_exists('name', $data) && $data['name'] && $data['name'] != $molecule->name) { + $name_change[$molecule->name] = $data['name']; + $overall_changes['name_change'] = [ + 'key' => 'Old', + 'value' => 'New', + 'changes' => $name_change, + 'old' => $molecule->name, + 'new' => $data['name'], + ]; + } + + $cas_changes = []; + $db_cas = $molecule->cas; + $deletable_cas = array_key_exists('existing_cas', $data) ? array_diff($db_cas, $data['existing_cas']) : []; + $new_cas = array_key_exists('new_cas', $data) ? (is_string($data['new_cas']) ? $data['new_cas'] : implode(',', $data['new_cas'])) : null; + if (count($deletable_cas) > 0 || $new_cas) { + $key = implode(',', $deletable_cas) == '' ? ' ' : implode(',', $deletable_cas); + $cas_changes[$key] = $new_cas; + $overall_changes['cas_changes'] = [ + 'key' => 'Delete', + 'value' => 'Add', + 'changes' => $cas_changes, + 'delete' => $deletable_cas, + 'add' => $new_cas, + ]; + } + + $organism_changes = []; + $db_organisms = $molecule->organisms->pluck('name')->toArray(); + $deletable_organisms = array_key_exists('existing_organisms', $data) ? array_diff($db_organisms, $data['existing_organisms']) : []; + $new_organisms = []; + $new_organisms_form_data = []; + if (array_key_exists('new_organisms', $data)) { + foreach ($data['new_organisms'] as $organism) { + if ($organism['name']) { + $new_organisms[] = $organism['name']; + $new_organisms_form_data[] = $organism; + } + } + } + if (count($deletable_organisms) > 0 || count($new_organisms) > 0) { + $key = implode(',', $deletable_organisms) == '' ? ' ' : implode(',', $deletable_organisms); + $organism_changes[$key] = implode(',', $new_organisms); + $overall_changes['organism_changes'] = [ + 'key' => 'Delete', + 'value' => 'Add', + 'changes' => $organism_changes, + 'delete' => $deletable_organisms, + 'add' => $new_organisms_form_data, + ]; + } + + $citation_changes = []; + $db_citations = $molecule->citations->where('title', '<>', null)->pluck('title')->toArray(); + $deletable_citations = array_key_exists('existing_citations', $data) ? array_diff($db_citations, $data['existing_citations']) : []; + $new_citations = []; + $new_citations_form_data = []; + if (array_key_exists('new_citations', $data)) { + foreach ($data['new_citations'] as $ciation) { + if ($ciation['title']) { + $new_citations[] = $ciation['title']; + $new_citations_form_data[] = $ciation; + } + } + } + if (count($deletable_citations) > 0 || count($new_citations) > 0) { + $key = implode(',', $deletable_citations) == '' ? ' ' : implode(',', $deletable_citations); + $citation_changes[$key] = implode(',', $new_citations); + $overall_changes['citation_changes'] = [ + 'key' => 'Delete', + 'value' => 'Add', + 'changes' => $citation_changes, + 'delete' => $deletable_citations, + 'add' => $new_citations_form_data, + ]; + } + + return $overall_changes; +} From cceba8e5406961751f91b58ecc755d3099b9996f Mon Sep 17 00:00:00 2001 From: Sagar Date: Wed, 2 Oct 2024 01:23:37 +0200 Subject: [PATCH 15/47] feat: now timeline can handle citations --- .../views/livewire/molecule-history-timeline.blade.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/resources/views/livewire/molecule-history-timeline.blade.php b/resources/views/livewire/molecule-history-timeline.blade.php index 702cb219..036d0579 100644 --- a/resources/views/livewire/molecule-history-timeline.blade.php +++ b/resources/views/livewire/molecule-history-timeline.blade.php @@ -71,6 +71,14 @@ Added:
{{implode(', ',array_diff($column_values['new_value'], $column_values['old_value']))}}
@endif @break + @case('citations') + @if ($column_values['old_value']) + Detached from:
{{$column_values['old_value']?:'N/A'}}
+ @endif + @if ($column_values['new_value']) + Attached to:
{{$column_values['new_value']?:'N/A'}}
+ @endif + @break @default Old Value:
{{$column_values['old_value']??'N/A'}}
New Value:
{{$column_values['new_value']??'N/A'}} From ae4bd28e39a6a2bcfc542de9eee09a3e46f781d2 Mon Sep 17 00:00:00 2001 From: Sagar Date: Wed, 2 Oct 2024 01:25:09 +0200 Subject: [PATCH 16/47] chore: removed dd statements. --- app/Filament/Dashboard/Resources/ReportResource.php | 2 -- app/Helper.php | 1 - app/Livewire/MoleculeHistoryTimeline.php | 3 --- 3 files changed, 6 deletions(-) diff --git a/app/Filament/Dashboard/Resources/ReportResource.php b/app/Filament/Dashboard/Resources/ReportResource.php index 25f001ff..185cbe68 100644 --- a/app/Filament/Dashboard/Resources/ReportResource.php +++ b/app/Filament/Dashboard/Resources/ReportResource.php @@ -611,7 +611,6 @@ public static function prepareApprovedChanges(Report $record, $livewire) public static function approveReport(array $data, Report $record, Molecule $molecule, $livewire): void { - // dd($data, $record, $molecule, $livewire); // Run SQL queries for the approved changes self::runSQLQueries($record); @@ -637,7 +636,6 @@ public static function runSQLQueries(Report $record): void { DB::transaction(function () use ($record) { self::$overall_changes = getOverallChanges(self::$approved_changes); - // dd(self::$overall_changes); // Check if 'molecule_id' is provided or use a default molecule for association/dissociation $molecule = Molecule::where('identifier', $record['mol_id_csv'])->first(); diff --git a/app/Helper.php b/app/Helper.php index 65b2508c..f1dffad3 100644 --- a/app/Helper.php +++ b/app/Helper.php @@ -201,7 +201,6 @@ function changeAudit(array $data): array if (array_key_exists('identifier', $value)) { $value['name'] = $value['name'].' (ID: '.$value['id'].')'.' (COCONUT ID: '.$value['identifier'].')'; } else { - // ! array_key_exists('name', $value) ? dd($value) : ''; $value['name'] = $value['name'].' (ID: '.$value['id'].')'; } } else { diff --git a/app/Livewire/MoleculeHistoryTimeline.php b/app/Livewire/MoleculeHistoryTimeline.php index 2c79262f..29675c18 100644 --- a/app/Livewire/MoleculeHistoryTimeline.php +++ b/app/Livewire/MoleculeHistoryTimeline.php @@ -18,8 +18,6 @@ public function getHistory() $audit_data[$index]['user_name'] = $audit->getMetadata()['user_name']; $audit_data[$index]['event'] = $audit->getMetadata()['audit_event']; $audit_data[$index]['created_at'] = date('Y/m/d', strtotime($audit->getMetadata()['audit_created_at'])); - // dd($audit->old_values, $audit->new_values); - // dd($audit->getModified()); $key = null; $old_key = $audit->old_values ? explode('.', array_keys($audit->old_values)[0])[0] : null; @@ -41,7 +39,6 @@ public function getHistory() array_push($audit_data, $initial_audit); $this->audit_data = $audit_data; - // dd($audit_data); } public function render() From 87363b3c620c71a65a291ea950162e30bf48776c Mon Sep 17 00:00:00 2001 From: Sagar Date: Wed, 2 Oct 2024 14:48:45 +0200 Subject: [PATCH 17/47] fix: conditional checks were refined to work with the data structures of audits. --- app/Livewire/MoleculeHistoryTimeline.php | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/app/Livewire/MoleculeHistoryTimeline.php b/app/Livewire/MoleculeHistoryTimeline.php index f12a0364..e5c70752 100644 --- a/app/Livewire/MoleculeHistoryTimeline.php +++ b/app/Livewire/MoleculeHistoryTimeline.php @@ -19,16 +19,19 @@ public function getHistory() $audit_data[$index]['event'] = $audit->getMetadata()['audit_event']; $audit_data[$index]['created_at'] = date('Y/m/d', strtotime($audit->getMetadata()['audit_created_at'])); - if (str_contains('.', array_keys($audit->old_values)[0])) { - $old_key = $audit->old_values ? explode('.', array_keys($audit->old_values)[0])[0] : null; - $new_key = $audit->new_values ? explode('.', array_keys($audit->new_values)[0])[0] : null; - - $old_key = $old_key ?: $new_key; - $new_key = $new_key ?: $old_key; + $values = !empty($audit->old_values) ? $audit->old_values : $audit->new_values; + $first_affected_column = !empty($values) ? array_keys($values)[0] : null; + + if (str_contains($first_affected_column, '.')) { + $affected_column = explode('.', $first_affected_column)[0]; + + $audit_data[$index]['affected_columns'][$affected_column]['old_value'] = $audit->old_values ? array_values($audit->old_values)[0] : null; + $audit_data[$index]['affected_columns'][$affected_column]['new_value'] = $audit->new_values ? array_values($audit->new_values)[0] : null; } else { - foreach ($audit->getModified() as $key => $value) { - $audit_data[$index]['affected_columns'][$key]['old_value'] = $value['old'] ?: null; - $audit_data[$index]['affected_columns'][$key]['new_value'] = $value['new'] ?: null; + foreach ($audit->getModified() as $affected_column => $value) { + + $audit_data[$index]['affected_columns'][$affected_column]['old_value'] = array_key_exists('old', $value) ? $value['old'] : null; + $audit_data[$index]['affected_columns'][$affected_column]['new_value'] = array_key_exists('new', $value) ? $value['new'] : null; } } } @@ -42,7 +45,6 @@ public function getHistory() array_push($audit_data, $initial_audit); $this->audit_data = $audit_data; - // dd($audit_data); } public function render() From 54bc73fdeadb6149993c2cfb3a8327ef8fd8eccc Mon Sep 17 00:00:00 2001 From: Sagar Date: Wed, 2 Oct 2024 15:02:15 +0200 Subject: [PATCH 18/47] fix: to capture audits from citations --- app/Helper.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Helper.php b/app/Helper.php index 3c4d62f2..297eff94 100644 --- a/app/Helper.php +++ b/app/Helper.php @@ -180,6 +180,7 @@ function changeAudit(array $data): array $whitelist = [ // 'id' => 'id', 'name' => 'name', + 'title' => 'title', // 'identifier' => 'identifier', ]; From c71fbc265a3b9049afb5c1b49cd65f0feb2a3044 Mon Sep 17 00:00:00 2001 From: Sagar Date: Wed, 2 Oct 2024 15:05:17 +0200 Subject: [PATCH 19/47] fix: additional checks --- app/Helper.php | 4 +++- app/Livewire/MoleculeHistoryTimeline.php | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/Helper.php b/app/Helper.php index 297eff94..39e3df31 100644 --- a/app/Helper.php +++ b/app/Helper.php @@ -195,12 +195,14 @@ function changeAudit(array $data): array $data[$key_type][$changed_model] = []; foreach ($changed_data_values as $key => $value) { $value = is_array($value) ? $value : $value->toArray(); - if ($value) { + if (array_key_exists('name', $value)) { if (array_key_exists('identifier', $value)) { $value['name'] = $value['name'].' (ID: '.$value['id'].')'.' (COCONUT ID: '.$value['identifier'].')'; } else { $value['name'] = $value['name'].' (ID: '.$value['id'].')'; } + } else { + $value['name'] = $value['title'].' (ID: '.$value['id'].')'; } $data[$key_type][$changed_model][$key] = array_intersect_key($value, $whitelist); } diff --git a/app/Livewire/MoleculeHistoryTimeline.php b/app/Livewire/MoleculeHistoryTimeline.php index e5c70752..dddb734f 100644 --- a/app/Livewire/MoleculeHistoryTimeline.php +++ b/app/Livewire/MoleculeHistoryTimeline.php @@ -19,12 +19,12 @@ public function getHistory() $audit_data[$index]['event'] = $audit->getMetadata()['audit_event']; $audit_data[$index]['created_at'] = date('Y/m/d', strtotime($audit->getMetadata()['audit_created_at'])); - $values = !empty($audit->old_values) ? $audit->old_values : $audit->new_values; - $first_affected_column = !empty($values) ? array_keys($values)[0] : null; + $values = ! empty($audit->old_values) ? $audit->old_values : $audit->new_values; + $first_affected_column = ! empty($values) ? array_keys($values)[0] : null; if (str_contains($first_affected_column, '.')) { $affected_column = explode('.', $first_affected_column)[0]; - + $audit_data[$index]['affected_columns'][$affected_column]['old_value'] = $audit->old_values ? array_values($audit->old_values)[0] : null; $audit_data[$index]['affected_columns'][$affected_column]['new_value'] = $audit->new_values ? array_values($audit->new_values)[0] : null; } else { From ceba3a99b99b98a9b439844bca81e7306e6cce4c Mon Sep 17 00:00:00 2001 From: Sagar Date: Tue, 24 Sep 2024 00:57:48 +0200 Subject: [PATCH 20/47] fix: key issue fixed --- app/Livewire/MoleculeHistoryTimeline.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/Livewire/MoleculeHistoryTimeline.php b/app/Livewire/MoleculeHistoryTimeline.php index dddb734f..fdb71291 100644 --- a/app/Livewire/MoleculeHistoryTimeline.php +++ b/app/Livewire/MoleculeHistoryTimeline.php @@ -18,6 +18,8 @@ public function getHistory() $audit_data[$index]['user_name'] = $audit->getMetadata()['user_name']; $audit_data[$index]['event'] = $audit->getMetadata()['audit_event']; $audit_data[$index]['created_at'] = date('Y/m/d', strtotime($audit->getMetadata()['audit_created_at'])); + // dd($audit->old_values, $audit->new_values); + // dd($audit->getModified()); $values = ! empty($audit->old_values) ? $audit->old_values : $audit->new_values; $first_affected_column = ! empty($values) ? array_keys($values)[0] : null; From f858ec03e252442ad4be2a84a03377e609c99539 Mon Sep 17 00:00:00 2001 From: Sagar Date: Tue, 24 Sep 2024 12:44:02 +0200 Subject: [PATCH 21/47] fix: disabled logging empty values and enabled handling of existing empty values in both old and new columns --- config/audit.php | 2 +- resources/views/livewire/molecule-history-timeline.blade.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/config/audit.php b/config/audit.php index df6dd561..bf34de57 100644 --- a/config/audit.php +++ b/config/audit.php @@ -101,7 +101,7 @@ | */ - 'empty_values' => true, + 'empty_values' => false, 'allowed_empty_values' => [ 'retrieved', ], diff --git a/resources/views/livewire/molecule-history-timeline.blade.php b/resources/views/livewire/molecule-history-timeline.blade.php index 65542b72..589ccd15 100644 --- a/resources/views/livewire/molecule-history-timeline.blade.php +++ b/resources/views/livewire/molecule-history-timeline.blade.php @@ -9,6 +9,7 @@
    @foreach ($audit_data as $audit) + @if (array_key_exists('affected_columns', $audit))
  • @@ -62,6 +63,7 @@ @endforeach
  • + @endif @endforeach
From 6396ce9e328e90b54edaa081de6b1ee391bf9eda Mon Sep 17 00:00:00 2001 From: Sagar Date: Tue, 24 Sep 2024 12:49:29 +0200 Subject: [PATCH 22/47] fix: now the timestamps are auto managed for the pivot table molecule_sample_location --- app/Models/Molecule.php | 2 +- app/Models/SampleLocation.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Models/Molecule.php b/app/Models/Molecule.php index 707e5cb3..1387e7c0 100644 --- a/app/Models/Molecule.php +++ b/app/Models/Molecule.php @@ -129,7 +129,7 @@ public function geo_locations(): BelongsToMany public function sampleLocations(): BelongsToMany { - return $this->belongsToMany(SampleLocation::class); + return $this->belongsToMany(SampleLocation::class)->withTimestamps(); } /** diff --git a/app/Models/SampleLocation.php b/app/Models/SampleLocation.php index c7f64a54..c54ec90e 100644 --- a/app/Models/SampleLocation.php +++ b/app/Models/SampleLocation.php @@ -38,7 +38,7 @@ public function organisms(): HasOne public function molecules(): BelongsToMany { - return $this->belongsToMany(Molecule::class); + return $this->belongsToMany(Molecule::class)->withTimestamps(); } public function transformAudit(array $data): array From cb40e705202d7131ccdd9c0dfcca235c6b04f8eb Mon Sep 17 00:00:00 2001 From: Sagar Date: Wed, 18 Sep 2024 02:00:13 +0200 Subject: [PATCH 23/47] wip: suggested changes are now stored in the reports table. SQL queries need to be built at the time of approving the report --- app/Actions/Coconut/SearchMolecule.php | 1 - .../Dashboard/Resources/CitationResource.php | 88 +------ .../Resources/CollectionResource.php | 3 - .../Resources/GeoLocationResource.php | 7 +- .../Dashboard/Resources/OrganismResource.php | 99 +------- .../Dashboard/Resources/ReportResource.php | 232 +++++++++++++++++- .../ReportResource/Pages/CreateReport.php | 9 + app/Http/Controllers/API/SearchController.php | 4 - app/Models/Citation.php | 91 +++++++ app/Models/GeoLocation.php | 10 + app/Models/Organism.php | 100 ++++++++ app/Models/Report.php | 7 +- 12 files changed, 445 insertions(+), 206 deletions(-) diff --git a/app/Actions/Coconut/SearchMolecule.php b/app/Actions/Coconut/SearchMolecule.php index c360495b..cdb3e5c5 100644 --- a/app/Actions/Coconut/SearchMolecule.php +++ b/app/Actions/Coconut/SearchMolecule.php @@ -354,7 +354,6 @@ private function executeQuery($statement) $ids_array = collect($hits)->pluck('id')->toArray(); $ids = implode(',', $ids_array); - // dd($ids); if ($ids != '') { diff --git a/app/Filament/Dashboard/Resources/CitationResource.php b/app/Filament/Dashboard/Resources/CitationResource.php index 00776312..28ee9b40 100644 --- a/app/Filament/Dashboard/Resources/CitationResource.php +++ b/app/Filament/Dashboard/Resources/CitationResource.php @@ -6,18 +6,12 @@ use App\Filament\Dashboard\Resources\CitationResource\RelationManagers\CollectionRelationManager; use App\Filament\Dashboard\Resources\CitationResource\RelationManagers\MoleculeRelationManager; use App\Models\Citation; -use Closure; -use Filament\Forms\Components\Section; -use Filament\Forms\Components\Textarea; -use Filament\Forms\Components\TextInput; use Filament\Forms\Form; -use Filament\Forms\Get; use Filament\Resources\Resource; use Filament\Tables; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Table; use Illuminate\Support\Facades\Cache; -use Illuminate\Support\HtmlString; use Tapp\FilamentAuditing\RelationManagers\AuditsRelationManager; class CitationResource extends Resource @@ -35,87 +29,7 @@ class CitationResource extends Resource public static function form(Form $form): Form { return $form - ->schema([ - Section::make() - ->schema([ - TextInput::make('failMessage') - ->default('') - ->hidden() - ->disabled(), - TextInput::make('doi') - ->label('DOI') - ->live(onBlur: true) - ->afterStateUpdated(function ($set, $state) { - if (doiRegxMatch($state)) { - $citationDetails = fetchDOICitation($state); - if ($citationDetails) { - $set('title', $citationDetails['title']); - $set('authors', $citationDetails['authors']); - $set('citation_text', $citationDetails['citation_text']); - $set('failMessage', 'Success'); - } else { - $set('failMessage', 'No citation found. Please fill in the details manually'); - } - } else { - $set('failMessage', 'Invalid DOI'); - } - }) - ->helperText(function ($get) { - - if ($get('failMessage') == 'Fetching') { - return new HtmlString(' - - - '); - } elseif ($get('failMessage') != 'Success') { - return new HtmlString(''.$get('failMessage').''); - } else { - return null; - } - }) - ->required() - ->unique() - ->rules([ - fn (Get $get): Closure => function (string $attribute, $value, Closure $fail) use ($get) { - if ($get('failMessage') != 'No citation found. Please fill in the details manually') { - $fail($get('failMessage')); - } - }, - ]) - ->validationMessages([ - 'unique' => 'The DOI already exists.', - ]), - ]), - - Section::make() - ->schema([ - TextInput::make('title') - ->disabled(function ($get, string $operation) { - if ($operation = 'edit' || $get('failMessage') == 'No citation found. Please fill in the details manually') { - return false; - } else { - return true; - } - }), - TextInput::make('authors') - ->disabled(function ($get, string $operation) { - if ($operation = 'edit' || $get('failMessage') == 'No citation found. Please fill in the details manually') { - return false; - } else { - return true; - } - }), - Textarea::make('citation_text') - ->label('Citation text / URL') - ->disabled(function ($get, string $operation) { - if ($operation = 'edit' || $get('failMessage') == 'No citation found. Please fill in the details manually') { - return false; - } else { - return true; - } - }), - ])->columns(1), - ]); + ->schema(Citation::getForm()); } public static function table(Table $table): Table diff --git a/app/Filament/Dashboard/Resources/CollectionResource.php b/app/Filament/Dashboard/Resources/CollectionResource.php index 500fe6cb..72d72403 100644 --- a/app/Filament/Dashboard/Resources/CollectionResource.php +++ b/app/Filament/Dashboard/Resources/CollectionResource.php @@ -131,9 +131,6 @@ public static function table(Table $table): Table public static function getRelations(): array { - // $record = static::getOwner(); - // dd(static::getOwner()); - // dd(static::$model::molecules()->get()); $arr = [ EntriesRelationManager::class, CitationsRelationManager::class, diff --git a/app/Filament/Dashboard/Resources/GeoLocationResource.php b/app/Filament/Dashboard/Resources/GeoLocationResource.php index 9288ff9c..2e96fcb7 100644 --- a/app/Filament/Dashboard/Resources/GeoLocationResource.php +++ b/app/Filament/Dashboard/Resources/GeoLocationResource.php @@ -5,7 +5,6 @@ use App\Filament\Dashboard\Resources\GeoLocationResource\Pages; use App\Filament\Dashboard\Resources\GeoLocationResource\Widgets\GeoLocationStats; use App\Models\GeoLocation; -use Filament\Forms\Components\TextInput; use Filament\Forms\Form; use Filament\Resources\Resource; use Filament\Tables; @@ -26,11 +25,7 @@ class GeoLocationResource extends Resource public static function form(Form $form): Form { return $form - ->schema([ - TextInput::make('name') - ->required() - ->maxLength(255), - ]); + ->schema(GeoLocation::getForm()); } public static function table(Table $table): Table diff --git a/app/Filament/Dashboard/Resources/OrganismResource.php b/app/Filament/Dashboard/Resources/OrganismResource.php index 2f162e54..9624a38e 100644 --- a/app/Filament/Dashboard/Resources/OrganismResource.php +++ b/app/Filament/Dashboard/Resources/OrganismResource.php @@ -9,8 +9,6 @@ use App\Forms\Components\OrganismsTable; use App\Models\Organism; use Archilex\AdvancedTables\Filters\AdvancedFilter; -use Filament\Forms; -use Filament\Forms\Components\Actions\Action; use Filament\Forms\Components\Grid; use Filament\Forms\Components\Group; use Filament\Forms\Components\Section; @@ -43,102 +41,9 @@ public static function form(Form $form): Form Group::make() ->schema([ Section::make('') - ->schema([ - Forms\Components\TextInput::make('name') - ->required() - ->unique() - ->maxLength(255) - ->suffixAction( - Action::make('infoFromSources') - ->icon('heroicon-m-clipboard') - // ->fillForm(function ($record, callable $get): array { - // $entered_name = $get('name'); - // $name = ucfirst(trim($entered_name)); - // $data = null; - // $iri = null; - // $organism = null; - // $rank = null; - - // if ($name && $name != '') { - // $data = Self::getOLSIRI($name, 'species'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'species'); - // Self::info("Mapped and updated: $name"); - // } else { - // $data = Self::getOLSIRI(explode(' ', $name)[0], 'genus'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'genus'); - // Self::info("Mapped and updated: $name"); - // } else { - // $data = Self::getOLSIRI(explode(' ', $name)[0], 'family'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'genus'); - // Self::info("Mapped and updated: $name"); - // } else { - // [$name, $iri, $organism, $rank] = Self::getGNFMatches($name, $record); - // } - // } - // } - // } - // return [ - // 'name' => $name, - // 'iri' => $iri, - // 'rank' => $rank, - // ]; - // }) - // ->form([ - // Forms\Components\TextInput::make('name')->readOnly(), - // Forms\Components\TextInput::make('iri')->readOnly(), - // Forms\Components\TextInput::make('rank')->readOnly(), - // ]) - // ->action(fn ( $record) => $record->advance()) - ->modalContent(function ($record, $get): View { - $name = ucfirst(trim($get('name'))); - $data = null; - // $iri = null; - // $organism = null; - // $rank = null; - - if ($name && $name != '') { - $data = self::getOLSIRI($name, 'species'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'species'); - // } else { - // $data = Self::getOLSIRI(explode(' ', $name)[0], 'genus'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'genus'); - // } else { - // $data = Self::getOLSIRI(explode(' ', $name)[0], 'family'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'genus'); - // } else { - // [$name, $iri, $organism, $rank] = Self::getGNFMatches($name, $record); - // } - // } - // } - } - - return view( - 'forms.components.organism-info', - [ - 'data' => $data, - ], - ); - }) - ->action(function (array $data, Organism $record): void { - // Self::updateOrganismModel($data['name'], $data['iri'], $record, $data['rank']); - }) - ->slideOver() - ), - Forms\Components\TextInput::make('iri') - ->label('IRI') - ->maxLength(255), - Forms\Components\TextInput::make('rank') - ->maxLength(255), - ]), + ->schema(Organism::getForm()), ]) ->columnSpan(1), - Group::make() ->schema([ Section::make('') @@ -254,7 +159,6 @@ protected static function getGNFMatches($name, $organism) $responseBody = json_decode($response->getBody(), true); return $responseBody; - // dd($responseBody); // if (isset($responseBody['names']) && count($responseBody['names']) > 0) { // $r_name = $responseBody['names'][0]; @@ -293,7 +197,6 @@ protected static function getGNFMatches($name, $organism) protected static function updateOrganismModel($name, $iri, $organism = null, $rank = null) { - // dd($name, $iri, $organism, $rank); if (! $organism) { $organism = Organism::where('name', $name)->first(); } diff --git a/app/Filament/Dashboard/Resources/ReportResource.php b/app/Filament/Dashboard/Resources/ReportResource.php index a26e7ad1..97997f4e 100644 --- a/app/Filament/Dashboard/Resources/ReportResource.php +++ b/app/Filament/Dashboard/Resources/ReportResource.php @@ -5,15 +5,20 @@ use App\Filament\Dashboard\Resources\ReportResource\Pages; use App\Filament\Dashboard\Resources\ReportResource\RelationManagers; use App\Models\Citation; +use App\Models\GeoLocation; use App\Models\Molecule; +use App\Models\Organism; use App\Models\Report; use Archilex\AdvancedTables\Filters\AdvancedFilter; use Filament\Forms\Components\Actions; use Filament\Forms\Components\Actions\Action; use Filament\Forms\Components\Grid; use Filament\Forms\Components\KeyValue; +use Filament\Forms\Components\Repeater; use Filament\Forms\Components\Select; use Filament\Forms\Components\SpatieTagsInput; +use Filament\Forms\Components\Tabs; +use Filament\Forms\Components\TagsInput; use Filament\Forms\Components\Textarea; use Filament\Forms\Components\TextInput; use Filament\Forms\Components\ToggleButtons; @@ -125,11 +130,228 @@ public static function form(Form $form): Form ->hidden(function (Get $get) { return $get('is_change'); }), - KeyValue::make('suggested_changes') - ->hintIcon('heroicon-m-question-mark-circle', tooltip: 'Enter the property (in the left column) and suggested change (in the right column)') - ->addActionLabel('Add property') - ->keyLabel('Property') - ->valueLabel('Suggested change') + // KeyValue::make('suggested_changes') + // ->hintIcon('heroicon-m-question-mark-circle', tooltip: 'Enter the property (in the left column) and suggested change (in the right column)') + // ->addActionLabel('Add property') + // ->keyLabel('Property') + // ->valueLabel('Suggested change') + // ->hidden(function (Get $get) { + // return ! $get('is_change'); + // }), + Tabs::make('Tabs') + ->tabs([ + Tabs\Tab::make('organisms_changes') + ->label('Organisms') + ->schema([ + Repeater::make('organisms_changes') + ->schema([ + Select::make('operation') + ->options([ + 'update' => 'Update', + 'remove' => 'Remove', + 'add' => 'Add', + ]) + ->default('update') + ->live(), + Select::make('organisms') + ->label('Organism') + ->searchable() + ->searchDebounce(500) + ->getSearchResultsUsing(function (string $search, Get $get): array { + return Molecule::where('identifier', $get('../../mol_id_csv'))->get()[0]->organisms()->where('name', 'ilike', "%{$search}%")->limit(10)->pluck('organisms.name', 'organisms.id')->toArray() ?? []; + }) + ->getOptionLabelUsing(fn ($value): ?string => Organism::find($value)?->name) + ->hidden(function (Get $get) { + return $get('operation') == 'add'; + }), + TextInput::make('name') + ->label('Change to') + ->hidden(function (Get $get) { + return $get('operation') != 'update'; + }), + Grid::make('new_organism_details') + ->schema(Organism::getForm())->columns(3) + ->hidden(function (Get $get) { + return $get('operation') != 'add'; + }) + ->columnStart(2), + ]) + ->reorderable(false) + ->columns(4), + + ]), + Tabs\Tab::make('geo_locations_changes') + ->label('Geo Locations') + ->schema([ + Repeater::make('geo_locations_changes') + ->schema([ + Select::make('operation') + ->options([ + 'update' => 'Update', + 'remove' => 'Remove', + 'add' => 'Add', + ]) + ->default('update') + ->live(), + Select::make('geo_locations') + ->label('Geo Location') + ->searchable() + ->searchDebounce(500) + ->getSearchResultsUsing(function (string $search, Get $get): array { + return Molecule::where('identifier', $get('../../mol_id_csv'))->get()[0]->geo_locations()->where('name', 'ilike', "%{$search}%")->limit(10)->pluck('geo_locations.name', 'geo_locations.id')->toArray(); + }) + ->getOptionLabelUsing(fn ($value): ?string => GeoLocation::find($value)?->name) + ->hidden(function (Get $get) { + return $get('operation') == 'add'; + }), + TextInput::make('name') + ->label('Change to') + ->hidden(function (Get $get) { + return $get('operation') != 'update'; + }), + Grid::make('new_geo_locations_details') + ->schema(GeoLocation::getForm())->columns(3) + ->hidden(function (Get $get) { + return $get('operation') != 'add'; + }) + ->columnStart(2), + ]) + ->reorderable(false) + ->columns(4), + ]), + Tabs\Tab::make('synonyms') + ->label('Synonyms') + ->schema([ + Repeater::make('synonyms_changes') + ->schema([ + Select::make('operation') + ->options([ + 'update' => 'Update', + 'remove' => 'Remove', + 'add' => 'Add', + ]) + ->default('update') + ->live(), + Select::make('synonyms') + ->label('Synonym') + ->searchable() + ->searchDebounce(500) + ->getSearchResultsUsing(function (string $search, Get $get): array { + $synonyms = Molecule::select('synonyms')->where('identifier', $get('../../mol_id_csv'))->get()[0]['synonyms']; + $matched_synonyms = []; + foreach ($synonyms as $synonym) { + str_contains(strtolower($synonym), strtolower($search)) ? array_push($matched_synonyms, $synonym) : null; + } + + return $matched_synonyms; + }) + ->hidden(function (Get $get) { + return $get('operation') == 'add'; + }), + TextInput::make('name') + ->label('Change to') + ->hidden(function (Get $get) { + return $get('operation') != 'update'; + }), + Grid::make('new_synonym_details') + ->schema([ + TagsInput::make('new_synonym') + ->label('New Synonym') + ->separator(',') + ->splitKeys([',']), + ])->columns(3) + ->hidden(function (Get $get) { + return $get('operation') != 'add'; + }) + ->columnStart(2), + ]) + ->reorderable(false) + ->columns(4), + ]), + Tabs\Tab::make('identifiers') + ->label('Identifiers') + ->schema([ + Repeater::make('identifiers_changes') + ->schema([ + Select::make('identifer_to_change') + ->options([ + 'name' => 'Name', + 'cas' => 'CAS', + ]) + ->default('name') + ->live(), + Select::make('current_Name') + ->options(function (Get $get): array { + return [Molecule::where('identifier', $get('../../mol_id_csv'))->get()[0]->name ?? '']; + }) + ->default(0) + ->disabled() + ->hidden(function (Get $get) { + return $get('identifer_to_change') == 'cas'; + }), + Select::make('current_CAS') + ->options(function (Get $get): array { + return [Molecule::where('identifier', $get('../../mol_id_csv'))->get()[0]->cas]; + }) + ->default(0) + ->disabled() + ->hidden(function (Get $get) { + return $get('identifer_to_change') == 'name'; + }), + TextInput::make('new_name') + ->label(function (Get $get) { + return $get('identifer_to_change') == 'name' ? 'New Name' : 'New CAS'; + }), + ]) + ->reorderable(false) + ->columns(4), + ]), + Tabs\Tab::make('citations') + ->label('Citations') + ->schema([ + Repeater::make('citations_changes') + ->schema([ + Select::make('operation') + ->options([ + 'update' => 'Update', + 'remove' => 'Remove', + 'add' => 'Add', + ]) + ->default('update') + ->live(), + Select::make('citations') + ->label('Citation') + ->searchable() + ->searchDebounce(500) + ->getSearchResultsUsing(function (string $search, Get $get): array { + return Molecule::where('identifier', $get('../../mol_id_csv'))->get()[0]->citations()->where('title', 'ilike', "%{$search}%")->limit(10)->pluck('citations.title', 'citations.id')->toArray(); + }) + ->getOptionLabelUsing(fn ($value): ?string => Citation::find($value)?->name) + ->hidden(function (Get $get) { + return $get('operation') == 'add'; + }), + TextInput::make('name') + ->label('Change to') + ->hidden(function (Get $get) { + return $get('operation') != 'update'; + }), + Grid::make('new_citation_details') + ->schema(Citation::getForm())->columns(3) + ->hidden(function (Get $get) { + return $get('operation') != 'add'; + }) + ->columnStart(2), + ]) + ->reorderable(false) + ->columns(4), + + ]), + + Tabs\Tab::make('Chemical Classifications') + ->schema([ + // ... + ]), + ]) ->hidden(function (Get $get) { return ! $get('is_change'); }), diff --git a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php index 937c3131..2878f2c6 100644 --- a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php +++ b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php @@ -67,6 +67,15 @@ protected function mutateFormDataBeforeCreate(array $data): array $data['user_id'] = auth()->id(); $data['status'] = 'submitted'; + $suggested_changes = []; + $suggested_changes['organisms_changes'] = $data['organisms_changes']; + $suggested_changes['geo_locations_changes'] = $data['geo_locations_changes']; + $suggested_changes['synonyms_changes'] = $data['synonyms_changes']; + $suggested_changes['identifiers_changes'] = $data['identifiers_changes']; + $suggested_changes['citations_changes'] = $data['citations_changes']; + + $data['suggested_changes'] = $suggested_changes; + return $data; } diff --git a/app/Http/Controllers/API/SearchController.php b/app/Http/Controllers/API/SearchController.php index 8cd31eb8..2a21f544 100644 --- a/app/Http/Controllers/API/SearchController.php +++ b/app/Http/Controllers/API/SearchController.php @@ -19,8 +19,6 @@ public function search(Request $request) $queryType = 'text'; $results = []; - //dd($request); - $limit = $request->query('limit'); $sort = $request->query('sort'); $limit = $limit ? $limit : 24; @@ -218,7 +216,6 @@ public function search(Request $request) $statement = $statement.')'; } $statement = $statement.' LIMIT '.$limit; - // dd($statement ); } else { if ($query) { $query = str_replace("'", "''", $query); @@ -289,7 +286,6 @@ public function search(Request $request) $page ); - //dd($pagination); return $pagination; } catch (QueryException $exception) { $message = $exception->getMessage(); diff --git a/app/Models/Citation.php b/app/Models/Citation.php index 3cc86333..94542b75 100644 --- a/app/Models/Citation.php +++ b/app/Models/Citation.php @@ -2,9 +2,15 @@ namespace App\Models; +use Closure; +use Filament\Forms\Components\Section; +use Filament\Forms\Components\Textarea; +use Filament\Forms\Components\TextInput; +use Filament\Forms\Get; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphToMany; +use Illuminate\Support\HtmlString; use OwenIt\Auditing\Contracts\Auditable; class Citation extends Model implements Auditable @@ -52,4 +58,89 @@ public function transformAudit(array $data): array { return changeAudit($data); } + + public static function getForm() + { + return [ + Section::make() + ->schema([ + TextInput::make('failMessage') + ->default('') + ->hidden() + ->disabled(), + TextInput::make('doi') + ->label('DOI') + ->live(onBlur: true) + ->afterStateUpdated(function ($set, $state) { + if (doiRegxMatch($state)) { + $citationDetails = fetchDOICitation($state); + if ($citationDetails) { + $set('title', $citationDetails['title']); + $set('authors', $citationDetails['authors']); + $set('citation_text', $citationDetails['citation_text']); + $set('failMessage', 'Success'); + } else { + $set('failMessage', 'No citation found. Please fill in the details manually'); + } + } else { + $set('failMessage', 'Invalid DOI'); + } + }) + ->helperText(function ($get) { + + if ($get('failMessage') == 'Fetching') { + return new HtmlString(' + + + '); + } elseif ($get('failMessage') != 'Success') { + return new HtmlString(''.$get('failMessage').''); + } else { + return null; + } + }) + ->required() + ->unique() + ->rules([ + fn (Get $get): Closure => function (string $attribute, $value, Closure $fail) use ($get) { + if ($get('failMessage') != 'No citation found. Please fill in the details manually') { + $fail($get('failMessage')); + } + }, + ]) + ->validationMessages([ + 'unique' => 'The DOI already exists.', + ]), + ]), + + Section::make() + ->schema([ + TextInput::make('title') + ->disabled(function ($get, string $operation) { + if ($operation = 'edit' || $get('failMessage') == 'No citation found. Please fill in the details manually') { + return false; + } else { + return true; + } + }), + TextInput::make('authors') + ->disabled(function ($get, string $operation) { + if ($operation = 'edit' || $get('failMessage') == 'No citation found. Please fill in the details manually') { + return false; + } else { + return true; + } + }), + Textarea::make('citation_text') + ->label('Citation text / URL') + ->disabled(function ($get, string $operation) { + if ($operation = 'edit' || $get('failMessage') == 'No citation found. Please fill in the details manually') { + return false; + } else { + return true; + } + }), + ])->columns(1), + ]; + } } diff --git a/app/Models/GeoLocation.php b/app/Models/GeoLocation.php index 12ae9b35..28bcd5ef 100644 --- a/app/Models/GeoLocation.php +++ b/app/Models/GeoLocation.php @@ -2,6 +2,7 @@ namespace App\Models; +use Filament\Forms\Components\TextInput; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use OwenIt\Auditing\Contracts\Auditable; @@ -29,4 +30,13 @@ public function transformAudit(array $data): array { return changeAudit($data); } + + public static function getForm(): array + { + return [ + TextInput::make('name') + ->required() + ->maxLength(255), + ]; + } } diff --git a/app/Models/Organism.php b/app/Models/Organism.php index 52be6e4d..ad4c09ab 100644 --- a/app/Models/Organism.php +++ b/app/Models/Organism.php @@ -2,6 +2,9 @@ namespace App\Models; +use Filament\Forms; +use Filament\Forms\Components\Actions\Action; +use Illuminate\Contracts\View\View; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsToMany; @@ -51,4 +54,101 @@ public function transformAudit(array $data): array { return changeAudit($data); } + + public static function getForm(): array + { + return [ + Forms\Components\TextInput::make('name') + ->required() + ->unique(Organism::class, 'name') + ->maxLength(255) + ->suffixAction( + Action::make('infoFromSources') + ->icon('heroicon-m-clipboard') + // ->fillForm(function ($record, callable $get): array { + // $entered_name = $get('name'); + // $name = ucfirst(trim($entered_name)); + // $data = null; + // $iri = null; + // $organism = null; + // $rank = null; + + // if ($name && $name != '') { + // $data = Self::getOLSIRI($name, 'species'); + // if ($data) { + // Self::updateOrganismModel($name, $data, $record, 'species'); + // Self::info("Mapped and updated: $name"); + // } else { + // $data = Self::getOLSIRI(explode(' ', $name)[0], 'genus'); + // if ($data) { + // Self::updateOrganismModel($name, $data, $record, 'genus'); + // Self::info("Mapped and updated: $name"); + // } else { + // $data = Self::getOLSIRI(explode(' ', $name)[0], 'family'); + // if ($data) { + // Self::updateOrganismModel($name, $data, $record, 'genus'); + // Self::info("Mapped and updated: $name"); + // } else { + // [$name, $iri, $organism, $rank] = Self::getGNFMatches($name, $record); + // } + // } + // } + // } + // return [ + // 'name' => $name, + // 'iri' => $iri, + // 'rank' => $rank, + // ]; + // }) + // ->form([ + // Forms\Components\TextInput::make('name')->readOnly(), + // Forms\Components\TextInput::make('iri')->readOnly(), + // Forms\Components\TextInput::make('rank')->readOnly(), + // ]) + // ->action(fn ( $record) => $record->advance()) + ->modalContent(function ($record, $get): View { + $name = ucfirst(trim($get('name'))); + $data = null; + // $iri = null; + // $organism = null; + // $rank = null; + + if ($name && $name != '') { + $data = self::getOLSIRI($name, 'species'); + // if ($data) { + // Self::updateOrganismModel($name, $data, $record, 'species'); + // } else { + // $data = Self::getOLSIRI(explode(' ', $name)[0], 'genus'); + // if ($data) { + // Self::updateOrganismModel($name, $data, $record, 'genus'); + // } else { + // $data = Self::getOLSIRI(explode(' ', $name)[0], 'family'); + // if ($data) { + // Self::updateOrganismModel($name, $data, $record, 'genus'); + // } else { + // [$name, $iri, $organism, $rank] = Self::getGNFMatches($name, $record); + // } + // } + // } + } + + return view( + 'forms.components.organism-info', + [ + 'data' => $data, + ], + ); + }) + ->action(function (array $data, Organism $record): void { + // Self::updateOrganismModel($data['name'], $data['iri'], $record, $data['rank']); + }) + ->slideOver() + ), + Forms\Components\TextInput::make('iri') + ->label('IRI') + ->maxLength(255), + Forms\Components\TextInput::make('rank') + ->maxLength(255), + ]; + } } diff --git a/app/Models/Report.php b/app/Models/Report.php index f6e45e66..71793af8 100644 --- a/app/Models/Report.php +++ b/app/Models/Report.php @@ -2,7 +2,6 @@ namespace App\Models; -use App\States\Report\ReportState; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; @@ -38,7 +37,6 @@ class Report extends Model implements Auditable protected $casts = [ 'suggested_changes' => 'array', - // 'status' => ReportState::class, ]; /** @@ -70,6 +68,11 @@ public function organisms(): MorphToMany return $this->morphedByMany(Organism::class, 'reportable'); } + // public function geoLocations(): MorphToMany + // { + // return $this->morphedByMany(Organism::class, 'reportable'); + // } + /** * Get all of the users that are assigned this report. */ From 367e9ca22a2f026c5d84b38d5c9cde079ddc3529 Mon Sep 17 00:00:00 2001 From: Sagar Date: Wed, 18 Sep 2024 02:00:13 +0200 Subject: [PATCH 24/47] wip: suggested changes are now stored in the reports table. SQL queries need to be built at the time of approving the report --- .../RelationManagers/MoleculesRelationManager.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/Filament/Dashboard/Resources/OrganismResource/RelationManagers/MoleculesRelationManager.php b/app/Filament/Dashboard/Resources/OrganismResource/RelationManagers/MoleculesRelationManager.php index df039774..c897b900 100644 --- a/app/Filament/Dashboard/Resources/OrganismResource/RelationManagers/MoleculesRelationManager.php +++ b/app/Filament/Dashboard/Resources/OrganismResource/RelationManagers/MoleculesRelationManager.php @@ -245,7 +245,6 @@ function (Molecule $molecule, $record): HtmlString { foreach ($molecues_with_muliple_locations as $molecule) { $current_sample_locations_subset = SampleLocation::findOrFail($molecule['sampleLocations']); $current_sample_locations_multiple = $records->where('id', $molecule['id'])[0]->sampleLocations()->where('organism_id', $this->getOwnerRecord()->id)->get(); - // dd($current_sample_locations_multiple, $current_sample_locations_subset); if ($current_sample_locations_multiple->pluck('id') == $current_sample_locations_subset->pluck('id')) { $currentOrganism->auditDetach('molecules', $molecule['id']); } From 49b918d8bf003d7daaebf0414d61058fda1531d3 Mon Sep 17 00:00:00 2001 From: Sagar Date: Thu, 26 Sep 2024 17:33:11 +0200 Subject: [PATCH 25/47] feat: improved suggestions by replacing the old key value pairs with tabs that can be approved by curators --- .../Dashboard/Resources/ReportResource.php | 398 ++++++++++++++---- .../ReportResource/Pages/EditReport.php | 11 + .../ReportResource/Pages/ViewReport.php | 11 + 3 files changed, 333 insertions(+), 87 deletions(-) diff --git a/app/Filament/Dashboard/Resources/ReportResource.php b/app/Filament/Dashboard/Resources/ReportResource.php index 97997f4e..19ff713f 100644 --- a/app/Filament/Dashboard/Resources/ReportResource.php +++ b/app/Filament/Dashboard/Resources/ReportResource.php @@ -12,8 +12,8 @@ use Archilex\AdvancedTables\Filters\AdvancedFilter; use Filament\Forms\Components\Actions; use Filament\Forms\Components\Actions\Action; +use Filament\Forms\Components\Checkbox; use Filament\Forms\Components\Grid; -use Filament\Forms\Components\KeyValue; use Filament\Forms\Components\Repeater; use Filament\Forms\Components\Select; use Filament\Forms\Components\SpatieTagsInput; @@ -30,6 +30,7 @@ use Filament\Tables\Columns\TextColumn; use Filament\Tables\Table; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Support\Facades\DB; use Illuminate\Support\HtmlString; use Illuminate\Support\Str; use Tapp\FilamentAuditing\RelationManagers\AuditsRelationManager; @@ -62,46 +63,26 @@ public static function form(Form $form): Form ->columnSpan(2), Actions::make([ Action::make('approve') - ->hidden(function (Get $get, string $operation) { - return ! auth()->user()->roles()->exists() || $get('status') == 'rejected' || $get('status') == 'approved' || $operation == 'create'; - }) ->form([ Textarea::make('reason'), ]) - ->action(function (array $data, Report $record, Molecule $molecule, $set): void { - - $record['status'] = 'approved'; - $record['reason'] = $data['reason']; - $record->save(); - - $set('status', 'rejected'); - - if ($record['mol_id_csv'] && ! $record['is_change']) { - $molecule_ids = explode(',', $record['mol_id_csv']); - $molecule = Molecule::whereIn('id', $molecule_ids)->get(); - foreach ($molecule as $mol) { - $mol->active = false; - $mol->save(); - } - } + ->action(function (array $data, Report $record, Molecule $molecule, $set, $livewire): void { + self::approveReport($data, $record, $molecule, $livewire); + $set('status', 'approved'); }), Action::make('reject') ->color('danger') - ->hidden(function (Get $get, string $operation) { - return ! auth()->user()->roles()->exists() || $get('status') == 'rejected' || $get('status') == 'approved' || $operation == 'create'; - }) ->form([ Textarea::make('reason'), ]) ->action(function (array $data, Report $record, $set): void { - - $record['status'] = 'rejected'; - $record['reason'] = $data['reason']; - $record->save(); - + self::rejectReport($data, $record); $set('status', 'rejected'); }), ]) + ->hidden(function (Get $get, string $operation) { + return ! auth()->user()->roles()->exists() || $get('status') == 'rejected' || $get('status') == 'approved' || $operation != 'edit'; + }) ->verticalAlignment(VerticalAlignment::End) ->columnStart(4), ]) @@ -130,21 +111,19 @@ public static function form(Form $form): Form ->hidden(function (Get $get) { return $get('is_change'); }), - // KeyValue::make('suggested_changes') - // ->hintIcon('heroicon-m-question-mark-circle', tooltip: 'Enter the property (in the left column) and suggested change (in the right column)') - // ->addActionLabel('Add property') - // ->keyLabel('Property') - // ->valueLabel('Suggested change') - // ->hidden(function (Get $get) { - // return ! $get('is_change'); - // }), - Tabs::make('Tabs') + Tabs::make('suggested_changes') ->tabs([ Tabs\Tab::make('organisms_changes') ->label('Organisms') ->schema([ Repeater::make('organisms_changes') ->schema([ + Checkbox::make('approve') + ->inline(false) + ->hidden(function (string $operation) { + return ! auth()->user()->roles()->exists() || $operation == 'create'; + }) + ->disabled(false), Select::make('operation') ->options([ 'update' => 'Update', @@ -152,7 +131,8 @@ public static function form(Form $form): Form 'add' => 'Add', ]) ->default('update') - ->live(), + ->live() + ->columnSpan(2), Select::make('organisms') ->label('Organism') ->searchable() @@ -163,12 +143,14 @@ public static function form(Form $form): Form ->getOptionLabelUsing(fn ($value): ?string => Organism::find($value)?->name) ->hidden(function (Get $get) { return $get('operation') == 'add'; - }), + }) + ->columnSpan(2), TextInput::make('name') ->label('Change to') ->hidden(function (Get $get) { return $get('operation') != 'update'; - }), + }) + ->columnSpan(2), Grid::make('new_organism_details') ->schema(Organism::getForm())->columns(3) ->hidden(function (Get $get) { @@ -177,7 +159,7 @@ public static function form(Form $form): Form ->columnStart(2), ]) ->reorderable(false) - ->columns(4), + ->columns(7), ]), Tabs\Tab::make('geo_locations_changes') @@ -185,6 +167,11 @@ public static function form(Form $form): Form ->schema([ Repeater::make('geo_locations_changes') ->schema([ + Checkbox::make('approve') + ->inline(false) + ->hidden(function (string $operation) { + return ! auth()->user()->roles()->exists() || $operation == 'create'; + }), Select::make('operation') ->options([ 'update' => 'Update', @@ -192,7 +179,8 @@ public static function form(Form $form): Form 'add' => 'Add', ]) ->default('update') - ->live(), + ->live() + ->columnSpan(2), Select::make('geo_locations') ->label('Geo Location') ->searchable() @@ -203,12 +191,14 @@ public static function form(Form $form): Form ->getOptionLabelUsing(fn ($value): ?string => GeoLocation::find($value)?->name) ->hidden(function (Get $get) { return $get('operation') == 'add'; - }), + }) + ->columnSpan(2), TextInput::make('name') ->label('Change to') ->hidden(function (Get $get) { return $get('operation') != 'update'; - }), + }) + ->columnSpan(2), Grid::make('new_geo_locations_details') ->schema(GeoLocation::getForm())->columns(3) ->hidden(function (Get $get) { @@ -217,13 +207,18 @@ public static function form(Form $form): Form ->columnStart(2), ]) ->reorderable(false) - ->columns(4), + ->columns(7), ]), Tabs\Tab::make('synonyms') ->label('Synonyms') ->schema([ Repeater::make('synonyms_changes') ->schema([ + Checkbox::make('approve') + ->inline(false) + ->hidden(function (string $operation) { + return ! auth()->user()->roles()->exists() || $operation == 'create'; + }), Select::make('operation') ->options([ 'update' => 'Update', @@ -231,7 +226,8 @@ public static function form(Form $form): Form 'add' => 'Add', ]) ->default('update') - ->live(), + ->live() + ->columnSpan(2), Select::make('synonyms') ->label('Synonym') ->searchable() @@ -239,20 +235,26 @@ public static function form(Form $form): Form ->getSearchResultsUsing(function (string $search, Get $get): array { $synonyms = Molecule::select('synonyms')->where('identifier', $get('../../mol_id_csv'))->get()[0]['synonyms']; $matched_synonyms = []; + $associative_matched_synonyms = []; foreach ($synonyms as $synonym) { str_contains(strtolower($synonym), strtolower($search)) ? array_push($matched_synonyms, $synonym) : null; } + foreach ($matched_synonyms as $item) { + $associative_matched_synonyms[$item] = $item; + } - return $matched_synonyms; + return $associative_matched_synonyms; }) ->hidden(function (Get $get) { return $get('operation') == 'add'; - }), + }) + ->columnSpan(2), TextInput::make('name') ->label('Change to') ->hidden(function (Get $get) { return $get('operation') != 'update'; - }), + }) + ->columnSpan(2), Grid::make('new_synonym_details') ->schema([ TagsInput::make('new_synonym') @@ -266,14 +268,19 @@ public static function form(Form $form): Form ->columnStart(2), ]) ->reorderable(false) - ->columns(4), + ->columns(7), ]), Tabs\Tab::make('identifiers') ->label('Identifiers') ->schema([ Repeater::make('identifiers_changes') ->schema([ - Select::make('identifer_to_change') + Checkbox::make('approve') + ->inline(false) + ->hidden(function (string $operation) { + return ! auth()->user()->roles()->exists() || $operation == 'create'; + }), + Select::make('change') ->options([ 'name' => 'Name', 'cas' => 'CAS', @@ -282,35 +289,63 @@ public static function form(Form $form): Form ->live(), Select::make('current_Name') ->options(function (Get $get): array { - return [Molecule::where('identifier', $get('../../mol_id_csv'))->get()[0]->name ?? '']; + $name = Molecule::where('identifier', $get('../../mol_id_csv'))->first()->name ?? ''; + + return [$name => $name]; }) - ->default(0) - ->disabled() ->hidden(function (Get $get) { - return $get('identifer_to_change') == 'cas'; - }), - Select::make('current_CAS') + return $get('change') == 'cas'; + }) + ->columnSpan(2), + Select::make('operation') + ->options([ + 'update' => 'Update', + 'remove' => 'Remove', + 'add' => 'Add', + ]) + ->default('update') + ->hidden(function (Get $get) { + return $get('change') == 'name'; + }) + ->live() + ->columnSpan(2), + Select::make('current_cas') + ->label('Current CAS') ->options(function (Get $get): array { - return [Molecule::where('identifier', $get('../../mol_id_csv'))->get()[0]->cas]; + $cas_ids = Molecule::where('identifier', $get('../../mol_id_csv'))->first()->cas ?? ''; + $associative_cas_ids = []; + foreach ($cas_ids as $item) { + $associative_cas_ids[$item] = $item; + } + + return $associative_cas_ids; }) - ->default(0) - ->disabled() ->hidden(function (Get $get) { - return $get('identifer_to_change') == 'name'; - }), + return $get('change') == 'name' || $get('operation') == 'add'; + }) + ->columnSpan(2), TextInput::make('new_name') ->label(function (Get $get) { - return $get('identifer_to_change') == 'name' ? 'New Name' : 'New CAS'; - }), + return $get('change') == 'name' ? 'New Name' : 'New CAS'; + }) + ->hidden(function (Get $get) { + return $get('operation') == 'remove'; + }) + ->columnSpan(2), ]) ->reorderable(false) - ->columns(4), + ->columns(7), ]), Tabs\Tab::make('citations') ->label('Citations') ->schema([ Repeater::make('citations_changes') ->schema([ + Checkbox::make('approve') + ->inline(false) + ->hidden(function (string $operation) { + return ! auth()->user()->roles()->exists() || $operation == 'create'; + }), Select::make('operation') ->options([ 'update' => 'Update', @@ -318,7 +353,8 @@ public static function form(Form $form): Form 'add' => 'Add', ]) ->default('update') - ->live(), + ->live() + ->columnSpan(2), Select::make('citations') ->label('Citation') ->searchable() @@ -329,12 +365,14 @@ public static function form(Form $form): Form ->getOptionLabelUsing(fn ($value): ?string => Citation::find($value)?->name) ->hidden(function (Get $get) { return $get('operation') == 'add'; - }), + }) + ->columnSpan(2), TextInput::make('name') ->label('Change to') ->hidden(function (Get $get) { return $get('operation') != 'update'; - }), + }) + ->columnSpan(2), Grid::make('new_citation_details') ->schema(Citation::getForm())->columns(3) ->hidden(function (Get $get) { @@ -343,12 +381,17 @@ public static function form(Form $form): Form ->columnStart(2), ]) ->reorderable(false) - ->columns(4), + ->columns(7), ]), Tabs\Tab::make('Chemical Classifications') ->schema([ + Checkbox::make('approve') + ->inline(false) + ->hidden(function (string $operation) { + return ! auth()->user()->roles()->exists() || $operation == 'create'; + }), // ... ]), ]) @@ -452,6 +495,7 @@ public static function form(Form $form): Form return true; } }) + ->live() ->hidden(function (Get $get, string $operation) { if ($operation != 'create') { return true; @@ -509,20 +553,8 @@ public static function table(Table $table): Table ->form([ Textarea::make('reason'), ]) - ->action(function (array $data, Report $record, Molecule $molecule): void { - - $record['status'] = 'approved'; - $record['reason'] = $data['reason']; - $record->save(); - - if ($record['mol_id_csv'] && ! $record['is_change']) { - $molecule_ids = explode(',', $record['mol_id_csv']); - $molecule = Molecule::whereIn('id', $molecule_ids)->get(); - foreach ($molecule as $mol) { - $mol->active = false; - $mol->save(); - } - } + ->action(function (array $data, Report $record, Molecule $molecule, $livewire): void { + self::approveReport($data, $record, $molecule, $livewire); }), Tables\Actions\Action::make('reject') // ->button() @@ -535,10 +567,7 @@ public static function table(Table $table): Table ]) ->action(function (array $data, Report $record): void { - - $record['status'] = 'rejected'; - $record['reason'] = $data['reason']; - $record->save(); + self::rejectReport($data, $record); }), ]) ->bulkActions([ @@ -578,4 +607,199 @@ public static function getEloquentQuery(): Builder return parent::getEloquentQuery(); } + + public static function approveReport(array $data, Report $record, Molecule $molecule, $livewire): void + { + $record['status'] = 'approved'; + $record['comment'] = $data['reason']; + + // In case of reporting a synthetic molecule, Deactivate Molecules + if ($record['mol_id_csv'] && ! $record['is_change']) { + $molecule_ids = explode(',', $record['mol_id_csv']); + $molecule = Molecule::whereIn('id', $molecule_ids)->get(); + foreach ($molecule as $mol) { + $mol->active = false; + $mol->save(); + } + } + + // In case of Changes, run SQL queries for the approved changes + if ($record['is_change']) { + + // To remove null values from the arrays before we assign them below + // dd(array_map(function($subArray) { + // return array_filter($subArray, function($value) { + // return !is_null($value); + // }); + // }, $livewire->data['organisms_changes'])); + + $suggestedChanges = $record->suggested_changes; + $suggestedChanges['organisms_changes'] = $livewire->data['organisms_changes']; + $suggestedChanges['geo_locations_changes'] = $livewire->data['geo_locations_changes']; + $suggestedChanges['synonyms_changes'] = $livewire->data['synonyms_changes']; + $suggestedChanges['identifiers_changes'] = $livewire->data['identifiers_changes']; + $suggestedChanges['citations_changes'] = $livewire->data['citations_changes']; + $record->suggested_changes = $suggestedChanges; + } + + // Run SQL queries for the approved changes + self::runSQLQueries($record); + + // Save the report record in any case + $record->save(); + } + + public static function rejectReport(array $data, Report $record): void + { + $record['status'] = 'rejected'; + $record['comment'] = $data['reason']; + $record->save(); + } + + public static function runSQLQueries(Report $record): void + { + DB::transaction(function () use ($record) { + // Check if organisms_changes exists and process it + if (isset($record->suggested_changes['organisms_changes'])) { + foreach ($record->suggested_changes['organisms_changes'] as $organism) { + if ($organism['approve'] && $organism['operation'] === 'update' && ! is_null($organism['organisms'])) { + // Perform update only if organisms ID is not null + // --------check if the organism name already exists + // --------need to handle iri and other fields of Organism for authentication + $db_organism = Organism::find($organism['organisms']); + $db_organism->name = $organism['name']; + $db_organism->save(); + } elseif ($organism['approve'] && $organism['operation'] === 'remove' && ! is_null($organism['organisms'])) { + // Perform delete only if organisms ID is not null + $db_organism = Organism::find($organism['organisms']); + $db_organism->delete(); + } elseif ($organism['approve'] && $organism['operation'] === 'add' && ! is_null($organism['name'])) { + // Perform insert only if name is not null (and other required fields can be checked too) + Organism::create([ + 'name' => $organism['name'], + 'iri' => $organism['iri'], + 'rank' => $organism['rank'], + ]); + } + } + } + + // Check if geo_locations_changes exists and process it + if (isset($record->suggested_changes['geo_locations_changes'])) { + foreach ($record->suggested_changes['geo_locations_changes'] as $geo_location) { + if ($geo_location['approve'] && $geo_location['operation'] === 'update' && ! is_null($geo_location['geo_locations'])) { + // Perform update only if geo_locations ID is not null + $db_geo_location = GeoLocation::find($geo_location['geo_locations']); + $db_geo_location->name = $geo_location['name']; + $db_geo_location->save(); + } elseif ($geo_location['approve'] && $geo_location['operation'] === 'remove' && ! is_null($geo_location['geo_locations'])) { + // Perform delete only if geo_locations ID is not null + $db_geo_location = GeoLocation::find($geo_location['geo_locations']); + $db_geo_location->delete(); + } elseif ($geo_location['approve'] && $geo_location['operation'] === 'add' && ! is_null($geo_location['name'])) { + // Perform insert only if name is not null + GeoLocation::create(['name' => $geo_location['name']]); + } + } + } + + // Check if synonyms_changes exists and process it + if (isset($record->suggested_changes['synonyms_changes'])) { + foreach ($record->suggested_changes['synonyms_changes'] as $synonym) { + if ($synonym['approve'] && $synonym['operation'] === 'update' && ! is_null($synonym['synonyms'])) { + // Perform update only if synonym name is not null + $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); + $synonyms = $db_molecule->synonyms; + foreach (array_keys($synonyms, $synonym['synonyms']) as $key) { + $synonyms[$key] = $synonym['name']; + } + $db_molecule->synonyms = $synonyms; + $db_molecule->save(); + } elseif ($synonym['approve'] && $synonym['operation'] === 'remove' && ! is_null($synonym['synonyms'])) { + // Perform delete only if synonym name is not null + $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); + $synonyms = $db_molecule->synonyms; + foreach (array_keys($synonyms, $synonym['synonyms']) as $key) { + unset($synonyms[$key]); + } + $db_molecule->synonyms = $synonyms; + $db_molecule->save(); + } elseif ($synonym['approve'] && $synonym['operation'] === 'add' && ! empty($synonym['new_synonym'])) { + // Perform insert only if new_synonym is not empty + $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); + $synonyms = $db_molecule->synonyms; + $synonyms = array_merge($synonyms, $synonym['new_synonym']); + $db_molecule->synonyms = $synonyms; + $db_molecule->save(); + } + } + } + + // Check if identifiers_changes exists and process it + if (isset($record->suggested_changes['identifiers_changes'])) { + foreach ($record->suggested_changes['identifiers_changes'] as $identifier) { + if ($identifier['approve'] && $identifier['change'] === 'name' && ! is_null($identifier['current_Name']) && ! is_null($identifier['new_name'])) { + // Update name if current name and new name are not null + $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); + $db_molecule->name = $identifier['new_name']; + $db_molecule->save(); + } elseif ($identifier['change'] == 'cas') { + if ($identifier['approve'] && $identifier['operation'] === 'update' && ! is_null($identifier['current_cas']) && ! is_null($identifier['new_name'])) { + // Update CAS if the current CAS and new name is not null + $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); + $cas = $db_molecule->cas; + foreach (array_keys($cas, $identifier['current_cas']) as $key) { + $cas[$key] = $identifier['new_name']; + } + $db_molecule->cas = $cas; + $db_molecule->save(); + } elseif ($identifier['approve'] && $identifier['operation'] === 'remove' && ! is_null($identifier['current_cas'])) { + // Perform delete only if CAS is not null + $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); + $cas = $db_molecule->cas; + foreach (array_keys($cas, $identifier['current_cas']) as $key) { + unset($cas[$key]); + } + $db_molecule->cas = $cas; + $db_molecule->save(); + } elseif ($identifier['approve'] && $identifier['operation'] === 'add' && ! is_null($identifier['new_name'])) { + // Perform insert only if new_name (CAS) is not null + $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); + $cas = $db_molecule->cas; + $cas[] = $identifier['new_name']; + $db_molecule->cas = $cas; + $db_molecule->save(); + } + } + } + } + + // Check if citations_changes exists and process it + if (isset($record->suggested_changes['citations_changes'])) { + foreach ($record->suggested_changes['citations_changes'] as $citation) { + if ($citation['approve'] && $citation['operation'] === 'update' && ! is_null($citation['citations'])) { + // Perform update only if citation ID is not null + $db_citation = Citation::find($citation['citations']); + // $db_citation->doi = $citation['doi']; + $db_citation->title = $citation['name']; + // $db_citation->authors = $citation['authors']; + // $db_citation->citation_text = $citation['citation_text']; + $db_citation->save(); + } elseif ($citation['approve'] && $citation['operation'] === 'remove' && ! is_null($citation['citations'])) { + // Perform delete only if citation ID is not null + $db_citation = Citation::find($citation['citations']); + $db_citation->delete(); + } elseif ($citation['approve'] && $citation['operation'] === 'add' && ! is_null($citation['name'])) { + // Perform insert only if name (citation ID) is not null + $db_citation = new Citation; + $db_citation->doi = $citation['doi']; + $db_citation->title = $citation['title']; + $db_citation->authors = $citation['authors']; + $db_citation->citation_text = $citation['citation_text']; + $db_citation->save(); + } + } + } + }); + } } diff --git a/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php b/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php index faec4f41..5471d32c 100644 --- a/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php +++ b/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php @@ -10,6 +10,17 @@ class EditReport extends EditRecord { protected static string $resource = ReportResource::class; + protected function mutateFormDataBeforeFill(array $data): array + { + $data['organisms_changes'] = $data['suggested_changes']['organisms_changes']; + $data['geo_locations_changes'] = $data['suggested_changes']['geo_locations_changes']; + $data['synonyms_changes'] = $data['suggested_changes']['synonyms_changes']; + $data['identifiers_changes'] = $data['suggested_changes']['identifiers_changes']; + $data['citations_changes'] = $data['suggested_changes']['citations_changes']; + + return $data; + } + protected function getHeaderActions(): array { return [ diff --git a/app/Filament/Dashboard/Resources/ReportResource/Pages/ViewReport.php b/app/Filament/Dashboard/Resources/ReportResource/Pages/ViewReport.php index 379e42c1..6e3966f4 100644 --- a/app/Filament/Dashboard/Resources/ReportResource/Pages/ViewReport.php +++ b/app/Filament/Dashboard/Resources/ReportResource/Pages/ViewReport.php @@ -8,4 +8,15 @@ class ViewReport extends ViewRecord { protected static string $resource = ReportResource::class; + + protected function mutateFormDataBeforeFill(array $data): array + { + $data['organisms_changes'] = $data['suggested_changes']['organisms_changes']; + $data['geo_locations_changes'] = $data['suggested_changes']['geo_locations_changes']; + $data['synonyms_changes'] = $data['suggested_changes']['synonyms_changes']; + $data['identifiers_changes'] = $data['suggested_changes']['identifiers_changes']; + $data['citations_changes'] = $data['suggested_changes']['citations_changes']; + + return $data; + } } From 5a669ccb5b88817c65dcb53e76f2d3e0143b6500 Mon Sep 17 00:00:00 2001 From: Sagar Date: Thu, 26 Sep 2024 17:34:17 +0200 Subject: [PATCH 26/47] fix: now the time line shows synonym and cas changes properly --- .../molecule-history-timeline.blade.php | 62 +++++++++++++------ 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/resources/views/livewire/molecule-history-timeline.blade.php b/resources/views/livewire/molecule-history-timeline.blade.php index 589ccd15..f3dd91bd 100644 --- a/resources/views/livewire/molecule-history-timeline.blade.php +++ b/resources/views/livewire/molecule-history-timeline.blade.php @@ -36,25 +36,49 @@ - - @switch(explode('.', $column_name)[0]) - @case('comment') - {{ $column_values['new_value'][0]['comment'] ?? 'N/A' }} - @break - @case('active') - {{ $column_values['new_value'] ? 'Activated' : 'Deactivated' }} - @break - @case('created') - Initial creation of the compound on COCONUT - @break - @case('organisms') - @case('sampleLocations') - Detached from:
{{ $column_values['old_value'] ?: 'N/A' }}
- Attached to:
{{ $column_values['new_value'] ?: 'N/A' }}
- @break - @default - Old Value:
{{ $column_values['old_value'] ?: 'N/A' }}
- New Value:
{{ $column_values['new_value'] ?: 'N/A' }} + + @switch(explode('.',$column_name)[0]) + @case('comment') + {{$column_values['new_value'][0]['comment'] ?? 'N/A'}} + @break + @case('active') + @if ($column_values['new_value']) + Activated + @else + Deactivated + @endif + @break + @case('created') + Initial creation of the compound on COCONUT + @break + @case('organisms') + @case('sampleLocations') + @if ($column_values['old_value']) + Detached from:
{{$column_values['old_value']?:'N/A'}}
+ @endif + @if ($column_values['new_value']) + Attached to:
{{$column_values['new_value']?:'N/A'}}
+ @endif + @break + @case('synonyms') + @if (array_diff($column_values['old_value'], $column_values['new_value'])) + Removed:
{{implode(', ',array_diff($column_values['old_value'], $column_values['new_value']))}}
+ @endif + @if (array_diff($column_values['new_value'], $column_values['old_value'])) + Added:
{{implode(', ',array_diff($column_values['new_value'], $column_values['old_value']))}}
+ @endif + @break + @case('cas') + @if (array_diff($column_values['old_value'], $column_values['new_value'])) + Removed:
{{implode(', ',array_diff($column_values['old_value'], $column_values['new_value']))}}
+ @endif + @if (array_diff($column_values['new_value'], $column_values['old_value'])) + Added:
{{implode(', ',array_diff($column_values['new_value'], $column_values['old_value']))}}
+ @endif + @break + @default + Old Value:
{{$column_values['old_value']??'N/A'}}
+ New Value:
{{$column_values['new_value']??'N/A'}} @endswitch
--}} From 51510be16f28d5132587473e5e02c7d56001c86b Mon Sep 17 00:00:00 2001 From: Sagar Date: Thu, 26 Sep 2024 17:35:19 +0200 Subject: [PATCH 27/47] chore: commented out the slide over (wip) --- app/Models/Organism.php | 159 ++++++++++++++++++++-------------------- 1 file changed, 80 insertions(+), 79 deletions(-) diff --git a/app/Models/Organism.php b/app/Models/Organism.php index ad4c09ab..489d5458 100644 --- a/app/Models/Organism.php +++ b/app/Models/Organism.php @@ -62,88 +62,89 @@ public static function getForm(): array ->required() ->unique(Organism::class, 'name') ->maxLength(255) - ->suffixAction( - Action::make('infoFromSources') - ->icon('heroicon-m-clipboard') - // ->fillForm(function ($record, callable $get): array { - // $entered_name = $get('name'); - // $name = ucfirst(trim($entered_name)); - // $data = null; - // $iri = null; - // $organism = null; - // $rank = null; + // ->suffixAction( + // Action::make('infoFromSources') + // ->icon('heroicon-m-clipboard') + // // ->fillForm(function ($record, callable $get): array { + // // $entered_name = $get('name'); + // // $name = ucfirst(trim($entered_name)); + // // $data = null; + // // $iri = null; + // // $organism = null; + // // $rank = null; - // if ($name && $name != '') { - // $data = Self::getOLSIRI($name, 'species'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'species'); - // Self::info("Mapped and updated: $name"); - // } else { - // $data = Self::getOLSIRI(explode(' ', $name)[0], 'genus'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'genus'); - // Self::info("Mapped and updated: $name"); - // } else { - // $data = Self::getOLSIRI(explode(' ', $name)[0], 'family'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'genus'); - // Self::info("Mapped and updated: $name"); - // } else { - // [$name, $iri, $organism, $rank] = Self::getGNFMatches($name, $record); - // } - // } - // } - // } - // return [ - // 'name' => $name, - // 'iri' => $iri, - // 'rank' => $rank, - // ]; - // }) - // ->form([ - // Forms\Components\TextInput::make('name')->readOnly(), - // Forms\Components\TextInput::make('iri')->readOnly(), - // Forms\Components\TextInput::make('rank')->readOnly(), - // ]) - // ->action(fn ( $record) => $record->advance()) - ->modalContent(function ($record, $get): View { - $name = ucfirst(trim($get('name'))); - $data = null; - // $iri = null; - // $organism = null; - // $rank = null; + // // if ($name && $name != '') { + // // $data = Self::getOLSIRI($name, 'species'); + // // if ($data) { + // // Self::updateOrganismModel($name, $data, $record, 'species'); + // // Self::info("Mapped and updated: $name"); + // // } else { + // // $data = Self::getOLSIRI(explode(' ', $name)[0], 'genus'); + // // if ($data) { + // // Self::updateOrganismModel($name, $data, $record, 'genus'); + // // Self::info("Mapped and updated: $name"); + // // } else { + // // $data = Self::getOLSIRI(explode(' ', $name)[0], 'family'); + // // if ($data) { + // // Self::updateOrganismModel($name, $data, $record, 'genus'); + // // Self::info("Mapped and updated: $name"); + // // } else { + // // [$name, $iri, $organism, $rank] = Self::getGNFMatches($name, $record); + // // } + // // } + // // } + // // } + // // return [ + // // 'name' => $name, + // // 'iri' => $iri, + // // 'rank' => $rank, + // // ]; + // // }) + // // ->form([ + // // Forms\Components\TextInput::make('name')->readOnly(), + // // Forms\Components\TextInput::make('iri')->readOnly(), + // // Forms\Components\TextInput::make('rank')->readOnly(), + // // ]) + // // ->action(fn ( $record) => $record->advance()) + // ->modalContent(function ($record, $get): View { + // $name = ucfirst(trim($get('name'))); + // $data = null; + // // $iri = null; + // // $organism = null; + // // $rank = null; - if ($name && $name != '') { - $data = self::getOLSIRI($name, 'species'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'species'); - // } else { - // $data = Self::getOLSIRI(explode(' ', $name)[0], 'genus'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'genus'); - // } else { - // $data = Self::getOLSIRI(explode(' ', $name)[0], 'family'); - // if ($data) { - // Self::updateOrganismModel($name, $data, $record, 'genus'); - // } else { - // [$name, $iri, $organism, $rank] = Self::getGNFMatches($name, $record); - // } - // } - // } - } + // if ($name && $name != '') { + // $data = self::getOLSIRI($name, 'species'); + // // if ($data) { + // // Self::updateOrganismModel($name, $data, $record, 'species'); + // // } else { + // // $data = Self::getOLSIRI(explode(' ', $name)[0], 'genus'); + // // if ($data) { + // // Self::updateOrganismModel($name, $data, $record, 'genus'); + // // } else { + // // $data = Self::getOLSIRI(explode(' ', $name)[0], 'family'); + // // if ($data) { + // // Self::updateOrganismModel($name, $data, $record, 'genus'); + // // } else { + // // [$name, $iri, $organism, $rank] = Self::getGNFMatches($name, $record); + // // } + // // } + // // } + // } - return view( - 'forms.components.organism-info', - [ - 'data' => $data, - ], - ); - }) - ->action(function (array $data, Organism $record): void { - // Self::updateOrganismModel($data['name'], $data['iri'], $record, $data['rank']); - }) - ->slideOver() - ), + // return view( + // 'forms.components.organism-info', + // [ + // 'data' => $data, + // ], + // ); + // }) + // ->action(function (array $data, Organism $record): void { + // // Self::updateOrganismModel($data['name'], $data['iri'], $record, $data['rank']); + // }) + // ->slideOver() + // ) + , Forms\Components\TextInput::make('iri') ->label('IRI') ->maxLength(255), From b75caa4eff6762705d76fdc2256a52b7722aacf3 Mon Sep 17 00:00:00 2001 From: Sagar Date: Thu, 26 Sep 2024 17:36:04 +0200 Subject: [PATCH 28/47] fix: minor fix related to creating citations --- app/Models/Citation.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Models/Citation.php b/app/Models/Citation.php index 94542b75..61f3d1c4 100644 --- a/app/Models/Citation.php +++ b/app/Models/Citation.php @@ -73,6 +73,7 @@ public static function getForm() ->live(onBlur: true) ->afterStateUpdated(function ($set, $state) { if (doiRegxMatch($state)) { + $set('failMessage', 'Fetching'); $citationDetails = fetchDOICitation($state); if ($citationDetails) { $set('title', $citationDetails['title']); @@ -103,7 +104,7 @@ public static function getForm() ->unique() ->rules([ fn (Get $get): Closure => function (string $attribute, $value, Closure $fail) use ($get) { - if ($get('failMessage') != 'No citation found. Please fill in the details manually') { + if ($get('failMessage') != 'Success') { $fail($get('failMessage')); } }, From 1475c470d5e054afffb9646f1674e4ee80bb9e46 Mon Sep 17 00:00:00 2001 From: Sagar Date: Sun, 29 Sep 2024 20:04:11 +0200 Subject: [PATCH 29/47] feat: improved the user friendliness (wip) --- .../Dashboard/Resources/ReportResource.php | 47 ++++++++++--------- .../ReportResource/Pages/CreateReport.php | 12 +++++ 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/app/Filament/Dashboard/Resources/ReportResource.php b/app/Filament/Dashboard/Resources/ReportResource.php index 19ff713f..e717152b 100644 --- a/app/Filament/Dashboard/Resources/ReportResource.php +++ b/app/Filament/Dashboard/Resources/ReportResource.php @@ -60,12 +60,18 @@ public static function form(Form $form): Form true => 'Request Changes to Data', ]) ->inline() + ->hidden(function () { + return request()->has('type'); + }) ->columnSpan(2), Actions::make([ Action::make('approve') ->form([ Textarea::make('reason'), ]) + ->hidden(function (Get $get, string $operation) { + return ! auth()->user()->roles()->exists() || $get('status') == 'rejected' || $get('status') == 'approved' || $operation != 'edit'; + }) ->action(function (array $data, Report $record, Molecule $molecule, $set, $livewire): void { self::approveReport($data, $record, $molecule, $livewire); $set('status', 'approved'); @@ -75,14 +81,18 @@ public static function form(Form $form): Form ->form([ Textarea::make('reason'), ]) + ->hidden(function (Get $get, string $operation) { + return ! auth()->user()->roles()->exists() || $get('status') == 'rejected' || $get('status') == 'approved' || $operation != 'edit'; + }) ->action(function (array $data, Report $record, $set): void { self::rejectReport($data, $record); $set('status', 'rejected'); }), + Action::make('viewCompoundPage') + ->color('info') + ->url(fn (): string => env('APP_URL').'/compounds/'.request()->compound_id) + ->openUrlInNewTab(), ]) - ->hidden(function (Get $get, string $operation) { - return ! auth()->user()->roles()->exists() || $get('status') == 'rejected' || $get('status') == 'approved' || $operation != 'edit'; - }) ->verticalAlignment(VerticalAlignment::End) ->columnStart(4), ]) @@ -96,14 +106,15 @@ public static function form(Form $form): Form return getReportTypes(); }) ->hidden(function (string $operation) { - if ($operation == 'create') { - return false; - } else { - return true; - } + return $operation != 'create' || request()->has('type'); }), TextInput::make('title') ->hintIcon('heroicon-m-question-mark-circle', tooltip: 'Title of the report. This is required.') + ->default(function () { + if (request()->type == 'change' && request()->has('compound_id')) { + return 'Request changes'; + } + }) ->required(), Textarea::make('evidence') ->hintIcon('heroicon-m-question-mark-circle', tooltip: 'Please provide Evidence/Comment to support your claims in this report. This will help our Curators in reviewing your report.') @@ -384,16 +395,6 @@ public static function form(Form $form): Form ->columns(7), ]), - - Tabs\Tab::make('Chemical Classifications') - ->schema([ - Checkbox::make('approve') - ->inline(false) - ->hidden(function (string $operation) { - return ! auth()->user()->roles()->exists() || $operation == 'create'; - }), - // ... - ]), ]) ->hidden(function (Get $get) { return ! $get('is_change'); @@ -409,7 +410,10 @@ public static function form(Form $form): Form $state, shouldOpenInNewTab: true, ), - ), + ) + ->hidden(function () { + return request()->has('type') && request()->type == 'change'; + }), Select::make('collections') ->hintIcon('heroicon-m-question-mark-circle', tooltip: 'Select the Collections you want to report. This will help our Curators in reviewing your report.') ->relationship('collections', 'title') @@ -497,9 +501,10 @@ public static function form(Form $form): Form }) ->live() ->hidden(function (Get $get, string $operation) { - if ($operation != 'create') { + if ($operation != 'create' || request()->type == 'change') { return true; - } elseif (! request()->has('compound_id') && $get('report_type') != 'molecule') { + } + if (! request()->has('compound_id') && $get('report_type') != 'molecule') { return true; } }) diff --git a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php index 2878f2c6..f9e0b47d 100644 --- a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php +++ b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php @@ -14,6 +14,18 @@ class CreateReport extends CreateRecord { protected static string $resource = ReportResource::class; + public function getTitle(): string + { + $title = 'Create Report'; + request()->type == 'change' ? $title = 'Request Changes' : $title = 'Report '; + if (request()->has('compound_id')) { + $molecule = Molecule::where('identifier', request()->compound_id)->first(); + $title = $title.' - '.$molecule->name.' ('.$molecule->identifier.')'; + } + + return __($title); + } + protected function afterFill(): void { $request = request(); From f650aee14efb75e65cb27a345ff1d53a2c8bbe79 Mon Sep 17 00:00:00 2001 From: Sagar Date: Wed, 2 Oct 2024 01:14:01 +0200 Subject: [PATCH 30/47] feat: the report changes form is made user friendly with pre-filled fields Accordingly changed the actions and eloquent queries. Commented out the table actions for now since they do not allow for approval of changes. --- .../Dashboard/Resources/ReportResource.php | 716 ++++++++---------- 1 file changed, 322 insertions(+), 394 deletions(-) diff --git a/app/Filament/Dashboard/Resources/ReportResource.php b/app/Filament/Dashboard/Resources/ReportResource.php index e717152b..25f001ff 100644 --- a/app/Filament/Dashboard/Resources/ReportResource.php +++ b/app/Filament/Dashboard/Resources/ReportResource.php @@ -13,6 +13,7 @@ use Filament\Forms\Components\Actions; use Filament\Forms\Components\Actions\Action; use Filament\Forms\Components\Checkbox; +use Filament\Forms\Components\Fieldset; use Filament\Forms\Components\Grid; use Filament\Forms\Components\Repeater; use Filament\Forms\Components\Select; @@ -45,6 +46,17 @@ class ReportResource extends Resource protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack'; + protected static $molecule = null; + + protected static $approved_changes = null; + + protected static $overall_changes = null; + + public function __construct() + { + self::$molecule = request()->has('compound_id') ? Molecule::where('identifier', request()->compound_id)->first() : null; + } + public static function form(Form $form): Form { return $form @@ -60,15 +72,19 @@ public static function form(Form $form): Form true => 'Request Changes to Data', ]) ->inline() - ->hidden(function () { - return request()->has('type'); + ->hidden(function (string $operation, $record) { + return $operation == 'create' ? request()->has('type') : true; }) ->columnSpan(2), Actions::make([ Action::make('approve') - ->form([ - Textarea::make('reason'), - ]) + ->form(function ($record, $livewire) { + self::$approved_changes = self::prepareApprovedChanges($record, $livewire); + $key_value_fields = getChangesToDisplayModal(self::$approved_changes); + array_unshift($key_value_fields, Textarea::make('reason')); + + return $key_value_fields; + }) ->hidden(function (Get $get, string $operation) { return ! auth()->user()->roles()->exists() || $get('status') == 'rejected' || $get('status') == 'approved' || $operation != 'edit'; }) @@ -90,7 +106,7 @@ public static function form(Form $form): Form }), Action::make('viewCompoundPage') ->color('info') - ->url(fn (): string => env('APP_URL').'/compounds/'.request()->compound_id) + ->url(fn (string $operation, $record): string => $operation === 'create' ? env('APP_URL').'/compounds/'.request()->compound_id : env('APP_URL').'/compounds/'.$record->mol_id_csv) ->openUrlInNewTab(), ]) ->verticalAlignment(VerticalAlignment::End) @@ -112,7 +128,7 @@ public static function form(Form $form): Form ->hintIcon('heroicon-m-question-mark-circle', tooltip: 'Title of the report. This is required.') ->default(function () { if (request()->type == 'change' && request()->has('compound_id')) { - return 'Request changes'; + return 'Request changes to '.request()->compound_id; } }) ->required(), @@ -124,275 +140,192 @@ public static function form(Form $form): Form }), Tabs::make('suggested_changes') ->tabs([ - Tabs\Tab::make('organisms_changes') - ->label('Organisms') + Tabs\Tab::make('compound_info_changes') + ->label('Compound Info') ->schema([ - Repeater::make('organisms_changes') + Fieldset::make('Geo Locations') ->schema([ - Checkbox::make('approve') + Checkbox::make('approve_geo_locations') + ->label('Approve') ->inline(false) ->hidden(function (string $operation) { return ! auth()->user()->roles()->exists() || $operation == 'create'; }) - ->disabled(false), - Select::make('operation') - ->options([ - 'update' => 'Update', - 'remove' => 'Remove', - 'add' => 'Add', - ]) - ->default('update') - ->live() - ->columnSpan(2), - Select::make('organisms') - ->label('Organism') - ->searchable() - ->searchDebounce(500) - ->getSearchResultsUsing(function (string $search, Get $get): array { - return Molecule::where('identifier', $get('../../mol_id_csv'))->get()[0]->organisms()->where('name', 'ilike', "%{$search}%")->limit(10)->pluck('organisms.name', 'organisms.id')->toArray() ?? []; - }) - ->getOptionLabelUsing(fn ($value): ?string => Organism::find($value)?->name) - ->hidden(function (Get $get) { - return $get('operation') == 'add'; - }) - ->columnSpan(2), - TextInput::make('name') - ->label('Change to') - ->hidden(function (Get $get) { - return $get('operation') != 'update'; - }) - ->columnSpan(2), - Grid::make('new_organism_details') - ->schema(Organism::getForm())->columns(3) - ->hidden(function (Get $get) { - return $get('operation') != 'add'; + ->columnSpan(1), + Select::make('existing_geo_locations') + ->label('Existing') + ->multiple() + ->options(function (): array { + $geo_locations = []; + if (self::$molecule) { + $geo_locations = self::$molecule->geo_locations->pluck('name', 'id')->toArray(); + } + + return $geo_locations; }) - ->columnStart(2), + ->columnSpan(4), + TagsInput::make('new_geo_locations') + ->label('New') + ->separator(',') + ->splitKeys([',']) + ->columnSpan(4), ]) - ->reorderable(false) - ->columns(7), - - ]), - Tabs\Tab::make('geo_locations_changes') - ->label('Geo Locations') - ->schema([ - Repeater::make('geo_locations_changes') + ->columns(9), + Fieldset::make('Synonyms') ->schema([ - Checkbox::make('approve') + Checkbox::make('approve_synonyms') + ->label('Approve') ->inline(false) ->hidden(function (string $operation) { return ! auth()->user()->roles()->exists() || $operation == 'create'; - }), - Select::make('operation') - ->options([ - 'update' => 'Update', - 'remove' => 'Remove', - 'add' => 'Add', - ]) - ->default('update') - ->live() - ->columnSpan(2), - Select::make('geo_locations') - ->label('Geo Location') - ->searchable() - ->searchDebounce(500) - ->getSearchResultsUsing(function (string $search, Get $get): array { - return Molecule::where('identifier', $get('../../mol_id_csv'))->get()[0]->geo_locations()->where('name', 'ilike', "%{$search}%")->limit(10)->pluck('geo_locations.name', 'geo_locations.id')->toArray(); }) - ->getOptionLabelUsing(fn ($value): ?string => GeoLocation::find($value)?->name) - ->hidden(function (Get $get) { - return $get('operation') == 'add'; - }) - ->columnSpan(2), - TextInput::make('name') - ->label('Change to') - ->hidden(function (Get $get) { - return $get('operation') != 'update'; - }) - ->columnSpan(2), - Grid::make('new_geo_locations_details') - ->schema(GeoLocation::getForm())->columns(3) - ->hidden(function (Get $get) { - return $get('operation') != 'add'; + ->columnSpan(1), + Select::make('existing_synonyms') + ->label('Existing') + ->multiple() + ->options(function (): array { + $synonyms = []; + if (self::$molecule) { + $synonyms = self::$molecule->synonyms; + } + + return $synonyms; }) - ->columnStart(2), + ->columnSpan(4), + TagsInput::make('new_synonyms') + ->label('New') + ->separator(',') + ->splitKeys([',']) + ->columnSpan(4), ]) - ->reorderable(false) - ->columns(7), - ]), - Tabs\Tab::make('synonyms') - ->label('Synonyms') - ->schema([ - Repeater::make('synonyms_changes') + ->columns(9), + Fieldset::make('Name') ->schema([ - Checkbox::make('approve') + Checkbox::make('approve_name') + ->label('Approve') ->inline(false) ->hidden(function (string $operation) { return ! auth()->user()->roles()->exists() || $operation == 'create'; - }), - Select::make('operation') - ->options([ - 'update' => 'Update', - 'remove' => 'Remove', - 'add' => 'Add', - ]) - ->default('update') - ->live() - ->columnSpan(2), - Select::make('synonyms') - ->label('Synonym') - ->searchable() - ->searchDebounce(500) - ->getSearchResultsUsing(function (string $search, Get $get): array { - $synonyms = Molecule::select('synonyms')->where('identifier', $get('../../mol_id_csv'))->get()[0]['synonyms']; - $matched_synonyms = []; - $associative_matched_synonyms = []; - foreach ($synonyms as $synonym) { - str_contains(strtolower($synonym), strtolower($search)) ? array_push($matched_synonyms, $synonym) : null; - } - foreach ($matched_synonyms as $item) { - $associative_matched_synonyms[$item] = $item; - } - - return $associative_matched_synonyms; }) - ->hidden(function (Get $get) { - return $get('operation') == 'add'; + ->columnSpan(1), + Textarea::make('name') + ->default(function () { + if (self::$molecule) { + return self::$molecule->name; + } }) - ->columnSpan(2), - TextInput::make('name') - ->label('Change to') - ->hidden(function (Get $get) { - return $get('operation') != 'update'; + ->columnSpan(4), + ]) + ->columns(9), + Fieldset::make('CAS') + ->schema([ + Checkbox::make('approve_cas') + ->label('Approve') + ->inline(false) + ->hidden(function (string $operation) { + return ! auth()->user()->roles()->exists() || $operation == 'create'; }) - ->columnSpan(2), - Grid::make('new_synonym_details') - ->schema([ - TagsInput::make('new_synonym') - ->label('New Synonym') - ->separator(',') - ->splitKeys([',']), - ])->columns(3) - ->hidden(function (Get $get) { - return $get('operation') != 'add'; + ->columnSpan(1), + Select::make('existing_cas') + ->label('Existing') + ->multiple() + ->options(function () { + if (self::$molecule) { + return self::$molecule->cas; + } }) - ->columnStart(2), + ->columnSpan(4), + TagsInput::make('new_cas') + ->label('New') + ->separator(',') + ->splitKeys([',']) + ->columnSpan(4), ]) - ->reorderable(false) - ->columns(7), + ->columns(9), ]), - Tabs\Tab::make('identifiers') - ->label('Identifiers') + Tabs\Tab::make('organisms_changes') + ->label('Organisms') ->schema([ - Repeater::make('identifiers_changes') + Fieldset::make('Organisms') ->schema([ - Checkbox::make('approve') - ->inline(false) + Checkbox::make('approve_existing_organisms') + ->label('Approve') ->hidden(function (string $operation) { return ! auth()->user()->roles()->exists() || $operation == 'create'; - }), - Select::make('change') - ->options([ - 'name' => 'Name', - 'cas' => 'CAS', - ]) - ->default('name') - ->live(), - Select::make('current_Name') - ->options(function (Get $get): array { - $name = Molecule::where('identifier', $get('../../mol_id_csv'))->first()->name ?? ''; - - return [$name => $name]; }) - ->hidden(function (Get $get) { - return $get('change') == 'cas'; - }) - ->columnSpan(2), - Select::make('operation') - ->options([ - 'update' => 'Update', - 'remove' => 'Remove', - 'add' => 'Add', - ]) - ->default('update') - ->hidden(function (Get $get) { - return $get('change') == 'name'; - }) - ->live() - ->columnSpan(2), - Select::make('current_cas') - ->label('Current CAS') - ->options(function (Get $get): array { - $cas_ids = Molecule::where('identifier', $get('../../mol_id_csv'))->first()->cas ?? ''; - $associative_cas_ids = []; - foreach ($cas_ids as $item) { - $associative_cas_ids[$item] = $item; + ->columnSpanFull(), + Select::make('existing_organisms') + ->label('Existing') + ->multiple() + ->options(function () { + if (self::$molecule) { + return self::$molecule->organisms->pluck('name', 'id')->toArray(); } - - return $associative_cas_ids; }) ->hidden(function (Get $get) { - return $get('change') == 'name' || $get('operation') == 'add'; - }) - ->columnSpan(2), - TextInput::make('new_name') - ->label(function (Get $get) { - return $get('change') == 'name' ? 'New Name' : 'New CAS'; + return $get('operation') == 'add'; }) - ->hidden(function (Get $get) { - return $get('operation') == 'remove'; + ->columnSpan(9), + ]) + ->columns(9), + + Repeater::make('new_organisms') + ->label('') + ->schema([ + Checkbox::make('approve_new_organism') + ->label('Approve') + ->hidden(function (string $operation) { + return ! auth()->user()->roles()->exists() || $operation == 'create'; }) - ->columnSpan(2), + ->disabled(false) + ->columnSpanFull(), + Grid::make('new_organism') + ->schema(Organism::getForm())->columns(4), ]) ->reorderable(false) - ->columns(7), + ->addActionLabel('Add New Organism') + ->defaultItems(0) + ->columns(9), + ]), Tabs\Tab::make('citations') ->label('Citations') ->schema([ - Repeater::make('citations_changes') + Fieldset::make('Citations') ->schema([ - Checkbox::make('approve') - ->inline(false) + Checkbox::make('approve_existing_citations') + ->label('Approve') ->hidden(function (string $operation) { return ! auth()->user()->roles()->exists() || $operation == 'create'; - }), - Select::make('operation') - ->options([ - 'update' => 'Update', - 'remove' => 'Remove', - 'add' => 'Add', - ]) - ->default('update') - ->live() - ->columnSpan(2), - Select::make('citations') - ->label('Citation') - ->searchable() - ->searchDebounce(500) - ->getSearchResultsUsing(function (string $search, Get $get): array { - return Molecule::where('identifier', $get('../../mol_id_csv'))->get()[0]->citations()->where('title', 'ilike', "%{$search}%")->limit(10)->pluck('citations.title', 'citations.id')->toArray(); - }) - ->getOptionLabelUsing(fn ($value): ?string => Citation::find($value)?->name) - ->hidden(function (Get $get) { - return $get('operation') == 'add'; }) - ->columnSpan(2), - TextInput::make('name') - ->label('Change to') - ->hidden(function (Get $get) { - return $get('operation') != 'update'; + ->columnSpanFull(), + Select::make('existing_citations') + ->label('Existing') + ->multiple() + ->options(function () { + if (self::$molecule) { + return self::$molecule->citations->where('title', '!=', null)->pluck('title', 'id')->toArray(); + } }) - ->columnSpan(2), - Grid::make('new_citation_details') - ->schema(Citation::getForm())->columns(3) - ->hidden(function (Get $get) { - return $get('operation') != 'add'; + ->columnSpan(9), + ]) + ->columns(9), + Repeater::make('new_citations') + ->label('') + ->schema([ + Checkbox::make('approve_new_citation') + ->label('Approve') + ->hidden(function (string $operation) { + return ! auth()->user()->roles()->exists() || $operation == 'create'; }) - ->columnStart(2), + ->columnSpanFull(), + Grid::make('new_citation') + ->schema(Citation::getForm())->columns(4), ]) ->reorderable(false) - ->columns(7), + ->addActionLabel('Add New Citation') + ->defaultItems(0) + ->columns(9), ]), ]) @@ -411,8 +344,8 @@ public static function form(Form $form): Form shouldOpenInNewTab: true, ), ) - ->hidden(function () { - return request()->has('type') && request()->type == 'change'; + ->hidden(function (string $operation, $record) { + return $operation == 'create' ? request()->has('type') && request()->type == 'change' : $record->is_change; }), Select::make('collections') ->hintIcon('heroicon-m-question-mark-circle', tooltip: 'Select the Collections you want to report. This will help our Curators in reviewing your report.') @@ -550,30 +483,30 @@ public static function table(Table $table): Table ->visible(function ($record) { return auth()->user()->roles()->exists() && $record['status'] == 'submitted'; }), - Tables\Actions\Action::make('approve') - // ->button() - ->hidden(function (Report $record) { - return ! auth()->user()->roles()->exists() || $record['status'] == 'draft' || $record['status'] == 'rejected' || $record['status'] == 'approved'; - }) - ->form([ - Textarea::make('reason'), - ]) - ->action(function (array $data, Report $record, Molecule $molecule, $livewire): void { - self::approveReport($data, $record, $molecule, $livewire); - }), - Tables\Actions\Action::make('reject') - // ->button() - ->color('danger') - ->hidden(function (Report $record) { - return ! auth()->user()->roles()->exists() || $record['status'] == 'draft' || $record['status'] == 'rejected' || $record['status'] == 'approved'; - }) - ->form([ - Textarea::make('reason'), - - ]) - ->action(function (array $data, Report $record): void { - self::rejectReport($data, $record); - }), + // Tables\Actions\Action::make('approve') + // // ->button() + // ->hidden(function (Report $record) { + // return ! auth()->user()->roles()->exists() || $record['status'] == 'draft' || $record['status'] == 'rejected' || $record['status'] == 'approved'; + // }) + // ->form([ + // Textarea::make('reason'), + // ]) + // ->action(function (array $data, Report $record, Molecule $molecule, $livewire): void { + // self::approveReport($data, $record, $molecule, $livewire); + // }), + // Tables\Actions\Action::make('reject') + // // ->button() + // ->color('danger') + // ->hidden(function (Report $record) { + // return ! auth()->user()->roles()->exists() || $record['status'] == 'draft' || $record['status'] == 'rejected' || $record['status'] == 'approved'; + // }) + // ->form([ + // Textarea::make('reason'), + + // ]) + // ->action(function (array $data, Report $record): void { + // self::rejectReport($data, $record); + // }), ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ @@ -613,10 +546,9 @@ public static function getEloquentQuery(): Builder return parent::getEloquentQuery(); } - public static function approveReport(array $data, Report $record, Molecule $molecule, $livewire): void + public static function prepareApprovedChanges(Report $record, $livewire) { - $record['status'] = 'approved'; - $record['comment'] = $data['reason']; + $approved_changes = []; // In case of reporting a synthetic molecule, Deactivate Molecules if ($record['mol_id_csv'] && ! $record['is_change']) { @@ -629,27 +561,67 @@ public static function approveReport(array $data, Report $record, Molecule $mole } // In case of Changes, run SQL queries for the approved changes + $approved_changes['mol_id_csv'] = $record['mol_id_csv']; if ($record['is_change']) { - // To remove null values from the arrays before we assign them below - // dd(array_map(function($subArray) { - // return array_filter($subArray, function($value) { - // return !is_null($value); - // }); - // }, $livewire->data['organisms_changes'])); - - $suggestedChanges = $record->suggested_changes; - $suggestedChanges['organisms_changes'] = $livewire->data['organisms_changes']; - $suggestedChanges['geo_locations_changes'] = $livewire->data['geo_locations_changes']; - $suggestedChanges['synonyms_changes'] = $livewire->data['synonyms_changes']; - $suggestedChanges['identifiers_changes'] = $livewire->data['identifiers_changes']; - $suggestedChanges['citations_changes'] = $livewire->data['citations_changes']; - $record->suggested_changes = $suggestedChanges; + if ($livewire->data['approve_geo_locations']) { + $approved_changes['existing_geo_locations'] = $livewire->data['existing_geo_locations']; + $approved_changes['new_geo_locations'] = $livewire->data['new_geo_locations']; + } + + if ($livewire->data['approve_synonyms']) { + $approved_changes['existing_synonyms'] = $livewire->data['existing_synonyms']; + $approved_changes['new_synonyms'] = $livewire->data['new_synonyms']; + } + + if ($livewire->data['approve_name']) { + $approved_changes['name'] = $livewire->data['name']; + } + + if ($livewire->data['approve_cas']) { + $approved_changes['existing_cas'] = $livewire->data['existing_cas']; + $approved_changes['new_cas'] = $livewire->data['new_cas']; + } + + if ($livewire->data['approve_existing_organisms']) { + $approved_changes['existing_organisms'] = $livewire->data['existing_organisms']; + } + if (count($livewire->data['new_organisms']) > 0) { + foreach ($livewire->data['new_organisms'] as $key => $organism) { + if ($organism['approve_new_organism']) { + $approved_changes['new_organisms'][] = $organism; + } + } + } + + if ($livewire->data['approve_existing_citations']) { + $approved_changes['existing_citations'] = $livewire->data['existing_citations']; + } + if (count($livewire->data['new_citations']) > 0) { + foreach ($livewire->data['new_citations'] as $key => $citation) { + if ($citation['approve_new_citation']) { + $approved_changes['new_citations'][] = $citation; + } + } + } } + return $approved_changes; + } + + public static function approveReport(array $data, Report $record, Molecule $molecule, $livewire): void + { + // dd($data, $record, $molecule, $livewire); // Run SQL queries for the approved changes self::runSQLQueries($record); + $suggested_changes = $record['suggested_changes']; + + $suggested_changes['approved_changes'] = self::$overall_changes; + $record['suggested_changes'] = $suggested_changes; + $record['comment'] = $data['reason']; + $record['status'] = 'approved'; + // Save the report record in any case $record->save(); } @@ -664,147 +636,103 @@ public static function rejectReport(array $data, Report $record): void public static function runSQLQueries(Report $record): void { DB::transaction(function () use ($record) { - // Check if organisms_changes exists and process it - if (isset($record->suggested_changes['organisms_changes'])) { - foreach ($record->suggested_changes['organisms_changes'] as $organism) { - if ($organism['approve'] && $organism['operation'] === 'update' && ! is_null($organism['organisms'])) { - // Perform update only if organisms ID is not null - // --------check if the organism name already exists - // --------need to handle iri and other fields of Organism for authentication - $db_organism = Organism::find($organism['organisms']); - $db_organism->name = $organism['name']; - $db_organism->save(); - } elseif ($organism['approve'] && $organism['operation'] === 'remove' && ! is_null($organism['organisms'])) { - // Perform delete only if organisms ID is not null - $db_organism = Organism::find($organism['organisms']); - $db_organism->delete(); - } elseif ($organism['approve'] && $organism['operation'] === 'add' && ! is_null($organism['name'])) { - // Perform insert only if name is not null (and other required fields can be checked too) - Organism::create([ - 'name' => $organism['name'], - 'iri' => $organism['iri'], - 'rank' => $organism['rank'], - ]); + self::$overall_changes = getOverallChanges(self::$approved_changes); + // dd(self::$overall_changes); + + // Check if 'molecule_id' is provided or use a default molecule for association/dissociation + $molecule = Molecule::where('identifier', $record['mol_id_csv'])->first(); + + // Apply Geo Location Changes + if (array_key_exists('geo_location_changes', self::$overall_changes)) { + if (! empty(self::$overall_changes['geo_location_changes']['delete'])) { + $detachable_geo_locations_ids = GeoLocation::whereIn('name', self::$overall_changes['geo_location_changes']['delete'])->pluck('id')->toArray(); + $molecule->auditDetach('geo_locations', $detachable_geo_locations_ids); + } + if (! empty(self::$overall_changes['geo_location_changes']['add'])) { + $geoLocations = explode(',', self::$overall_changes['geo_location_changes']['add']); + foreach ($geoLocations as $newLocation) { + $geo_location = GeoLocation::firstOrCreate(['name' => $newLocation]); + $molecule->auditAttach('geo_locations', $geo_location); } } } - // Check if geo_locations_changes exists and process it - if (isset($record->suggested_changes['geo_locations_changes'])) { - foreach ($record->suggested_changes['geo_locations_changes'] as $geo_location) { - if ($geo_location['approve'] && $geo_location['operation'] === 'update' && ! is_null($geo_location['geo_locations'])) { - // Perform update only if geo_locations ID is not null - $db_geo_location = GeoLocation::find($geo_location['geo_locations']); - $db_geo_location->name = $geo_location['name']; - $db_geo_location->save(); - } elseif ($geo_location['approve'] && $geo_location['operation'] === 'remove' && ! is_null($geo_location['geo_locations'])) { - // Perform delete only if geo_locations ID is not null - $db_geo_location = GeoLocation::find($geo_location['geo_locations']); - $db_geo_location->delete(); - } elseif ($geo_location['approve'] && $geo_location['operation'] === 'add' && ! is_null($geo_location['name'])) { - // Perform insert only if name is not null - GeoLocation::create(['name' => $geo_location['name']]); - } + // Apply Synonym Changes + if (array_key_exists('synonym_changes', self::$overall_changes)) { + $db_synonyms = $molecule->synonyms; + if (! empty(self::$overall_changes['synonym_changes']['delete'])) { + $db_synonyms = array_diff($db_synonyms, self::$overall_changes['synonym_changes']['delete']); + $molecule->synonyms = $db_synonyms; + } + if (! empty(self::$overall_changes['synonym_changes']['add'])) { + $synonyms = explode(',', self::$overall_changes['synonym_changes']['add']); + $db_synonyms = array_merge($db_synonyms, $synonyms); + $molecule->synonyms = $db_synonyms; } } - // Check if synonyms_changes exists and process it - if (isset($record->suggested_changes['synonyms_changes'])) { - foreach ($record->suggested_changes['synonyms_changes'] as $synonym) { - if ($synonym['approve'] && $synonym['operation'] === 'update' && ! is_null($synonym['synonyms'])) { - // Perform update only if synonym name is not null - $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); - $synonyms = $db_molecule->synonyms; - foreach (array_keys($synonyms, $synonym['synonyms']) as $key) { - $synonyms[$key] = $synonym['name']; - } - $db_molecule->synonyms = $synonyms; - $db_molecule->save(); - } elseif ($synonym['approve'] && $synonym['operation'] === 'remove' && ! is_null($synonym['synonyms'])) { - // Perform delete only if synonym name is not null - $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); - $synonyms = $db_molecule->synonyms; - foreach (array_keys($synonyms, $synonym['synonyms']) as $key) { - unset($synonyms[$key]); - } - $db_molecule->synonyms = $synonyms; - $db_molecule->save(); - } elseif ($synonym['approve'] && $synonym['operation'] === 'add' && ! empty($synonym['new_synonym'])) { - // Perform insert only if new_synonym is not empty - $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); - $synonyms = $db_molecule->synonyms; - $synonyms = array_merge($synonyms, $synonym['new_synonym']); - $db_molecule->synonyms = $synonyms; - $db_molecule->save(); - } + // Apply Name Changes + if (array_key_exists('name_change', self::$overall_changes)) { + $molecule->name = self::$overall_changes['name_change']['new']; + $molecule->save(); + $molecule->refresh(); + } + + // Apply CAS Changes + if (array_key_exists('cas_changes', self::$overall_changes)) { + $db_cas = $molecule->cas; + if (! empty(self::$overall_changes['cas_changes']['delete'])) { + $db_cas = array_diff($db_cas, self::$overall_changes['cas_changes']['delete']); + $molecule->cas = $db_cas; + } + if (! empty(self::$overall_changes['cas_changes']['add'])) { + $cas = explode(',', self::$overall_changes['cas_changes']['add']); + $db_cas = array_merge($db_cas, $cas); + $molecule->cas = $db_cas; } } - // Check if identifiers_changes exists and process it - if (isset($record->suggested_changes['identifiers_changes'])) { - foreach ($record->suggested_changes['identifiers_changes'] as $identifier) { - if ($identifier['approve'] && $identifier['change'] === 'name' && ! is_null($identifier['current_Name']) && ! is_null($identifier['new_name'])) { - // Update name if current name and new name are not null - $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); - $db_molecule->name = $identifier['new_name']; - $db_molecule->save(); - } elseif ($identifier['change'] == 'cas') { - if ($identifier['approve'] && $identifier['operation'] === 'update' && ! is_null($identifier['current_cas']) && ! is_null($identifier['new_name'])) { - // Update CAS if the current CAS and new name is not null - $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); - $cas = $db_molecule->cas; - foreach (array_keys($cas, $identifier['current_cas']) as $key) { - $cas[$key] = $identifier['new_name']; - } - $db_molecule->cas = $cas; - $db_molecule->save(); - } elseif ($identifier['approve'] && $identifier['operation'] === 'remove' && ! is_null($identifier['current_cas'])) { - // Perform delete only if CAS is not null - $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); - $cas = $db_molecule->cas; - foreach (array_keys($cas, $identifier['current_cas']) as $key) { - unset($cas[$key]); - } - $db_molecule->cas = $cas; - $db_molecule->save(); - } elseif ($identifier['approve'] && $identifier['operation'] === 'add' && ! is_null($identifier['new_name'])) { - // Perform insert only if new_name (CAS) is not null - $db_molecule = Molecule::where('identifier', $record->mol_id_csv)->first(); - $cas = $db_molecule->cas; - $cas[] = $identifier['new_name']; - $db_molecule->cas = $cas; - $db_molecule->save(); - } + // Apply Organism Changes: Dissociate from Molecule + if (array_key_exists('organism_changes', self::$overall_changes)) { + if (! empty(self::$overall_changes['organism_changes']['delete'])) { + $organismIds = Organism::whereIn('name', self::$overall_changes['organism_changes']['delete'])->pluck('id')->toArray(); + $molecule->auditDetach('organisms', $organismIds); + } + if (! empty(self::$overall_changes['organism_changes']['add'])) { + foreach (self::$overall_changes['organism_changes']['add'] as $newOrganism) { + $organism = Organism::firstOrCreate([ + 'name' => $newOrganism['name'], + 'iri' => $newOrganism['iri'], + 'rank' => $newOrganism['rank'], + 'molecule_count' => 1, + 'slug' => Str::slug($newOrganism['name']), + ]); + $molecule->auditAttach('organisms', $organism); } } } - // Check if citations_changes exists and process it - if (isset($record->suggested_changes['citations_changes'])) { - foreach ($record->suggested_changes['citations_changes'] as $citation) { - if ($citation['approve'] && $citation['operation'] === 'update' && ! is_null($citation['citations'])) { - // Perform update only if citation ID is not null - $db_citation = Citation::find($citation['citations']); - // $db_citation->doi = $citation['doi']; - $db_citation->title = $citation['name']; - // $db_citation->authors = $citation['authors']; - // $db_citation->citation_text = $citation['citation_text']; - $db_citation->save(); - } elseif ($citation['approve'] && $citation['operation'] === 'remove' && ! is_null($citation['citations'])) { - // Perform delete only if citation ID is not null - $db_citation = Citation::find($citation['citations']); - $db_citation->delete(); - } elseif ($citation['approve'] && $citation['operation'] === 'add' && ! is_null($citation['name'])) { - // Perform insert only if name (citation ID) is not null - $db_citation = new Citation; - $db_citation->doi = $citation['doi']; - $db_citation->title = $citation['title']; - $db_citation->authors = $citation['authors']; - $db_citation->citation_text = $citation['citation_text']; - $db_citation->save(); + // Apply Citation Changes: Dissociate from Molecule + if (array_key_exists('citation_changes', self::$overall_changes)) { + if (! empty(self::$overall_changes['citation_changes']['delete'])) { + $citations = Citation::whereIn('title', self::$overall_changes['citation_changes']['delete'])->get(); + $citationIds = $citations->pluck('id')->toArray(); + $molecule->auditDetach('citations', $citationIds); + } + if (! empty(self::$overall_changes['citation_changes']['add'])) { + foreach (self::$overall_changes['citation_changes']['add'] as $newCitation) { + $citation = Citation::firstOrCreate([ + 'doi' => $newCitation['doi'], + 'title' => $newCitation['title'], + 'authors' => $newCitation['authors'], + 'citation_text' => $newCitation['citation_text'], + ]); + $molecule->auditAttach('citations', $citation); } } } + + $molecule->save(); }); } } From 97a11dbe46e24b9d2db238d3604ca2f3ae8a9a99 Mon Sep 17 00:00:00 2001 From: Sagar Date: Wed, 2 Oct 2024 01:16:16 +0200 Subject: [PATCH 31/47] feat: enabled create time pop-up modal to display overall changes being requested The data structure of suggested changes is altered to suit the needs. --- .../ReportResource/Pages/CreateReport.php | 76 ++++++++++++++++--- 1 file changed, 67 insertions(+), 9 deletions(-) diff --git a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php index f9e0b47d..53cfb665 100644 --- a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php +++ b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php @@ -8,30 +8,46 @@ use App\Models\Collection; use App\Models\Molecule; use App\Models\Organism; +use Filament\Actions\Action; use Filament\Resources\Pages\CreateRecord; class CreateReport extends CreateRecord { protected static string $resource = ReportResource::class; + protected $molecule; + public function getTitle(): string { $title = 'Create Report'; request()->type == 'change' ? $title = 'Request Changes' : $title = 'Report '; if (request()->has('compound_id')) { - $molecule = Molecule::where('identifier', request()->compound_id)->first(); - $title = $title.' - '.$molecule->name.' ('.$molecule->identifier.')'; + $title = $title.' - '.$this->molecule->name.' ('.$this->molecule->identifier.')'; } return __($title); } + protected function beforeFill(): void + { + if (request()->has('compound_id')) { + $this->molecule = Molecule::where('identifier', request()->compound_id)->first(); + } + } + protected function afterFill(): void { $request = request(); + $this->data['compound_id'] = $request->compound_id; if ($request->type == 'change') { $this->data['is_change'] = true; + $this->data['existing_geo_locations'] = $this->molecule->geo_locations->pluck('name')->toArray(); + $this->data['existing_synonyms'] = $this->molecule->synonyms; + $this->data['existing_cas'] = array_values($this->molecule->cas); + $this->data['existing_organisms'] = $this->molecule->organisms->pluck('name')->toArray(); + $this->data['existing_citations'] = $this->molecule->citations->where('title', '!=', null)->pluck('title')->toArray(); } + if ($request->has('collection_uuid')) { $collection = Collection::where('uuid', $request->collection_uuid)->get(); $id = $collection[0]->id; @@ -79,14 +95,40 @@ protected function mutateFormDataBeforeCreate(array $data): array $data['user_id'] = auth()->id(); $data['status'] = 'submitted'; - $suggested_changes = []; - $suggested_changes['organisms_changes'] = $data['organisms_changes']; - $suggested_changes['geo_locations_changes'] = $data['geo_locations_changes']; - $suggested_changes['synonyms_changes'] = $data['synonyms_changes']; - $suggested_changes['identifiers_changes'] = $data['identifiers_changes']; - $suggested_changes['citations_changes'] = $data['citations_changes']; + if ($data['is_change'] == true) { + $suggested_changes = []; + $suggested_changes['existing_geo_locations'] = $data['existing_geo_locations']; + $suggested_changes['new_geo_locations'] = $data['new_geo_locations']; + $suggested_changes['approve_geo_locations'] = false; + + $suggested_changes['existing_synonyms'] = $data['existing_synonyms']; + $suggested_changes['new_synonyms'] = $data['new_synonyms']; + $suggested_changes['approve_synonyms'] = false; + + $suggested_changes['name'] = $data['name']; + $suggested_changes['approve_name'] = false; + + $suggested_changes['existing_cas'] = $data['existing_cas']; + $suggested_changes['new_cas'] = $data['new_cas']; + $suggested_changes['approve_cas'] = false; - $data['suggested_changes'] = $suggested_changes; + $suggested_changes['existing_organisms'] = $data['existing_organisms']; + $suggested_changes['approve_existing_organisms'] = false; + + $suggested_changes['new_organisms'] = $data['new_organisms']; + + $suggested_changes['existing_citations'] = $data['existing_citations']; + $suggested_changes['approve_existing_citations'] = false; + + $suggested_changes['new_citations'] = $data['new_citations']; + + $suggested_changes['overall_changes'] = getOverallChanges($data); + + // seperate copy for Curators + $suggested_changes['curator'] = $suggested_changes; + + $data['suggested_changes'] = $suggested_changes; + } return $data; } @@ -104,4 +146,20 @@ protected function afterCreate(): void ReportSubmitted::dispatch($this->record); } + + protected function getCreateFormAction(): Action + { + return parent::getCreateFormAction() + ->submit(null) + ->form(function () { + return getChangesToDisplayModal($this->data); + }) + ->modalHidden(function () { + return ! $this->data['is_change']; + }) + ->action(function () { + $this->closeActionModal(); + $this->create(); + }); + } } From 0f2acbe1701cf1baf766c4319fa400088717540d Mon Sep 17 00:00:00 2001 From: Sagar Date: Wed, 2 Oct 2024 01:21:12 +0200 Subject: [PATCH 32/47] feat: altered the edit and view pages to load the new structure of the suggested changes View and edit pages now use a separate curator copy of suggested changes so as to allow further modifications. --- .../ReportResource/Pages/EditReport.php | 65 +++++++++++++++++-- .../ReportResource/Pages/ViewReport.php | 32 +++++++-- 2 files changed, 87 insertions(+), 10 deletions(-) diff --git a/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php b/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php index 5471d32c..e3a7475b 100644 --- a/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php +++ b/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php @@ -12,11 +12,66 @@ class EditReport extends EditRecord protected function mutateFormDataBeforeFill(array $data): array { - $data['organisms_changes'] = $data['suggested_changes']['organisms_changes']; - $data['geo_locations_changes'] = $data['suggested_changes']['geo_locations_changes']; - $data['synonyms_changes'] = $data['suggested_changes']['synonyms_changes']; - $data['identifiers_changes'] = $data['suggested_changes']['identifiers_changes']; - $data['citations_changes'] = $data['suggested_changes']['citations_changes']; + if ($data['is_change'] == true) { + $curators_copy_changes = $data['suggested_changes']['curator']; + $data['existing_geo_locations'] = $curators_copy_changes['existing_geo_locations']; + $data['new_geo_locations'] = $curators_copy_changes['new_geo_locations']; + $data['approve_geo_locations'] = $curators_copy_changes['approve_geo_locations']; + + $data['existing_synonyms'] = $curators_copy_changes['existing_synonyms']; + $data['new_synonyms'] = $curators_copy_changes['new_synonyms']; + $data['approve_synonyms'] = $curators_copy_changes['approve_synonyms']; + + $data['name'] = $curators_copy_changes['name']; + $data['approve_name'] = $curators_copy_changes['approve_name']; + + $data['existing_cas'] = $curators_copy_changes['existing_cas']; + $data['new_cas'] = $curators_copy_changes['new_cas']; + $data['approve_cas'] = $curators_copy_changes['approve_cas']; + + $data['existing_organisms'] = $curators_copy_changes['existing_organisms']; + $data['approve_existing_organisms'] = $curators_copy_changes['approve_existing_organisms']; + + $data['new_organisms'] = $curators_copy_changes['new_organisms']; + + $data['existing_citations'] = $curators_copy_changes['existing_citations']; + $data['approve_existing_citations'] = $curators_copy_changes['approve_existing_citations']; + + $data['new_citations'] = $curators_copy_changes['new_citations']; + } + + return $data; + } + + protected function mutateFormDataBeforeSave(array $data): array + { + if ($data['is_change'] == true) { + $data['suggested_changes']['curator']['existing_geo_locations'] = $data['existing_geo_locations']; + $data['suggested_changes']['curator']['new_geo_locations'] = $data['new_geo_locations']; + $data['suggested_changes']['curator']['approve_geo_locations'] = $data['approve_geo_locations']; + + $data['suggested_changes']['curator']['existing_synonyms'] = $data['existing_synonyms']; + $data['suggested_changes']['curator']['new_synonyms'] = $data['new_synonyms']; + $data['suggested_changes']['curator']['approve_synonyms'] = $data['approve_synonyms']; + + $data['suggested_changes']['curator']['name'] = $data['name']; + $data['suggested_changes']['curator']['approve_name'] = $data['approve_name']; + + $data['suggested_changes']['curator']['existing_cas'] = $data['existing_cas']; + $data['suggested_changes']['curator']['new_cas'] = $data['new_cas']; + $data['suggested_changes']['curator']['approve_cas'] = $data['approve_cas']; + + $data['suggested_changes']['curator']['existing_organisms'] = $data['existing_organisms']; + $data['suggested_changes']['curator']['approve_existing_organisms'] = $data['approve_existing_organisms']; + + $data['suggested_changes']['curator']['new_organisms'] = $data['new_organisms']; + + $data['suggested_changes']['curator']['existing_citations'] = $data['existing_citations']; + $data['suggested_changes']['curator']['approve_existing_citations'] = $data['approve_existing_citations']; + + $data['suggested_changes']['curator']['new_citations'] = $data['new_citations']; + + } return $data; } diff --git a/app/Filament/Dashboard/Resources/ReportResource/Pages/ViewReport.php b/app/Filament/Dashboard/Resources/ReportResource/Pages/ViewReport.php index 6e3966f4..fedf1343 100644 --- a/app/Filament/Dashboard/Resources/ReportResource/Pages/ViewReport.php +++ b/app/Filament/Dashboard/Resources/ReportResource/Pages/ViewReport.php @@ -11,11 +11,33 @@ class ViewReport extends ViewRecord protected function mutateFormDataBeforeFill(array $data): array { - $data['organisms_changes'] = $data['suggested_changes']['organisms_changes']; - $data['geo_locations_changes'] = $data['suggested_changes']['geo_locations_changes']; - $data['synonyms_changes'] = $data['suggested_changes']['synonyms_changes']; - $data['identifiers_changes'] = $data['suggested_changes']['identifiers_changes']; - $data['citations_changes'] = $data['suggested_changes']['citations_changes']; + if ($data['is_change'] == true) { + $curators_copy_changes = $data['suggested_changes']['curator']; + $data['existing_geo_locations'] = $curators_copy_changes['existing_geo_locations']; + $data['new_geo_locations'] = $curators_copy_changes['new_geo_locations']; + $data['approve_geo_locations'] = $curators_copy_changes['approve_geo_locations']; + + $data['existing_synonyms'] = $curators_copy_changes['existing_synonyms']; + $data['new_synonyms'] = $curators_copy_changes['new_synonyms']; + $data['approve_synonyms'] = $curators_copy_changes['approve_synonyms']; + + $data['name'] = $curators_copy_changes['name']; + $data['approve_name'] = $curators_copy_changes['approve_name']; + + $data['existing_cas'] = $curators_copy_changes['existing_cas']; + $data['new_cas'] = $curators_copy_changes['new_cas']; + $data['approve_cas'] = $curators_copy_changes['approve_cas']; + + $data['existing_organisms'] = $curators_copy_changes['existing_organisms']; + $data['approve_existing_organisms'] = $curators_copy_changes['approve_existing_organisms']; + + $data['new_organisms'] = $curators_copy_changes['new_organisms']; + + $data['existing_citations'] = $curators_copy_changes['existing_citations']; + $data['approve_existing_citations'] = $curators_copy_changes['approve_existing_citations']; + + $data['new_citations'] = $curators_copy_changes['new_citations']; + } return $data; } From ed645af1020a8607daad6e2ed9f567b66300bab8 Mon Sep 17 00:00:00 2001 From: Sagar Date: Wed, 2 Oct 2024 01:23:01 +0200 Subject: [PATCH 33/47] feat: new helper functions and fixes to the old ones to accommodate report suggestions workflow. --- app/Helper.php | 149 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 148 insertions(+), 1 deletion(-) diff --git a/app/Helper.php b/app/Helper.php index 39e3df31..76386b5f 100644 --- a/app/Helper.php +++ b/app/Helper.php @@ -1,6 +1,8 @@ 'id', 'name' => 'name', 'title' => 'title', + 'title' => 'title', // 'identifier' => 'identifier', ]; @@ -195,14 +198,16 @@ function changeAudit(array $data): array $data[$key_type][$changed_model] = []; foreach ($changed_data_values as $key => $value) { $value = is_array($value) ? $value : $value->toArray(); + if (array_key_exists('name', $value)) { if (array_key_exists('name', $value)) { if (array_key_exists('identifier', $value)) { $value['name'] = $value['name'].' (ID: '.$value['id'].')'.' (COCONUT ID: '.$value['identifier'].')'; } else { + // ! array_key_exists('name', $value) ? dd($value) : ''; $value['name'] = $value['name'].' (ID: '.$value['id'].')'; } } else { - $value['name'] = $value['title'].' (ID: '.$value['id'].')'; + $value['title'] = $value['title'].' (ID: '.$value['id'].')'; } $data[$key_type][$changed_model][$key] = array_intersect_key($value, $whitelist); } @@ -235,3 +240,145 @@ function flattenArray(array $array, $prefix = ''): array return $result; } + +function getChangesToDisplayModal($data) +{ + $key_values = []; + $overall_changes = getOverallChanges($data); + + foreach ($overall_changes as $key => $value) { + if (count($value['changes']) == 0) { + continue; + } + array_push($key_values, KeyValue::make($key) + ->addable(false) + ->deletable(false) + ->keyLabel($value['key']) + ->valueLabel($value['value']) + ->editableKeys(false) + ->editableValues(false) + ->default( + $value['changes'] + )); + } + + return $key_values; +} + +function getOverallChanges($data) +{ + $overall_changes = []; + $geo_location_changes = []; + $molecule = Molecule::where('identifier', $data['mol_id_csv'])->first(); + + $db_geo_locations = $molecule->geo_locations->pluck('name')->toArray(); + $deletable_locations = array_key_exists('existing_geo_locations', $data) ? array_diff($db_geo_locations, $data['existing_geo_locations']) : []; + $new_locations = array_key_exists('new_geo_locations', $data) ? (is_string($data['new_geo_locations']) ? $data['new_geo_locations'] : implode(',', $data['new_geo_locations'])) : null; + if (count($deletable_locations) > 0 || $new_locations) { + $key = implode(',', $deletable_locations) == '' ? ' ' : implode(',', $deletable_locations); + $geo_location_changes[$key] = $new_locations; + $overall_changes['geo_location_changes'] = [ + 'key' => 'Delete', + 'value' => 'Add', + 'changes' => $geo_location_changes, + 'delete' => $deletable_locations, + 'add' => $new_locations, + ]; + } + + $synonym_changes = []; + $db_synonyms = $molecule->synonyms; + $deletable_synonyms = array_key_exists('existing_synonyms', $data) ? array_diff($db_synonyms, $data['existing_synonyms']) : []; + $new_synonyms = array_key_exists('new_synonyms', $data) ? (is_string($data['new_synonyms']) ? $data['new_synonyms'] : implode(',', $data['new_synonyms'])) : null; + if (count($deletable_synonyms) > 0 || $new_synonyms) { + $key = implode(',', $deletable_synonyms) == '' ? ' ' : implode(',', $deletable_synonyms); + $synonym_changes[$key] = $new_synonyms; + $overall_changes['synonym_changes'] = [ + 'key' => 'Delete', + 'value' => 'Add', + 'changes' => $synonym_changes, + 'delete' => $deletable_synonyms, + 'add' => $new_synonyms, + ]; + } + + $name_change = []; + if (array_key_exists('name', $data) && $data['name'] && $data['name'] != $molecule->name) { + $name_change[$molecule->name] = $data['name']; + $overall_changes['name_change'] = [ + 'key' => 'Old', + 'value' => 'New', + 'changes' => $name_change, + 'old' => $molecule->name, + 'new' => $data['name'], + ]; + } + + $cas_changes = []; + $db_cas = $molecule->cas; + $deletable_cas = array_key_exists('existing_cas', $data) ? array_diff($db_cas, $data['existing_cas']) : []; + $new_cas = array_key_exists('new_cas', $data) ? (is_string($data['new_cas']) ? $data['new_cas'] : implode(',', $data['new_cas'])) : null; + if (count($deletable_cas) > 0 || $new_cas) { + $key = implode(',', $deletable_cas) == '' ? ' ' : implode(',', $deletable_cas); + $cas_changes[$key] = $new_cas; + $overall_changes['cas_changes'] = [ + 'key' => 'Delete', + 'value' => 'Add', + 'changes' => $cas_changes, + 'delete' => $deletable_cas, + 'add' => $new_cas, + ]; + } + + $organism_changes = []; + $db_organisms = $molecule->organisms->pluck('name')->toArray(); + $deletable_organisms = array_key_exists('existing_organisms', $data) ? array_diff($db_organisms, $data['existing_organisms']) : []; + $new_organisms = []; + $new_organisms_form_data = []; + if (array_key_exists('new_organisms', $data)) { + foreach ($data['new_organisms'] as $organism) { + if ($organism['name']) { + $new_organisms[] = $organism['name']; + $new_organisms_form_data[] = $organism; + } + } + } + if (count($deletable_organisms) > 0 || count($new_organisms) > 0) { + $key = implode(',', $deletable_organisms) == '' ? ' ' : implode(',', $deletable_organisms); + $organism_changes[$key] = implode(',', $new_organisms); + $overall_changes['organism_changes'] = [ + 'key' => 'Delete', + 'value' => 'Add', + 'changes' => $organism_changes, + 'delete' => $deletable_organisms, + 'add' => $new_organisms_form_data, + ]; + } + + $citation_changes = []; + $db_citations = $molecule->citations->where('title', '<>', null)->pluck('title')->toArray(); + $deletable_citations = array_key_exists('existing_citations', $data) ? array_diff($db_citations, $data['existing_citations']) : []; + $new_citations = []; + $new_citations_form_data = []; + if (array_key_exists('new_citations', $data)) { + foreach ($data['new_citations'] as $ciation) { + if ($ciation['title']) { + $new_citations[] = $ciation['title']; + $new_citations_form_data[] = $ciation; + } + } + } + if (count($deletable_citations) > 0 || count($new_citations) > 0) { + $key = implode(',', $deletable_citations) == '' ? ' ' : implode(',', $deletable_citations); + $citation_changes[$key] = implode(',', $new_citations); + $overall_changes['citation_changes'] = [ + 'key' => 'Delete', + 'value' => 'Add', + 'changes' => $citation_changes, + 'delete' => $deletable_citations, + 'add' => $new_citations_form_data, + ]; + } + + return $overall_changes; +} From 6c1c1aa8619cea273a96b8133e117b8e6602440f Mon Sep 17 00:00:00 2001 From: Sagar Date: Wed, 2 Oct 2024 01:23:37 +0200 Subject: [PATCH 34/47] feat: now timeline can handle citations --- .../views/livewire/molecule-history-timeline.blade.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/resources/views/livewire/molecule-history-timeline.blade.php b/resources/views/livewire/molecule-history-timeline.blade.php index f3dd91bd..b7c3bc5c 100644 --- a/resources/views/livewire/molecule-history-timeline.blade.php +++ b/resources/views/livewire/molecule-history-timeline.blade.php @@ -76,6 +76,14 @@ Added:
{{implode(', ',array_diff($column_values['new_value'], $column_values['old_value']))}}
@endif @break + @case('citations') + @if ($column_values['old_value']) + Detached from:
{{$column_values['old_value']?:'N/A'}}
+ @endif + @if ($column_values['new_value']) + Attached to:
{{$column_values['new_value']?:'N/A'}}
+ @endif + @break @default Old Value:
{{$column_values['old_value']??'N/A'}}
New Value:
{{$column_values['new_value']??'N/A'}} From 0eb2497dd5628a63bdd4492446f5ed3b38982a26 Mon Sep 17 00:00:00 2001 From: Sagar Date: Wed, 2 Oct 2024 01:25:09 +0200 Subject: [PATCH 35/47] chore: removed dd statements. --- app/Filament/Dashboard/Resources/ReportResource.php | 2 -- app/Helper.php | 1 - app/Livewire/MoleculeHistoryTimeline.php | 2 -- 3 files changed, 5 deletions(-) diff --git a/app/Filament/Dashboard/Resources/ReportResource.php b/app/Filament/Dashboard/Resources/ReportResource.php index 25f001ff..185cbe68 100644 --- a/app/Filament/Dashboard/Resources/ReportResource.php +++ b/app/Filament/Dashboard/Resources/ReportResource.php @@ -611,7 +611,6 @@ public static function prepareApprovedChanges(Report $record, $livewire) public static function approveReport(array $data, Report $record, Molecule $molecule, $livewire): void { - // dd($data, $record, $molecule, $livewire); // Run SQL queries for the approved changes self::runSQLQueries($record); @@ -637,7 +636,6 @@ public static function runSQLQueries(Report $record): void { DB::transaction(function () use ($record) { self::$overall_changes = getOverallChanges(self::$approved_changes); - // dd(self::$overall_changes); // Check if 'molecule_id' is provided or use a default molecule for association/dissociation $molecule = Molecule::where('identifier', $record['mol_id_csv'])->first(); diff --git a/app/Helper.php b/app/Helper.php index 76386b5f..1a24fd47 100644 --- a/app/Helper.php +++ b/app/Helper.php @@ -203,7 +203,6 @@ function changeAudit(array $data): array if (array_key_exists('identifier', $value)) { $value['name'] = $value['name'].' (ID: '.$value['id'].')'.' (COCONUT ID: '.$value['identifier'].')'; } else { - // ! array_key_exists('name', $value) ? dd($value) : ''; $value['name'] = $value['name'].' (ID: '.$value['id'].')'; } } else { diff --git a/app/Livewire/MoleculeHistoryTimeline.php b/app/Livewire/MoleculeHistoryTimeline.php index fdb71291..dddb734f 100644 --- a/app/Livewire/MoleculeHistoryTimeline.php +++ b/app/Livewire/MoleculeHistoryTimeline.php @@ -18,8 +18,6 @@ public function getHistory() $audit_data[$index]['user_name'] = $audit->getMetadata()['user_name']; $audit_data[$index]['event'] = $audit->getMetadata()['audit_event']; $audit_data[$index]['created_at'] = date('Y/m/d', strtotime($audit->getMetadata()['audit_created_at'])); - // dd($audit->old_values, $audit->new_values); - // dd($audit->getModified()); $values = ! empty($audit->old_values) ? $audit->old_values : $audit->new_values; $first_affected_column = ! empty($values) ? array_keys($values)[0] : null; From 206dc4b7f998d84dd3750b2c6ca00a65bf499481 Mon Sep 17 00:00:00 2001 From: Sagar Date: Wed, 2 Oct 2024 17:41:29 +0200 Subject: [PATCH 36/47] feat: now only the fields requested for changes are available and the rest are disabled in edit page --- .../Dashboard/Resources/ReportResource.php | 34 +++++++++++++++++-- .../ReportResource/Pages/CreateReport.php | 5 +-- .../ReportResource/Pages/EditReport.php | 27 ++++++++++++++- 3 files changed, 61 insertions(+), 5 deletions(-) diff --git a/app/Filament/Dashboard/Resources/ReportResource.php b/app/Filament/Dashboard/Resources/ReportResource.php index 185cbe68..7326af3a 100644 --- a/app/Filament/Dashboard/Resources/ReportResource.php +++ b/app/Filament/Dashboard/Resources/ReportResource.php @@ -163,11 +163,17 @@ public static function form(Form $form): Form return $geo_locations; }) + ->disabled(function (Get $get) { + return ! $get('show_geo_location_existing'); + }) ->columnSpan(4), TagsInput::make('new_geo_locations') ->label('New') ->separator(',') ->splitKeys([',']) + ->disabled(function (Get $get) { + return ! $get('show_geo_location_new'); + }) ->columnSpan(4), ]) ->columns(9), @@ -191,11 +197,17 @@ public static function form(Form $form): Form return $synonyms; }) + ->disabled(function (Get $get) { + return ! $get('show_synonym_existing'); + }) ->columnSpan(4), TagsInput::make('new_synonyms') ->label('New') ->separator(',') ->splitKeys([',']) + ->disabled(function (Get $get) { + return ! $get('show_synonym_new'); + }) ->columnSpan(4), ]) ->columns(9), @@ -214,6 +226,9 @@ public static function form(Form $form): Form return self::$molecule->name; } }) + ->disabled(function (Get $get) { + return ! $get('show_name_change'); + }) ->columnSpan(4), ]) ->columns(9), @@ -234,11 +249,17 @@ public static function form(Form $form): Form return self::$molecule->cas; } }) + ->disabled(function (Get $get) { + return ! $get('show_cas_existing'); + }) ->columnSpan(4), TagsInput::make('new_cas') ->label('New') ->separator(',') ->splitKeys([',']) + ->disabled(function (Get $get) { + return ! $get('show_cas_new'); + }) ->columnSpan(4), ]) ->columns(9), @@ -262,8 +283,8 @@ public static function form(Form $form): Form return self::$molecule->organisms->pluck('name', 'id')->toArray(); } }) - ->hidden(function (Get $get) { - return $get('operation') == 'add'; + ->disabled(function (Get $get) { + return ! $get('show_organism_existing'); }) ->columnSpan(9), ]) @@ -285,6 +306,9 @@ public static function form(Form $form): Form ->reorderable(false) ->addActionLabel('Add New Organism') ->defaultItems(0) + ->disabled(function (Get $get) { + return ! $get('show_organism_new'); + }) ->columns(9), ]), @@ -307,6 +331,9 @@ public static function form(Form $form): Form return self::$molecule->citations->where('title', '!=', null)->pluck('title', 'id')->toArray(); } }) + ->disabled(function (Get $get) { + return ! $get('show_citation_existing'); + }) ->columnSpan(9), ]) ->columns(9), @@ -325,6 +352,9 @@ public static function form(Form $form): Form ->reorderable(false) ->addActionLabel('Add New Citation') ->defaultItems(0) + ->disabled(function (Get $get) { + return ! $get('show_citation_new'); + }) ->columns(9), ]), diff --git a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php index 53cfb665..b65c15bc 100644 --- a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php +++ b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php @@ -122,11 +122,12 @@ protected function mutateFormDataBeforeCreate(array $data): array $suggested_changes['new_citations'] = $data['new_citations']; - $suggested_changes['overall_changes'] = getOverallChanges($data); - // seperate copy for Curators $suggested_changes['curator'] = $suggested_changes; + // Overall Changes suggested + $suggested_changes['overall_changes'] = getOverallChanges($data); + $data['suggested_changes'] = $suggested_changes; } diff --git a/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php b/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php index e3a7475b..ffaaa40e 100644 --- a/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php +++ b/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php @@ -13,6 +13,32 @@ class EditReport extends EditRecord protected function mutateFormDataBeforeFill(array $data): array { if ($data['is_change'] == true) { + // initiate the flags to show only the fields that need to be shown + $data['show_geo_location_existing'] = $data['suggested_changes']['overall_changes']['geo_location_changes']['delete'] ? true : false; + if (array_key_exists('geo_location_changes', $data['suggested_changes']['overall_changes'])) { + $data['show_geo_location_existing'] = $data['suggested_changes']['overall_changes']['geo_location_changes']['delete'] ? true : false; + $data['show_geo_location_new'] = $data['suggested_changes']['overall_changes']['geo_location_changes']['add'] ? true : false; + } + if (array_key_exists('synonym_changes', $data['suggested_changes']['overall_changes'])) { + $data['show_synonym_existing'] = $data['suggested_changes']['overall_changes']['synonym_changes']['delete'] ? true : false; + $data['show_synonym_new'] = $data['suggested_changes']['overall_changes']['synonym_changes']['add'] ? true : false; + } + if (array_key_exists('name_change', $data['suggested_changes']['overall_changes'])) { + $data['show_name_change'] = $data['suggested_changes']['overall_changes']['name_change'] ? true : false; + } + if (array_key_exists('cas_changes', $data['suggested_changes']['overall_changes'])) { + $data['show_cas_existing'] = $data['suggested_changes']['overall_changes']['cas_changes']['delete'] ? true : false; + $data['show_cas_new'] = $data['suggested_changes']['overall_changes']['cas_changes']['add'] ? true : false; + } + if (array_key_exists('organism_changes', $data['suggested_changes']['overall_changes'])) { + $data['show_organism_existing'] = $data['suggested_changes']['overall_changes']['organism_changes']['delete'] ? true : false; + $data['show_organism_new'] = $data['suggested_changes']['overall_changes']['organism_changes']['add'] ? true : false; + } + if (array_key_exists('citation_changes', $data['suggested_changes']['overall_changes'])) { + $data['show_citation_existing'] = $data['suggested_changes']['overall_changes']['citation_changes']['delete'] ? true : false; + $data['show_citation_new'] = $data['suggested_changes']['overall_changes']['citation_changes']['add'] ? true : false; + } + $curators_copy_changes = $data['suggested_changes']['curator']; $data['existing_geo_locations'] = $curators_copy_changes['existing_geo_locations']; $data['new_geo_locations'] = $curators_copy_changes['new_geo_locations']; @@ -70,7 +96,6 @@ protected function mutateFormDataBeforeSave(array $data): array $data['suggested_changes']['curator']['approve_existing_citations'] = $data['approve_existing_citations']; $data['suggested_changes']['curator']['new_citations'] = $data['new_citations']; - } return $data; From 7e83f7b3c9ba4b2236c1cf201056dec040bb7dad Mon Sep 17 00:00:00 2001 From: Sagar Date: Wed, 2 Oct 2024 23:56:12 +0200 Subject: [PATCH 37/47] fix: the disabling of non-suggested fields is restricted only to edit --- .../Dashboard/Resources/ReportResource.php | 58 +++++++++++-------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/app/Filament/Dashboard/Resources/ReportResource.php b/app/Filament/Dashboard/Resources/ReportResource.php index 7326af3a..c926a01e 100644 --- a/app/Filament/Dashboard/Resources/ReportResource.php +++ b/app/Filament/Dashboard/Resources/ReportResource.php @@ -163,17 +163,19 @@ public static function form(Form $form): Form return $geo_locations; }) - ->disabled(function (Get $get) { - return ! $get('show_geo_location_existing'); + ->disabled(function (Get $get, string $operation) { + return ! $get('show_geo_location_existing') && $operation == 'edit'; }) + ->dehydrated() ->columnSpan(4), TagsInput::make('new_geo_locations') ->label('New') ->separator(',') ->splitKeys([',']) - ->disabled(function (Get $get) { - return ! $get('show_geo_location_new'); + ->disabled(function (Get $get, string $operation) { + return ! $get('show_geo_location_new') && $operation == 'edit'; }) + ->dehydrated() ->columnSpan(4), ]) ->columns(9), @@ -197,17 +199,19 @@ public static function form(Form $form): Form return $synonyms; }) - ->disabled(function (Get $get) { - return ! $get('show_synonym_existing'); + ->disabled(function (Get $get, string $operation) { + return ! $get('show_synonym_existing') && $operation == 'edit'; }) + ->dehydrated() ->columnSpan(4), TagsInput::make('new_synonyms') ->label('New') ->separator(',') ->splitKeys([',']) - ->disabled(function (Get $get) { - return ! $get('show_synonym_new'); + ->disabled(function (Get $get, string $operation) { + return ! $get('show_synonym_new') && $operation == 'edit'; }) + ->dehydrated() ->columnSpan(4), ]) ->columns(9), @@ -226,9 +230,10 @@ public static function form(Form $form): Form return self::$molecule->name; } }) - ->disabled(function (Get $get) { - return ! $get('show_name_change'); + ->disabled(function (Get $get, string $operation) { + return ! $get('show_name_change') && $operation == 'edit'; }) + ->dehydrated() ->columnSpan(4), ]) ->columns(9), @@ -249,17 +254,19 @@ public static function form(Form $form): Form return self::$molecule->cas; } }) - ->disabled(function (Get $get) { - return ! $get('show_cas_existing'); + ->disabled(function (Get $get, string $operation) { + return ! $get('show_cas_existing') && $operation == 'edit'; }) + ->dehydrated() ->columnSpan(4), TagsInput::make('new_cas') ->label('New') ->separator(',') ->splitKeys([',']) - ->disabled(function (Get $get) { - return ! $get('show_cas_new'); + ->disabled(function (Get $get, string $operation) { + return ! $get('show_cas_new') && $operation == 'edit'; }) + ->dehydrated() ->columnSpan(4), ]) ->columns(9), @@ -283,9 +290,10 @@ public static function form(Form $form): Form return self::$molecule->organisms->pluck('name', 'id')->toArray(); } }) - ->disabled(function (Get $get) { - return ! $get('show_organism_existing'); + ->disabled(function (Get $get, string $operation) { + return ! $get('show_organism_existing') && $operation == 'edit'; }) + ->dehydrated() ->columnSpan(9), ]) ->columns(9), @@ -298,7 +306,6 @@ public static function form(Form $form): Form ->hidden(function (string $operation) { return ! auth()->user()->roles()->exists() || $operation == 'create'; }) - ->disabled(false) ->columnSpanFull(), Grid::make('new_organism') ->schema(Organism::getForm())->columns(4), @@ -306,9 +313,10 @@ public static function form(Form $form): Form ->reorderable(false) ->addActionLabel('Add New Organism') ->defaultItems(0) - ->disabled(function (Get $get) { - return ! $get('show_organism_new'); + ->disabled(function (Get $get, string $operation) { + return ! $get('show_organism_new') && $operation == 'edit'; }) + ->dehydrated() ->columns(9), ]), @@ -331,9 +339,10 @@ public static function form(Form $form): Form return self::$molecule->citations->where('title', '!=', null)->pluck('title', 'id')->toArray(); } }) - ->disabled(function (Get $get) { - return ! $get('show_citation_existing'); + ->disabled(function (Get $get, string $operation) { + return ! $get('show_citation_existing') && $operation == 'edit'; }) + ->dehydrated() ->columnSpan(9), ]) ->columns(9), @@ -352,9 +361,10 @@ public static function form(Form $form): Form ->reorderable(false) ->addActionLabel('Add New Citation') ->defaultItems(0) - ->disabled(function (Get $get) { - return ! $get('show_citation_new'); + ->disabled(function (Get $get, string $operation) { + return ! $get('show_citation_new') && $operation == 'edit'; }) + ->dehydrated() ->columns(9), ]), @@ -646,7 +656,7 @@ public static function approveReport(array $data, Report $record, Molecule $mole $suggested_changes = $record['suggested_changes']; - $suggested_changes['approved_changes'] = self::$overall_changes; + $suggested_changes['curator']['approved_changes'] = self::$overall_changes; $record['suggested_changes'] = $suggested_changes; $record['comment'] = $data['reason']; $record['status'] = 'approved'; From 607535c06e0cb0753193872c621a12d62fc36155 Mon Sep 17 00:00:00 2001 From: Sagar Date: Wed, 2 Oct 2024 23:56:52 +0200 Subject: [PATCH 38/47] fix: saving the overall suggested changes so that they are available in both the original and curator jsons --- .../Resources/ReportResource/Pages/CreateReport.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php index b65c15bc..17fa0d54 100644 --- a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php +++ b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php @@ -122,12 +122,12 @@ protected function mutateFormDataBeforeCreate(array $data): array $suggested_changes['new_citations'] = $data['new_citations']; - // seperate copy for Curators - $suggested_changes['curator'] = $suggested_changes; - // Overall Changes suggested $suggested_changes['overall_changes'] = getOverallChanges($data); + // seperate copy for Curators + $suggested_changes['curator'] = $suggested_changes; + $data['suggested_changes'] = $suggested_changes; } From 9c2d3f343c729a37929a6d5e452228a3ce1151d2 Mon Sep 17 00:00:00 2001 From: Sagar Date: Wed, 2 Oct 2024 23:58:30 +0200 Subject: [PATCH 39/47] feat: original suggestions are saved and never touched, instead a separate copy is made available for curators to work on --- .../ReportResource/Pages/EditReport.php | 80 ++++++++++--------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php b/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php index ffaaa40e..0983d19d 100644 --- a/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php +++ b/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php @@ -12,34 +12,34 @@ class EditReport extends EditRecord protected function mutateFormDataBeforeFill(array $data): array { - if ($data['is_change'] == true) { - // initiate the flags to show only the fields that need to be shown - $data['show_geo_location_existing'] = $data['suggested_changes']['overall_changes']['geo_location_changes']['delete'] ? true : false; - if (array_key_exists('geo_location_changes', $data['suggested_changes']['overall_changes'])) { - $data['show_geo_location_existing'] = $data['suggested_changes']['overall_changes']['geo_location_changes']['delete'] ? true : false; - $data['show_geo_location_new'] = $data['suggested_changes']['overall_changes']['geo_location_changes']['add'] ? true : false; + if ($this->record['is_change'] == true) { + // initiate the flags to show only the fields that need to be shown - overall changes are always from the initial suggestions + $data['show_geo_location_existing'] = $this->record['suggested_changes']['overall_changes']['geo_location_changes']['delete'] ? true : false; + if (array_key_exists('geo_location_changes', $this->record['suggested_changes']['overall_changes'])) { + $data['show_geo_location_existing'] = $this->record['suggested_changes']['overall_changes']['geo_location_changes']['delete'] ? true : false; + $data['show_geo_location_new'] = $this->record['suggested_changes']['overall_changes']['geo_location_changes']['add'] ? true : false; } - if (array_key_exists('synonym_changes', $data['suggested_changes']['overall_changes'])) { - $data['show_synonym_existing'] = $data['suggested_changes']['overall_changes']['synonym_changes']['delete'] ? true : false; - $data['show_synonym_new'] = $data['suggested_changes']['overall_changes']['synonym_changes']['add'] ? true : false; + if (array_key_exists('synonym_changes', $this->record['suggested_changes']['overall_changes'])) { + $data['show_synonym_existing'] = $this->record['suggested_changes']['overall_changes']['synonym_changes']['delete'] ? true : false; + $data['show_synonym_new'] = $this->record['suggested_changes']['overall_changes']['synonym_changes']['add'] ? true : false; } - if (array_key_exists('name_change', $data['suggested_changes']['overall_changes'])) { - $data['show_name_change'] = $data['suggested_changes']['overall_changes']['name_change'] ? true : false; + if (array_key_exists('name_change', $this->record['suggested_changes']['overall_changes'])) { + $data['show_name_change'] = $this->record['suggested_changes']['overall_changes']['name_change'] ? true : false; } - if (array_key_exists('cas_changes', $data['suggested_changes']['overall_changes'])) { - $data['show_cas_existing'] = $data['suggested_changes']['overall_changes']['cas_changes']['delete'] ? true : false; - $data['show_cas_new'] = $data['suggested_changes']['overall_changes']['cas_changes']['add'] ? true : false; + if (array_key_exists('cas_changes', $this->record['suggested_changes']['overall_changes'])) { + $data['show_cas_existing'] = $this->record['suggested_changes']['overall_changes']['cas_changes']['delete'] ? true : false; + $data['show_cas_new'] = $this->record['suggested_changes']['overall_changes']['cas_changes']['add'] ? true : false; } - if (array_key_exists('organism_changes', $data['suggested_changes']['overall_changes'])) { - $data['show_organism_existing'] = $data['suggested_changes']['overall_changes']['organism_changes']['delete'] ? true : false; - $data['show_organism_new'] = $data['suggested_changes']['overall_changes']['organism_changes']['add'] ? true : false; + if (array_key_exists('organism_changes', $this->record['suggested_changes']['overall_changes'])) { + $data['show_organism_existing'] = $this->record['suggested_changes']['overall_changes']['organism_changes']['delete'] ? true : false; + $data['show_organism_new'] = $this->record['suggested_changes']['overall_changes']['organism_changes']['add'] ? true : false; } - if (array_key_exists('citation_changes', $data['suggested_changes']['overall_changes'])) { - $data['show_citation_existing'] = $data['suggested_changes']['overall_changes']['citation_changes']['delete'] ? true : false; - $data['show_citation_new'] = $data['suggested_changes']['overall_changes']['citation_changes']['add'] ? true : false; + if (array_key_exists('citation_changes', $this->record['suggested_changes']['overall_changes'])) { + $data['show_citation_existing'] = $this->record['suggested_changes']['overall_changes']['citation_changes']['delete'] ? true : false; + $data['show_citation_new'] = $this->record['suggested_changes']['overall_changes']['citation_changes']['add'] ? true : false; } - $curators_copy_changes = $data['suggested_changes']['curator']; + $curators_copy_changes = $this->record['suggested_changes']['curator']; $data['existing_geo_locations'] = $curators_copy_changes['existing_geo_locations']; $data['new_geo_locations'] = $curators_copy_changes['new_geo_locations']; $data['approve_geo_locations'] = $curators_copy_changes['approve_geo_locations']; @@ -71,31 +71,33 @@ protected function mutateFormDataBeforeFill(array $data): array protected function mutateFormDataBeforeSave(array $data): array { - if ($data['is_change'] == true) { - $data['suggested_changes']['curator']['existing_geo_locations'] = $data['existing_geo_locations']; - $data['suggested_changes']['curator']['new_geo_locations'] = $data['new_geo_locations']; - $data['suggested_changes']['curator']['approve_geo_locations'] = $data['approve_geo_locations']; - $data['suggested_changes']['curator']['existing_synonyms'] = $data['existing_synonyms']; - $data['suggested_changes']['curator']['new_synonyms'] = $data['new_synonyms']; - $data['suggested_changes']['curator']['approve_synonyms'] = $data['approve_synonyms']; + if ($this->record->is_change) { + $temp = $data; + $data = $this->record->toArray(); - $data['suggested_changes']['curator']['name'] = $data['name']; - $data['suggested_changes']['curator']['approve_name'] = $data['approve_name']; + $data['suggested_changes']['curator']['existing_geo_locations'] = $temp['existing_geo_locations'] ?? $this->record['suggested_changes']['curator']['existing_geo_locations']; + $data['suggested_changes']['curator']['new_geo_locations'] = $temp['new_geo_locations'] ?? $this->record['suggested_changes']['curator']['new_geo_locations']; + $data['suggested_changes']['curator']['approve_geo_locations'] = $temp['approve_geo_locations']; - $data['suggested_changes']['curator']['existing_cas'] = $data['existing_cas']; - $data['suggested_changes']['curator']['new_cas'] = $data['new_cas']; - $data['suggested_changes']['curator']['approve_cas'] = $data['approve_cas']; + $data['suggested_changes']['curator']['existing_synonyms'] = $temp['existing_synonyms'] ?? $this->record['suggested_changes']['curator']['existing_synonyms']; + $data['suggested_changes']['curator']['new_synonyms'] = $temp['new_synonyms'] ?? $this->record['suggested_changes']['curator']['new_synonyms']; + $data['suggested_changes']['curator']['approve_synonyms'] = $temp['approve_synonyms']; - $data['suggested_changes']['curator']['existing_organisms'] = $data['existing_organisms']; - $data['suggested_changes']['curator']['approve_existing_organisms'] = $data['approve_existing_organisms']; + $data['suggested_changes']['curator']['name'] = $temp['name'] ?? $this->record['suggested_changes']['curator']['name']; + $data['suggested_changes']['curator']['approve_name'] = $temp['approve_name']; - $data['suggested_changes']['curator']['new_organisms'] = $data['new_organisms']; + $data['suggested_changes']['curator']['existing_cas'] = $temp['existing_cas'] ?? $this->record['suggested_changes']['curator']['existing_cas']; + $data['suggested_changes']['curator']['new_cas'] = $temp['new_cas'] ?? $this->record['suggested_changes']['curator']['new_cas']; + $data['suggested_changes']['curator']['approve_cas'] = $temp['approve_cas']; - $data['suggested_changes']['curator']['existing_citations'] = $data['existing_citations']; - $data['suggested_changes']['curator']['approve_existing_citations'] = $data['approve_existing_citations']; + $data['suggested_changes']['curator']['existing_organisms'] = $temp['existing_organisms'] ?? $this->record['suggested_changes']['curator']['existing_organisms']; + $data['suggested_changes']['curator']['new_organisms'] = $temp['new_organisms'] ?? $this->record['suggested_changes']['curator']['new_organisms']; + $data['suggested_changes']['curator']['approve_existing_organisms'] = $temp['approve_existing_organisms']; - $data['suggested_changes']['curator']['new_citations'] = $data['new_citations']; + $data['suggested_changes']['curator']['existing_citations'] = $temp['existing_citations'] ?? $this->record['suggested_changes']['curator']['existing_citations']; + $data['suggested_changes']['curator']['new_citations'] = $temp['new_citations'] ?? $this->record['suggested_changes']['curator']['new_citations']; + $data['suggested_changes']['curator']['approve_existing_citations'] = $temp['approve_existing_citations']; } return $data; From 31ddfb038febdef6c36a746eeaf1084c92c036d6 Mon Sep 17 00:00:00 2001 From: Sagar Date: Thu, 3 Oct 2024 00:59:02 +0200 Subject: [PATCH 40/47] fix: deleted the old statement --- .../Dashboard/Resources/ReportResource/Pages/EditReport.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php b/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php index 0983d19d..341c5358 100644 --- a/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php +++ b/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php @@ -14,7 +14,6 @@ protected function mutateFormDataBeforeFill(array $data): array { if ($this->record['is_change'] == true) { // initiate the flags to show only the fields that need to be shown - overall changes are always from the initial suggestions - $data['show_geo_location_existing'] = $this->record['suggested_changes']['overall_changes']['geo_location_changes']['delete'] ? true : false; if (array_key_exists('geo_location_changes', $this->record['suggested_changes']['overall_changes'])) { $data['show_geo_location_existing'] = $this->record['suggested_changes']['overall_changes']['geo_location_changes']['delete'] ? true : false; $data['show_geo_location_new'] = $this->record['suggested_changes']['overall_changes']['geo_location_changes']['add'] ? true : false; From 53847b0a3c477004955d546d6d22b51dfd9ddcf9 Mon Sep 17 00:00:00 2001 From: Sagar Date: Tue, 8 Oct 2024 12:18:51 +0200 Subject: [PATCH 41/47] fix: which items received approval is now saved when approved, no need to save the form before approval --- .../Dashboard/Resources/ReportResource.php | 3 ++ .../ReportResource/Pages/EditReport.php | 27 +--------------- app/Helper.php | 31 +++++++++++++++++++ 3 files changed, 35 insertions(+), 26 deletions(-) diff --git a/app/Filament/Dashboard/Resources/ReportResource.php b/app/Filament/Dashboard/Resources/ReportResource.php index c926a01e..479a9d77 100644 --- a/app/Filament/Dashboard/Resources/ReportResource.php +++ b/app/Filament/Dashboard/Resources/ReportResource.php @@ -660,6 +660,9 @@ public static function approveReport(array $data, Report $record, Molecule $mole $record['suggested_changes'] = $suggested_changes; $record['comment'] = $data['reason']; $record['status'] = 'approved'; + $formData = copyChangesToCuratorJSON($record, $livewire->data); + $suggested_changes['curator'] = $formData['suggested_changes']['curator']; + $record['suggested_changes'] = $suggested_changes; // Save the report record in any case $record->save(); diff --git a/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php b/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php index 341c5358..ac45b0c8 100644 --- a/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php +++ b/app/Filament/Dashboard/Resources/ReportResource/Pages/EditReport.php @@ -70,33 +70,8 @@ protected function mutateFormDataBeforeFill(array $data): array protected function mutateFormDataBeforeSave(array $data): array { - if ($this->record->is_change) { - $temp = $data; - $data = $this->record->toArray(); - - $data['suggested_changes']['curator']['existing_geo_locations'] = $temp['existing_geo_locations'] ?? $this->record['suggested_changes']['curator']['existing_geo_locations']; - $data['suggested_changes']['curator']['new_geo_locations'] = $temp['new_geo_locations'] ?? $this->record['suggested_changes']['curator']['new_geo_locations']; - $data['suggested_changes']['curator']['approve_geo_locations'] = $temp['approve_geo_locations']; - - $data['suggested_changes']['curator']['existing_synonyms'] = $temp['existing_synonyms'] ?? $this->record['suggested_changes']['curator']['existing_synonyms']; - $data['suggested_changes']['curator']['new_synonyms'] = $temp['new_synonyms'] ?? $this->record['suggested_changes']['curator']['new_synonyms']; - $data['suggested_changes']['curator']['approve_synonyms'] = $temp['approve_synonyms']; - - $data['suggested_changes']['curator']['name'] = $temp['name'] ?? $this->record['suggested_changes']['curator']['name']; - $data['suggested_changes']['curator']['approve_name'] = $temp['approve_name']; - - $data['suggested_changes']['curator']['existing_cas'] = $temp['existing_cas'] ?? $this->record['suggested_changes']['curator']['existing_cas']; - $data['suggested_changes']['curator']['new_cas'] = $temp['new_cas'] ?? $this->record['suggested_changes']['curator']['new_cas']; - $data['suggested_changes']['curator']['approve_cas'] = $temp['approve_cas']; - - $data['suggested_changes']['curator']['existing_organisms'] = $temp['existing_organisms'] ?? $this->record['suggested_changes']['curator']['existing_organisms']; - $data['suggested_changes']['curator']['new_organisms'] = $temp['new_organisms'] ?? $this->record['suggested_changes']['curator']['new_organisms']; - $data['suggested_changes']['curator']['approve_existing_organisms'] = $temp['approve_existing_organisms']; - - $data['suggested_changes']['curator']['existing_citations'] = $temp['existing_citations'] ?? $this->record['suggested_changes']['curator']['existing_citations']; - $data['suggested_changes']['curator']['new_citations'] = $temp['new_citations'] ?? $this->record['suggested_changes']['curator']['new_citations']; - $data['suggested_changes']['curator']['approve_existing_citations'] = $temp['approve_existing_citations']; + $data = copyChangesToCuratorJSON($this->record, $data); } return $data; diff --git a/app/Helper.php b/app/Helper.php index f1dffad3..36ab3aae 100644 --- a/app/Helper.php +++ b/app/Helper.php @@ -379,3 +379,34 @@ function getOverallChanges($data) return $overall_changes; } + +function copyChangesToCuratorJSON($record, $data) +{ + $temp = $data; + $data = $record->toArray(); + + $data['suggested_changes']['curator']['existing_geo_locations'] = $temp['existing_geo_locations'] ?? $record['suggested_changes']['curator']['existing_geo_locations']; + $data['suggested_changes']['curator']['new_geo_locations'] = $temp['new_geo_locations'] ?? $record['suggested_changes']['curator']['new_geo_locations']; + $data['suggested_changes']['curator']['approve_geo_locations'] = $temp['approve_geo_locations'] ?? false; + + $data['suggested_changes']['curator']['existing_synonyms'] = $temp['existing_synonyms'] ?? $record['suggested_changes']['curator']['existing_synonyms']; + $data['suggested_changes']['curator']['new_synonyms'] = $temp['new_synonyms'] ?? $record['suggested_changes']['curator']['new_synonyms']; + $data['suggested_changes']['curator']['approve_synonyms'] = $temp['approve_synonyms'] ?? false; + + $data['suggested_changes']['curator']['name'] = $temp['name'] ?? $record['suggested_changes']['curator']['name']; + $data['suggested_changes']['curator']['approve_name'] = $temp['approve_name'] ?? false; + + $data['suggested_changes']['curator']['existing_cas'] = $temp['existing_cas'] ?? $record['suggested_changes']['curator']['existing_cas']; + $data['suggested_changes']['curator']['new_cas'] = $temp['new_cas'] ?? $record['suggested_changes']['curator']['new_cas']; + $data['suggested_changes']['curator']['approve_cas'] = $temp['approve_cas'] ?? false; + + $data['suggested_changes']['curator']['existing_organisms'] = $temp['existing_organisms'] ?? $record['suggested_changes']['curator']['existing_organisms']; + $data['suggested_changes']['curator']['new_organisms'] = $temp['new_organisms'] ?? $record['suggested_changes']['curator']['new_organisms']; + $data['suggested_changes']['curator']['approve_existing_organisms'] = $temp['approve_existing_organisms'] ?? false; + + $data['suggested_changes']['curator']['existing_citations'] = $temp['existing_citations'] ?? $record['suggested_changes']['curator']['existing_citations']; + $data['suggested_changes']['curator']['new_citations'] = $temp['new_citations'] ?? $record['suggested_changes']['curator']['new_citations']; + $data['suggested_changes']['curator']['approve_existing_citations'] = $temp['approve_existing_citations'] ?? false; + + return $data; +} From 0ded27821bb44bc9c1b0bd1678d4c48421c76983 Mon Sep 17 00:00:00 2001 From: Sagar Date: Tue, 8 Oct 2024 12:34:30 +0200 Subject: [PATCH 42/47] fix: redirect to view page after the report is approved --- app/Filament/Dashboard/Resources/ReportResource.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/Filament/Dashboard/Resources/ReportResource.php b/app/Filament/Dashboard/Resources/ReportResource.php index 479a9d77..d337071f 100644 --- a/app/Filament/Dashboard/Resources/ReportResource.php +++ b/app/Filament/Dashboard/Resources/ReportResource.php @@ -100,8 +100,8 @@ public static function form(Form $form): Form ->hidden(function (Get $get, string $operation) { return ! auth()->user()->roles()->exists() || $get('status') == 'rejected' || $get('status') == 'approved' || $operation != 'edit'; }) - ->action(function (array $data, Report $record, $set): void { - self::rejectReport($data, $record); + ->action(function (array $data, Report $record, $set, $livewire): void { + self::rejectReport($data, $record, $livewire); $set('status', 'rejected'); }), Action::make('viewCompoundPage') @@ -545,7 +545,7 @@ public static function table(Table $table): Table // ]) // ->action(function (array $data, Report $record): void { - // self::rejectReport($data, $record); + // self::rejectReport($data, $record, $livewire); // }), ]) ->bulkActions([ @@ -666,13 +666,17 @@ public static function approveReport(array $data, Report $record, Molecule $mole // Save the report record in any case $record->save(); + + $livewire->redirect(ReportResource::getUrl('view', ['record' => $record->id])); } - public static function rejectReport(array $data, Report $record): void + public static function rejectReport(array $data, Report $record, $livewire): void { $record['status'] = 'rejected'; $record['comment'] = $data['reason']; $record->save(); + + $livewire->redirect(ReportResource::getUrl('view', ['record' => $record->id])); } public static function runSQLQueries(Report $record): void From 5670f315438e52c401ab34b70f95c876fd5db469 Mon Sep 17 00:00:00 2001 From: Sagar Date: Tue, 8 Oct 2024 19:45:25 +0200 Subject: [PATCH 43/47] fix: save modal is only displayed if it is a change --- .../Dashboard/Resources/ReportResource/Pages/CreateReport.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php index 17fa0d54..c23f02c0 100644 --- a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php +++ b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php @@ -150,6 +150,9 @@ protected function afterCreate(): void protected function getCreateFormAction(): Action { + if (! $this->data['is_change']) { + return parent::getCreateFormAction(); + } return parent::getCreateFormAction() ->submit(null) ->form(function () { From 658ff2f4e1eba5da2b421f804d908ffca8c171ca Mon Sep 17 00:00:00 2001 From: Sagar Date: Tue, 8 Oct 2024 19:46:09 +0200 Subject: [PATCH 44/47] fix: saving doi for reporting --- app/Filament/Dashboard/Resources/ReportResource.php | 5 ++--- app/Models/Report.php | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Filament/Dashboard/Resources/ReportResource.php b/app/Filament/Dashboard/Resources/ReportResource.php index d337071f..5fd48424 100644 --- a/app/Filament/Dashboard/Resources/ReportResource.php +++ b/app/Filament/Dashboard/Resources/ReportResource.php @@ -375,7 +375,6 @@ public static function form(Form $form): Form TextInput::make('doi') ->hintIcon('heroicon-m-question-mark-circle', tooltip: 'Provide the DOI link to the resource you are reporting so as to help curators verify.') ->label('DOI') - ->url() ->suffixAction( fn (?string $state): Action => Action::make('visit') ->icon('heroicon-s-link') @@ -385,7 +384,7 @@ public static function form(Form $form): Form ), ) ->hidden(function (string $operation, $record) { - return $operation == 'create' ? request()->has('type') && request()->type == 'change' : $record->is_change; + return $operation == 'create' && request()->has('type') && request()->type == 'change' ? true : false; }), Select::make('collections') ->hintIcon('heroicon-m-question-mark-circle', tooltip: 'Select the Collections you want to report. This will help our Curators in reviewing your report.') @@ -474,7 +473,7 @@ public static function form(Form $form): Form }) ->live() ->hidden(function (Get $get, string $operation) { - if ($operation != 'create' || request()->type == 'change') { + if ($operation != 'create' || request()->has('type')) { return true; } if (! request()->has('compound_id') && $get('report_type') != 'molecule') { diff --git a/app/Models/Report.php b/app/Models/Report.php index 71793af8..f6713949 100644 --- a/app/Models/Report.php +++ b/app/Models/Report.php @@ -33,6 +33,7 @@ class Report extends Model implements Auditable 'user_id', 'suggested_changes', 'is_change', + 'doi', ]; protected $casts = [ From ca3dfdf4f629b0d124643e3a6155ce6ff3a58cbe Mon Sep 17 00:00:00 2001 From: Sagar Date: Thu, 10 Oct 2024 16:49:59 +0200 Subject: [PATCH 45/47] fix: various fixes to the reporting workflow --- .../Dashboard/Resources/MoleculeResource.php | 19 ++--- .../Dashboard/Resources/ReportResource.php | 76 +++++++++++-------- .../ReportResource/Pages/CreateReport.php | 8 +- app/Helper.php | 9 +++ 4 files changed, 63 insertions(+), 49 deletions(-) diff --git a/app/Filament/Dashboard/Resources/MoleculeResource.php b/app/Filament/Dashboard/Resources/MoleculeResource.php index 79ed12c5..52aed617 100644 --- a/app/Filament/Dashboard/Resources/MoleculeResource.php +++ b/app/Filament/Dashboard/Resources/MoleculeResource.php @@ -125,7 +125,9 @@ public static function table(Table $table): Table ]) ->action(function (array $data, Molecule $record): void { $record->active = ! $record->active; - self::saveComment($record, $data['reason']); + $record->active ? $record->status = 'APPROVED' : $record->status = 'REVOKED'; + $record->comment = prepareComment($data['reason']); + $record->save(); }) ->modalHidden(function (Molecule $record) { return ! $record['active']; @@ -144,7 +146,9 @@ public static function table(Table $table): Table ->action(function (array $data, Collection $records): void { foreach ($records as $record) { $record->active = ! $record->active; - self::saveComment($record, $data['reason']); + $record->active ? $record->status = 'APPROVED' : $record->status = 'REVOKED'; + $record->comment = prepareComment($data['reason']); + $record->save(); } }) // ->modalHidden(function (Molecule $record) { @@ -207,15 +211,4 @@ public static function getNavigationBadge(): ?string { return Cache::get('stats.molecules'); } - - public static function saveComment($record, $reason) - { - $record->comment = [[ - 'timestamp' => now(), - 'changed_by' => auth()->user()->id, - 'comment' => $reason, - ]]; - - $record->save(); - } } diff --git a/app/Filament/Dashboard/Resources/ReportResource.php b/app/Filament/Dashboard/Resources/ReportResource.php index 5fd48424..7a065ade 100644 --- a/app/Filament/Dashboard/Resources/ReportResource.php +++ b/app/Filament/Dashboard/Resources/ReportResource.php @@ -79,11 +79,15 @@ public static function form(Form $form): Form Actions::make([ Action::make('approve') ->form(function ($record, $livewire) { - self::$approved_changes = self::prepareApprovedChanges($record, $livewire); - $key_value_fields = getChangesToDisplayModal(self::$approved_changes); - array_unshift($key_value_fields, Textarea::make('reason')); - - return $key_value_fields; + if ($record['is_change']) { + self::$approved_changes = self::prepareApprovedChanges($record, $livewire); + $key_value_fields = getChangesToDisplayModal(self::$approved_changes); + array_unshift($key_value_fields, Textarea::make('reason')); + + return $key_value_fields; + } else { + return [Textarea::make('reason')]; + } }) ->hidden(function (Get $get, string $operation) { return ! auth()->user()->roles()->exists() || $get('status') == 'rejected' || $get('status') == 'approved' || $operation != 'edit'; @@ -107,8 +111,14 @@ public static function form(Form $form): Form Action::make('viewCompoundPage') ->color('info') ->url(fn (string $operation, $record): string => $operation === 'create' ? env('APP_URL').'/compounds/'.request()->compound_id : env('APP_URL').'/compounds/'.$record->mol_id_csv) - ->openUrlInNewTab(), + ->openUrlInNewTab() + ->hidden(function (Get $get, string $operation) { + return ! request()->has('type'); + }), ]) + ->hidden(function (Get $get) { + return $get('report_type') != 'molecule'; + }) ->verticalAlignment(VerticalAlignment::End) ->columnStart(4), ]) @@ -589,17 +599,6 @@ public static function prepareApprovedChanges(Report $record, $livewire) { $approved_changes = []; - // In case of reporting a synthetic molecule, Deactivate Molecules - if ($record['mol_id_csv'] && ! $record['is_change']) { - $molecule_ids = explode(',', $record['mol_id_csv']); - $molecule = Molecule::whereIn('id', $molecule_ids)->get(); - foreach ($molecule as $mol) { - $mol->active = false; - $mol->save(); - } - } - - // In case of Changes, run SQL queries for the approved changes $approved_changes['mol_id_csv'] = $record['mol_id_csv']; if ($record['is_change']) { @@ -650,22 +649,33 @@ public static function prepareApprovedChanges(Report $record, $livewire) public static function approveReport(array $data, Report $record, Molecule $molecule, $livewire): void { - // Run SQL queries for the approved changes - self::runSQLQueries($record); - - $suggested_changes = $record['suggested_changes']; - - $suggested_changes['curator']['approved_changes'] = self::$overall_changes; - $record['suggested_changes'] = $suggested_changes; - $record['comment'] = $data['reason']; - $record['status'] = 'approved'; - $formData = copyChangesToCuratorJSON($record, $livewire->data); - $suggested_changes['curator'] = $formData['suggested_changes']['curator']; - $record['suggested_changes'] = $suggested_changes; - - // Save the report record in any case - $record->save(); - + // In case of reporting a synthetic molecule, Deactivate Molecules + if ($record['mol_id_csv'] && ! $record['is_change']) { + $molecule_ids = explode(',', $record['mol_id_csv']); + $molecule = Molecule::whereIn('identifier', $molecule_ids)->get(); + foreach ($molecule as $mol) { + $mol->active = false; + $mol->status = 'REVOKED'; + $mol->comment = prepareComment($data['reason']); + $mol->save(); + } + } else { + // In case of Changes + // Run SQL queries for the approved changes + self::runSQLQueries($record); + + $suggested_changes = $record['suggested_changes']; + + $suggested_changes['curator']['approved_changes'] = self::$overall_changes; + $record['suggested_changes'] = $suggested_changes; + $record->comment = prepareComment($data['reason']); + $record['status'] = 'approved'; + $formData = copyChangesToCuratorJSON($record, $livewire->data); + $suggested_changes['curator'] = $formData['suggested_changes']['curator']; + $record['suggested_changes'] = $suggested_changes; + + $record->save(); + } $livewire->redirect(ReportResource::getUrl('view', ['record' => $record->id])); } diff --git a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php index c23f02c0..d42df368 100644 --- a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php +++ b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php @@ -43,9 +43,11 @@ protected function afterFill(): void $this->data['is_change'] = true; $this->data['existing_geo_locations'] = $this->molecule->geo_locations->pluck('name')->toArray(); $this->data['existing_synonyms'] = $this->molecule->synonyms; - $this->data['existing_cas'] = array_values($this->molecule->cas); + $this->data['existing_cas'] = array_values($this->molecule->cas ?? []); $this->data['existing_organisms'] = $this->molecule->organisms->pluck('name')->toArray(); $this->data['existing_citations'] = $this->molecule->citations->where('title', '!=', null)->pluck('title')->toArray(); + } else { + $this->data['is_change'] = false; } if ($request->has('collection_uuid')) { @@ -94,8 +96,7 @@ protected function mutateFormDataBeforeCreate(array $data): array { $data['user_id'] = auth()->id(); $data['status'] = 'submitted'; - - if ($data['is_change'] == true) { + if ($data['is_change']) { $suggested_changes = []; $suggested_changes['existing_geo_locations'] = $data['existing_geo_locations']; $suggested_changes['new_geo_locations'] = $data['new_geo_locations']; @@ -153,6 +154,7 @@ protected function getCreateFormAction(): Action if (! $this->data['is_change']) { return parent::getCreateFormAction(); } + return parent::getCreateFormAction() ->submit(null) ->form(function () { diff --git a/app/Helper.php b/app/Helper.php index 36ab3aae..47688cc8 100644 --- a/app/Helper.php +++ b/app/Helper.php @@ -410,3 +410,12 @@ function copyChangesToCuratorJSON($record, $data) return $data; } + +function prepareComment($reason) +{ + return [[ + 'timestamp' => now(), + 'changed_by' => auth()->user()->id, + 'comment' => $reason, + ]]; +} From bf48f25b69d1c19169abbb1a5e25628b8494ea5a Mon Sep 17 00:00:00 2001 From: Venkata Chandra Sekhar Nainala Date: Wed, 13 Nov 2024 15:41:10 +0100 Subject: [PATCH 46/47] fix: conditional hidden issue fix --- app/Filament/Dashboard/Resources/ReportResource.php | 4 ++-- .../Dashboard/Resources/ReportResource/Pages/CreateReport.php | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/Filament/Dashboard/Resources/ReportResource.php b/app/Filament/Dashboard/Resources/ReportResource.php index 7a065ade..be36d481 100644 --- a/app/Filament/Dashboard/Resources/ReportResource.php +++ b/app/Filament/Dashboard/Resources/ReportResource.php @@ -72,8 +72,8 @@ public static function form(Form $form): Form true => 'Request Changes to Data', ]) ->inline() - ->hidden(function (string $operation, $record) { - return $operation == 'create' ? request()->has('type') : true; + ->hidden(function (string $operation, $get) { + return $get('type') == 'change' ? true : false; }) ->columnSpan(2), Actions::make([ diff --git a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php index d42df368..9881cd99 100644 --- a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php +++ b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php @@ -39,7 +39,9 @@ protected function afterFill(): void { $request = request(); $this->data['compound_id'] = $request->compound_id; + if ($request->type == 'change') { + $this->data['type'] = $request->type; $this->data['is_change'] = true; $this->data['existing_geo_locations'] = $this->molecule->geo_locations->pluck('name')->toArray(); $this->data['existing_synonyms'] = $this->molecule->synonyms; From 8d224dd8f4e405194c30a160ba30ca296ac57cad Mon Sep 17 00:00:00 2001 From: Sagar Date: Fri, 15 Nov 2024 14:58:42 +0100 Subject: [PATCH 47/47] fix: hidden field issues are fixed --- .../Dashboard/Resources/ReportResource.php | 40 ++++++++++++++----- .../ReportResource/Pages/CreateReport.php | 27 ++++++++++++- 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/app/Filament/Dashboard/Resources/ReportResource.php b/app/Filament/Dashboard/Resources/ReportResource.php index be36d481..76f94812 100644 --- a/app/Filament/Dashboard/Resources/ReportResource.php +++ b/app/Filament/Dashboard/Resources/ReportResource.php @@ -73,7 +73,7 @@ public static function form(Form $form): Form ]) ->inline() ->hidden(function (string $operation, $get) { - return $get('type') == 'change' ? true : false; + return $operation == 'create' ? $get('type') != null : true; }) ->columnSpan(2), Actions::make([ @@ -82,11 +82,23 @@ public static function form(Form $form): Form if ($record['is_change']) { self::$approved_changes = self::prepareApprovedChanges($record, $livewire); $key_value_fields = getChangesToDisplayModal(self::$approved_changes); - array_unshift($key_value_fields, Textarea::make('reason')); + array_unshift($key_value_fields, + Textarea::make('reason') + ->helperText(function ($get) { + if (count(self::$approved_changes) <= 1) { + return new HtmlString(' You must select at least one change to approve '); + } else { + return null; + } + }) + ->disabled(count(self::$approved_changes) <= 1) + ); return $key_value_fields; } else { - return [Textarea::make('reason')]; + return [ + Textarea::make('reason'), + ]; } }) ->hidden(function (Get $get, string $operation) { @@ -95,6 +107,11 @@ public static function form(Form $form): Form ->action(function (array $data, Report $record, Molecule $molecule, $set, $livewire): void { self::approveReport($data, $record, $molecule, $livewire); $set('status', 'approved'); + }) + ->modalSubmitAction(function () { + if (count(self::$approved_changes) <= 1) { + return false; + } }), Action::make('reject') ->color('danger') @@ -113,7 +130,7 @@ public static function form(Form $form): Form ->url(fn (string $operation, $record): string => $operation === 'create' ? env('APP_URL').'/compounds/'.request()->compound_id : env('APP_URL').'/compounds/'.$record->mol_id_csv) ->openUrlInNewTab() ->hidden(function (Get $get, string $operation) { - return ! request()->has('type'); + return ! $get('type'); }), ]) ->hidden(function (Get $get) { @@ -131,13 +148,13 @@ public static function form(Form $form): Form ->options(function () { return getReportTypes(); }) - ->hidden(function (string $operation) { - return $operation != 'create' || request()->has('type'); + ->hidden(function (string $operation, $get) { + return $operation != 'create' || $get('type'); }), TextInput::make('title') ->hintIcon('heroicon-m-question-mark-circle', tooltip: 'Title of the report. This is required.') - ->default(function () { - if (request()->type == 'change' && request()->has('compound_id')) { + ->default(function ($get) { + if ($get('type') == 'change' && request()->has('compound_id')) { return 'Request changes to '.request()->compound_id; } }) @@ -393,8 +410,9 @@ public static function form(Form $form): Form shouldOpenInNewTab: true, ), ) - ->hidden(function (string $operation, $record) { - return $operation == 'create' && request()->has('type') && request()->type == 'change' ? true : false; + ->hidden(function (string $operation, $get, ?Report $record) { + return true; + // return $operation == 'create' && $get('type') && $get('type') == 'change' ? true : false; }), Select::make('collections') ->hintIcon('heroicon-m-question-mark-circle', tooltip: 'Select the Collections you want to report. This will help our Curators in reviewing your report.') @@ -483,7 +501,7 @@ public static function form(Form $form): Form }) ->live() ->hidden(function (Get $get, string $operation) { - if ($operation != 'create' || request()->has('type')) { + if ($operation != 'create' || $get('type')) { return true; } if (! request()->has('compound_id') && $get('report_type') != 'molecule') { diff --git a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php index 9881cd99..91d33a89 100644 --- a/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php +++ b/app/Filament/Dashboard/Resources/ReportResource/Pages/CreateReport.php @@ -17,6 +17,14 @@ class CreateReport extends CreateRecord protected $molecule; + protected $is_change = false; + + protected $mol_id_csv = null; + + protected $report_type = null; + + protected $evidence = null; + public function getTitle(): string { $title = 'Create Report'; @@ -30,6 +38,8 @@ public function getTitle(): string protected function beforeFill(): void { + $this->data['type'] = request()->type; + if (request()->has('compound_id')) { $this->molecule = Molecule::where('identifier', request()->compound_id)->first(); } @@ -39,10 +49,12 @@ protected function afterFill(): void { $request = request(); $this->data['compound_id'] = $request->compound_id; + $this->data['type'] = $request->type; if ($request->type == 'change') { - $this->data['type'] = $request->type; $this->data['is_change'] = true; + $this->is_change = true; + $this->data['existing_geo_locations'] = $this->molecule->geo_locations->pluck('name')->toArray(); $this->data['existing_synonyms'] = $this->molecule->synonyms; $this->data['existing_cas'] = array_values($this->molecule->cas ?? []); @@ -73,6 +85,14 @@ protected function afterFill(): void } } + protected function afterValidate(): void + { + $this->mol_id_csv = $this->data['mol_id_csv']; + $this->is_change = $this->data['is_change']; + $this->report_type = $this->data['report_type']; + $this->evidence = $this->data['evidence']; + } + protected function beforeCreate(): void { if ($this->data['report_type'] == 'collection') { @@ -98,6 +118,11 @@ protected function mutateFormDataBeforeCreate(array $data): array { $data['user_id'] = auth()->id(); $data['status'] = 'submitted'; + $data['mol_id_csv'] = $this->mol_id_csv; + $data['is_change'] = $this->is_change; + $data['report_type'] = $this->report_type; + $data['evidence'] = $this->evidence; + if ($data['is_change']) { $suggested_changes = []; $suggested_changes['existing_geo_locations'] = $data['existing_geo_locations'];