Compare commits
No commits in common. "0bed01ff68918bafa72402a277a6b822c9a15995" and "74557097316592e700599f618b9c76b184406a06" have entirely different histories.
0bed01ff68
...
7455709731
@ -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:**
|
||||
|
@ -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';
|
||||
}
|
||||
|
@ -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'),
|
||||
];
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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(),
|
||||
];
|
||||
}
|
||||
}
|
@ -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(),
|
||||
];
|
||||
}
|
||||
}
|
@ -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(),
|
||||
];
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
return $next($sync);
|
||||
}
|
||||
|
@ -1,398 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use DateTime;
|
||||
use DateTimeZone;
|
||||
|
||||
final class TimezoneList
|
||||
{
|
||||
/**
|
||||
* HTML entities.
|
||||
*/
|
||||
private const MINUS = '−';
|
||||
private const PLUS = '+';
|
||||
private const WHITESPACE = ' ';
|
||||
|
||||
/**
|
||||
* 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}";
|
||||
}
|
||||
}
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user