fix: restore full-suite green signals across platform workflows #351
@ -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')
|
||||
|
||||
|
Before Width: | Height: | Size: 238 KiB |
|
Before Width: | Height: | Size: 282 KiB |
|
Before Width: | Height: | Size: 387 KiB |
|
Before Width: | Height: | Size: 238 KiB |
|
Before Width: | Height: | Size: 218 KiB |
|
Before Width: | Height: | Size: 217 KiB |
|
Before Width: | Height: | Size: 262 KiB |
|
Before Width: | Height: | Size: 294 KiB |
|
Before Width: | Height: | Size: 219 KiB |
|
Before Width: | Height: | Size: 217 KiB |
@ -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')
|
||||
|
||||