This commit is contained in:
Dr Masroor Ehsan 2025-01-20 21:16:03 +06:00
parent 6cb641788b
commit 0ef46cce58
33 changed files with 734 additions and 21 deletions

View File

@ -507,18 +507,14 @@ private function renderImageLink(string $data_id, string $img_src, string $data_
private function generateViewerButtons(Study $study): string private function generateViewerButtons(Study $study): string
{ {
$btns = []; $btns = [];
$btns[] = $this->renderButton($study->hash, 'fa-eye', 'btn-outline', '', route('viewer.ohif', $study->hash), true); $btns[] = $this->renderImageLink(
$btns[] = Blade::render('staff.worklist.partials._dropdown-menu', $study->hash, 'eye.png', '', 'OHIF Viewer', route('viewer.ohif', $study->hash), true
[ );
'items' => [ $btns[] = $this->renderImageLink(
[ $study->hash, 'weasis.png', '', 'WEASIS Viewer', $study->links()['weasis'], false
'url' => route('viewer.stone', $study->hash), );
'text' => 'Stone', $btns[] = $this->renderImageLink(
'blank' => true, $study->hash, 'live.png', '', 'STONE Viewer', route('viewer.stone', $study->hash), true
'icon' => 'fa-circle-info',
],
],
]
); );
return implode("\r", $btns); return implode("\r", $btns);

View File

@ -0,0 +1,76 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\DicomServerResource\Pages;
use App\Models\DicomServer;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
class DicomServerResource extends Resource
{
protected static ?string $model = DicomServer::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
public static function form(Form $form): Form
{
return $form
->schema([
//
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('id')
->label('ID')
->sortable(),
Tables\Columns\CheckboxColumn::make('is_active')
->label('Active')
->disabled()
->sortable(),
Tables\Columns\TextColumn::make('server_name')
->label('Name')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('host')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('port')
->searchable()
->sortable(),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListDicomServers::route('/'),
'create' => Pages\CreateDicomServer::route('/create'),
'edit' => Pages\EditDicomServer::route('/{record}/edit'),
];
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\DicomServerResource\Pages;
use App\Filament\Resources\DicomServerResource;
use Filament\Resources\Pages\CreateRecord;
class CreateDicomServer extends CreateRecord
{
protected static string $resource = DicomServerResource::class;
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\DicomServerResource\Pages;
use App\Filament\Resources\DicomServerResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditDicomServer extends EditRecord
{
protected static string $resource = DicomServerResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\DicomServerResource\Pages;
use App\Filament\Resources\DicomServerResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListDicomServers extends ListRecords
{
protected static string $resource = DicomServerResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@ -0,0 +1,73 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\FacilityResource\Pages;
use App\Models\Facility;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
class FacilityResource extends Resource
{
protected static ?string $model = Facility::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
public static function form(Form $form): Form
{
return $form
->schema([
//
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('id')
->label('ID')
->sortable(),
Tables\Columns\CheckboxColumn::make('is_active')
->label('Active')
->disabled()
->sortable(),
Tables\Columns\TextColumn::make('name')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('institute.name')
->name('Institute')
->searchable()
->sortable(),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListFacilities::route('/'),
'create' => Pages\CreateFacility::route('/create'),
'edit' => Pages\EditFacility::route('/{record}/edit'),
];
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\FacilityResource\Pages;
use App\Filament\Resources\FacilityResource;
use Filament\Resources\Pages\CreateRecord;
class CreateFacility extends CreateRecord
{
protected static string $resource = FacilityResource::class;
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\FacilityResource\Pages;
use App\Filament\Resources\FacilityResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditFacility extends EditRecord
{
protected static string $resource = FacilityResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\FacilityResource\Pages;
use App\Filament\Resources\FacilityResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListFacilities extends ListRecords
{
protected static string $resource = FacilityResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@ -0,0 +1,69 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\InstituteResource\Pages;
use App\Models\Institute;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
class InstituteResource extends Resource
{
protected static ?string $model = Institute::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
public static function form(Form $form): Form
{
return $form
->schema([
//
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('id')
->label('ID')
->sortable(),
Tables\Columns\CheckboxColumn::make('is_active')
->label('Active')
->disabled()
->sortable(),
Tables\Columns\TextColumn::make('name')
->searchable()
->sortable(),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListInstitutes::route('/'),
'create' => Pages\CreateInstitute::route('/create'),
'edit' => Pages\EditInstitute::route('/{record}/edit'),
];
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\InstituteResource\Pages;
use App\Filament\Resources\InstituteResource;
use Filament\Resources\Pages\CreateRecord;
class CreateInstitute extends CreateRecord
{
protected static string $resource = InstituteResource::class;
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\InstituteResource\Pages;
use App\Filament\Resources\InstituteResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditInstitute extends EditRecord
{
protected static string $resource = InstituteResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\InstituteResource\Pages;
use App\Filament\Resources\InstituteResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListInstitutes extends ListRecords
{
protected static string $resource = InstituteResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@ -0,0 +1,60 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\RadiologistResource\Pages;
use App\Models\Radiologist;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
class RadiologistResource extends Resource
{
protected static ?string $model = Radiologist::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
public static function form(Form $form): Form
{
return $form
->schema([
//
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
//
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListRadiologists::route('/'),
'create' => Pages\CreateRadiologist::route('/create'),
'edit' => Pages\EditRadiologist::route('/{record}/edit'),
];
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\RadiologistResource\Pages;
use App\Filament\Resources\RadiologistResource;
use Filament\Resources\Pages\CreateRecord;
class CreateRadiologist extends CreateRecord
{
protected static string $resource = RadiologistResource::class;
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\RadiologistResource\Pages;
use App\Filament\Resources\RadiologistResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditRadiologist extends EditRecord
{
protected static string $resource = RadiologistResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\RadiologistResource\Pages;
use App\Filament\Resources\RadiologistResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListRadiologists extends ListRecords
{
protected static string $resource = RadiologistResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@ -0,0 +1,82 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\UserResource\Pages;
use App\Models\User;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
class UserResource extends Resource
{
protected static ?string $model = User::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
public static function form(Form $form): Form
{
return $form
->schema([
//
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('id')
->label('ID')
->sortable(),
Tables\Columns\CheckboxColumn::make('is_active')
->label('Active')
->disabled()
->sortable(),
Tables\Columns\TextColumn::make('username')
->label('Username')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('display_name')
->label('Name')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('institute.name')
->label('Institute')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('facility.name')
->label('Fac')
->searchable()
->sortable(),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListUsers::route('/'),
'create' => Pages\CreateUser::route('/create'),
'edit' => Pages\EditUser::route('/{record}/edit'),
];
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\UserResource\Pages;
use App\Filament\Resources\UserResource;
use Filament\Resources\Pages\CreateRecord;
class CreateUser extends CreateRecord
{
protected static string $resource = UserResource::class;
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\UserResource\Pages;
use App\Filament\Resources\UserResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditUser extends EditRecord
{
protected static string $resource = UserResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\UserResource\Pages;
use App\Filament\Resources\UserResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListUsers extends ListRecords
{
protected static string $resource = UserResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@ -30,6 +30,11 @@ public function ohifViewerUrl(): Uri
return $this->restEndpoint($this->ohif_viewer_path); return $this->restEndpoint($this->ohif_viewer_path);
} }
public function wadoUrl(): Uri
{
return $this->restEndpoint($this->wado_path);
}
private function restEndpoint(string $path): Uri private function restEndpoint(string $path): Uri
{ {
return Uri::of($this->rest_api_endpoint)->withPath($path); return Uri::of($this->rest_api_endpoint)->withPath($path);

View File

@ -4,12 +4,18 @@
use App\Models\Traits\Active; use App\Models\Traits\Active;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Institute extends BaseModel class Institute extends BaseModel
{ {
use Active; use Active;
use HasFactory; use HasFactory;
public function facilities(): HasMany
{
return $this->hasMany(Facility::class);
}
protected function casts(): array protected function casts(): array
{ {
return [ return [

View File

@ -237,6 +237,15 @@ public function getOhifMprLink(): ?string
return null; return null;
} }
public function getWeasisLink(): ?string
{
if (me()->may(Permission::StudyDownload)) {
return PacsUrlGen::weasisUrl($this->dicomServer, $this);
}
return null;
}
public function links(): array public function links(): array
{ {
return [ return [
@ -245,6 +254,7 @@ public function links(): array
'zip' => $this->getArchiveLink(), 'zip' => $this->getArchiveLink(),
'stone' => $this->getStoneLink(), 'stone' => $this->getStoneLink(),
'ohif' => $this->getOhifLink(), 'ohif' => $this->getOhifLink(),
'weasis' => $this->getWeasisLink(),
'ohif.mpr' => $this->getOhifMprLink(), 'ohif.mpr' => $this->getOhifMprLink(),
'ohif.seg' => $this->getOhifSegmentationLink(), 'ohif.seg' => $this->getOhifSegmentationLink(),
]; ];
@ -256,6 +266,7 @@ public function allowed(): array
'zip' => filled($this->getArchiveLink()), 'zip' => filled($this->getArchiveLink()),
'stone' => filled($this->getStoneLink()), 'stone' => filled($this->getStoneLink()),
'ohif' => filled($this->getOhifLink()), 'ohif' => filled($this->getOhifLink()),
'weasis' => filled($this->getWeasisLink()),
'ohif.mpr' => filled($this->getOhifMprLink()), 'ohif.mpr' => filled($this->getOhifMprLink()),
'ohif.seg' => filled($this->getOhifSegmentationLink()), 'ohif.seg' => filled($this->getOhifSegmentationLink()),
]; ];

View File

@ -9,8 +9,10 @@
use App\Services\UserService; use App\Services\UserService;
use Carbon\Carbon; use Carbon\Carbon;
use Database\Factories\UserFactory; use Database\Factories\UserFactory;
use Filament\Models\Contracts\FilamentUser;
use Filament\Panel; use Filament\Panel;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Foundation\Auth\User as Authenticatable;
@ -156,6 +158,21 @@ public function radiologistProfile(): HasOne
return $this->hasOne(RadiologistProfile::class); return $this->hasOne(RadiologistProfile::class);
} }
public function institute(): BelongsTo
{
return $this->belongsTo(Institute::class);
}
public function facility(): BelongsTo
{
return $this->belongsTo(Facility::class);
}
public function canAccessPanel(Panel $panel): bool
{
return $this->isAdmin();
}
/** /**
* Get the attributes that should be cast. * Get the attributes that should be cast.
* *
@ -170,9 +187,4 @@ protected function casts(): array
'password' => 'hashed', 'password' => 'hashed',
]; ];
} }
public function canAccessPanel(Panel $panel): bool
{
return $this->isAdmin();
}
} }

View File

@ -0,0 +1,58 @@
<?php
namespace App\Providers\Filament;
use Filament\Http\Middleware\Authenticate;
use Filament\Http\Middleware\AuthenticateSession;
use Filament\Http\Middleware\DisableBladeIconComponents;
use Filament\Http\Middleware\DispatchServingFilamentEvent;
use Filament\Pages;
use Filament\Panel;
use Filament\PanelProvider;
use Filament\Support\Colors\Color;
use Filament\Widgets;
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
use Illuminate\Cookie\Middleware\EncryptCookies;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
use Illuminate\Routing\Middleware\SubstituteBindings;
use Illuminate\Session\Middleware\StartSession;
use Illuminate\View\Middleware\ShareErrorsFromSession;
class AdminPanelProvider extends PanelProvider
{
public function panel(Panel $panel): Panel
{
return $panel
->default()
->id('admin')
->path('admin')
->login()
->colors([
'primary' => Color::Amber,
])
->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources')
->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages')
->pages([
Pages\Dashboard::class,
])
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets')
->widgets([
Widgets\AccountWidget::class,
Widgets\FilamentInfoWidget::class,
])
->middleware([
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartSession::class,
AuthenticateSession::class,
ShareErrorsFromSession::class,
VerifyCsrfToken::class,
SubstituteBindings::class,
DisableBladeIconComponents::class,
DispatchServingFilamentEvent::class,
])
->authMiddleware([
Authenticate::class,
]);
}
}

View File

@ -4,7 +4,7 @@
use App\Models\DicomServer; use App\Models\DicomServer;
use App\Models\Study; use App\Models\Study;
use Uri; use Illuminate\Support\Uri;
final class PacsUrlGen final class PacsUrlGen
{ {
@ -34,6 +34,19 @@ public static function ohifViewerMpr(DicomServer $host, Study $study): string
return (string) $url; return (string) $url;
} }
public static function weasisUrl(DicomServer $host, Study $study, bool $close = false): string
{
$parts = [];
if ($close) {
$parts[] = '$dicom:close --all';
}
$parts[] = sprintf('$dicom:rs --url "%s"', $host->wadoUrl());
$parts[] = sprintf('-r "studyUID=%s"', $study->study_instance_uid);
// $parts[] = '--query-ext "&includedefaults=false"';
return sprintf('weasis://%s', urlencode(implode(' ', $parts)));
}
public static function ohifSegmentation(DicomServer $host, Study $study): string public static function ohifSegmentation(DicomServer $host, Study $study): string
{ {
$url = $host->ohifViewerUrl() $url = $host->ohifViewerUrl()

View File

@ -20,6 +20,7 @@ public function up(): void
$table->string('ae_title')->nullable(); $table->string('ae_title')->nullable();
$table->string('username')->nullable(); $table->string('username')->nullable();
$table->string('password')->nullable(); $table->string('password')->nullable();
$table->string('wado_path')->nullable();
$table->string('stone_viewer_path')->nullable(); $table->string('stone_viewer_path')->nullable();
$table->string('ohif_viewer_path')->nullable(); $table->string('ohif_viewer_path')->nullable();
$table->string('meddream_viewer_path')->nullable(); $table->string('meddream_viewer_path')->nullable();

View File

@ -63,6 +63,7 @@ public function run(): void
'host' => 'pacs.mylabctg.com', 'host' => 'pacs.mylabctg.com',
'port' => 8042, 'port' => 8042,
'rest_api_endpoint' => 'http://pacs.mylabctg.com:8042/', 'rest_api_endpoint' => 'http://pacs.mylabctg.com:8042/',
'wado_path' => 'dicom-web',
'ae_title' => 'RADFUSION', 'ae_title' => 'RADFUSION',
'stone_viewer_path' => 'stone-webviewer/index.html', 'stone_viewer_path' => 'stone-webviewer/index.html',
'ohif_viewer_path' => 'ohif/viewer', 'ohif_viewer_path' => 'ohif/viewer',
@ -76,6 +77,7 @@ public function run(): void
'port' => 8043, 'port' => 8043,
'rest_api_endpoint' => 'http://pacs.mylabctg.com:8042/', 'rest_api_endpoint' => 'http://pacs.mylabctg.com:8042/',
'ae_title' => 'RADFUSION', 'ae_title' => 'RADFUSION',
'wado_path' => 'dicom-web',
'stone_viewer_path' => 'stone-webviewer/index.html', 'stone_viewer_path' => 'stone-webviewer/index.html',
'ohif_viewer_path' => 'ohif/viewer', 'ohif_viewer_path' => 'ohif/viewer',
'institute_id' => $chev->id, 'institute_id' => $chev->id,

View File

@ -1 +1 @@
<img src="{{ $src }}" class="{{ $class }}" data-bs-toggle="tooltip" data-bs-placement="top" title="{{ $tip }}"> <img src="{{ $src }}" class="{{ $class }}" @include('_partials._tooltip', compact('tip'))>

View File

@ -1 +1 @@
data-bs-toggle="tooltip" data-bs-placement="top" data-bs-original-title="{{ $tip }}" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-original-title="{{ $tip }}" title="{{ $tip }}"

View File

@ -132,6 +132,9 @@ class="d-flex justify-content-between align-items-start border-end pb-4 pb-sm-0
@if ($study->allowed()['ohif']) @if ($study->allowed()['ohif'])
<a target="_blank" href="{{ $study->links()['ohif'] }}">O</a> | <a target="_blank" href="{{ $study->links()['ohif'] }}">O</a> |
@endif @endif
@if ($study->allowed()['weasis'])
<a target="_blank" href="{{ $study->links()['weasis'] }}">O</a> |
@endif
@if ($study->allowed()['ohif.mpr']) @if ($study->allowed()['ohif.mpr'])
<a target="_blank" href="{{ $study->links()['ohif.mpr'] }}">OM</a> | <a target="_blank" href="{{ $study->links()['ohif.mpr'] }}">OM</a> |
@endif @endif

View File

@ -1,3 +1,4 @@
<a @if ($blank) target="_blank" @endif href="{{ $url ?? '#' }}" data-id="{{ $data_id }}" class="ms-1 {{ $data_class }}" @include('_partials._tooltip', ['tip' => $text])> <a @if ($blank) target="_blank" @endif href="{{ $url ?? '#' }}" @include('_partials._tooltip', ['tip' => $text]) data-id="{{ $data_id }}" class="me-2 {{ $data_class }}">
<img src="{{ $img_src }}" width="{{ $width }}px" height="{{ $width }}px"> <img src="{{ $img_src }}" width="{{ $width }}px" height="{{ $width }}px">
</a> </a>