319-environment-owned-surface-routing-shell-context-contract #380
@ -137,11 +137,14 @@ public static function canAccess(): bool
|
||||
return true;
|
||||
}
|
||||
|
||||
return (int) (app(GovernanceDecisionRegisterBuilder::class)->build(
|
||||
$counts = app(GovernanceDecisionRegisterBuilder::class)->build(
|
||||
workspace: $workspace,
|
||||
visibleTenants: $visibleTenants,
|
||||
registerState: 'open',
|
||||
)['counts']['open'] ?? 0) > 0;
|
||||
)['counts'] ?? [];
|
||||
|
||||
return (int) ($counts['open'] ?? 0) > 0
|
||||
|| (int) ($counts['recently_closed'] ?? 0) > 0;
|
||||
}
|
||||
|
||||
public function mount(): void
|
||||
@ -416,7 +419,19 @@ private function ensureRegisterIsVisible(): void
|
||||
return;
|
||||
}
|
||||
|
||||
if ((int) ($this->registerPayload()['counts']['open'] ?? 0) === 0) {
|
||||
$counts = $this->unfilteredRegisterPayload()['counts'] ?? [];
|
||||
|
||||
if ((int) ($counts['open'] ?? 0) > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((int) ($counts['recently_closed'] ?? 0) > 0) {
|
||||
$this->redirect($this->pageUrl(['register_state' => 'recently_closed']), navigate: true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ((int) ($counts['open'] ?? 0) === 0) {
|
||||
abort(403);
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
use App\Support\Filament\CanonicalAdminTenantFilterState;
|
||||
use App\Support\Navigation\CanonicalNavigationContext;
|
||||
use App\Support\OperateHub\OperateHubShell;
|
||||
use App\Support\OperationRunLinks;
|
||||
use App\Support\OperationRunOutcome;
|
||||
use App\Support\OperationRunStatus;
|
||||
use App\Support\Operations\OperationLifecyclePolicy;
|
||||
@ -23,6 +24,7 @@
|
||||
use App\Support\Ui\ActionSurface\Enums\ActionSurfaceType;
|
||||
use App\Support\Workspaces\WorkspaceContext;
|
||||
use App\Models\User;
|
||||
use App\Services\Auth\ManagedEnvironmentAccessScopeResolver;
|
||||
use App\Services\Auth\WorkspaceCapabilityResolver;
|
||||
use BackedEnum;
|
||||
use Filament\Actions\Action;
|
||||
@ -347,6 +349,7 @@ public function table(Table $table): Table
|
||||
->query(function (): Builder {
|
||||
$workspaceId = app(WorkspaceContext::class)->currentWorkspaceId(request());
|
||||
$tenantFilter = $this->currentTenantFilterId();
|
||||
$allowedTenantIds = $this->allowedTenantIdsForWorkspaceScope($workspaceId);
|
||||
|
||||
$query = OperationRun::query()
|
||||
->with('user')
|
||||
@ -359,6 +362,18 @@ public function table(Table $table): Table
|
||||
! $workspaceId,
|
||||
fn (Builder $query): Builder => $query->whereRaw('1 = 0'),
|
||||
)
|
||||
->when(
|
||||
$workspaceId && $allowedTenantIds !== null,
|
||||
function (Builder $query) use ($allowedTenantIds): Builder {
|
||||
return $query->where(function (Builder $query) use ($allowedTenantIds): void {
|
||||
$query->whereNull('managed_environment_id');
|
||||
|
||||
if ($allowedTenantIds !== []) {
|
||||
$query->orWhereIn('managed_environment_id', $allowedTenantIds);
|
||||
}
|
||||
});
|
||||
},
|
||||
)
|
||||
->when(
|
||||
$tenantFilter !== null,
|
||||
fn (Builder $query): Builder => $query->where('managed_environment_id', $tenantFilter),
|
||||
@ -437,9 +452,22 @@ private function scopedSummaryQuery(): ?Builder
|
||||
}
|
||||
|
||||
$tenantFilter = $this->currentTenantFilterId();
|
||||
$allowedTenantIds = $this->allowedTenantIdsForWorkspaceScope($workspaceId);
|
||||
|
||||
return OperationRun::query()
|
||||
->where('workspace_id', (int) $workspaceId)
|
||||
->when(
|
||||
$allowedTenantIds !== null,
|
||||
function (Builder $query) use ($allowedTenantIds): Builder {
|
||||
return $query->where(function (Builder $query) use ($allowedTenantIds): void {
|
||||
$query->whereNull('managed_environment_id');
|
||||
|
||||
if ($allowedTenantIds !== []) {
|
||||
$query->orWhereIn('managed_environment_id', $allowedTenantIds);
|
||||
}
|
||||
});
|
||||
},
|
||||
)
|
||||
->when(
|
||||
$tenantFilter !== null,
|
||||
fn (Builder $query): Builder => $query->where('managed_environment_id', $tenantFilter),
|
||||
@ -509,6 +537,29 @@ private function currentTenantFilterId(): ?int
|
||||
return $this->normalizeEntitledTenantFilter($tenantFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Null means inherited access to all environments in the workspace.
|
||||
*
|
||||
* @return list<int>|null
|
||||
*/
|
||||
private function allowedTenantIdsForWorkspaceScope(mixed $workspaceId): ?array
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
if (! $user instanceof User || ! is_int($workspaceId)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$allowedIds = app(ManagedEnvironmentAccessScopeResolver::class)
|
||||
->allowedManagedEnvironmentIdsForWorkspace($user, $workspaceId);
|
||||
|
||||
if ($allowedIds === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return array_values(array_unique(array_map('intval', $allowedIds)));
|
||||
}
|
||||
|
||||
private function normalizeEntitledTenantFilter(mixed $value): ?int
|
||||
{
|
||||
if (! is_numeric($value)) {
|
||||
|
||||
@ -20,6 +20,14 @@ public static function getLabel(): string
|
||||
return 'Register tenant';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return class-string<Model>
|
||||
*/
|
||||
public function getModel(): string
|
||||
{
|
||||
return ManagedEnvironment::class;
|
||||
}
|
||||
|
||||
public static function canView(): bool
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
@ -111,7 +111,12 @@ public static function getUrl(array $parameters = [], bool $isAbsolute = true, ?
|
||||
return url('/admin');
|
||||
}
|
||||
|
||||
return url('/admin/workspaces/'.($workspace->slug ?? $workspace->getKey()).'/environments/'.$resolvedTenant->getRouteKey());
|
||||
$url = url('/admin/workspaces/'.($workspace->slug ?? $workspace->getKey()).'/environments/'.$resolvedTenant->getRouteKey());
|
||||
$query = array_diff_key($parameters, array_flip(['tenant', 'environment', 'workspace']));
|
||||
|
||||
return $query === []
|
||||
? $url
|
||||
: $url.'?'.http_build_query($query);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -96,7 +96,7 @@ public function bootstrapOwner(): void
|
||||
abort(403, 'Not allowed');
|
||||
}
|
||||
|
||||
app(TenantMembershipManager::class)->grantScope($tenant, $user, $user, source: 'diagnostic');
|
||||
app(TenantMembershipManager::class)->grantScope($tenant, $user, $user, sourceRef: 'diagnostic');
|
||||
|
||||
$this->mount();
|
||||
}
|
||||
|
||||
@ -4844,7 +4844,9 @@ private function completionSummaryBootstrapLabel(): string
|
||||
$runs = is_array($runs) ? $runs : [];
|
||||
|
||||
if ($runs !== []) {
|
||||
return 'Started';
|
||||
return $this->completionSummaryBootstrapCompleted()
|
||||
? 'Completed'
|
||||
: 'Started';
|
||||
}
|
||||
|
||||
return $this->completionSummarySelectedBootstrapTypes() === []
|
||||
@ -4879,6 +4881,10 @@ private function completionSummaryBootstrapDetail(): string
|
||||
return sprintf('%d action(s) selected', count($selectedTypes));
|
||||
}
|
||||
|
||||
if ($this->completionSummaryBootstrapCompleted()) {
|
||||
return sprintf('%d action(s) completed', count($runs));
|
||||
}
|
||||
|
||||
if (count($runs) < count($selectedTypes)) {
|
||||
return sprintf('%d of %d action(s) started', count($runs), count($selectedTypes));
|
||||
}
|
||||
@ -4895,6 +4901,41 @@ private function completionSummaryBootstrapSummary(): string
|
||||
);
|
||||
}
|
||||
|
||||
private function completionSummaryBootstrapCompleted(): bool
|
||||
{
|
||||
if (! $this->onboardingSession instanceof TenantOnboardingSession) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$selectedTypes = $this->completionSummarySelectedBootstrapTypes();
|
||||
|
||||
if ($selectedTypes === []) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$runs = $this->onboardingSession->state['bootstrap_operation_runs'] ?? null;
|
||||
$runs = is_array($runs) ? $runs : [];
|
||||
|
||||
if ($runs === [] || count($runs) < count($selectedTypes)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$runIds = array_values(array_filter(array_map(
|
||||
static fn (mixed $value): ?int => is_numeric($value) ? (int) $value : null,
|
||||
$runs,
|
||||
)));
|
||||
|
||||
if (count($runIds) < count($selectedTypes)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return OperationRun::query()
|
||||
->whereIn('id', $runIds)
|
||||
->where('status', OperationRunStatus::Completed->value)
|
||||
->where('outcome', OperationRunOutcome::Succeeded->value)
|
||||
->count() >= count($selectedTypes);
|
||||
}
|
||||
|
||||
private function showCompletionSummaryBootstrapRecovery(): bool
|
||||
{
|
||||
return $this->completionSummaryBootstrapActionRequiredDetail() !== null;
|
||||
@ -4910,6 +4951,7 @@ private function completionSummaryBootstrapColor(): string
|
||||
return match ($this->completionSummaryBootstrapLabel()) {
|
||||
'Action required' => 'warning',
|
||||
'Started' => 'info',
|
||||
'Completed' => 'success',
|
||||
'Selected' => 'warning',
|
||||
default => 'gray',
|
||||
};
|
||||
|
||||
@ -55,6 +55,8 @@ protected function getViewData(): array
|
||||
->limit(5)
|
||||
->get([
|
||||
'id',
|
||||
'workspace_id',
|
||||
'managed_environment_id',
|
||||
'type',
|
||||
'status',
|
||||
'outcome',
|
||||
|
||||
@ -146,6 +146,11 @@ public function panel(Panel $panel): Panel
|
||||
->icon('heroicon-o-queue-list')
|
||||
->group(fn (): string => __('localization.navigation.monitoring'))
|
||||
->sort(10),
|
||||
NavigationItem::make('Alerts')
|
||||
->url(fn (): string => route('filament.admin.alerts'))
|
||||
->icon('heroicon-o-bell-alert')
|
||||
->group(fn (): string => __('localization.navigation.monitoring'))
|
||||
->sort(23),
|
||||
NavigationItem::make(fn (): string => __('localization.navigation.audit_log'))
|
||||
->url(fn (): string => route('admin.monitoring.audit-log'))
|
||||
->icon('heroicon-o-clipboard-document-list')
|
||||
@ -161,7 +166,7 @@ public function panel(Panel $panel): Panel
|
||||
fn () => view('filament.partials.context-bar')->render()
|
||||
)
|
||||
->renderHook(
|
||||
PanelsRenderHook::BODY_END,
|
||||
PanelsRenderHook::PAGE_START,
|
||||
fn (): string => request()->routeIs('admin.workspace.managed-tenants.index', 'admin.onboarding', 'admin.onboarding.draft', 'filament.admin.pages.choose-tenant')
|
||||
? ''
|
||||
: ((bool) config('tenantpilot.bulk_operations.progress_widget_enabled', true)
|
||||
@ -224,12 +229,10 @@ public function panel(Panel $panel): Panel
|
||||
Authenticate::class,
|
||||
]);
|
||||
|
||||
if (! app()->runningUnitTests()) {
|
||||
$theme = PanelThemeAsset::resolve('resources/css/filament/admin/theme.css');
|
||||
$theme = PanelThemeAsset::resolve('resources/css/filament/admin/theme.css');
|
||||
|
||||
if (is_string($theme)) {
|
||||
$panel->theme($theme);
|
||||
}
|
||||
if (is_string($theme)) {
|
||||
$panel->theme($theme);
|
||||
}
|
||||
|
||||
return $panel;
|
||||
|
||||
@ -51,7 +51,7 @@ public function panel(Panel $panel): Panel
|
||||
])
|
||||
->navigationItems([
|
||||
NavigationItem::make(fn (): string => __('localization.navigation.operations'))
|
||||
->url(fn (): string => route('admin.operations.index'))
|
||||
->url(fn (): string => OperationRunLinks::index())
|
||||
->icon('heroicon-o-queue-list')
|
||||
->group(fn (): string => __('localization.navigation.monitoring'))
|
||||
->sort(10),
|
||||
|
||||
@ -18,6 +18,11 @@ final class ManagedEnvironmentAccessScopeResolver
|
||||
*/
|
||||
private array $scopeIdsByUserWorkspace = [];
|
||||
|
||||
/**
|
||||
* @var array<int, Workspace|null>
|
||||
*/
|
||||
private array $workspaceById = [];
|
||||
|
||||
public function __construct(
|
||||
private readonly WorkspaceCapabilityResolver $workspaceCapabilityResolver,
|
||||
) {}
|
||||
@ -44,7 +49,7 @@ public function decision(User $user, ManagedEnvironment $tenant, ?string $requir
|
||||
);
|
||||
}
|
||||
|
||||
$workspace = Workspace::query()->whereKey($workspaceId)->first();
|
||||
$workspace = $this->workspaceForId($workspaceId);
|
||||
|
||||
if (! $workspace instanceof Workspace) {
|
||||
return new ManagedEnvironmentAccessDecision(
|
||||
@ -139,7 +144,7 @@ public function canAccess(User $user, ManagedEnvironment $tenant): bool
|
||||
*/
|
||||
public function allowedManagedEnvironmentIdsForWorkspace(User $user, int $workspaceId): ?array
|
||||
{
|
||||
$workspace = Workspace::query()->whereKey($workspaceId)->first();
|
||||
$workspace = $this->workspaceForId($workspaceId);
|
||||
|
||||
if (! $workspace instanceof Workspace || $this->workspaceCapabilityResolver->getRole($user, $workspace) === null) {
|
||||
return [];
|
||||
@ -187,6 +192,7 @@ public function prime(User $user, array $tenantIds): void
|
||||
public function clearCache(): void
|
||||
{
|
||||
$this->scopeIdsByUserWorkspace = [];
|
||||
$this->workspaceById = [];
|
||||
}
|
||||
|
||||
public function applyWorkspaceScopeToQuery(Builder $query, User $user, int $workspaceId, string $qualifiedEnvironmentColumn): Builder
|
||||
@ -233,6 +239,15 @@ private function scopeIdsForWorkspace(User $user, int $workspaceId): ?array
|
||||
return $this->scopeIdsByUserWorkspace[$cacheKey];
|
||||
}
|
||||
|
||||
private function workspaceForId(int $workspaceId): ?Workspace
|
||||
{
|
||||
if (! array_key_exists($workspaceId, $this->workspaceById)) {
|
||||
$this->workspaceById[$workspaceId] = Workspace::query()->whereKey($workspaceId)->first();
|
||||
}
|
||||
|
||||
return $this->workspaceById[$workspaceId];
|
||||
}
|
||||
|
||||
private function hydrateTenantBoundary(ManagedEnvironment $tenant): ?ManagedEnvironment
|
||||
{
|
||||
if ($tenant->exists && $tenant->workspace_id !== null) {
|
||||
|
||||
@ -199,6 +199,15 @@ public function startCompareForVisibleAssignments(BaselineProfile $profile, User
|
||||
$blockedCount = 0;
|
||||
$targets = [];
|
||||
|
||||
$this->capabilityResolver->primeMemberships(
|
||||
$initiator,
|
||||
$assignments
|
||||
->pluck('managed_environment_id')
|
||||
->filter(static fn (mixed $id): bool => is_numeric($id))
|
||||
->map(static fn (mixed $id): int => (int) $id)
|
||||
->all(),
|
||||
);
|
||||
|
||||
foreach ($assignments as $assignment) {
|
||||
$tenant = $assignment->tenant;
|
||||
|
||||
|
||||
@ -46,6 +46,15 @@ public function build(BaselineProfile $profile, User $user, array $filters = [])
|
||||
->with('tenant')
|
||||
->get();
|
||||
|
||||
$this->capabilityResolver->primeMemberships(
|
||||
$user,
|
||||
$assignments
|
||||
->pluck('managed_environment_id')
|
||||
->filter(static fn (mixed $id): bool => is_numeric($id))
|
||||
->map(static fn (mixed $id): int => (int) $id)
|
||||
->all(),
|
||||
);
|
||||
|
||||
$visibleTenants = $this->visibleTenants($assignments, $user);
|
||||
$referenceResolution = $this->snapshotTruthResolver->resolveCompareSnapshot($profile);
|
||||
$referenceSnapshot = $this->resolvedSnapshot($referenceResolution);
|
||||
|
||||
@ -405,6 +405,7 @@ private function operationsSection(
|
||||
tenant: $selectedTenant,
|
||||
context: $navigationContext,
|
||||
problemClass: $dominantProblemClass,
|
||||
workspace: $workspace,
|
||||
),
|
||||
'entries' => $entries,
|
||||
'empty_state' => $selectedTenant instanceof ManagedEnvironment
|
||||
|
||||
@ -84,8 +84,11 @@ public static function index(
|
||||
bool $allTenants = false,
|
||||
?string $problemClass = null,
|
||||
?string $operationType = null,
|
||||
?Workspace $workspace = null,
|
||||
): string {
|
||||
$workspace = self::resolveWorkspace($tenant);
|
||||
$workspace = $tenant instanceof ManagedEnvironment
|
||||
? self::resolveWorkspace($tenant)
|
||||
: ($workspace ?? self::resolveWorkspace());
|
||||
|
||||
if (! $workspace instanceof Workspace) {
|
||||
return url('/admin');
|
||||
|
||||
@ -13,7 +13,7 @@ class="flex w-full flex-col items-start gap-3 sm:flex-row sm:flex-wrap sm:items-
|
||||
@if (filled($context['provider'] ?? null))
|
||||
<div data-testid="tenant-dashboard-context-chip-provider" data-provider-key="{{ $context['providerKey'] ?? '' }}" class="inline-flex items-center gap-2 whitespace-nowrap rounded-2xl border border-gray-200 bg-white/80 px-4 py-2 text-sm font-medium text-gray-700 shadow-sm backdrop-blur dark:border-white/10 dark:bg-white/5 dark:text-gray-200">
|
||||
@if (($context['providerKey'] ?? null) === 'microsoft')
|
||||
<svg data-testid="tenant-dashboard-context-chip-provider-microsoft-logo" viewBox="0 0 16 16" aria-hidden="true" class="h-4 w-4 shrink-0">
|
||||
<svg data-testid="tenant-dashboard-context-chip-provider-microsoft-logo" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true" class="h-4 w-4 shrink-0">
|
||||
<rect x="1" y="1" width="6" height="6" fill="#f25022" />
|
||||
<rect x="9" y="1" width="6" height="6" fill="#7fba00" />
|
||||
<rect x="1" y="9" width="6" height="6" fill="#00a4ef" />
|
||||
@ -33,4 +33,4 @@ class="flex w-full flex-col items-start gap-3 sm:flex-row sm:flex-wrap sm:items-
|
||||
<span>{{ __('localization.dashboard.overview.context_latest_activity_chip', ['time' => $context['latestActivity']]) }}</span>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1 +1,3 @@
|
||||
<livewire:bulk-operation-progress />
|
||||
@if (\Filament\Facades\Filament::getCurrentPanel()?->getId() === 'admin' && auth()->user() instanceof \App\Models\User)
|
||||
<livewire:bulk-operation-progress />
|
||||
@endif
|
||||
|
||||
@ -386,10 +386,18 @@
|
||||
abort_unless($allowed, 404);
|
||||
};
|
||||
|
||||
Route::middleware(['web', 'auth', 'ensure-correct-guard:web', 'ensure-workspace-member'])
|
||||
Route::middleware([
|
||||
'web',
|
||||
'panel:admin',
|
||||
'ensure-correct-guard:web',
|
||||
DisableBladeIconComponents::class,
|
||||
DispatchServingFilamentEvent::class,
|
||||
FilamentAuthenticate::class,
|
||||
'ensure-workspace-member',
|
||||
])
|
||||
->prefix('/admin/workspaces/{workspace}')
|
||||
->group(function (): void {
|
||||
Route::get('/', WorkspaceOverview::class)
|
||||
Route::get('/overview', WorkspaceOverview::class)
|
||||
->name('admin.workspace.home');
|
||||
|
||||
Route::get('/ping', fn () => response()->noContent())->name('admin.workspace.ping');
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
use App\Models\Finding;
|
||||
use App\Models\OperationRun;
|
||||
use App\Models\ProviderConnection;
|
||||
use App\Support\OperationRunLinks;
|
||||
use App\Support\OperationRunOutcome;
|
||||
use App\Support\OperationRunStatus;
|
||||
use App\Support\Workspaces\WorkspaceContext;
|
||||
@ -33,6 +34,7 @@
|
||||
'outcome' => OperationRunOutcome::Failed->value,
|
||||
'completed_at' => now()->subHour(),
|
||||
]);
|
||||
$operationPath = (string) parse_url(OperationRunLinks::tenantlessView($operation), PHP_URL_PATH);
|
||||
|
||||
$backupSet = BackupSet::factory()->create([
|
||||
'managed_environment_id' => (int) $tenant->getKey(),
|
||||
@ -62,17 +64,18 @@
|
||||
],
|
||||
]);
|
||||
|
||||
$page = visit(TenantDashboard::getUrl(panel: 'tenant', tenant: $tenant))
|
||||
$page = visit(TenantDashboard::getUrl(panel: 'admin', tenant: $tenant))
|
||||
->waitForText($tenant->name)
|
||||
->waitForText('Backup posture')
|
||||
->assertScript("document.querySelector('[data-testid=\"tenant-dashboard-posture-pill\"]') !== null", true)
|
||||
->assertScript("document.querySelector('[data-testid=\"tenant-dashboard-context-chip-workspace\"]') !== null", true)
|
||||
->assertScript("document.querySelector('[data-testid=\"tenant-dashboard-context-chip-provider\"][data-provider-key=\"microsoft\"]') !== null", true)
|
||||
->assertScript("document.querySelector('[data-testid=\"tenant-dashboard-context-chip-provider-microsoft-logo\"]') !== null", true)
|
||||
->assertScript("(() => { const logo = document.querySelector('[data-testid=\"tenant-dashboard-context-chip-provider-microsoft-logo\"]'); if (! logo) return false; const rect = logo.getBoundingClientRect(); return rect.width <= 20 && rect.height <= 20; })()", true)
|
||||
->assertScript("document.querySelector('[data-testid=\"tenant-dashboard-context-chip-latest-activity\"]') !== null", true)
|
||||
->assertScript("document.querySelector('[data-testid=\"tenant-dashboard-context-chip-latest-activity-icon\"]') !== null", true)
|
||||
->assertScript("(() => { const chips = document.querySelector('[data-testid=\"tenant-dashboard-context-chips\"]'); const firstKpi = document.querySelector('[data-testid=\"tenant-dashboard-kpi\"]'); if (! chips || ! firstKpi) return false; return chips.getBoundingClientRect().top < firstKpi.getBoundingClientRect().top; })()", true)
|
||||
->assertScript("(() => { const subtitle = Array.from(document.querySelectorAll('p')).find((node) => node.textContent?.includes('Tenant governance overview')); const chips = document.querySelector('[data-testid=\"tenant-dashboard-context-chips\"]'); if (! subtitle || ! chips) return false; return chips.getBoundingClientRect().top - subtitle.getBoundingClientRect().bottom <= 40; })()", true)
|
||||
->assertScript("(() => { const subtitle = Array.from(document.querySelectorAll('p')).find((node) => node.textContent?.includes('governance overview')); const chips = document.querySelector('[data-testid=\"tenant-dashboard-context-chips\"]'); if (! subtitle || ! chips) return false; return chips.getBoundingClientRect().top - subtitle.getBoundingClientRect().bottom <= 64; })()", true)
|
||||
->assertScript("(() => { const workspace = document.querySelector('[data-testid=\"tenant-dashboard-context-chip-workspace\"]'); const provider = document.querySelector('[data-testid=\"tenant-dashboard-context-chip-provider\"]'); const activity = document.querySelector('[data-testid=\"tenant-dashboard-context-chip-latest-activity\"]'); if (! workspace || ! provider || ! activity) return false; const tops = [workspace, provider, activity].map((element) => Math.round(element.getBoundingClientRect().top)); return Math.max(...tops) - Math.min(...tops) <= 2; })()", true)
|
||||
->assertSee('Recommended next actions')
|
||||
->assertSee('Operations needing attention')
|
||||
@ -108,9 +111,10 @@
|
||||
->assertScript("! document.body.innerHTML.includes('fixed bottom-4 right-4 z-[999999] w-96 space-y-2')", true)
|
||||
->assertScript("(() => { const overview = document.querySelector('[data-testid=\"tenant-dashboard-overview\"]'); const main = document.querySelector('[data-testid=\"tenant-dashboard-overview-main\"]'); if (! overview || ! main) return false; const overviewWidth = overview.getBoundingClientRect().width; const mainWidth = main.getBoundingClientRect().width; return overviewWidth >= 600 && mainWidth >= 400; })()", true)
|
||||
->assertScript("document.querySelectorAll('[data-testid=\"tenant-dashboard-overview\"] table').length === 0", true)
|
||||
->click('Review operation')
|
||||
->assertSeeIn('[data-testid="ops-ux-activity-feedback-primary-action"]', 'View operation')
|
||||
->click('[data-testid="ops-ux-activity-feedback-primary-action"]')
|
||||
->waitForText('Show all operations')
|
||||
->assertScript("window.location.pathname.includes('/admin/operations/{$operation->getKey()}')", true)
|
||||
->assertScript("window.location.pathname === '{$operationPath}'", true)
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertNoConsoleLogs();
|
||||
|
||||
|
||||
@ -52,7 +52,6 @@
|
||||
'entra_tenant_id' => (string) $tenant->managed_environment_id,
|
||||
'tenant_name' => (string) $tenant->name,
|
||||
'environment' => 'prod',
|
||||
'provider_connection_id' => (int) $connection->getKey(),
|
||||
],
|
||||
]);
|
||||
|
||||
@ -67,28 +66,24 @@
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertRoute('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()])
|
||||
->assertSee('Onboarding draft')
|
||||
->assertSee('Verify access')
|
||||
->assertSee('Status: Not started')
|
||||
->waitForText('Use existing connection')
|
||||
->refresh()
|
||||
->waitForText('Status: Not started')
|
||||
->waitForText('Use existing connection')
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertRoute('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()])
|
||||
->assertSee('Verify access')
|
||||
->assertSee('Status: Not started')
|
||||
->click('Select an existing connection or create a new one.')
|
||||
->assertSee('Edit selected connection')
|
||||
->click('Create new connection')
|
||||
->check('internal:label="Dedicated override"s')
|
||||
->check('Create new connection')
|
||||
->waitForText('Dedicated override')
|
||||
->check('Dedicated override')
|
||||
->waitForText('Dedicated client secret')
|
||||
->fill('[type="password"]', 'browser-only-secret')
|
||||
->assertValue('[type="password"]', 'browser-only-secret')
|
||||
->refresh()
|
||||
->waitForText('Status: Not started')
|
||||
->waitForText('Use existing connection')
|
||||
->assertRoute('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()])
|
||||
->assertSee('Verify access')
|
||||
->click('Select an existing connection or create a new one.')
|
||||
->assertSee('Edit selected connection')
|
||||
->click('Create new connection')
|
||||
->check('internal:label="Dedicated override"s')
|
||||
->check('Create new connection')
|
||||
->waitForText('Dedicated override')
|
||||
->check('Dedicated override')
|
||||
->waitForText('Dedicated client secret')
|
||||
->assertValue('[type="password"]', '');
|
||||
});
|
||||
|
||||
@ -285,5 +280,6 @@
|
||||
$page
|
||||
->wait(7)
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertSee('Bootstrap completed across 1 operation(s).');
|
||||
->assertSee('Completed - 1 action(s) completed')
|
||||
->assertSee('Complete onboarding');
|
||||
});
|
||||
|
||||
@ -53,11 +53,11 @@ function operationActivityFeedbackSmokeLoginUrl(User $user, ManagedEnvironment $
|
||||
]);
|
||||
|
||||
visit(operationActivityFeedbackSmokeLoginUrl($user, $tenant))
|
||||
->waitForText('Dashboard')
|
||||
->waitForText($tenant->name)
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertNoConsoleLogs();
|
||||
|
||||
$inventoryPage = visit(InventoryItemResource::getUrl('index', panel: 'tenant', tenant: $tenant))
|
||||
$inventoryPage = visit(InventoryItemResource::getUrl('index', panel: 'admin', tenant: $tenant))
|
||||
->resize(1440, 1200)
|
||||
->assertScript('window.innerWidth >= 1400', true)
|
||||
->waitForText('Inventory Items')
|
||||
@ -183,7 +183,7 @@ function operationActivityFeedbackSmokeLoginUrl(User $user, ManagedEnvironment $
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertNoConsoleLogs();
|
||||
|
||||
$page = visit(FindingResource::getUrl('index', panel: 'tenant', tenant: $tenant))
|
||||
$page = visit(FindingResource::getUrl('index', panel: 'admin', tenant: $tenant))
|
||||
->resize(1440, 1200);
|
||||
|
||||
$page
|
||||
@ -252,11 +252,11 @@ function operationActivityFeedbackSmokeLoginUrl(User $user, ManagedEnvironment $
|
||||
]);
|
||||
|
||||
visit(operationActivityFeedbackSmokeLoginUrl($user, $tenant))
|
||||
->waitForText('Dashboard')
|
||||
->waitForText($tenant->name)
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertNoConsoleLogs();
|
||||
|
||||
visit(InventoryItemResource::getUrl('index', panel: 'tenant', tenant: $tenant))
|
||||
visit(InventoryItemResource::getUrl('index', panel: 'admin', tenant: $tenant))
|
||||
->resize(1440, 1200)
|
||||
->waitForText('Inventory Items')
|
||||
->waitForText('Capturing evidence.')
|
||||
@ -285,11 +285,11 @@ function operationActivityFeedbackSmokeLoginUrl(User $user, ManagedEnvironment $
|
||||
]);
|
||||
|
||||
visit(operationActivityFeedbackSmokeLoginUrl($user, $tenant))
|
||||
->waitForText('Dashboard')
|
||||
->waitForText($tenant->name)
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertNoConsoleLogs();
|
||||
|
||||
$page = visit(InventoryItemResource::getUrl('index', panel: 'tenant', tenant: $tenant))
|
||||
$page = visit(InventoryItemResource::getUrl('index', panel: 'admin', tenant: $tenant))
|
||||
->resize(1440, 1200)
|
||||
->waitForText('Inventory Items')
|
||||
->waitForText('Acknowledge')
|
||||
|
||||
@ -48,7 +48,10 @@
|
||||
|
||||
visit(OperationRunLinks::tenantlessView($run))
|
||||
->waitForText(OperationRunLinks::identifier((int) $run->getKey()))
|
||||
->assertRoute('admin.operations.view', ['run' => (int) $run->getKey()])
|
||||
->assertRoute('admin.operations.view', [
|
||||
'workspace' => (int) $run->workspace_id,
|
||||
'run' => (int) $run->getKey(),
|
||||
])
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertSee(OperationRunLinks::identifier((int) $run->getKey()));
|
||||
});
|
||||
});
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Filament\Resources\TenantReviewResource;
|
||||
use App\Models\ReviewPack;
|
||||
use App\Models\ManagedEnvironment;
|
||||
use App\Models\ReviewPack;
|
||||
use App\Support\TenantReviewStatus;
|
||||
use App\Support\Workspaces\WorkspaceContext;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
@ -106,7 +106,8 @@
|
||||
->waitForText('Published ManagedEnvironment')
|
||||
->assertDontSee('No Published ManagedEnvironment')
|
||||
->assertDontSee('No published review available yet')
|
||||
->click('Review öffnen')
|
||||
->assertSeeIn('tbody tr.fi-ta-row:first-of-type td:last-child', 'Review öffnen')
|
||||
->click('tbody tr.fi-ta-row:first-of-type td:last-child a')
|
||||
->waitForText('Ergebniszusammenfassung')
|
||||
->assertSee('Governance-Paket herunterladen')
|
||||
->assertSee('Governance-Paket')
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -72,11 +72,16 @@
|
||||
|
||||
visit($operationsIndexUrl)
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertRoute('admin.operations.index');
|
||||
->assertRoute('admin.operations.index', [
|
||||
'workspace' => (int) $tenant->workspace_id,
|
||||
]);
|
||||
|
||||
visit(OperationRunLinks::tenantlessView($run))
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertRoute('admin.operations.view', ['run' => (int) $run->getKey()])
|
||||
->assertRoute('admin.operations.view', [
|
||||
'workspace' => (int) $run->workspace_id,
|
||||
'run' => (int) $run->getKey(),
|
||||
])
|
||||
->assertSee(OperationRunLinks::identifier((int) $run->getKey()));
|
||||
});
|
||||
|
||||
|
||||
@ -84,7 +84,7 @@
|
||||
]);
|
||||
session()->put(WorkspaceContext::SESSION_KEY, (int) $staleTenant->workspace_id);
|
||||
|
||||
visit(EvidenceSnapshotResource::getUrl('view', ['record' => $staleSnapshot], tenant: $staleTenant, panel: 'tenant'))
|
||||
visit(EvidenceSnapshotResource::getUrl('view', ['record' => $staleSnapshot], tenant: $staleTenant, panel: 'admin'))
|
||||
->waitForText('Outcome summary')
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertSee('Stale')
|
||||
@ -103,7 +103,7 @@
|
||||
->assertSee('Refresh the source review before sharing this pack')
|
||||
->assertSee('Download');
|
||||
|
||||
visit(ReviewPackResource::getUrl('view', ['record' => $stalePack], tenant: $staleTenant, panel: 'tenant'))
|
||||
visit(ReviewPackResource::getUrl('view', ['record' => $stalePack], tenant: $staleTenant, panel: 'admin'))
|
||||
->waitForText('Outcome summary')
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertSee('Internal only')
|
||||
|
||||
@ -123,11 +123,11 @@ function seedSpec177InventoryItemFilterPaginationFixtures(ManagedEnvironment $te
|
||||
]);
|
||||
session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);
|
||||
|
||||
$coverageUrl = InventoryCoverage::getUrl(panel: 'tenant', tenant: $tenant);
|
||||
$coverageUrl = InventoryCoverage::getUrl(panel: 'admin', tenant: $tenant);
|
||||
$basisRunUrl = OperationRunLinks::view($run, $tenant);
|
||||
$inventoryItemsUrl = InventoryItemResource::getUrl('index', panel: 'tenant', tenant: $tenant);
|
||||
$inventoryItemsUrl = InventoryItemResource::getUrl('index', panel: 'admin', tenant: $tenant);
|
||||
|
||||
$searchPage = visit(InventoryItemResource::getUrl('index', panel: 'tenant', tenant: $tenant));
|
||||
$searchPage = visit(InventoryItemResource::getUrl('index', panel: 'admin', tenant: $tenant));
|
||||
|
||||
$searchPage
|
||||
->waitForText('Inventory Items')
|
||||
@ -162,7 +162,10 @@ function seedSpec177InventoryItemFilterPaginationFixtures(ManagedEnvironment $te
|
||||
visit($basisRunUrl)
|
||||
->waitForText('Operation #'.(int) $run->getKey())
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertRoute('admin.operations.view', ['run' => (int) $run->getKey()])
|
||||
->assertRoute('admin.operations.view', [
|
||||
'workspace' => (int) $run->workspace_id,
|
||||
'run' => (int) $run->getKey(),
|
||||
])
|
||||
->assertSee('Inventory sync coverage')
|
||||
->assertSee('Need follow-up');
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
|
||||
uses(BuildsBaselineCompareMatrixFixtures::class);
|
||||
|
||||
pest()->browser()->timeout(15_000);
|
||||
pest()->browser()->timeout(20_000);
|
||||
|
||||
it('smokes dense multi-tenant scanning and finding drilldown continuity', function (): void {
|
||||
$fixture = $this->makeBaselineCompareMatrixFixture();
|
||||
|
||||
@ -143,7 +143,7 @@ function spec192ApprovedFindingException(ManagedEnvironment $tenant, User $reque
|
||||
->assertSee('Review compare matrix')
|
||||
->assertSee('Compare now');
|
||||
|
||||
visit(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshot], tenant: $tenant, panel: 'tenant'))
|
||||
visit(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshot], tenant: $tenant, panel: 'admin'))
|
||||
->waitForText('Related context')
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertScript("document.querySelectorAll('[data-supporting-group-kind]').length === 0", true)
|
||||
@ -266,7 +266,7 @@ function spec192ApprovedFindingException(ManagedEnvironment $tenant, User $reque
|
||||
]);
|
||||
session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);
|
||||
|
||||
visit(ReviewPackResource::getUrl('view', ['record' => $pack], tenant: $tenant, panel: 'tenant'))
|
||||
visit(ReviewPackResource::getUrl('view', ['record' => $pack], tenant: $tenant, panel: 'admin'))
|
||||
->waitForText('Download')
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertSee('Regenerate');
|
||||
|
||||
@ -73,7 +73,7 @@
|
||||
->assertNoConsoleLogs()
|
||||
->assertSee('Quiet monitoring mode');
|
||||
|
||||
visit(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
||||
visit(\App\Support\OperationRunLinks::tenantlessView($run))
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertNoConsoleLogs()
|
||||
->assertSee('Monitoring detail')
|
||||
@ -84,8 +84,10 @@
|
||||
->assertNoConsoleLogs()
|
||||
->assertSee('Alert deliveries');
|
||||
|
||||
visit('/admin/t/'.$diagnosticsTenant->external_id.'/diagnostics')
|
||||
visit(\App\Filament\Pages\TenantDashboard::getUrl(tenant: $diagnosticsTenant))
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertNoConsoleLogs()
|
||||
->assertSee('Missing owner');
|
||||
->assertSee($diagnosticsTenant->name)
|
||||
->click('[aria-label="More"]')
|
||||
->assertSee('Open support diagnostics');
|
||||
});
|
||||
|
||||
@ -10,20 +10,20 @@
|
||||
use App\Models\EvidenceSnapshot;
|
||||
use App\Models\Finding;
|
||||
use App\Models\FindingException;
|
||||
use App\Models\ManagedEnvironment;
|
||||
use App\Models\OperationRun;
|
||||
use App\Models\PlatformUser;
|
||||
use App\Models\ReviewPack;
|
||||
use App\Models\ManagedEnvironment;
|
||||
use App\Models\User;
|
||||
use App\Services\Findings\FindingExceptionService;
|
||||
use App\Support\Auth\PlatformCapabilities;
|
||||
use App\Support\Evidence\EvidenceCompletenessState;
|
||||
use App\Support\Evidence\EvidenceSnapshotStatus;
|
||||
use App\Support\OperationRunOutcome;
|
||||
use App\Support\OperationRunStatus;
|
||||
use App\Support\System\SystemOperationRunLinks;
|
||||
use App\Support\TenantReviewCompletenessState;
|
||||
use App\Support\TenantReviewStatus;
|
||||
use App\Support\Auth\PlatformCapabilities;
|
||||
use App\Support\System\SystemOperationRunLinks;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
pest()->browser()->timeout(20_000);
|
||||
@ -65,6 +65,8 @@ function spec194ApprovedFindingException(ManagedEnvironment $tenant, User $reque
|
||||
|
||||
function spec194SmokeLoginUrl(User $user, ManagedEnvironment $tenant, string $redirect = ''): string
|
||||
{
|
||||
$redirect = spec194RelativeRedirect($redirect);
|
||||
|
||||
return route('admin.local.smoke-login', array_filter([
|
||||
'email' => $user->email,
|
||||
'tenant' => $tenant->external_id,
|
||||
@ -73,11 +75,31 @@ function spec194SmokeLoginUrl(User $user, ManagedEnvironment $tenant, string $re
|
||||
], static fn (?string $value): bool => filled($value)));
|
||||
}
|
||||
|
||||
function spec194RelativeRedirect(string $redirect): string
|
||||
{
|
||||
$redirect = trim($redirect);
|
||||
|
||||
if ($redirect === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$parts = parse_url($redirect);
|
||||
|
||||
if ($parts === false || ! isset($parts['path'])) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $parts['path']
|
||||
.(isset($parts['query']) ? '?'.$parts['query'] : '')
|
||||
.(isset($parts['fragment']) ? '#'.$parts['fragment'] : '');
|
||||
}
|
||||
|
||||
it('smokes tenant and admin governance semantics through modal entry points', function (): void {
|
||||
[$user, $tenant] = createUserWithTenant(
|
||||
role: 'owner',
|
||||
workspaceRole: 'manager',
|
||||
workspaceRole: 'owner',
|
||||
ensureDefaultMicrosoftProviderConnection: false,
|
||||
clearCapabilityCaches: true,
|
||||
);
|
||||
|
||||
$finding = Finding::factory()->for($tenant)->create();
|
||||
@ -147,12 +169,13 @@ function spec194SmokeLoginUrl(User $user, ManagedEnvironment $tenant, string $re
|
||||
tenant: $archivedTenant,
|
||||
user: $user,
|
||||
role: 'owner',
|
||||
workspaceRole: 'manager',
|
||||
workspaceRole: 'owner',
|
||||
ensureDefaultMicrosoftProviderConnection: false,
|
||||
clearCapabilityCaches: true,
|
||||
);
|
||||
|
||||
visit(spec194SmokeLoginUrl($user, $tenant))
|
||||
->waitForText('Dashboard')
|
||||
->waitForText($tenant->name)
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertNoConsoleLogs();
|
||||
|
||||
@ -177,14 +200,14 @@ function spec194SmokeLoginUrl(User $user, ManagedEnvironment $tenant, string $re
|
||||
->assertNoConsoleLogs()
|
||||
->click('Publish review')
|
||||
->waitForText('Publication reason')
|
||||
->click('Cancel')
|
||||
->click('button:has-text("Cancel")')
|
||||
->click('[aria-label="More"]')
|
||||
->assertSee('Refresh review')
|
||||
->assertSee('Export executive pack')
|
||||
->click('[aria-label="Danger"]')
|
||||
->click('Archive review')
|
||||
->waitForText('Archive reason')
|
||||
->click('Cancel')
|
||||
->click('button:has-text("Cancel")')
|
||||
->assertSee('Publish review')
|
||||
->assertSee('Evidence snapshot');
|
||||
|
||||
@ -194,10 +217,10 @@ function spec194SmokeLoginUrl(User $user, ManagedEnvironment $tenant, string $re
|
||||
->assertNoConsoleLogs()
|
||||
->click('Refresh evidence')
|
||||
->waitForText('Confirm')
|
||||
->click('Cancel')
|
||||
->click('button:has-text("Cancel")')
|
||||
->click('Expire snapshot')
|
||||
->waitForText('Expiry reason')
|
||||
->click('Cancel')
|
||||
->click('button:has-text("Cancel")')
|
||||
->assertSee('Refresh evidence')
|
||||
->assertSee('Expire snapshot');
|
||||
|
||||
@ -206,9 +229,10 @@ function spec194SmokeLoginUrl(User $user, ManagedEnvironment $tenant, string $re
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertNoConsoleLogs()
|
||||
->click('[aria-label="Lifecycle"]')
|
||||
->click('Archive')
|
||||
->waitForText('Archive')
|
||||
->click('button:has-text("Archive")')
|
||||
->waitForText('Archive reason')
|
||||
->click('Cancel')
|
||||
->click('button:has-text("Cancel")')
|
||||
->assertSee('Lifecycle');
|
||||
|
||||
visit(TenantResource::getUrl('edit', ['record' => $tenant], panel: 'admin'))
|
||||
@ -217,13 +241,21 @@ function spec194SmokeLoginUrl(User $user, ManagedEnvironment $tenant, string $re
|
||||
->assertNoConsoleLogs()
|
||||
->assertSee('Lifecycle');
|
||||
|
||||
visit(TenantResource::getUrl('view', ['record' => $archivedTenant], panel: 'admin'))
|
||||
visit(spec194SmokeLoginUrl(
|
||||
$user,
|
||||
$archivedTenant,
|
||||
TenantResource::getUrl('view', ['record' => $archivedTenant], panel: 'admin'),
|
||||
))
|
||||
->waitForText('Related context')
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertNoConsoleLogs()
|
||||
->assertSee('Lifecycle');
|
||||
|
||||
visit(TenantResource::getUrl('edit', ['record' => $archivedTenant], panel: 'admin'))
|
||||
visit(spec194SmokeLoginUrl(
|
||||
$user,
|
||||
$archivedTenant,
|
||||
TenantResource::getUrl('edit', ['record' => $archivedTenant], panel: 'admin'),
|
||||
))
|
||||
->waitForText('Related context')
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertNoConsoleLogs()
|
||||
|
||||
@ -95,6 +95,7 @@
|
||||
session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);
|
||||
|
||||
visit(route('admin.operations.index', [
|
||||
'workspace' => $tenant->workspace,
|
||||
'managed_environment_id' => (int) $tenant->getKey(),
|
||||
'activeTab' => 'active',
|
||||
]))
|
||||
@ -151,8 +152,14 @@
|
||||
'baseline_profile_id' => (int) $profile->getKey(),
|
||||
]);
|
||||
|
||||
$this->actingAs($user);
|
||||
$tenant->makeCurrent();
|
||||
$this->actingAs($user)->withSession([
|
||||
WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
|
||||
WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY => [
|
||||
(string) $tenant->workspace_id => (int) $tenant->getKey(),
|
||||
],
|
||||
]);
|
||||
session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
$matrixUrl = BaselineProfileResource::compareMatrixUrl($profile).'?subject_key='.urlencode($subjectKey);
|
||||
|
||||
@ -161,11 +168,11 @@
|
||||
'baseline_profile_id' => (int) $profile->getKey(),
|
||||
'subject_key' => $subjectKey,
|
||||
],
|
||||
panel: 'tenant',
|
||||
panel: 'admin',
|
||||
tenant: $tenant,
|
||||
))
|
||||
->waitForText('Open compare matrix')
|
||||
->assertSee('Launch the compare matrix with the currently known baseline profile and any carried subject focus from this tenant landing.');
|
||||
->assertSee('Launch the compare matrix with the currently known baseline profile and any carried subject focus from this environment landing.');
|
||||
|
||||
visit($matrixUrl)
|
||||
->waitForText('Focused subject')
|
||||
|
||||
@ -73,7 +73,7 @@ function spec202SmokeLoginUrl(User $user, ManagedEnvironment $tenant, string $re
|
||||
]);
|
||||
|
||||
visit(spec202SmokeLoginUrl($user, $tenant))
|
||||
->waitForText('Dashboard')
|
||||
->waitForText($tenant->name)
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertNoConsoleLogs();
|
||||
|
||||
@ -148,7 +148,7 @@ function spec202SmokeLoginUrl(User $user, ManagedEnvironment $tenant, string $re
|
||||
]);
|
||||
|
||||
visit(spec202SmokeLoginUrl($user, $tenant))
|
||||
->waitForText('Dashboard')
|
||||
->waitForText($tenant->name)
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertNoConsoleLogs();
|
||||
|
||||
@ -160,4 +160,4 @@ function spec202SmokeLoginUrl(User $user, ManagedEnvironment $tenant, string $re
|
||||
->assertSee('Support readiness')
|
||||
->assertSee('Capture: blocked. Compare: blocked.')
|
||||
->assertSee('Stored scope is invalid and must be repaired before capture or compare can continue.');
|
||||
});
|
||||
});
|
||||
|
||||
@ -71,7 +71,7 @@ function spec265SmokeLoginUrl(User $user, ManagedEnvironment $tenant, string $re
|
||||
]);
|
||||
|
||||
visit(spec265SmokeLoginUrl($user, $tenant))
|
||||
->waitForText('Dashboard')
|
||||
->waitForText($tenant->name)
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertNoConsoleLogs();
|
||||
|
||||
@ -82,7 +82,8 @@ function spec265SmokeLoginUrl(User $user, ManagedEnvironment $tenant, string $re
|
||||
->assertSee('The register is currently filtered to one tenant.')
|
||||
->assertSee($tenant->name)
|
||||
->assertSee('Showing 1 result')
|
||||
->click('tbody tr.fi-ta-row')
|
||||
->assertSeeIn('tbody tr.fi-ta-row:first-of-type', $tenant->name)
|
||||
->click('tbody tr.fi-ta-row:first-of-type')
|
||||
->waitForText('Opened from the workspace decision register')
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertNoConsoleLogs()
|
||||
|
||||
@ -41,7 +41,7 @@
|
||||
],
|
||||
]);
|
||||
|
||||
visit(StoredReportResource::getUrl('index', tenant: $tenant, panel: 'tenant'))
|
||||
visit(StoredReportResource::getUrl('index', tenant: $tenant, panel: 'admin'))
|
||||
->waitForText('Stored reports')
|
||||
->assertSee('Permission posture report')
|
||||
->assertSee('Current')
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
->assertSee('Active')
|
||||
->click('Spec 279 Production')
|
||||
->waitForText('Spec 279 Production')
|
||||
->assertPathContains('/admin/t/spec-279-production')
|
||||
->assertPathContains('/admin/workspaces/'.$environment->workspace->slug.'/environments/spec-279-production')
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertNoConsoleLogs();
|
||||
});
|
||||
|
||||
@ -14,9 +14,7 @@
|
||||
$member = User::factory()->create([
|
||||
'email' => 'browser-tenant-member@example.test',
|
||||
]);
|
||||
$member->tenants()->syncWithoutDetaching([
|
||||
$tenant->getKey() => ['role' => 'readonly'],
|
||||
]);
|
||||
createUserWithTenant(tenant: $tenant, user: $member, role: 'readonly');
|
||||
|
||||
$this->actingAs($owner)->withSession([
|
||||
WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
|
||||
@ -28,28 +26,27 @@
|
||||
$viewPage
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertSee((string) $tenant->name)
|
||||
->assertSee('Manage memberships')
|
||||
->assertSee('Manage access scope')
|
||||
->assertScript("document.body.innerText.includes('Add member')", false)
|
||||
->assertScript("document.body.innerText.includes('browser-tenant-member@example.test')", false);
|
||||
|
||||
$membershipsPage = $viewPage->click('Manage memberships');
|
||||
$membershipsPage = $viewPage->click('Manage access scope');
|
||||
|
||||
$membershipsPage
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertSee('Manage tenant memberships')
|
||||
->assertSee('Back to tenant overview')
|
||||
->assertSee('ManagedEnvironment access is managed here. Use the tenant overview for provider state, verification, and operational context.');
|
||||
->assertSee('Manage environment access scope')
|
||||
->assertSee('Back to environment overview')
|
||||
->assertSee('Workspace membership defines the role. Explicit environment scopes only narrow which workspace members can see this environment.');
|
||||
|
||||
$membershipsPage->script(<<<'JS'
|
||||
window.scrollTo(0, document.body.scrollHeight);
|
||||
JS);
|
||||
|
||||
$membershipsPage
|
||||
->waitForText('Add member')
|
||||
->waitForText('Add explicit access scope')
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertSee('Manage tenant memberships')
|
||||
->assertSee('Add member')
|
||||
->assertSee('Manage environment access scope')
|
||||
->assertSee('Add explicit access scope')
|
||||
->assertSee('browser-tenant-member@example.test')
|
||||
->assertSee('Change role')
|
||||
->assertSee('Remove');
|
||||
->assertSee('Remove explicit scope');
|
||||
});
|
||||
|
||||
@ -44,7 +44,7 @@ public function test_renders_canonical_detail_for_a_workspace_member_when_tenant
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
||||
->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
||||
->get(\App\Support\OperationRunLinks::tenantlessView($run))
|
||||
->assertOk()
|
||||
->assertSee(\App\Support\OperationRunLinks::identifier($run))
|
||||
->assertSee('Policy sync')
|
||||
@ -70,7 +70,7 @@ public function test_renders_canonical_detail_gracefully_when_tenant_id_is_null(
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
||||
->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
||||
->get(\App\Support\OperationRunLinks::tenantlessView($run))
|
||||
->assertOk()
|
||||
->assertSee('No target scope details were recorded for this operation.');
|
||||
}
|
||||
@ -89,7 +89,7 @@ public function test_returns_404_on_canonical_detail_for_non_members(): void
|
||||
]);
|
||||
|
||||
$this->actingAs($otherUser)
|
||||
->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
||||
->get(\App\Support\OperationRunLinks::tenantlessView($run))
|
||||
->assertNotFound();
|
||||
}
|
||||
|
||||
@ -118,7 +118,7 @@ public function test_renders_canonical_detail_db_only_with_no_job_dispatch(): vo
|
||||
|
||||
assertNoOutboundHttp(function () use ($user, $run): void {
|
||||
$this->actingAs($user)
|
||||
->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
||||
->get(\App\Support\OperationRunLinks::tenantlessView($run))
|
||||
->assertOk()
|
||||
->assertSee('Verification report');
|
||||
});
|
||||
|
||||
@ -25,7 +25,7 @@ public function test_hides_operations_kpi_stats_when_tenant_context_is_absent():
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
||||
->get(route('admin.operations.index'))
|
||||
->get(\App\Support\OperationRunLinks::index())
|
||||
->assertOk()
|
||||
->assertDontSee('Total Operations (30 days)')
|
||||
->assertDontSee('Active Operations')
|
||||
|
||||
@ -38,7 +38,7 @@ public function test_renders_workspace_operations_list_with_tenantless_runs_when
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
||||
->get(route('admin.operations.index'))
|
||||
->get(\App\Support\OperationRunLinks::index())
|
||||
->assertOk()
|
||||
->assertSee('Tenantless run')
|
||||
->assertSee('ManagedEnvironment run');
|
||||
@ -70,7 +70,7 @@ public function test_renders_workspace_operations_list_workspace_wide_even_with_
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
||||
->get(route('admin.operations.index'))
|
||||
->get(\App\Support\OperationRunLinks::index())
|
||||
->assertOk()
|
||||
->assertSee('ManagedEnvironment run')
|
||||
->assertSee('Tenantless run');
|
||||
|
||||
@ -38,7 +38,7 @@ public function test_shows_restore_related_links_on_canonical_detail_for_restore
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
||||
->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
||||
->get(\App\Support\OperationRunLinks::tenantlessView($run))
|
||||
->assertOk()
|
||||
->assertSee('Open')
|
||||
->assertSee('View restore run');
|
||||
@ -61,7 +61,7 @@ public function test_shows_only_generic_links_for_tenantless_runs_on_canonical_d
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
||||
->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
||||
->get(\App\Support\OperationRunLinks::tenantlessView($run))
|
||||
->assertOk()
|
||||
->assertSee('Operations')
|
||||
->assertSee(OperationRunLinks::index(), false)
|
||||
@ -80,7 +80,7 @@ public function test_does_not_show_legacy_admin_details_cta_and_keeps_canonical_
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
||||
->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
||||
->get(\App\Support\OperationRunLinks::tenantlessView($run))
|
||||
->assertOk()
|
||||
->assertDontSee('Admin details')
|
||||
->assertDontSee('/admin/t/'.$tenant->external_id.'/operations/r/'.$run->getKey(), false);
|
||||
@ -89,7 +89,7 @@ public function test_does_not_show_legacy_admin_details_cta_and_keeps_canonical_
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
||||
->get(route('admin.operations.index'))
|
||||
->get(OperationRunLinks::index())
|
||||
->assertOk()
|
||||
->assertSee('Open run detail');
|
||||
}
|
||||
@ -122,11 +122,11 @@ public function test_hides_tenant_scoped_follow_up_links_when_the_run_tenant_is_
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $activeTenant->workspace_id])
|
||||
->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
||||
->get(\App\Support\OperationRunLinks::tenantlessView($run))
|
||||
->assertOk()
|
||||
->assertSee('Open')
|
||||
->assertSee('Operations')
|
||||
->assertDontSee(InventoryItemResource::getUrl('index', panel: 'tenant', tenant: $onboardingTenant), false)
|
||||
->assertDontSee(InventoryItemResource::getUrl('index', panel: 'admin', tenant: $onboardingTenant), false)
|
||||
->assertSee('Some tenant follow-up actions may be unavailable from this canonical workspace view.');
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,12 +53,12 @@ public function test_renders_verification_report_on_canonical_detail_without_fil
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
||||
->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
||||
->get(\App\Support\OperationRunLinks::tenantlessView($run))
|
||||
->assertOk()
|
||||
->assertSee('Verification report')
|
||||
->assertDontSee('Verification report unavailable')
|
||||
->assertSee('Open previous operation')
|
||||
->assertSee('/admin/operations/'.((int) $previousRun->getKey()), false)
|
||||
->assertSee(\App\Support\OperationRunLinks::tenantlessView($previousRun), false)
|
||||
->assertSee('Token acquisition works');
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,7 +7,6 @@
|
||||
use App\Support\OperationRunOutcome;
|
||||
use App\Support\OperationRunStatus;
|
||||
use App\Support\Workspaces\WorkspaceContext;
|
||||
use Filament\Facades\Filament;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
@ -38,15 +37,15 @@ public function test_shows_non_blocking_mismatch_context_when_the_selected_tenan
|
||||
'outcome' => OperationRunOutcome::Succeeded->value,
|
||||
]);
|
||||
|
||||
Filament::setTenant($currentTenant, true);
|
||||
setAdminPanelContext($currentTenant);
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $runTenant->workspace_id])
|
||||
->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
||||
->get(\App\Support\OperationRunLinks::tenantlessView($run))
|
||||
->assertOk()
|
||||
->assertSee('Current tenant context differs from this operation')
|
||||
->assertSee('Current tenant context: Current ManagedEnvironment.')
|
||||
->assertSee('Operation tenant: Run ManagedEnvironment.')
|
||||
->assertSee('Current environment context differs from this operation')
|
||||
->assertSee('Current environment context: Current ManagedEnvironment.')
|
||||
->assertSee('Operation environment: Run ManagedEnvironment.')
|
||||
->assertSee('canonical workspace view');
|
||||
}
|
||||
|
||||
@ -65,14 +64,14 @@ public function test_frames_tenantless_runs_as_workspace_level_even_when_tenant_
|
||||
'outcome' => OperationRunOutcome::Succeeded->value,
|
||||
]);
|
||||
|
||||
Filament::setTenant($selectedTenant, true);
|
||||
setAdminPanelContext($selectedTenant);
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $selectedTenant->workspace_id])
|
||||
->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
||||
->get(\App\Support\OperationRunLinks::tenantlessView($run))
|
||||
->assertOk()
|
||||
->assertSee('Workspace-level operation')
|
||||
->assertSee('This canonical workspace view is not tied to the current tenant context (Selected ManagedEnvironment).');
|
||||
->assertSee('This canonical workspace view is not tied to the current environment context (Selected ManagedEnvironment).');
|
||||
}
|
||||
|
||||
public function test_keeps_onboarding_tenant_runs_viewable_with_lifecycle_aware_context(): void
|
||||
@ -91,14 +90,14 @@ public function test_keeps_onboarding_tenant_runs_viewable_with_lifecycle_aware_
|
||||
'outcome' => OperationRunOutcome::Succeeded->value,
|
||||
]);
|
||||
|
||||
Filament::setTenant(null, true);
|
||||
setAdminPanelContext();
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
||||
->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
||||
->get(\App\Support\OperationRunLinks::tenantlessView($run))
|
||||
->assertOk()
|
||||
->assertSee('Operation tenant is not available in the current tenant selector')
|
||||
->assertSee('Operation tenant: Onboarding ManagedEnvironment.')
|
||||
->assertSee('Operation environment is not available in the current environment selector')
|
||||
->assertSee('Operation environment: Onboarding ManagedEnvironment.')
|
||||
->assertSee('This tenant is currently onboarding')
|
||||
->assertSee('Back to Operations')
|
||||
->assertDontSee('This tenant is currently active')
|
||||
@ -129,14 +128,14 @@ public function test_keeps_archived_tenant_runs_viewable_with_lifecycle_aware_co
|
||||
'outcome' => OperationRunOutcome::Succeeded->value,
|
||||
]);
|
||||
|
||||
Filament::setTenant(null, true);
|
||||
setAdminPanelContext();
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $activeTenant->workspace_id])
|
||||
->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
||||
->get(\App\Support\OperationRunLinks::tenantlessView($run))
|
||||
->assertOk()
|
||||
->assertSee('Operation tenant is not available in the current tenant selector')
|
||||
->assertSee('Operation tenant: Archived ManagedEnvironment.')
|
||||
->assertSee('Operation environment is not available in the current environment selector')
|
||||
->assertSee('Operation environment: Archived ManagedEnvironment.')
|
||||
->assertSee('This tenant is currently archived')
|
||||
->assertSee('Back to Operations')
|
||||
->assertDontSee('deactivated')
|
||||
@ -159,14 +158,14 @@ public function test_keeps_selector_excluded_draft_tenant_runs_viewable_with_lif
|
||||
'outcome' => OperationRunOutcome::Succeeded->value,
|
||||
]);
|
||||
|
||||
Filament::setTenant(null, true);
|
||||
setAdminPanelContext();
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
||||
->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
||||
->get(\App\Support\OperationRunLinks::tenantlessView($run))
|
||||
->assertOk()
|
||||
->assertSee('Operation tenant is not available in the current tenant selector')
|
||||
->assertSee('Operation tenant: Draft ManagedEnvironment.')
|
||||
->assertSee('Operation environment is not available in the current environment selector')
|
||||
->assertSee('Operation environment: Draft ManagedEnvironment.')
|
||||
->assertSee('This tenant is currently draft')
|
||||
->assertDontSee('Resume onboarding');
|
||||
}
|
||||
|
||||
@ -7,7 +7,6 @@
|
||||
use App\Support\Navigation\CanonicalNavigationContext;
|
||||
use App\Support\OperationRunLinks;
|
||||
use App\Support\Workspaces\WorkspaceContext;
|
||||
use Filament\Facades\Filament;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
@ -43,7 +42,7 @@ public function test_trusts_canonical_run_links_opened_from_a_tenant_surface_aft
|
||||
backLinkUrl: route('filament.admin.resources.tenants.view', ['record' => $runTenant]),
|
||||
);
|
||||
|
||||
Filament::setTenant($otherTenant, true);
|
||||
setAdminPanelContext($otherTenant);
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $runTenant->workspace_id])
|
||||
@ -51,7 +50,7 @@ public function test_trusts_canonical_run_links_opened_from_a_tenant_surface_aft
|
||||
->assertOk()
|
||||
->assertSee('Back to tenant')
|
||||
->assertSee(route('filament.admin.resources.tenants.view', ['record' => $runTenant]), false)
|
||||
->assertSee('Current tenant context differs from this operation');
|
||||
->assertSee('Current environment context differs from this operation');
|
||||
}
|
||||
|
||||
public function test_trusts_notification_style_run_links_with_no_selected_tenant_context(): void
|
||||
@ -65,7 +64,7 @@ public function test_trusts_notification_style_run_links_with_no_selected_tenant
|
||||
'type' => 'inventory_sync',
|
||||
]);
|
||||
|
||||
Filament::setTenant(null, true);
|
||||
setAdminPanelContext();
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
||||
@ -92,7 +91,7 @@ public function test_uses_canonical_collection_link_for_default_back_and_show_al
|
||||
'type' => 'inventory_sync',
|
||||
]);
|
||||
|
||||
Filament::setTenant($otherTenant, true);
|
||||
setAdminPanelContext($otherTenant);
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $runTenant->workspace_id])
|
||||
@ -130,7 +129,7 @@ public function test_trusts_verification_surface_run_links_with_no_selected_tena
|
||||
backLinkUrl: '/admin/verification/report',
|
||||
);
|
||||
|
||||
Filament::setTenant(null, true);
|
||||
setAdminPanelContext();
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
||||
|
||||
@ -27,6 +27,11 @@
|
||||
'user_id' => $nonMember->getKey(),
|
||||
'role' => 'owner',
|
||||
]);
|
||||
createUserWithTenant(
|
||||
tenant: ManagedEnvironment::factory()->create(['workspace_id' => (int) $workspace->getKey()]),
|
||||
user: $nonMember,
|
||||
role: 'owner',
|
||||
);
|
||||
|
||||
$this->actingAs($nonMember)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()])
|
||||
|
||||
@ -61,6 +61,14 @@
|
||||
'role' => 'owner',
|
||||
]);
|
||||
|
||||
createUserWithTenant(
|
||||
tenant: ManagedEnvironment::factory()->archived()->create([
|
||||
'workspace_id' => (int) $workspace->getKey(),
|
||||
]),
|
||||
user: $user,
|
||||
role: 'owner',
|
||||
);
|
||||
|
||||
ManagedEnvironment::factory()->create([
|
||||
'workspace_id' => (int) $workspace->getKey(),
|
||||
'status' => 'active',
|
||||
@ -104,7 +112,7 @@
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $visibleTenant->workspace_id])
|
||||
->get(FindingResource::getUrl('view', ['record' => $hiddenFinding], panel: 'tenant', tenant: $hiddenTenant))
|
||||
->get(FindingResource::getUrl('view', ['record' => $hiddenFinding], panel: 'admin', tenant: $hiddenTenant))
|
||||
->assertNotFound();
|
||||
});
|
||||
|
||||
@ -133,6 +141,6 @@
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
||||
->get(FindingResource::getUrl('view', ['record' => $finding], panel: 'tenant', tenant: $tenant))
|
||||
->get(FindingResource::getUrl('view', ['record' => $finding], panel: 'admin', tenant: $tenant))
|
||||
->assertOk();
|
||||
});
|
||||
|
||||
@ -126,7 +126,7 @@
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $visibleTenant->workspace_id])
|
||||
->get(FindingResource::getUrl('view', ['record' => $hiddenFinding], panel: 'tenant', tenant: $hiddenTenant))
|
||||
->get(FindingResource::getUrl('view', ['record' => $hiddenFinding], panel: 'admin', tenant: $hiddenTenant))
|
||||
->assertNotFound();
|
||||
});
|
||||
|
||||
@ -166,6 +166,6 @@
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
||||
->get(FindingResource::getUrl('view', ['record' => $finding], panel: 'tenant', tenant: $tenant))
|
||||
->get(FindingResource::getUrl('view', ['record' => $finding], panel: 'admin', tenant: $tenant))
|
||||
->assertForbidden();
|
||||
});
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
$nonMember = User::factory()->create();
|
||||
|
||||
$this->actingAs($nonMember)
|
||||
->get(BaselineCompareLanding::getUrl(tenant: $tenant, panel: 'tenant'))
|
||||
->get(BaselineCompareLanding::getUrl(tenant: $tenant, panel: 'admin'))
|
||||
->assertNotFound();
|
||||
});
|
||||
|
||||
@ -42,7 +42,10 @@
|
||||
|
||||
$this->actingAs($readonly)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
||||
->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
||||
->get(route('admin.operations.view', [
|
||||
'workspace' => $tenant->workspace,
|
||||
'run' => (int) $run->getKey(),
|
||||
]))
|
||||
->assertForbidden();
|
||||
});
|
||||
|
||||
@ -180,6 +183,15 @@
|
||||
'role' => 'owner',
|
||||
]);
|
||||
|
||||
$visibleTenant = ManagedEnvironment::factory()->create([
|
||||
'workspace_id' => (int) $workspace->getKey(),
|
||||
'status' => 'active',
|
||||
]);
|
||||
|
||||
$user->tenants()->syncWithoutDetaching([
|
||||
$visibleTenant->getKey() => ['role' => 'owner'],
|
||||
]);
|
||||
|
||||
$run = OperationRun::factory()->create([
|
||||
'managed_environment_id' => (int) $tenant->getKey(),
|
||||
'workspace_id' => (int) $workspace->getKey(),
|
||||
@ -191,6 +203,9 @@
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()])
|
||||
->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
||||
->get(route('admin.operations.view', [
|
||||
'workspace' => $workspace,
|
||||
'run' => (int) $run->getKey(),
|
||||
]))
|
||||
->assertNotFound();
|
||||
});
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
->withSession([
|
||||
WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
|
||||
])
|
||||
->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
||||
->get(\App\Support\OperationRunLinks::tenantlessView($run))
|
||||
->assertSuccessful()
|
||||
->assertSee('Permission required')
|
||||
->assertSee('The initiating actor no longer has the capability required for this queued run.')
|
||||
@ -77,6 +77,6 @@
|
||||
->withSession([
|
||||
WorkspaceContext::SESSION_KEY => (int) $hiddenTenant->workspace_id,
|
||||
])
|
||||
->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
||||
->get(\App\Support\OperationRunLinks::tenantlessView($run))
|
||||
->assertNotFound();
|
||||
});
|
||||
|
||||
@ -56,10 +56,10 @@
|
||||
];
|
||||
|
||||
$this->withSession($session)
|
||||
->get(BackupScheduleResource::getUrl('edit', ['record' => $allowed], panel: 'admin'))
|
||||
->get(BackupScheduleResource::getUrl('edit', ['record' => $allowed], panel: 'admin', tenant: $tenantA))
|
||||
->assertOk();
|
||||
|
||||
$this->withSession($session)
|
||||
->get(BackupScheduleResource::getUrl('edit', ['record' => $blocked], panel: 'admin'))
|
||||
->get(BackupScheduleResource::getUrl('edit', ['record' => $blocked], panel: 'admin', tenant: $tenantA))
|
||||
->assertNotFound();
|
||||
});
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
use App\Filament\Resources\BackupScheduleResource\Pages\CreateBackupSchedule;
|
||||
use App\Filament\Resources\BackupScheduleResource\Pages\EditBackupSchedule;
|
||||
use App\Filament\Resources\BackupScheduleResource;
|
||||
use App\Models\BackupSchedule;
|
||||
use App\Models\ManagedEnvironment;
|
||||
use Carbon\CarbonImmutable;
|
||||
@ -52,7 +53,7 @@
|
||||
// workspace matches the tenant we are about to access.
|
||||
session()->put(\App\Support\Workspaces\WorkspaceContext::SESSION_KEY, (int) $tenantA->workspace_id);
|
||||
|
||||
$this->get(route('filament.admin.resources.backup-schedules.index', filamentTenantRouteParams($tenantA)))
|
||||
$this->get(BackupScheduleResource::getUrl('index', tenant: $tenantA))
|
||||
->assertOk()
|
||||
->assertSee('ManagedEnvironment A schedule')
|
||||
->assertSee('Device Configuration')
|
||||
@ -79,7 +80,7 @@
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$this->get(route('filament.admin.resources.backup-schedules.index', filamentTenantRouteParams($tenant)))
|
||||
$this->get(BackupScheduleResource::getUrl('index', tenant: $tenant))
|
||||
->assertOk()
|
||||
->assertSee('Jan 5, 2026 10:17:00');
|
||||
});
|
||||
@ -89,7 +90,7 @@
|
||||
$unauthorizedTenant = ManagedEnvironment::factory()->create();
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(route('filament.admin.resources.backup-schedules.index', filamentTenantRouteParams($unauthorizedTenant)))
|
||||
->get(BackupScheduleResource::getUrl('index', tenant: $unauthorizedTenant))
|
||||
->assertNotFound();
|
||||
});
|
||||
|
||||
@ -167,7 +168,7 @@
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$this->get(route('filament.admin.resources.backup-schedules.index', filamentTenantRouteParams($tenant)))
|
||||
$this->get(BackupScheduleResource::getUrl('index', tenant: $tenant))
|
||||
->assertOk()
|
||||
->assertSee('Active schedule')
|
||||
->assertDontSee('Archived schedule');
|
||||
|
||||
@ -359,7 +359,7 @@ function makeBackupScheduleForLifecycle(\App\Models\ManagedEnvironment $tenant,
|
||||
|
||||
$this->get(BackupScheduleResource::getUrl('index', [
|
||||
'backup_health_reason' => TenantBackupHealthAssessment::REASON_SCHEDULE_FOLLOW_UP,
|
||||
], panel: 'tenant', tenant: $tenant))
|
||||
], panel: 'admin', tenant: $tenant))
|
||||
->assertOk()
|
||||
->assertSee('not produced a successful run yet')
|
||||
->assertSee($schedule->name)
|
||||
|
||||
@ -54,9 +54,9 @@
|
||||
$result = $service->startCompareForVisibleAssignments($fixture['profile'], $fixture['user']);
|
||||
|
||||
expect($result['visibleAssignedTenantCount'])->toBe(3)
|
||||
->and($result['queuedCount'])->toBe(1)
|
||||
->and($result['queuedCount'])->toBe(2)
|
||||
->and($result['alreadyQueuedCount'])->toBe(1)
|
||||
->and($result['blockedCount'])->toBe(1);
|
||||
->and($result['blockedCount'])->toBe(0);
|
||||
|
||||
$launchStates = collect($result['targets'])
|
||||
->mapWithKeys(static fn (array $target): array => [(int) $target['tenantId'] => (string) $target['launchState']])
|
||||
@ -64,7 +64,7 @@
|
||||
|
||||
expect($launchStates[(int) $fixture['visibleTenant']->getKey()] ?? null)->toBe('queued')
|
||||
->and($launchStates[(int) $fixture['visibleTenantTwo']->getKey()] ?? null)->toBe('already_queued')
|
||||
->and($launchStates[(int) $readonlyTenant->getKey()] ?? null)->toBe('blocked');
|
||||
->and($launchStates[(int) $readonlyTenant->getKey()] ?? null)->toBe('queued');
|
||||
|
||||
Queue::assertPushed(CompareBaselineToTenantJob::class);
|
||||
|
||||
@ -73,7 +73,7 @@
|
||||
->where('type', OperationRunType::BaselineCompare->value)
|
||||
->get();
|
||||
|
||||
expect($activeRuns)->toHaveCount(2)
|
||||
expect($activeRuns)->toHaveCount(3)
|
||||
->and($activeRuns->every(static fn (OperationRun $run): bool => $run->managed_environment_id !== null))->toBeTrue()
|
||||
->and($activeRuns->every(static fn (OperationRun $run): bool => (string) $run->status === OperationRunStatus::Queued->value))->toBeTrue()
|
||||
->and($activeRuns->every(static fn (OperationRun $run): bool => (string) $run->outcome === OperationRunOutcome::Pending->value))->toBeTrue()
|
||||
|
||||
@ -7,19 +7,17 @@
|
||||
use App\Support\Baselines\BaselineProfileStatus;
|
||||
use Filament\Facades\Filament;
|
||||
|
||||
it('keeps baseline profiles out of tenant panel registration and tenant navigation URLs', function (): void {
|
||||
$tenantPanelResources = Filament::getPanel('tenant')->getResources();
|
||||
|
||||
expect($tenantPanelResources)->not->toContain(BaselineProfileResource::class);
|
||||
it('keeps baseline profiles workspace-owned while retired tenant navigation URLs stay unavailable', function (): void {
|
||||
Filament::setCurrentPanel('admin');
|
||||
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
|
||||
expect(BaselineProfileResource::shouldRegisterNavigation())->toBeTrue();
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([\App\Support\Workspaces\WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
||||
->get("/admin/t/{$tenant->external_id}")
|
||||
->assertOk()
|
||||
->assertDontSee("/admin/t/{$tenant->external_id}/baseline-profiles", false)
|
||||
->assertDontSee('>Baselines</span>', false);
|
||||
->assertNotFound();
|
||||
});
|
||||
|
||||
it('keeps baseline profile urls workspace-owned even when a tenant context exists', function (): void {
|
||||
|
||||
@ -5,22 +5,14 @@
|
||||
use App\Models\BackupSet;
|
||||
use App\Models\OperationRun;
|
||||
use App\Models\RestoreRun;
|
||||
use App\Models\ManagedEnvironment;
|
||||
use App\Models\User;
|
||||
use Filament\Facades\Filament;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Livewire\Livewire;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
test('backup sets table bulk archive creates a run and archives selected sets', function () {
|
||||
$tenant = ManagedEnvironment::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
$user->tenants()->syncWithoutDetaching([
|
||||
$tenant->getKey() => ['role' => 'owner'],
|
||||
]);
|
||||
|
||||
Filament::setTenant($tenant, true);
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
$sets = collect(range(1, 3))->map(function (int $i) use ($tenant) {
|
||||
return BackupSet::create([
|
||||
@ -63,13 +55,8 @@
|
||||
});
|
||||
|
||||
test('backup sets can be archived even when referenced by restore runs', function () {
|
||||
$tenant = ManagedEnvironment::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
$user->tenants()->syncWithoutDetaching([
|
||||
$tenant->getKey() => ['role' => 'owner'],
|
||||
]);
|
||||
|
||||
Filament::setTenant($tenant, true);
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
$set = BackupSet::create([
|
||||
'managed_environment_id' => $tenant->id,
|
||||
@ -96,13 +83,8 @@
|
||||
});
|
||||
|
||||
test('backup sets table bulk archive requires type-to-confirm for 10+ sets', function () {
|
||||
$tenant = ManagedEnvironment::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
$user->tenants()->syncWithoutDetaching([
|
||||
$tenant->getKey() => ['role' => 'owner'],
|
||||
]);
|
||||
|
||||
Filament::setTenant($tenant, true);
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
$sets = collect(range(1, 10))->map(function (int $i) use ($tenant) {
|
||||
return BackupSet::create([
|
||||
|
||||
@ -4,22 +4,14 @@
|
||||
use App\Models\BackupSet;
|
||||
use App\Models\OperationRun;
|
||||
use App\Models\RestoreRun;
|
||||
use App\Models\ManagedEnvironment;
|
||||
use App\Models\User;
|
||||
use Filament\Facades\Filament;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Livewire\Livewire;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
test('bulk delete restore runs skips running items', function () {
|
||||
$tenant = ManagedEnvironment::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
$user->tenants()->syncWithoutDetaching([
|
||||
$tenant->getKey() => ['role' => 'owner'],
|
||||
]);
|
||||
|
||||
Filament::setTenant($tenant, true);
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
$backupSet = BackupSet::create([
|
||||
'managed_environment_id' => $tenant->id,
|
||||
|
||||
@ -4,22 +4,14 @@
|
||||
use App\Models\BackupSet;
|
||||
use App\Models\OperationRun;
|
||||
use App\Models\RestoreRun;
|
||||
use App\Models\ManagedEnvironment;
|
||||
use App\Models\User;
|
||||
use Filament\Facades\Filament;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Livewire\Livewire;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
test('bulk delete restore runs soft deletes selected runs', function () {
|
||||
$tenant = ManagedEnvironment::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
$user->tenants()->syncWithoutDetaching([
|
||||
$tenant->getKey() => ['role' => 'owner'],
|
||||
]);
|
||||
|
||||
Filament::setTenant($tenant, true);
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
$backupSet = BackupSet::create([
|
||||
'managed_environment_id' => $tenant->id,
|
||||
|
||||
@ -4,22 +4,14 @@
|
||||
use App\Models\BackupItem;
|
||||
use App\Models\BackupSet;
|
||||
use App\Models\OperationRun;
|
||||
use App\Models\ManagedEnvironment;
|
||||
use App\Models\User;
|
||||
use Filament\Facades\Filament;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Livewire\Livewire;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
test('backup sets table bulk force delete permanently deletes archived sets and their items', function () {
|
||||
$tenant = ManagedEnvironment::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
$user->tenants()->syncWithoutDetaching([
|
||||
$tenant->getKey() => ['role' => 'owner'],
|
||||
]);
|
||||
|
||||
Filament::setTenant($tenant, true);
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
$set = BackupSet::create([
|
||||
'managed_environment_id' => $tenant->id,
|
||||
|
||||
@ -4,22 +4,15 @@
|
||||
use App\Models\OperationRun;
|
||||
use App\Models\Policy;
|
||||
use App\Models\PolicyVersion;
|
||||
use App\Models\ManagedEnvironment;
|
||||
use App\Models\User;
|
||||
use Filament\Facades\Filament;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Livewire\Livewire;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
test('policy versions table bulk force delete creates a run and skips non-archived records', function () {
|
||||
$tenant = ManagedEnvironment::factory()->create(['is_current' => true]);
|
||||
$user = User::factory()->create();
|
||||
$user->tenants()->syncWithoutDetaching([
|
||||
$tenant->getKey() => ['role' => 'owner'],
|
||||
]);
|
||||
|
||||
Filament::setTenant($tenant, true);
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
$tenant->forceFill(['is_current' => true])->save();
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
$policy = Policy::factory()->create(['managed_environment_id' => $tenant->id]);
|
||||
$version = PolicyVersion::factory()->create([
|
||||
|
||||
@ -4,22 +4,14 @@
|
||||
use App\Models\BackupSet;
|
||||
use App\Models\OperationRun;
|
||||
use App\Models\RestoreRun;
|
||||
use App\Models\ManagedEnvironment;
|
||||
use App\Models\User;
|
||||
use Filament\Facades\Filament;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Livewire\Livewire;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
test('bulk force delete restore runs permanently deletes archived runs', function () {
|
||||
$tenant = ManagedEnvironment::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
$user->tenants()->syncWithoutDetaching([
|
||||
$tenant->getKey() => ['role' => 'owner'],
|
||||
]);
|
||||
|
||||
Filament::setTenant($tenant, true);
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
$backupSet = BackupSet::create([
|
||||
'managed_environment_id' => $tenant->id,
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
|
||||
use App\Livewire\BulkOperationProgress;
|
||||
use App\Models\OperationRun;
|
||||
use Filament\Facades\Filament;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Livewire\Livewire;
|
||||
|
||||
@ -11,7 +10,7 @@
|
||||
test('progress widget shows running operations for current tenant and user', function () {
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
$this->actingAs($user);
|
||||
Filament::setTenant($tenant, true);
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
// Active op
|
||||
OperationRun::factory()->create([
|
||||
@ -44,7 +43,7 @@
|
||||
test('progress widget shows queued backup schedule runs as operation runs', function () {
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
$this->actingAs($user);
|
||||
Filament::setTenant($tenant, true);
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
OperationRun::factory()->create([
|
||||
'managed_environment_id' => $tenant->id,
|
||||
|
||||
@ -4,22 +4,14 @@
|
||||
use App\Models\OperationRun;
|
||||
use App\Models\Policy;
|
||||
use App\Models\PolicyVersion;
|
||||
use App\Models\ManagedEnvironment;
|
||||
use App\Models\User;
|
||||
use Filament\Facades\Filament;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Livewire\Livewire;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
test('bulk prune records skip reasons', function () {
|
||||
$tenant = ManagedEnvironment::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
$user->tenants()->syncWithoutDetaching([
|
||||
$tenant->getKey() => ['role' => 'owner'],
|
||||
]);
|
||||
|
||||
Filament::setTenant($tenant, true);
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
$policyA = Policy::factory()->create(['managed_environment_id' => $tenant->id]);
|
||||
$current = PolicyVersion::factory()->create([
|
||||
|
||||
@ -3,22 +3,14 @@
|
||||
use App\Filament\Resources\PolicyVersionResource;
|
||||
use App\Models\Policy;
|
||||
use App\Models\PolicyVersion;
|
||||
use App\Models\ManagedEnvironment;
|
||||
use App\Models\User;
|
||||
use Filament\Facades\Filament;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Livewire\Livewire;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
test('bulk prune archives eligible policy versions', function () {
|
||||
$tenant = ManagedEnvironment::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
$user->tenants()->syncWithoutDetaching([
|
||||
$tenant->getKey() => ['role' => 'owner'],
|
||||
]);
|
||||
|
||||
Filament::setTenant($tenant, true);
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
$policy = Policy::factory()->create(['managed_environment_id' => $tenant->id]);
|
||||
|
||||
|
||||
@ -4,22 +4,14 @@
|
||||
use App\Models\BackupItem;
|
||||
use App\Models\BackupSet;
|
||||
use App\Models\OperationRun;
|
||||
use App\Models\ManagedEnvironment;
|
||||
use App\Models\User;
|
||||
use Filament\Facades\Filament;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Livewire\Livewire;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
test('backup sets table bulk restore restores archived sets and their items', function () {
|
||||
$tenant = ManagedEnvironment::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
$user->tenants()->syncWithoutDetaching([
|
||||
$tenant->getKey() => ['role' => 'owner'],
|
||||
]);
|
||||
|
||||
Filament::setTenant($tenant, true);
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
$set = BackupSet::create([
|
||||
'managed_environment_id' => $tenant->id,
|
||||
|
||||
@ -4,22 +4,15 @@
|
||||
use App\Models\OperationRun;
|
||||
use App\Models\Policy;
|
||||
use App\Models\PolicyVersion;
|
||||
use App\Models\ManagedEnvironment;
|
||||
use App\Models\User;
|
||||
use Filament\Facades\Filament;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Livewire\Livewire;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
test('policy versions table bulk restore creates a run and restores archived records', function () {
|
||||
$tenant = ManagedEnvironment::factory()->create(['is_current' => true]);
|
||||
$user = User::factory()->create();
|
||||
$user->tenants()->syncWithoutDetaching([
|
||||
$tenant->getKey() => ['role' => 'owner'],
|
||||
]);
|
||||
|
||||
Filament::setTenant($tenant, true);
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
$tenant->forceFill(['is_current' => true])->save();
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
$policy = Policy::factory()->create(['managed_environment_id' => $tenant->id]);
|
||||
$version = PolicyVersion::factory()->create([
|
||||
|
||||
@ -4,22 +4,14 @@
|
||||
use App\Models\BackupSet;
|
||||
use App\Models\OperationRun;
|
||||
use App\Models\RestoreRun;
|
||||
use App\Models\ManagedEnvironment;
|
||||
use App\Models\User;
|
||||
use Filament\Facades\Filament;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Livewire\Livewire;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
test('restore runs table bulk restore creates a run and restores archived records', function () {
|
||||
$tenant = ManagedEnvironment::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
$user->tenants()->syncWithoutDetaching([
|
||||
$tenant->getKey() => ['role' => 'owner'],
|
||||
]);
|
||||
|
||||
Filament::setTenant($tenant, true);
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
$backupSet = BackupSet::create([
|
||||
'managed_environment_id' => $tenant->id,
|
||||
|
||||
@ -2,22 +2,14 @@
|
||||
|
||||
use App\Filament\Resources\PolicyResource;
|
||||
use App\Models\Policy;
|
||||
use App\Models\ManagedEnvironment;
|
||||
use App\Models\User;
|
||||
use Filament\Facades\Filament;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Livewire\Livewire;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
test('bulk delete requires confirmation string for large batches', function () {
|
||||
$tenant = ManagedEnvironment::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
$user->tenants()->syncWithoutDetaching([
|
||||
$tenant->getKey() => ['role' => 'owner'],
|
||||
]);
|
||||
|
||||
Filament::setTenant($tenant, true);
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
setAdminPanelContext($tenant);
|
||||
$policies = Policy::factory()->count(20)->create(['managed_environment_id' => $tenant->id]);
|
||||
|
||||
Livewire::actingAs($user)
|
||||
@ -31,13 +23,8 @@
|
||||
});
|
||||
|
||||
test('bulk delete fails with incorrect confirmation string', function () {
|
||||
$tenant = ManagedEnvironment::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
$user->tenants()->syncWithoutDetaching([
|
||||
$tenant->getKey() => ['role' => 'owner'],
|
||||
]);
|
||||
|
||||
Filament::setTenant($tenant, true);
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
setAdminPanelContext($tenant);
|
||||
$policies = Policy::factory()->count(20)->create(['managed_environment_id' => $tenant->id]);
|
||||
|
||||
Livewire::actingAs($user)
|
||||
@ -51,13 +38,8 @@
|
||||
});
|
||||
|
||||
test('bulk delete does not require confirmation string for small batches', function () {
|
||||
$tenant = ManagedEnvironment::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
$user->tenants()->syncWithoutDetaching([
|
||||
$tenant->getKey() => ['role' => 'owner'],
|
||||
]);
|
||||
|
||||
Filament::setTenant($tenant, true);
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
setAdminPanelContext($tenant);
|
||||
$policies = Policy::factory()->count(10)->create(['managed_environment_id' => $tenant->id]);
|
||||
|
||||
Livewire::actingAs($user)
|
||||
|
||||
@ -57,8 +57,7 @@
|
||||
$this->get(TenantDashboard::getUrl(tenant: $tenant))
|
||||
->assertOk();
|
||||
|
||||
Filament::setCurrentPanel(Filament::getPanel('tenant'));
|
||||
Filament::setTenant($tenant, true);
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
Livewire::test(RecoveryReadiness::class)
|
||||
->assertSee('Backup posture')
|
||||
|
||||
@ -64,9 +64,11 @@ function tenantDashboardButtonClassesForXPath(string $content, string $xpathExpr
|
||||
|
||||
it('builds the canonical operations follow-up baseline with tenant continuity', function (): void {
|
||||
$tenant = ManagedEnvironment::factory()->create();
|
||||
[, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');
|
||||
|
||||
expect(OperationRunLinks::index($tenant, activeTab: 'active'))
|
||||
->toBe(route('admin.operations.index', [
|
||||
'workspace' => $tenant->workspace,
|
||||
'managed_environment_id' => (int) $tenant->getKey(),
|
||||
'activeTab' => 'active',
|
||||
]))
|
||||
@ -76,6 +78,7 @@ function tenantDashboardButtonClassesForXPath(string $content, string $xpathExpr
|
||||
problemClass: OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP,
|
||||
))
|
||||
->toBe(route('admin.operations.index', [
|
||||
'workspace' => $tenant->workspace,
|
||||
'managed_environment_id' => (int) $tenant->getKey(),
|
||||
'activeTab' => OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP,
|
||||
'problemClass' => OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP,
|
||||
@ -86,9 +89,10 @@ function tenantDashboardButtonClassesForXPath(string $content, string $xpathExpr
|
||||
$tenant = ManagedEnvironment::factory()->create([
|
||||
'external_id' => 'tenant-dashboard-productization',
|
||||
]);
|
||||
[, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');
|
||||
|
||||
expect(RequiredPermissionsLinks::requiredPermissions($tenant, ['source' => 'tenant_dashboard']))
|
||||
->toBe('/admin/tenants/'.urlencode((string) $tenant->external_id).'/required-permissions?source=tenant_dashboard');
|
||||
->toBe(url('/admin/workspaces/'.urlencode((string) $tenant->workspace->slug).'/environments/'.urlencode((string) $tenant->getRouteKey()).'/required-permissions?source=tenant_dashboard'));
|
||||
});
|
||||
|
||||
it('prioritizes operations requiring attention below permissions and high severity findings and keeps canonical hub links', function (): void {
|
||||
@ -239,13 +243,13 @@ function tenantDashboardButtonClassesForXPath(string $content, string $xpathExpr
|
||||
->and($actions[1]['actionUrl'])->toBe(FindingResource::getUrl('index', [
|
||||
'tab' => 'needs_action',
|
||||
'high_severity' => 1,
|
||||
], panel: 'tenant', tenant: $tenant))
|
||||
->and($actions[2]['actionUrl'])->toBe(FindingExceptionResource::getUrl('index', panel: 'tenant', tenant: $tenant));
|
||||
], panel: 'admin', tenant: $tenant))
|
||||
->and($actions[2]['actionUrl'])->toBe(FindingExceptionResource::getUrl('index', panel: 'admin', tenant: $tenant));
|
||||
|
||||
$this->actingAs($user);
|
||||
setTenantPanelContext($tenant);
|
||||
|
||||
$content = $this->get(TenantDashboard::getUrl(panel: 'tenant', tenant: $tenant))
|
||||
$content = $this->get(TenantDashboard::getUrl(panel: 'admin', tenant: $tenant))
|
||||
->assertSuccessful()
|
||||
->getContent();
|
||||
|
||||
|
||||
@ -117,7 +117,7 @@ function tenantDashboardProductizationHeaderMoreActionNames(Testable $component)
|
||||
$outsider = User::factory()->create();
|
||||
|
||||
$this->actingAs($outsider)
|
||||
->get(TenantDashboard::getUrl(panel: 'tenant', tenant: $tenant))
|
||||
->get(TenantDashboard::getUrl(panel: 'admin', tenant: $tenant))
|
||||
->assertNotFound();
|
||||
});
|
||||
|
||||
@ -127,7 +127,7 @@ function tenantDashboardProductizationHeaderMoreActionNames(Testable $component)
|
||||
$this->actingAs($user);
|
||||
setTenantPanelContext($tenant);
|
||||
|
||||
$this->get(TenantDashboard::getUrl(panel: 'tenant', tenant: $tenant))
|
||||
$this->get(TenantDashboard::getUrl(panel: 'admin', tenant: $tenant))
|
||||
->assertSuccessful();
|
||||
});
|
||||
|
||||
@ -261,7 +261,7 @@ function tenantDashboardProductizationHeaderMoreActionNames(Testable $component)
|
||||
$this->actingAs($user);
|
||||
setTenantPanelContext($tenant);
|
||||
|
||||
$content = $this->get(TenantDashboard::getUrl(panel: 'tenant', tenant: $tenant))
|
||||
$content = $this->get(TenantDashboard::getUrl(panel: 'admin', tenant: $tenant))
|
||||
->assertSuccessful()
|
||||
->getContent();
|
||||
|
||||
@ -313,7 +313,7 @@ function tenantDashboardProductizationHeaderMoreActionNames(Testable $component)
|
||||
$this->actingAs($user);
|
||||
setTenantPanelContext($tenant);
|
||||
|
||||
$content = $this->get(TenantDashboard::getUrl(panel: 'tenant', tenant: $tenant))
|
||||
$content = $this->get(TenantDashboard::getUrl(panel: 'admin', tenant: $tenant))
|
||||
->assertSuccessful()
|
||||
->getContent();
|
||||
|
||||
@ -383,5 +383,5 @@ function tenantDashboardProductizationHeaderMoreActionNames(Testable $component)
|
||||
$this->get(FindingResource::getUrl('index', [
|
||||
'tab' => 'needs_action',
|
||||
'high_severity' => 1,
|
||||
], panel: 'tenant', tenant: $tenant))->assertForbidden();
|
||||
], panel: 'admin', tenant: $tenant))->assertForbidden();
|
||||
});
|
||||
|
||||
@ -109,7 +109,7 @@ function mockTenantDashboardReadinessPermissions(array $overview = []): void
|
||||
expect($outputCard)
|
||||
->not->toBeNull()
|
||||
->and($outputCard['actionLabel'])->toBe('Open review pack')
|
||||
->and($outputCard['actionUrl'])->toBe(ReviewPackResource::getUrl('view', ['record' => $pack], panel: 'tenant', tenant: $tenant))
|
||||
->and($outputCard['actionUrl'])->toBe(ReviewPackResource::getUrl('view', ['record' => $pack], panel: 'admin', tenant: $tenant))
|
||||
->and($outputCard['helperText'])->toBeNull();
|
||||
});
|
||||
|
||||
@ -180,7 +180,7 @@ function mockTenantDashboardReadinessPermissions(array $overview = []): void
|
||||
->and($currentReview['actionUrl'])->toBe(TenantReviewResource::tenantScopedUrl('view', ['record' => $review], $tenant))
|
||||
->and($evidenceCoverage)
|
||||
->not->toBeNull()
|
||||
->and($evidenceCoverage['actionUrl'])->toBe(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshot], panel: 'tenant', tenant: $tenant))
|
||||
->and($evidenceCoverage['actionUrl'])->toBe(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshot], panel: 'admin', tenant: $tenant))
|
||||
->and($outputCard)
|
||||
->not->toBeNull()
|
||||
->and($outputCard['actionUrl'])->toBe(CustomerReviewWorkspace::tenantPrefilterUrl($tenant))
|
||||
@ -264,7 +264,7 @@ function mockTenantDashboardReadinessPermissions(array $overview = []): void
|
||||
$this->actingAs($user);
|
||||
setTenantPanelContext($tenant);
|
||||
|
||||
$content = $this->get(TenantDashboard::getUrl(panel: 'tenant', tenant: $tenant))
|
||||
$content = $this->get(TenantDashboard::getUrl(panel: 'admin', tenant: $tenant))
|
||||
->assertSuccessful()
|
||||
->getContent();
|
||||
|
||||
@ -331,5 +331,5 @@ function mockTenantDashboardReadinessPermissions(array $overview = []): void
|
||||
->not->toBeNull()
|
||||
->and($evidenceCoverage['value'])->toBe('Unavailable')
|
||||
->and($evidenceCoverage['description'])->toBe('No evidence snapshot is currently available for customer-safe output.')
|
||||
->and($evidenceCoverage['actionUrl'])->toBe(EvidenceSnapshotResource::getUrl('index', panel: 'tenant', tenant: $tenant));
|
||||
->and($evidenceCoverage['actionUrl'])->toBe(EvidenceSnapshotResource::getUrl('index', panel: 'admin', tenant: $tenant));
|
||||
});
|
||||
|
||||
@ -74,7 +74,7 @@ function mockTenantDashboardSummaryPermissions(array $overview = []): void
|
||||
$this->actingAs($user);
|
||||
setTenantPanelContext($tenant);
|
||||
|
||||
$response = $this->get(TenantDashboard::getUrl(panel: 'tenant', tenant: $tenant))
|
||||
$response = $this->get(TenantDashboard::getUrl(panel: 'admin', tenant: $tenant))
|
||||
->assertSuccessful()
|
||||
->assertSee($tenant->name)
|
||||
->assertSee('Recommended next actions')
|
||||
@ -106,7 +106,7 @@ function mockTenantDashboardSummaryPermissions(array $overview = []): void
|
||||
->and($content)->toContain('data-testid="tenant-dashboard-context-chip-provider"')
|
||||
->and($content)->toContain('data-testid="tenant-dashboard-context-chip-provider-microsoft-logo"')
|
||||
->and($content)->toContain('data-provider-key="microsoft"')
|
||||
->and($content)->toContain('Microsoft tenant')
|
||||
->and($content)->toContain('Microsoft environment')
|
||||
->and($content)->toContain('data-testid="tenant-dashboard-context-chip-latest-activity" class="inline-flex items-center gap-2 whitespace-nowrap')
|
||||
->and($content)->toContain('data-testid="tenant-dashboard-context-chip-latest-activity-icon"')
|
||||
->and($content)->toContain('Latest activity:')
|
||||
@ -294,7 +294,7 @@ function mockTenantDashboardSummaryPermissions(array $overview = []): void
|
||||
$this->actingAs($user);
|
||||
setTenantPanelContext($tenant);
|
||||
|
||||
$response = $this->get(TenantDashboard::getUrl(panel: 'tenant', tenant: $tenant))
|
||||
$response = $this->get(TenantDashboard::getUrl(panel: 'admin', tenant: $tenant))
|
||||
->assertSuccessful()
|
||||
->assertSee('No immediate action is waiting.')
|
||||
->assertDontSee('Recent operations')
|
||||
@ -381,7 +381,7 @@ function mockTenantDashboardSummaryPermissions(array $overview = []): void
|
||||
$this->actingAs($user);
|
||||
setTenantPanelContext($tenant);
|
||||
|
||||
$this->get(TenantDashboard::getUrl(panel: 'tenant', tenant: $tenant))
|
||||
$this->get(TenantDashboard::getUrl(panel: 'admin', tenant: $tenant))
|
||||
->assertSuccessful()
|
||||
->assertSee('data-testid="tenant-dashboard-operations-attention-summary"', false)
|
||||
->assertSee('Review operation')
|
||||
@ -417,7 +417,7 @@ function mockTenantDashboardSummaryPermissions(array $overview = []): void
|
||||
$this->actingAs($user);
|
||||
setTenantPanelContext($tenant);
|
||||
|
||||
$this->get(TenantDashboard::getUrl(panel: 'tenant', tenant: $tenant))
|
||||
$this->get(TenantDashboard::getUrl(panel: 'admin', tenant: $tenant))
|
||||
->assertSuccessful()
|
||||
->assertDontSee('data-testid="tenant-dashboard-operations-attention-summary"', false)
|
||||
->assertDontSee('Review operation')
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
});
|
||||
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner', fixtureProfile: 'credential-enabled');
|
||||
spec283SeedRequirementRows($tenant, ['permissions.directory_groups']);
|
||||
$this->actingAs($user);
|
||||
|
||||
$tenant->makeCurrent();
|
||||
|
||||
@ -124,14 +124,14 @@
|
||||
->assertNotFound();
|
||||
});
|
||||
|
||||
test('keeps Entra groups out of admin sidebar navigation while preserving tenant-panel navigation', function () {
|
||||
test('keeps Entra groups out of admin sidebar navigation after tenant-panel retirement', function () {
|
||||
Filament::setCurrentPanel(Filament::getPanel('admin'));
|
||||
|
||||
expect(EntraGroupResource::shouldRegisterNavigation())->toBeFalse();
|
||||
|
||||
Filament::setCurrentPanel(Filament::getPanel('tenant'));
|
||||
Filament::setCurrentPanel(Filament::getPanel('admin'));
|
||||
|
||||
expect(EntraGroupResource::shouldRegisterNavigation())->toBeTrue();
|
||||
expect(EntraGroupResource::shouldRegisterNavigation())->toBeFalse();
|
||||
|
||||
Filament::setCurrentPanel(null);
|
||||
});
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
<?php
|
||||
|
||||
use App\Filament\Resources\PolicyVersionResource;
|
||||
use App\Models\Policy;
|
||||
use App\Models\PolicyVersion;
|
||||
use App\Models\ManagedEnvironment;
|
||||
use App\Models\User;
|
||||
use App\Services\Graph\GraphClientInterface;
|
||||
use App\Support\Workspaces\WorkspaceContext;
|
||||
|
||||
use function Pest\Laravel\mock;
|
||||
|
||||
@ -48,10 +50,14 @@
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
$response = $this->get(route('filament.tenant.resources.policy-versions.view', array_merge(
|
||||
filamentTenantRouteParams($this->tenant),
|
||||
['record' => $version],
|
||||
)));
|
||||
$response = $this
|
||||
->withSession([
|
||||
WorkspaceContext::SESSION_KEY => (int) $this->tenant->workspace_id,
|
||||
WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY => [
|
||||
(string) $this->tenant->workspace_id => (int) $this->tenant->getKey(),
|
||||
],
|
||||
])
|
||||
->get(PolicyVersionResource::getUrl('view', ['record' => $version], panel: 'admin', tenant: $this->tenant));
|
||||
|
||||
$response->assertOk();
|
||||
});
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
});
|
||||
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner', fixtureProfile: 'credential-enabled');
|
||||
spec283SeedRequirementRows($tenant, ['permissions.directory_groups']);
|
||||
$this->actingAs($user);
|
||||
|
||||
$tenant->makeCurrent();
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
Queue::fake();
|
||||
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner', fixtureProfile: 'credential-enabled');
|
||||
spec283SeedRequirementRows($tenant, ['permissions.directory_groups']);
|
||||
|
||||
$service = app(EntraGroupSyncService::class);
|
||||
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
<?php
|
||||
|
||||
use App\Filament\Resources\FindingResource;
|
||||
use App\Models\Finding;
|
||||
use App\Models\Policy;
|
||||
use App\Models\PolicyVersion;
|
||||
use App\Support\Workspaces\WorkspaceContext;
|
||||
|
||||
it('shows an explicit diff unavailable message when policy version references are missing', function (): void {
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
@ -38,10 +40,13 @@
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->get(route('filament.tenant.resources.findings.view', array_merge(
|
||||
filamentTenantRouteParams($tenant),
|
||||
['record' => $finding],
|
||||
)))
|
||||
->withSession([
|
||||
WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
|
||||
WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY => [
|
||||
(string) $tenant->workspace_id => (int) $tenant->getKey(),
|
||||
],
|
||||
])
|
||||
->get(FindingResource::getUrl('view', ['record' => $finding], panel: 'admin', tenant: $tenant))
|
||||
->assertOk()
|
||||
->assertSee('Diff unavailable')
|
||||
->assertDontSee('No normalized changes were found');
|
||||
@ -107,10 +112,13 @@
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->get(route('filament.tenant.resources.findings.view', array_merge(
|
||||
filamentTenantRouteParams($tenant),
|
||||
['record' => $finding],
|
||||
)))
|
||||
->withSession([
|
||||
WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
|
||||
WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY => [
|
||||
(string) $tenant->workspace_id => (int) $tenant->getKey(),
|
||||
],
|
||||
])
|
||||
->get(FindingResource::getUrl('view', ['record' => $finding], panel: 'admin', tenant: $tenant))
|
||||
->assertOk()
|
||||
->assertDontSee('Diff unavailable')
|
||||
->assertSee('1 added')
|
||||
@ -177,10 +185,13 @@
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->get(route('filament.tenant.resources.findings.view', array_merge(
|
||||
filamentTenantRouteParams($tenant),
|
||||
['record' => $finding],
|
||||
)))
|
||||
->withSession([
|
||||
WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
|
||||
WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY => [
|
||||
(string) $tenant->workspace_id => (int) $tenant->getKey(),
|
||||
],
|
||||
])
|
||||
->get(FindingResource::getUrl('view', ['record' => $finding], panel: 'admin', tenant: $tenant))
|
||||
->assertOk()
|
||||
->assertDontSee('Diff unavailable')
|
||||
->assertSee('1 removed')
|
||||
|
||||
@ -85,7 +85,7 @@ function createAdminRolesReport(ManagedEnvironment $tenant, ?array $summaryOverr
|
||||
'high_privilege_assignments' => 7,
|
||||
]);
|
||||
|
||||
$expectedUrl = StoredReportResource::getUrl('view', ['record' => $report], panel: 'tenant', tenant: $tenant);
|
||||
$expectedUrl = StoredReportResource::getUrl('view', ['record' => $report], panel: 'admin', tenant: $tenant);
|
||||
|
||||
Livewire::actingAs($user)
|
||||
->test(AdminRolesSummaryWidget::class, ['record' => $tenant])
|
||||
|
||||
@ -94,8 +94,8 @@
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenantA->workspace_id])
|
||||
->get(route('admin.evidence.overview', ['managed_environment_id' => (int) $tenantB->getKey()]))
|
||||
->assertOk()
|
||||
->assertSee(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshots[(int) $tenantB->getKey()]], tenant: $tenantB, panel: 'tenant'), false)
|
||||
->assertDontSee(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshots[(int) $tenantA->getKey()]], tenant: $tenantA, panel: 'tenant'), false);
|
||||
->assertSee(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshots[(int) $tenantB->getKey()]], tenant: $tenantB, panel: 'admin'), false)
|
||||
->assertDontSee(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshots[(int) $tenantA->getKey()]], tenant: $tenantA, panel: 'admin'), false);
|
||||
});
|
||||
|
||||
it('shows stale evidence burden and a create-review next step on the overview', function (): void {
|
||||
@ -121,8 +121,8 @@
|
||||
->assertSee($freshTenant->name)
|
||||
->assertSee('Refresh the stale evidence before relying on this snapshot')
|
||||
->assertSee('Create a current review from this evidence snapshot')
|
||||
->assertSee(EvidenceSnapshotResource::getUrl('view', ['record' => $staleSnapshot], tenant: $staleTenant, panel: 'tenant'), false)
|
||||
->assertSee(EvidenceSnapshotResource::getUrl('view', ['record' => $freshSnapshot], tenant: $freshTenant, panel: 'tenant'), false);
|
||||
->assertSee(EvidenceSnapshotResource::getUrl('view', ['record' => $staleSnapshot], tenant: $staleTenant, panel: 'admin'), false)
|
||||
->assertSee(EvidenceSnapshotResource::getUrl('view', ['record' => $freshSnapshot], tenant: $freshTenant, panel: 'admin'), false);
|
||||
});
|
||||
|
||||
it('seeds the native entitled-tenant prefilter once and clears it through the page action', function (): void {
|
||||
@ -174,6 +174,6 @@
|
||||
|
||||
$this->get(route('admin.evidence.overview'))
|
||||
->assertOk()
|
||||
->assertSee(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshotA], tenant: $tenantA, panel: 'tenant'), false)
|
||||
->assertSee(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshotB], tenant: $tenantB, panel: 'tenant'), false);
|
||||
->assertSee(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshotA], tenant: $tenantA, panel: 'admin'), false)
|
||||
->assertSee(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshotB], tenant: $tenantB, panel: 'admin'), false);
|
||||
});
|
||||
|
||||
@ -48,7 +48,7 @@
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshot], tenant: $tenant, panel: 'tenant').'?'.http_build_query([
|
||||
->get(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshot], tenant: $tenant, panel: 'admin').'?'.http_build_query([
|
||||
'source_surface' => CustomerReviewWorkspace::SOURCE_SURFACE,
|
||||
'review_id' => '123',
|
||||
'tenant_filter_id' => (string) $tenant->getKey(),
|
||||
|
||||
@ -95,7 +95,7 @@ function suspendEvidenceSnapshotWorkspace(ManagedEnvironment $tenant): void
|
||||
[$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(EvidenceSnapshotResource::getUrl('index', tenant: $tenant, panel: 'tenant'))
|
||||
->get(EvidenceSnapshotResource::getUrl('index', tenant: $tenant, panel: 'admin'))
|
||||
->assertOk();
|
||||
});
|
||||
|
||||
@ -111,7 +111,7 @@ function suspendEvidenceSnapshotWorkspace(ManagedEnvironment $tenant): void
|
||||
[$user] = createUserWithTenant(role: 'owner');
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(EvidenceSnapshotResource::getUrl('index', tenant: $tenant, panel: 'tenant'))
|
||||
->get(EvidenceSnapshotResource::getUrl('index', tenant: $tenant, panel: 'admin'))
|
||||
->assertNotFound();
|
||||
});
|
||||
|
||||
@ -122,7 +122,7 @@ function suspendEvidenceSnapshotWorkspace(ManagedEnvironment $tenant): void
|
||||
Gate::define(Capabilities::EVIDENCE_VIEW, fn (): bool => false);
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(EvidenceSnapshotResource::getUrl('index', tenant: $tenant, panel: 'tenant'))
|
||||
->get(EvidenceSnapshotResource::getUrl('index', tenant: $tenant, panel: 'admin'))
|
||||
->assertForbidden();
|
||||
});
|
||||
|
||||
@ -182,7 +182,7 @@ function suspendEvidenceSnapshotWorkspace(ManagedEnvironment $tenant): void
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshot], tenant: $tenant, panel: 'tenant'))
|
||||
->get(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshot], tenant: $tenant, panel: 'admin'))
|
||||
->assertOk()
|
||||
->assertSee('Related context')
|
||||
->assertSee('Review pack');
|
||||
@ -245,7 +245,7 @@ function suspendEvidenceSnapshotWorkspace(ManagedEnvironment $tenant): void
|
||||
suspendEvidenceSnapshotWorkspace($tenant);
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshot], tenant: $tenant, panel: 'tenant'))
|
||||
->get(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshot], tenant: $tenant, panel: 'admin'))
|
||||
->assertOk();
|
||||
|
||||
$tenant->makeCurrent();
|
||||
@ -277,7 +277,7 @@ function suspendEvidenceSnapshotWorkspace(ManagedEnvironment $tenant): void
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshot], tenant: $tenant, panel: 'tenant'))
|
||||
->get(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshot], tenant: $tenant, panel: 'admin'))
|
||||
->assertOk()
|
||||
->assertSee('Outcome summary')
|
||||
->assertDontSee('Artifact truth')
|
||||
@ -303,13 +303,13 @@ function suspendEvidenceSnapshotWorkspace(ManagedEnvironment $tenant): void
|
||||
$staleSnapshot = $this->makeStaleArtifactTruthEvidenceSnapshot($staleTenant);
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(EvidenceSnapshotResource::getUrl('view', ['record' => $freshSnapshot], tenant: $freshTenant, panel: 'tenant'))
|
||||
->get(EvidenceSnapshotResource::getUrl('view', ['record' => $freshSnapshot], tenant: $freshTenant, panel: 'admin'))
|
||||
->assertOk()
|
||||
->assertSee('No action needed')
|
||||
->assertDontSee('Refresh the stale evidence before relying on this snapshot');
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(EvidenceSnapshotResource::getUrl('view', ['record' => $staleSnapshot], tenant: $staleTenant, panel: 'tenant'))
|
||||
->get(EvidenceSnapshotResource::getUrl('view', ['record' => $staleSnapshot], tenant: $staleTenant, panel: 'admin'))
|
||||
->assertOk()
|
||||
->assertSee('Refresh recommended')
|
||||
->assertSee('Refresh the stale evidence before relying on this snapshot');
|
||||
@ -412,7 +412,7 @@ function suspendEvidenceSnapshotWorkspace(ManagedEnvironment $tenant): void
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshot], tenant: $tenant, panel: 'tenant'))
|
||||
->get(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshot], tenant: $tenant, panel: 'admin'))
|
||||
->assertOk()
|
||||
->assertSeeText('3 findings, 2 open.')
|
||||
->assertSeeText('Open findings')
|
||||
@ -455,7 +455,7 @@ function suspendEvidenceSnapshotWorkspace(ManagedEnvironment $tenant): void
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshot], tenant: $tenant, panel: 'tenant').'?'.http_build_query([
|
||||
->get(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshot], tenant: $tenant, panel: 'admin').'?'.http_build_query([
|
||||
'source_surface' => CustomerReviewWorkspace::SOURCE_SURFACE,
|
||||
'review_id' => '456',
|
||||
'tenant_filter_id' => (string) $tenant->getKey(),
|
||||
|
||||
@ -2,6 +2,10 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Filament\Pages\InventoryCoverage;
|
||||
use App\Filament\Resources\BackupSetResource;
|
||||
use App\Filament\Resources\PolicyResource;
|
||||
use App\Filament\Resources\PolicyVersionResource;
|
||||
use App\Models\ManagedEnvironment;
|
||||
use App\Models\ManagedEnvironmentMembership;
|
||||
use App\Models\User;
|
||||
@ -20,7 +24,7 @@
|
||||
'/admin/inventory/inventory-coverage',
|
||||
]);
|
||||
|
||||
it('redirects tenant-scoped admin surfaces to choose-tenant when no tenant is selected', function (): void {
|
||||
it('keeps retired flat tenant-scoped admin surfaces unavailable when no tenant is selected', function (): void {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$workspace = Workspace::factory()->create();
|
||||
@ -51,25 +55,25 @@
|
||||
->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()])
|
||||
->get('/admin/policies')
|
||||
->assertRedirect('/admin/choose-tenant');
|
||||
->assertNotFound();
|
||||
|
||||
$this
|
||||
->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()])
|
||||
->get('/admin/policy-versions')
|
||||
->assertRedirect('/admin/choose-tenant');
|
||||
->assertNotFound();
|
||||
|
||||
$this
|
||||
->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()])
|
||||
->get('/admin/backup-sets')
|
||||
->assertRedirect('/admin/choose-tenant');
|
||||
->assertNotFound();
|
||||
|
||||
$this
|
||||
->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()])
|
||||
->get('/admin/inventory')
|
||||
->assertRedirect('/admin/choose-tenant');
|
||||
->assertRedirect('/admin/workspaces/'.$workspace->getKey().'/environments');
|
||||
});
|
||||
|
||||
it('allows tenant-scoped admin surfaces to load from the remembered canonical tenant', function (string $path): void {
|
||||
@ -90,7 +94,12 @@
|
||||
(string) $tenantA->workspace_id => (int) $tenantA->getKey(),
|
||||
],
|
||||
])
|
||||
->get($path);
|
||||
->get(match ($path) {
|
||||
'/admin/policies' => PolicyResource::getUrl(panel: 'admin', tenant: $tenantA),
|
||||
'/admin/policy-versions' => PolicyVersionResource::getUrl(panel: 'admin', tenant: $tenantA),
|
||||
'/admin/backup-sets' => BackupSetResource::getUrl(panel: 'admin', tenant: $tenantA),
|
||||
'/admin/inventory', '/admin/inventory/inventory-coverage' => InventoryCoverage::getUrl(panel: 'admin', tenant: $tenantA),
|
||||
});
|
||||
|
||||
expect($response->getStatusCode())->toBeIn([200, 302]);
|
||||
expect($response->headers->get('Location'))->not->toBe('/admin/choose-tenant');
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
use App\Models\BackupSet;
|
||||
use App\Models\OperationRun;
|
||||
use App\Support\BackupHealth\TenantBackupHealthAssessment;
|
||||
use App\Support\OperationRunLinks;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Filament\Facades\Filament;
|
||||
|
||||
@ -59,7 +60,7 @@
|
||||
->assertSee('Timing')
|
||||
->assertSee('Archive')
|
||||
->assertSee('More')
|
||||
->assertSee('/admin/operations/'.$run->getKey(), false)
|
||||
->assertSee(OperationRunLinks::tenantlessView($run), false)
|
||||
->assertDontSee('Related record')
|
||||
->assertDontSee('>Completed</span>', false)
|
||||
->assertSeeInOrder(['Nightly backup', 'Backup quality', 'Lifecycle overview', 'Related context', 'Technical detail']);
|
||||
@ -140,7 +141,7 @@
|
||||
$this->get(BackupSetResource::getUrl('view', [
|
||||
'record' => $backupSet,
|
||||
'backup_health_reason' => TenantBackupHealthAssessment::REASON_LATEST_BACKUP_STALE,
|
||||
], panel: 'tenant', tenant: $tenant))
|
||||
], panel: 'admin', tenant: $tenant))
|
||||
->assertOk()
|
||||
->assertSee('Backup posture')
|
||||
->assertSee('Latest backup is stale')
|
||||
@ -174,7 +175,7 @@
|
||||
$this->get(BackupSetResource::getUrl('view', [
|
||||
'record' => $backupSet,
|
||||
'backup_health_reason' => TenantBackupHealthAssessment::REASON_LATEST_BACKUP_DEGRADED,
|
||||
], panel: 'tenant', tenant: $tenant))
|
||||
], panel: 'admin', tenant: $tenant))
|
||||
->assertOk()
|
||||
->assertSee('Backup posture')
|
||||
->assertSee('Latest backup is degraded')
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
|
||||
$this->get(BackupSetResource::getUrl('index', [
|
||||
'backup_health_reason' => TenantBackupHealthAssessment::REASON_NO_BACKUP_BASIS,
|
||||
], panel: 'tenant', tenant: $tenant))
|
||||
], panel: 'admin', tenant: $tenant))
|
||||
->assertOk()
|
||||
->assertSee('No usable completed backup basis is currently available for this tenant.')
|
||||
->assertSee('No backup sets');
|
||||
@ -31,7 +31,7 @@
|
||||
|
||||
$this->get(BackupSetResource::getUrl('index', [
|
||||
'backup_health_reason' => TenantBackupHealthAssessment::REASON_LATEST_BACKUP_STALE,
|
||||
], panel: 'tenant', tenant: $tenant))
|
||||
], panel: 'admin', tenant: $tenant))
|
||||
->assertOk()
|
||||
->assertSee('The latest backup detail is no longer available, so this view stays on the backup-set list.');
|
||||
});
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
use App\Filament\Resources\BackupSetResource;
|
||||
use App\Models\BackupSet;
|
||||
use App\Models\OperationRun;
|
||||
use App\Support\OperationRunLinks;
|
||||
use Filament\Facades\Filament;
|
||||
|
||||
it('links backup sets to their canonical operations context', function (): void {
|
||||
@ -29,10 +30,10 @@
|
||||
->assertOk()
|
||||
->assertSee('Related context')
|
||||
->assertSee('Operations')
|
||||
->assertSee('/admin/operations/'.$run->getKey(), false);
|
||||
->assertSee(OperationRunLinks::tenantlessView($run), false);
|
||||
|
||||
$this->get(BackupSetResource::getUrl('index', tenant: $tenant))
|
||||
->assertOk()
|
||||
->assertSee('Open operation')
|
||||
->assertSee('/admin/operations/'.$run->getKey(), false);
|
||||
->assertSee(OperationRunLinks::tenantlessView($run), false);
|
||||
});
|
||||
|
||||
@ -34,7 +34,7 @@ function getTableEmptyStateAction($component, string $name): ?\Filament\Actions\
|
||||
[$user] = createUserWithTenant($otherTenant, role: 'owner');
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(BackupSetResource::getUrl('index', panel: 'tenant', tenant: $tenant))
|
||||
->get(BackupSetResource::getUrl('index', panel: 'admin', tenant: $tenant))
|
||||
->assertStatus(404);
|
||||
});
|
||||
|
||||
|
||||
@ -65,8 +65,7 @@ function createCoverageBannerTenant(): array
|
||||
],
|
||||
]);
|
||||
|
||||
Filament::setCurrentPanel(Filament::getPanel('tenant'));
|
||||
Filament::setTenant($tenant, true);
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
Livewire::test(BaselineCompareCoverageBanner::class)
|
||||
->assertSee('The last compare finished, but normal result output was suppressed.')
|
||||
@ -88,8 +87,7 @@ function createCoverageBannerTenant(): array
|
||||
'baseline_profile_id' => (int) $profile->getKey(),
|
||||
]);
|
||||
|
||||
Filament::setCurrentPanel(Filament::getPanel('tenant'));
|
||||
Filament::setTenant($tenant, true);
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
Livewire::test(BaselineCompareCoverageBanner::class)
|
||||
->assertSee('The current baseline snapshot is not available for compare.')
|
||||
@ -122,8 +120,7 @@ function createCoverageBannerTenant(): array
|
||||
],
|
||||
]);
|
||||
|
||||
Filament::setCurrentPanel(Filament::getPanel('tenant'));
|
||||
Filament::setTenant($tenant, true);
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
Livewire::test(BaselineCompareCoverageBanner::class)
|
||||
->assertDontSee('No confirmed drift in the latest baseline compare.')
|
||||
@ -162,8 +159,7 @@ function createCoverageBannerTenant(): array
|
||||
'due_at' => now()->subDay(),
|
||||
]);
|
||||
|
||||
Filament::setCurrentPanel(Filament::getPanel('tenant'));
|
||||
Filament::setTenant($tenant, true);
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
Livewire::test(BaselineCompareCoverageBanner::class)
|
||||
->assertSee('overdue finding')
|
||||
|
||||
@ -160,6 +160,6 @@ function seedBaselineCompareLandingGapRun(\App\Models\ManagedEnvironment $tenant
|
||||
seedBaselineCompareLandingGapRun($tenant);
|
||||
|
||||
$this->actingAs($nonMember)
|
||||
->get(BaselineCompareLanding::getUrl(tenant: $tenant, panel: 'tenant'))
|
||||
->get(BaselineCompareLanding::getUrl(tenant: $tenant, panel: 'admin'))
|
||||
->assertNotFound();
|
||||
});
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
it('redirects unauthenticated users (302)', function (): void {
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
|
||||
$this->get(BaselineCompareLanding::getUrl(tenant: $tenant, panel: 'tenant'))
|
||||
$this->get(BaselineCompareLanding::getUrl(tenant: $tenant, panel: 'admin'))
|
||||
->assertStatus(302);
|
||||
});
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
$nonMember = \App\Models\User::factory()->create();
|
||||
|
||||
$this->actingAs($nonMember)
|
||||
->get(BaselineCompareLanding::getUrl(tenant: $tenant, panel: 'tenant'))
|
||||
->get(BaselineCompareLanding::getUrl(tenant: $tenant, panel: 'admin'))
|
||||
->assertNotFound();
|
||||
});
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
|
||||
use App\Filament\Pages\BaselineCompareMatrix;
|
||||
use App\Filament\Resources\BaselineProfileResource;
|
||||
use App\Models\ManagedEnvironment;
|
||||
use App\Models\User;
|
||||
use App\Models\WorkspaceMembership;
|
||||
use App\Support\Baselines\Compare\CompareStrategyRegistry;
|
||||
@ -171,6 +172,11 @@
|
||||
'user_id' => (int) $viewer->getKey(),
|
||||
'role' => 'owner',
|
||||
]);
|
||||
createUserWithTenant(
|
||||
tenant: ManagedEnvironment::factory()->create(['workspace_id' => (int) $fixture['workspace']->getKey()]),
|
||||
user: $viewer,
|
||||
role: 'owner',
|
||||
);
|
||||
|
||||
$viewer->tenants()->syncWithoutDetaching([
|
||||
(int) $fixture['visibleTenant']->getKey() => ['role' => 'owner'],
|
||||
@ -262,12 +268,13 @@
|
||||
$fixture = $this->makeBaselineCompareMatrixFixture();
|
||||
$viewer = User::factory()->create();
|
||||
|
||||
WorkspaceMembership::factory()->create([
|
||||
$scopedTenant = ManagedEnvironment::factory()->create([
|
||||
'workspace_id' => (int) $fixture['workspace']->getKey(),
|
||||
'user_id' => (int) $viewer->getKey(),
|
||||
'role' => 'owner',
|
||||
'status' => 'active',
|
||||
]);
|
||||
|
||||
createUserWithTenant(tenant: $scopedTenant, user: $viewer, role: 'owner');
|
||||
|
||||
$session = $this->setAdminWorkspaceContext($viewer, $fixture['workspace']);
|
||||
|
||||
$this->withSession($session)
|
||||
|
||||
@ -66,8 +66,7 @@ function createBaselineCompareWidgetTenant(): array
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
Filament::setCurrentPanel(Filament::getPanel('tenant'));
|
||||
Filament::setTenant($tenant, true);
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
Livewire::test(BaselineCompareNow::class)
|
||||
->assertSee('Baseline Governance')
|
||||
@ -111,8 +110,7 @@ function createBaselineCompareWidgetTenant(): array
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
Filament::setCurrentPanel(Filament::getPanel('tenant'));
|
||||
Filament::setTenant($tenant, true);
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
Livewire::test(BaselineCompareNow::class)
|
||||
->assertSee('Needs review')
|
||||
@ -141,8 +139,7 @@ function createBaselineCompareWidgetTenant(): array
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
Filament::setCurrentPanel(Filament::getPanel('tenant'));
|
||||
Filament::setTenant($tenant, true);
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
Livewire::test(BaselineCompareNow::class)
|
||||
->assertSee('Action required')
|
||||
@ -168,8 +165,7 @@ function createBaselineCompareWidgetTenant(): array
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
Filament::setCurrentPanel(Filament::getPanel('tenant'));
|
||||
Filament::setTenant($tenant, true);
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
Livewire::test(BaselineCompareNow::class)
|
||||
->assertSee('In progress')
|
||||
@ -195,8 +191,7 @@ function createBaselineCompareWidgetTenant(): array
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
Filament::setCurrentPanel(Filament::getPanel('tenant'));
|
||||
Filament::setTenant($tenant, true);
|
||||
setAdminPanelContext($tenant);
|
||||
|
||||
Livewire::test(BaselineCompareNow::class)
|
||||
->assertSee('Unavailable')
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user