Compare commits

..

No commits in common. "0bed01ff68918bafa72402a277a6b822c9a15995" and "74557097316592e700599f618b9c76b184406a06" have entirely different histories.

14 changed files with 55 additions and 773 deletions

View File

@ -17,8 +17,8 @@ ## Installation
1. **Clone the repository:**
```sh
git clone https://github.com/masroore/pixelbridge-pacs.git
cd pixelbridge-pacs
git clone https://github.com/masroore/radfusion-pacs.git
cd radfusion-pacs
```
2. **Install dependencies:**

View File

@ -6,14 +6,13 @@ enum Role: string
{
case Guest = 'guest';
case Patient = 'patient';
case Clinician = 'clinic';
case Technician = 'tech';
case Radiologist = 'rad';
case Reviewer = 'review';
case Associate = 'assoc';
case SystemAgent = 'sys';
case SiteAdmin = 'site-admin';
case Clinician = 'clinician';
case Technician = 'technician';
case Radiologist = 'radiologist';
case Associate = 'associate';
case SystemAgent = 'system_agent';
case SiteAdmin = 'site_admin';
case Clerk = 'clerk';
case Transcriptionist = 'trans';
case Transcriptionist = 'transcriptionist';
case Admin = 'admin';
}

View File

@ -1,196 +0,0 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\UserResource\Pages;
use App\Models\Department;
use App\Models\User;
use App\Services\ACL\RoleService;
use App\Services\TimezoneList;
use Filament\Forms;
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Actions\BulkActionGroup;
use Filament\Tables\Actions\EditAction;
use Filament\Tables\Actions\ViewAction;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
use Ramsey\Uuid\Uuid;
class UserResource extends Resource
{
protected static ?string $model = User::class;
protected static ?string $navigationIcon = 'heroicon-o-users';
public static function form(Form $form): Form
{
$isCreate = $form->getOperation() === 'create';
return $form
->schema([
Forms\Components\TextInput::make('guid')
->label('Unique ID')
->default(sprintf('USR-%s', Str::of(Uuid::uuid4())->lower()))
->disabled()
->dehydrated()
->required()
->maxLength(40)
->unique(ignoreRecord: true),
Toggle::make('is_active')
->required(),
TextInput::make('prefix')
->maxLength(80),
TextInput::make('first_name')
->required()
->maxLength(120),
TextInput::make('last_name')
->maxLength(120),
TextInput::make('display_name')
->required()
->maxLength(160),
TextInput::make('username')
->unique(ignoreRecord: true)
->required()
->maxLength(24),
TextInput::make('password')
->password()
->revealable()
->dehydrated(fn ($state) => filled($state))
->dehydrateStateUsing(fn ($state) => Hash::make($state))
->required(fn (string $context): bool => $context === 'create')
->maxLength(32),
TextInput::make('phone')
->unique(ignoreRecord: true)
->tel()
->telRegex('/^\+?[1-9]\d{8,14}$/')
->maxLength(80),
TextInput::make('email')
->unique(ignoreRecord: true)
->email()
->maxLength(80),
DateTimePicker::make('email_verified_at'),
TextInput::make('profile_photo_path')
->maxLength(255),
FileUpload::make('signature_image_path')
->disk('public')
->visibility('public')
->directory('signatures')
->preserveFilenames()
->getUploadedFileNameForStorageUsing(
function (TemporaryUploadedFile $file) {
return Str::of(pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME))
->slug()
->prepend(now()->timestamp . '_')
->append('.' . $file->getClientOriginalExtension());
}
)
->image(),
Textarea::make('signature_text')
->columnSpanFull(),
Select::make('organization_id')
->label('Organization')
->live()
->relationship('organization', 'name'),
Select::make('department_id')
->label('Department')
->options(function (Get $get) {
$organization_id = $get('organization_id');
$result = [];
if ($organization_id != null) {
$result = Department::active()->organization($organization_id)->pluck('name', 'id')->toArray();
}
return $result;
}),
Select::make('roles')
->relationship('roles', 'name')
->multiple()
->required(fn (string $context): bool => $context === 'create')
->searchable()
// ->options(RoleService::select())
->afterStateUpdated(function ($state, User $user) {
$user->assignRole($state);
}),
Select::make('timezone')
->options(
(new TimezoneList)->splitGroup(true)->toArray(false)
)
->required()
->default('Asia/Dhaka'),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\IconColumn::make('is_active')
->label('Active?')
->boolean(),
TextColumn::make('display_name')
->label('Name')
->searchable(),
TextColumn::make('username')
->searchable(),
TextColumn::make('email')
->searchable(),
// ImageColumn::make('signature_image_path'),
TextColumn::make('organization.name')
->label('Org')
->badge()
->sortable(),
TextColumn::make('department.name')
->label('Dept')
->sortable(),
TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('guid')
->limit(16)
->searchable(),
])
->filters([
//
])
->actions([
ViewAction::make(),
EditAction::make(),
])
->bulkActions([
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'),
'view' => Pages\ViewUser::route('/{record}'),
'edit' => Pages\EditUser::route('/{record}/edit'),
];
}
}

View File

@ -1,11 +0,0 @@
<?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

@ -1,20 +0,0 @@
<?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\ViewAction::make(),
Actions\DeleteAction::make(),
];
}
}

View File

@ -1,19 +0,0 @@
<?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

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

View File

@ -10,6 +10,7 @@
use App\Http\Requests\AssignPhysicianRequest;
use App\Models\User;
use App\Services\AuditTrail\Activity;
use Carbon\Carbon;
class AssignmentController extends HashedStudyControllerBase
{
@ -17,17 +18,13 @@ public function show()
{
abort_unless(me()->may(Permission::AssignRadiologist), 403);
$study = $this->getStudy('assignedPhysicians');
$rads = User::active()
->role(Role::Radiologist)
->get(['id', 'display_name', 'profile_photo_path', 'first_name', 'last_name', 'created_at'])
->each(fn ($rad) => $rad->info = ['workload' => '', 'last_seen' => '']);
$rads = User::active()->role(Role::Radiologist)->get(['id', 'display_name', 'profile_photo_path', 'first_name', 'last_name', 'created_at']);
$stats = Radiologists::worklist_stats(3, ReportStatus::Finalized->value);
foreach ($stats as $rad) {
$found = $rads->where('id', $rad->id)->first();
if ($found) {
$found->info['workload'] = $rad->workload;
$found->info['last_seen'] = $rad->last_seen?->diffForHumans() ?? '-';
$found->info['last_seen'] = ($rad->last_seen ?? Carbon::now()->addHours(-random_int(1, 36)))->diffForHumans();
}
}

View File

@ -3,13 +3,17 @@
namespace App\Models;
use App\Models\Traits\Active;
use App\Models\Traits\HasOrganization;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Department extends Model
{
use Active;
use HasOrganization;
public function organization(): BelongsTo
{
return $this->belongsTo(Organization::class);
}
protected function casts(): array
{

View File

@ -5,15 +5,14 @@
use App\Domain\ACL\Permission;
use App\Domain\ACL\Role;
use App\Models\Traits\Active;
use App\Models\Traits\HasDepartment;
use App\Models\Traits\HashableId;
use App\Models\Traits\HasOrganization;
use App\Services\UserService;
use Carbon\Carbon;
use Database\Factories\UserFactory;
use Filament\Models\Contracts\FilamentUser;
use Filament\Panel;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Database\Eloquent\Relations\HasOne;
@ -31,7 +30,6 @@ class User extends Authenticatable implements FilamentUser
{
use Active;
use HasApiTokens;
use HasDepartment, HasOrganization;
/** @use HasFactory<UserFactory> */
use HasFactory;
use HashableId;
@ -42,7 +40,26 @@ class User extends Authenticatable implements FilamentUser
public array $info = [];
protected $guarded = ['id'];
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'is_active',
'first_name',
'last_name',
'display_name',
'username',
'email',
'phone',
'site_id',
'facility_id',
'profile_photo_path',
'timezone',
'last_seen_at',
'password',
];
/**
* The attributes that should be hidden for serialization.
@ -142,9 +159,19 @@ public function radiologistProfile(): HasOne
return $this->hasOne(RadiologistProfile::class);
}
public function institute(): BelongsTo
{
return $this->belongsTo(Organization::class);
}
public function facility(): BelongsTo
{
return $this->belongsTo(Department::class);
}
public function canAccessPanel(Panel $panel): bool
{
return $this->isAdmin() && $this->is_active;
return $this->isAdmin();
}
public function panels(): HasManyThrough

View File

@ -1,28 +0,0 @@
<?php
namespace App\Services\ACL;
use App\Domain\ACL\Role;
use Spatie\Permission\Models\Role as SpatieRole;
final class RoleService
{
private static array $roles = [];
private static function initCache(): void
{
if (empty(self::$roles)) {
self::$roles = SpatieRole::pluck('id', 'name')->toArray();
}
}
public static function select(): array
{
// self::initCache();
return collect(Role::cases())
// ->mapWithKeys(fn (Role $r) => [self::$roles[$r->value] => $r->name])
->mapWithKeys(fn (Role $r) => [$r->value => $r->name])
->toArray();
}
}

View File

@ -4,22 +4,13 @@
use App\Services\Pacs\Sync\StudiesSync;
use Closure;
use Exception;
use Illuminate\Support\Facades\Log;
final readonly class ScanStudies
{
public function __invoke(StudiesSync $sync, Closure $next): StudiesSync
{
$study_ids = [];
try {
$study_ids = $sync->getClient()->getStudiesIds();
} catch (Exception $e) {
Log::error($e->getMessage());
}
if (! empty($study_ids)) {
$sync->setStudyIds($study_ids);
}
$study_ids = $sync->getClient()->getStudiesIds();
$sync->setStudyIds($study_ids);
return $next($sync);
}

View File

@ -1,398 +0,0 @@
<?php
namespace App\Services;
use DateTime;
use DateTimeZone;
final class TimezoneList
{
/**
* HTML entities.
*/
private const MINUS = '&#8722;';
private const PLUS = '&#43;';
private const WHITESPACE = '&#160;';
/**
* General timezones.
*
* @var array<string>
*/
protected array $generalTimezones = [
'GMT',
'UTC',
];
/**
* All continents of the world.
*
* @var array<string, string>
*/
protected array $continents = [
'Africa' => DateTimeZone::AFRICA,
'America' => DateTimeZone::AMERICA,
'Antarctica' => DateTimeZone::ANTARCTICA,
'Arctic' => DateTimeZone::ARCTIC,
'Asia' => DateTimeZone::ASIA,
'Atlantic' => DateTimeZone::ATLANTIC,
'Australia' => DateTimeZone::AUSTRALIA,
'Europe' => DateTimeZone::EUROPE,
'Indian' => DateTimeZone::INDIAN,
'Pacific' => DateTimeZone::PACIFIC,
];
/**
* The filter of the groups to get.
*/
protected array $groupsFilter = [];
/**
* Status of grouping the return list.
*/
protected bool $splitGroup = true;
/**
* Status of showing timezone offset.
*/
protected bool $showOffset = true;
/**
* The offset prefix in list.
*/
protected string $offsetPrefix = 'GMT/UTC';
/**
* Set the filter of the groups want to get.
*
* @return $this
*/
public function onlyGroups(array $groups = []): static
{
$this->groupsFilter = $groups;
return $this;
}
/**
* Set the filter of the groups do not want to get.
*
* @return $this
*/
public function excludeGroups(array $groups = []): static
{
if (empty($groups)) {
$this->groupsFilter = [];
return $this;
}
$this->groupsFilter = array_values(array_diff(array_keys($this->continents), $groups));
if (! in_array('General', $groups)) {
$this->groupsFilter[] = 'General';
}
return $this;
}
/**
* Decide whether to split group or not.
*
* @return $this
*/
public function splitGroup(bool $status = true): static
{
$this->splitGroup = (bool) $status;
return $this;
}
/**
* Decide whether to show the offset or not.
*
* @return $this
*/
public function showOffset(bool $status = true): static
{
$this->showOffset = (bool) $status;
return $this;
}
/**
* Return new static to reset all config.
*
* @return $this
*/
public function reset(): static
{
return new self;
}
/**
* Create an array of timezones.
*/
public function toArray(bool $htmlEncode = true): mixed
{
$list = [];
// If do not split group
if (! $this->splitGroup) {
if ($this->includeGeneral()) {
foreach ($this->generalTimezones as $timezone) {
$list[$timezone] = $this->formatTimezone($timezone, null, $htmlEncode);
}
}
foreach ($this->loadContinents() as $continent => $mask) {
$timezones = DateTimeZone::listIdentifiers($mask);
foreach ($timezones as $timezone) {
$list[$timezone] = $this->formatTimezone($timezone, null, $htmlEncode);
}
}
return $list;
}
// If split group
if ($this->includeGeneral()) {
foreach ($this->generalTimezones as $timezone) {
$list['General'][$timezone] = $this->formatTimezone($timezone, null, $htmlEncode);
}
}
foreach ($this->loadContinents() as $continent => $mask) {
$timezones = DateTimeZone::listIdentifiers($mask);
foreach ($timezones as $timezone) {
$list[$continent][$timezone] = $this->formatTimezone($timezone, $continent, $htmlEncode);
}
}
return $list;
}
/**
* Alias of the `toSelectBox()` method.
*
* @param string $name The name of the select tag
* @param string|null $selected The selected value
* @param array|string|null $attrs The HTML attributes of select tag
* @param bool $htmlEncode Use HTML entities for values of select tag
*
*@deprecated 6.0.0 This method name no longer matches the semantics
*/
public function create(string $name, ?string $selected = null, array|string|null $attrs = null, bool $htmlEncode = true): string
{
return $this->toSelectBox($name, $selected, $attrs, $htmlEncode);
}
/**
* Create a select box of timezones.
*
* @param string $name The name of the select tag
* @param string|null $selected The selected value
* @param array|string|null $attrs The HTML attributes of select tag
* @param bool $htmlEncode Use HTML entities for values of select tag
* @return string
*/
public function toSelectBox(string $name, ?string $selected = null, array|string|null $attrs = null, bool $htmlEncode = true)
{
// Attributes for select element
$attrString = null;
if (! empty($attrs)) {
if (is_array($attrs)) {
foreach ($attrs as $attr_name => $attr_value) {
$attrString .= ' ' . $attr_name . '="' . $attr_value . '"';
}
} else {
$attrString = $attrs;
}
}
if ($this->splitGroup) {
return $this->makeSelectTagWithGroup($name, $selected, $attrString, $htmlEncode);
}
return $this->makeSelectTagWithoutGroup($name, $selected, $attrString, $htmlEncode);
}
/**
* Generate select element with the optgroup tag.
*
* @param string $name The name of the select tag
* @param null|string $selected The selected value
* @param null|string $attrs The HTML attributes of select tag
* @param bool $htmlEncode Use HTML entities for values of select tag
* @return string
*/
protected function makeSelectTagWithGroup(string $name, ?string $selected = null, ?string $attrs = null, bool $htmlEncode = true)
{
$attrs = ! empty($attrs) ? ' ' . trim((string) $attrs) : '';
$output = '<select name="' . (string) $name . '"' . $attrs . '>';
if ($this->includeGeneral()) {
$output .= '<optgroup label="General">';
foreach ($this->generalTimezones as $timezone) {
$output .= $this->makeOptionTag($this->formatTimezone($timezone, null, $htmlEncode), $timezone, ($selected == $timezone));
}
$output .= '</optgroup>';
}
foreach ($this->loadContinents() as $continent => $mask) {
$timezones = DateTimeZone::listIdentifiers($mask);
$output .= '<optgroup label="' . $continent . '">';
foreach ($timezones as $timezone) {
$output .= $this->makeOptionTag($this->formatTimezone($timezone, $continent, $htmlEncode), $timezone, ($selected == $timezone));
}
$output .= '</optgroup>';
}
$output .= '</select>';
return $output;
}
/**
* Generate select element without the optgroup tag.
*
* @param string $name The name of the select tag
* @param null|string $selected The selected value
* @param null|string $attrs The HTML attributes of select tag
* @param bool $htmlEncode Use HTML entities for values of select tag
* @return string
*/
protected function makeSelectTagWithoutGroup(string $name, ?string $selected = null, ?string $attrs = null, bool $htmlEncode = true)
{
$attrs = ! empty($attrs) ? ' ' . trim((string) $attrs) : '';
$output = '<select name="' . (string) $name . '"' . $attrs . '>';
if ($this->includeGeneral()) {
foreach ($this->generalTimezones as $timezone) {
$output .= $this->makeOptionTag($this->formatTimezone($timezone, null, $htmlEncode), $timezone, ($selected == $timezone));
}
}
foreach ($this->loadContinents() as $continent => $mask) {
$timezones = DateTimeZone::listIdentifiers($mask);
foreach ($timezones as $timezone) {
$output .= $this->makeOptionTag($this->formatTimezone($timezone, null, $htmlEncode), $timezone, ($selected == $timezone));
}
}
$output .= '</select>';
return $output;
}
/**
* Generate the option HTML tag.
*/
protected function makeOptionTag(string $display, string $value, bool $selected = false): string
{
$attrs = (bool) $selected ? ' selected="selected"' : '';
return '<option value="' . $value . '"' . $attrs . '>' . $display . '</option>';
}
/**
* DetermineCheck if the general timezones is loaded in the returned result.
*/
protected function includeGeneral(): bool
{
return empty($this->groupsFilter) || in_array('General', $this->groupsFilter);
}
/**
* Load filtered continents.
*/
protected function loadContinents(): array
{
if (empty($this->groupsFilter)) {
return $this->continents;
}
return array_filter($this->continents, function ($key) {
return in_array($key, $this->groupsFilter);
}, ARRAY_FILTER_USE_KEY);
}
/**
* Format to display timezones.
*/
protected function formatTimezone(string $timezone, ?string $cutOffContinent = null, bool $htmlEncode = true): string
{
$displayedTimezone = empty($cutOffContinent) ? $timezone : substr($timezone, strlen($cutOffContinent) + 1);
$normalizedTimezone = $this->normalizeTimezone($displayedTimezone, $htmlEncode);
if (! $this->showOffset) {
return $normalizedTimezone;
}
$offset = $this->normalizeOffset($this->getOffset($timezone), $htmlEncode);
$separator = $this->normalizeSeparator($htmlEncode);
return '(' . $this->offsetPrefix . $offset . ')' . $separator . $normalizedTimezone;
}
/**
* Normalize the offset.
*/
protected function normalizeOffset(string $offset, bool $htmlEncode = true): string
{
$search = ['-', '+'];
$replace = $htmlEncode ? [' ' . self::MINUS . ' ', ' ' . self::PLUS . ' '] : [' - ', ' + '];
return str_replace($search, $replace, $offset);
}
/**
* Normalize the timezone.
*/
protected function normalizeTimezone(string $timezone, bool $htmlEncode = true): string
{
$search = ['St_', '/', '_'];
$replace = ['St. ', ' / ', ' '];
return str_replace($search, $replace, $timezone);
}
/**
* Normalize the separator between the timezone and offset.
*/
protected function normalizeSeparator(bool $htmlEncode = true): string
{
return $htmlEncode ? str_repeat(self::WHITESPACE, 5) : ' ';
}
/**
* Get the timezone offset.
*/
protected function getOffset(string $timezone): string
{
$time = new DateTime('', new DateTimeZone($timezone));
return $time->format('P');
}
/**
* Get the difference of timezone to Coordinated Universal Time (UTC).
*/
protected function getUTCOffset(string $timezone): string
{
$dateTimeZone = new DateTimeZone($timezone);
$utcTime = new DateTime('', new DateTimeZone('UTC'));
$offset = $dateTimeZone->getOffset($utcTime);
$format = gmdate('H:i', abs($offset));
return $offset >= 0 ? "+{$format}" : "-{$format}";
}
}

View File

@ -82,7 +82,7 @@ public function run(): void
'dicom_port' => 4242,
'rest_api_endpoint' => 'http://pacs.mylabctg.com:8042/',
'wado_path' => 'dicom-web',
'ae_title' => 'BLACKFISH',
'ae_title' => 'RADFUSION',
'stone_viewer_path' => 'stone-webviewer/index.html',
'ohif_viewer_path' => 'ohif/viewer',
]
@ -97,52 +97,7 @@ public function run(): void
'dicom_port' => 4242,
'rest_api_endpoint' => 'http://helsinki.mylabctg.com:8042/',
'wado_path' => 'dicom-web',
'ae_title' => 'BLACKFISH',
'stone_viewer_path' => 'stone-webviewer/index.html',
'ohif_viewer_path' => 'ohif/viewer',
]
);
DicomServer::create(
[
'is_active' => true,
'server_name' => 'SGP-1',
'geo_code' => 'SG',
'host' => 'singapore.mylabctg.com',
'http_port' => 8042,
'dicom_port' => 4242,
'rest_api_endpoint' => 'http://singapore.mylabctg.com:8042/',
'wado_path' => 'dicom-web',
'ae_title' => 'BLACKFISH',
'stone_viewer_path' => 'stone-webviewer/index.html',
'ohif_viewer_path' => 'ohif/viewer',
]
);
DicomServer::create(
[
'is_active' => true,
'server_name' => 'Texas',
'geo_code' => 'US',
'host' => 'texas.mylabctg.com',
'http_port' => 8042,
'dicom_port' => 4242,
'rest_api_endpoint' => 'http://texas.mylabctg.com:8042/',
'wado_path' => 'dicom-web',
'ae_title' => 'BLACKFISH',
'stone_viewer_path' => 'stone-webviewer/index.html',
'ohif_viewer_path' => 'ohif/viewer',
]
);
DicomServer::create(
[
'is_active' => false,
'server_name' => 'San Jose',
'geo_code' => 'US',
'host' => 'san-jose.mylabctg.com',
'http_port' => 8042,
'dicom_port' => 4242,
'rest_api_endpoint' => 'http://san-jose.mylabctg.com:8042/',
'wado_path' => 'dicom-web',
'ae_title' => 'BLACKFISH',
'ae_title' => 'RADFUSION',
'stone_viewer_path' => 'stone-webviewer/index.html',
'ohif_viewer_path' => 'ohif/viewer',
]
@ -156,7 +111,7 @@ public function run(): void
'http_port' => 8043,
'dicom_port' => 4242,
'rest_api_endpoint' => 'http://pacs.mylabctg.com:8042/',
'ae_title' => 'BLACKFISH',
'ae_title' => 'RADFUSION',
'wado_path' => 'dicom-web',
'stone_viewer_path' => 'stone-webviewer/index.html',
'ohif_viewer_path' => 'ohif/viewer',