Fix issues with superadmin org filtering logic (#2638)
Fixes #2636 ## Changes - Displays trials scheduled for cancellation alongside non-trials scheduled for cancellation - Adds filter for "bad states" — active orgs that have a cancelled subscription, orgs with a cancellation date in the past, and empty subscription ids currently, but could be extended as necessary - Displays scheduled-for-cancellation trials in the "trialing" filter as well - Improves display of future cancellation durations for both active subscriptions and trials - Surfaces issues where a trial cancellation was scheduled for the past but the org is still active - Swaps out `sl-tooltip`s for `btrix-popover`s in popovers with longer details - Adds correct heading levels, `tabindex`, and orientation for popovers in use here ## Follow-ups Once #2637 is merged we can ~~swap out the `sl-tooltip`s for `btrix-popover`s here~~ _done!_ & in the superadmin stats card
This commit is contained in:
parent
199e28ce7c
commit
7f44f43647
@ -33,6 +33,7 @@ enum OrgFilter {
|
|||||||
Inactive = "inactive",
|
Inactive = "inactive",
|
||||||
Trialing = "trialing",
|
Trialing = "trialing",
|
||||||
ScheduledCancel = "scheduled-cancel",
|
ScheduledCancel = "scheduled-cancel",
|
||||||
|
BadStates = "bad-states",
|
||||||
}
|
}
|
||||||
|
|
||||||
const none = html`
|
const none = html`
|
||||||
@ -180,6 +181,11 @@ export class OrgsList extends BtrixElement {
|
|||||||
icon: "calendar2-x",
|
icon: "calendar2-x",
|
||||||
filter: OrgFilter.ScheduledCancel,
|
filter: OrgFilter.ScheduledCancel,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: msg("Unexpected States"),
|
||||||
|
icon: "exclamation-triangle",
|
||||||
|
filter: OrgFilter.BadStates,
|
||||||
|
},
|
||||||
].map((options) => this.renderFilterButton(searchResults, options))}
|
].map((options) => this.renderFilterButton(searchResults, options))}
|
||||||
</sl-radio-group>
|
</sl-radio-group>
|
||||||
</btrix-overflow-scroll>
|
</btrix-overflow-scroll>
|
||||||
@ -257,22 +263,54 @@ export class OrgsList extends BtrixElement {
|
|||||||
!!org.subscription &&
|
!!org.subscription &&
|
||||||
!(
|
!(
|
||||||
org.subscription.status === SubscriptionStatus.Active ||
|
org.subscription.status === SubscriptionStatus.Active ||
|
||||||
org.subscription.status === SubscriptionStatus.Trialing
|
org.subscription.status === SubscriptionStatus.Trialing ||
|
||||||
|
org.subscription.status === SubscriptionStatus.TrialingCanceled
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
case OrgFilter.Trialing:
|
case OrgFilter.Trialing:
|
||||||
return (
|
return (
|
||||||
!!org.subscription &&
|
!!org.subscription &&
|
||||||
org.subscription.status === SubscriptionStatus.Trialing
|
(org.subscription.status === SubscriptionStatus.Trialing ||
|
||||||
|
org.subscription.status === SubscriptionStatus.TrialingCanceled)
|
||||||
);
|
);
|
||||||
case OrgFilter.ScheduledCancel:
|
case OrgFilter.ScheduledCancel:
|
||||||
return (
|
return (
|
||||||
!!org.subscription &&
|
!!org.subscription &&
|
||||||
org.subscription.status === SubscriptionStatus.Active &&
|
((org.subscription.status === SubscriptionStatus.Active &&
|
||||||
!!org.subscription.futureCancelDate
|
!!org.subscription.futureCancelDate) ||
|
||||||
|
org.subscription.status === SubscriptionStatus.TrialingCanceled)
|
||||||
);
|
);
|
||||||
case OrgFilter.All:
|
case OrgFilter.All:
|
||||||
return true;
|
return true;
|
||||||
|
case OrgFilter.BadStates:
|
||||||
|
// Check if org should be disabled but isn't
|
||||||
|
if (
|
||||||
|
!org.readOnly &&
|
||||||
|
org.subscription &&
|
||||||
|
[
|
||||||
|
SubscriptionStatus.Cancelled,
|
||||||
|
SubscriptionStatus.PausedPaymentFailed,
|
||||||
|
].includes(org.subscription.status)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if org is scheduled to cancel in the past
|
||||||
|
if (
|
||||||
|
org.subscription?.futureCancelDate &&
|
||||||
|
new Date(org.subscription.futureCancelDate).getTime() -
|
||||||
|
new Date().getTime() <
|
||||||
|
0
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if org has empty subscription id
|
||||||
|
if (org.subscription && !org.subscription.subId) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -740,9 +778,10 @@ export class OrgsList extends BtrixElement {
|
|||||||
if (org.storageQuotaReached || org.execMinutesQuotaReached) {
|
if (org.storageQuotaReached || org.execMinutesQuotaReached) {
|
||||||
status = {
|
status = {
|
||||||
icon: html`<sl-icon
|
icon: html`<sl-icon
|
||||||
|
tabindex="0"
|
||||||
class="text-base text-danger"
|
class="text-base text-danger"
|
||||||
name="exclamation-triangle-fill"
|
name="exclamation-triangle-fill"
|
||||||
label=${msg("Issue")}
|
label=${msg("Active with issue")}
|
||||||
>
|
>
|
||||||
</sl-icon>`,
|
</sl-icon>`,
|
||||||
description: org.storageQuotaReached
|
description: org.storageQuotaReached
|
||||||
@ -754,9 +793,10 @@ export class OrgsList extends BtrixElement {
|
|||||||
if (org.readOnly) {
|
if (org.readOnly) {
|
||||||
status = {
|
status = {
|
||||||
icon: html`<sl-icon
|
icon: html`<sl-icon
|
||||||
|
tabindex="0"
|
||||||
class="text-base text-neutral-400"
|
class="text-base text-neutral-400"
|
||||||
name="ban"
|
name="ban"
|
||||||
label=${msg("disabled")}
|
label=${msg("Disabled")}
|
||||||
>
|
>
|
||||||
</sl-icon>`,
|
</sl-icon>`,
|
||||||
description: org.readOnlyReason
|
description: org.readOnlyReason
|
||||||
@ -768,6 +808,7 @@ export class OrgsList extends BtrixElement {
|
|||||||
let subscription: {
|
let subscription: {
|
||||||
icon: TemplateResult<1>;
|
icon: TemplateResult<1>;
|
||||||
description: string | TemplateResult<1>;
|
description: string | TemplateResult<1>;
|
||||||
|
unexpectedState?: true;
|
||||||
} = {
|
} = {
|
||||||
icon: none,
|
icon: none,
|
||||||
description: msg("No Subscription"),
|
description: msg("No Subscription"),
|
||||||
@ -784,16 +825,21 @@ export class OrgsList extends BtrixElement {
|
|||||||
) {
|
) {
|
||||||
subscription = {
|
subscription = {
|
||||||
icon: html`<sl-icon
|
icon: html`<sl-icon
|
||||||
|
tabindex="0"
|
||||||
class="text-base text-warning"
|
class="text-base text-warning"
|
||||||
name="calendar2-x"
|
name="calendar2-x"
|
||||||
label=${msg("Subscription Cancellation Scheduled")}
|
label=${msg("Subscription Cancellation Scheduled")}
|
||||||
></sl-icon>`,
|
></sl-icon>`,
|
||||||
description: html`${msg("Subscription Cancellation Scheduled")}
|
description: html`<h3 class="font-bold">
|
||||||
|
${msg("Subscription Cancellation Scheduled")}
|
||||||
|
</h3>
|
||||||
|
<hr class="my-2" />
|
||||||
<div class="mt-2 text-xs">
|
<div class="mt-2 text-xs">
|
||||||
${msg("Subscription will be cancelled in")}
|
${msg("Cancels in")}
|
||||||
${this.localize.humanizeDuration(
|
${this.localize.humanizeDuration(
|
||||||
new Date(org.subscription.futureCancelDate).getTime() -
|
new Date(org.subscription.futureCancelDate).getTime() -
|
||||||
new Date().getTime(),
|
new Date().getTime(),
|
||||||
|
{ compact: true, verbose: true },
|
||||||
)}
|
)}
|
||||||
(${this.localize.date(org.subscription.futureCancelDate, {
|
(${this.localize.date(org.subscription.futureCancelDate, {
|
||||||
timeStyle: "medium",
|
timeStyle: "medium",
|
||||||
@ -808,7 +854,8 @@ export class OrgsList extends BtrixElement {
|
|||||||
0
|
0
|
||||||
) {
|
) {
|
||||||
subscription = {
|
subscription = {
|
||||||
icon: html`<sl-icon
|
icon: html` <div tabindex="0" class="flex flex-row gap-1">
|
||||||
|
<sl-icon
|
||||||
class="text-base text-warning"
|
class="text-base text-warning"
|
||||||
name="calendar2-x"
|
name="calendar2-x"
|
||||||
label=${msg("Subscription Cancellation Scheduled")}
|
label=${msg("Subscription Cancellation Scheduled")}
|
||||||
@ -816,21 +863,24 @@ export class OrgsList extends BtrixElement {
|
|||||||
<sl-icon
|
<sl-icon
|
||||||
class="text-base text-danger"
|
class="text-base text-danger"
|
||||||
name="x-octagon-fill"
|
name="x-octagon-fill"
|
||||||
label=${msg("Subscription Cancellation Scheduled")}
|
label=${msg("Issue")}
|
||||||
></sl-icon>`,
|
></sl-icon>
|
||||||
description: html`${msg(
|
</div>`,
|
||||||
"Subscription Cancellation Scheduled in the Past",
|
description: html`<h3 class="font-bold">
|
||||||
)}
|
${msg("Subscription Cancellation Scheduled in the Past")}
|
||||||
<div class="mt-2 text-xs">
|
</h3>
|
||||||
${msg("Subscription was scheduled for cancellation at")}
|
<div class="mt-2">
|
||||||
|
${msg("Subscription was scheduled for cancellation at")}${" "}
|
||||||
${this.localize.date(org.subscription.futureCancelDate, {
|
${this.localize.date(org.subscription.futureCancelDate, {
|
||||||
timeStyle: "medium",
|
timeStyle: "medium",
|
||||||
dateStyle: "medium",
|
dateStyle: "medium",
|
||||||
})}
|
})}
|
||||||
|
${" "}${msg("but is still active.")}
|
||||||
</div>
|
</div>
|
||||||
<div class="my-2 font-bold text-danger-300">
|
<div class="mt-2 font-bold text-danger">
|
||||||
${msg("This indicates something has gone wrong.")}
|
${msg("This indicates something has gone wrong.")}
|
||||||
</div>`,
|
</div>`,
|
||||||
|
unexpectedState: true,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
subscription = {
|
subscription = {
|
||||||
@ -854,14 +904,82 @@ export class OrgsList extends BtrixElement {
|
|||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case SubscriptionStatus.TrialingCanceled:
|
case SubscriptionStatus.TrialingCanceled:
|
||||||
subscription = {
|
if (
|
||||||
icon: html`<sl-icon
|
org.subscription.futureCancelDate &&
|
||||||
class="text-base text-neutral-400"
|
new Date(org.subscription.futureCancelDate).getTime() -
|
||||||
name="x-square-fill"
|
new Date().getTime() >=
|
||||||
label=${msg("Trial Cancelled")}
|
0
|
||||||
></sl-icon>`,
|
) {
|
||||||
description: msg("Trial Canceled"),
|
subscription = {
|
||||||
};
|
icon: html`<sl-icon
|
||||||
|
tabindex="1"
|
||||||
|
class="text-base text-neutral-400"
|
||||||
|
name="x-square-fill"
|
||||||
|
label=${msg("Trial Cancelled")}
|
||||||
|
></sl-icon>`,
|
||||||
|
description: html`<h3 class="font-bold">
|
||||||
|
${msg("Trial Cancellation Scheduled")}
|
||||||
|
</h3>
|
||||||
|
<hr class="my-2" />
|
||||||
|
<div class="mt-2 text-xs">
|
||||||
|
${msg("Cancels in")}
|
||||||
|
${this.localize.humanizeDuration(
|
||||||
|
new Date(org.subscription.futureCancelDate).getTime() -
|
||||||
|
new Date().getTime(),
|
||||||
|
{ compact: true, verbose: true },
|
||||||
|
)}
|
||||||
|
(${this.localize.date(org.subscription.futureCancelDate, {
|
||||||
|
timeStyle: "medium",
|
||||||
|
dateStyle: "medium",
|
||||||
|
})})
|
||||||
|
</div>`,
|
||||||
|
};
|
||||||
|
} else if (
|
||||||
|
org.subscription.futureCancelDate &&
|
||||||
|
new Date(org.subscription.futureCancelDate).getTime() -
|
||||||
|
new Date().getTime() <
|
||||||
|
0
|
||||||
|
) {
|
||||||
|
subscription = {
|
||||||
|
icon: html`<div tabindex="0" class="flex flex-row gap-1">
|
||||||
|
<sl-icon
|
||||||
|
class="text-base text-neutral-400"
|
||||||
|
name="x-square-fill"
|
||||||
|
label=${msg("Trial Cancelled")}
|
||||||
|
></sl-icon>
|
||||||
|
<sl-icon
|
||||||
|
class="text-base text-danger"
|
||||||
|
name="x-octagon-fill"
|
||||||
|
label=${msg("Issue")}
|
||||||
|
></sl-icon>
|
||||||
|
</div>`,
|
||||||
|
description: html`<h3 class="font-bold">
|
||||||
|
${msg("Trial Cancellation Scheduled in the Past")}
|
||||||
|
</h3>
|
||||||
|
<div class="mt-2 text-xs">
|
||||||
|
${msg("Trial was scheduled for cancellation at")}
|
||||||
|
${this.localize.date(org.subscription.futureCancelDate, {
|
||||||
|
timeStyle: "medium",
|
||||||
|
dateStyle: "medium",
|
||||||
|
})}
|
||||||
|
${msg("but is still active.")}
|
||||||
|
</div>
|
||||||
|
<div class="mt-2 font-bold text-danger">
|
||||||
|
${msg("This indicates something has gone wrong.")}
|
||||||
|
</div>`,
|
||||||
|
unexpectedState: true,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
subscription = {
|
||||||
|
icon: html`<sl-icon
|
||||||
|
class="text-base text-neutral-400"
|
||||||
|
name="x-square-fill"
|
||||||
|
label=${msg("Trial Cancelled")}
|
||||||
|
></sl-icon>`,
|
||||||
|
description: msg("Trial Cancelled"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case SubscriptionStatus.PausedPaymentFailed:
|
case SubscriptionStatus.PausedPaymentFailed:
|
||||||
subscription = {
|
subscription = {
|
||||||
@ -899,6 +1017,7 @@ export class OrgsList extends BtrixElement {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const useTooltip = typeof subscription.description === "string";
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<btrix-table-row
|
<btrix-table-row
|
||||||
@ -910,10 +1029,14 @@ export class OrgsList extends BtrixElement {
|
|||||||
<sl-tooltip content=${status.description} hoist>
|
<sl-tooltip content=${status.description} hoist>
|
||||||
${status.icon}
|
${status.icon}
|
||||||
</sl-tooltip>
|
</sl-tooltip>
|
||||||
<sl-tooltip hoist>
|
${useTooltip
|
||||||
<span slot="content">${subscription.description}</span>
|
? html`<sl-tooltip hoist content=${subscription.description}>
|
||||||
${subscription.icon}
|
${subscription.icon}
|
||||||
</sl-tooltip>
|
</sl-tooltip>`
|
||||||
|
: html`<btrix-popover placement="top" hoist>
|
||||||
|
<span slot="content">${subscription.description}</span>
|
||||||
|
${subscription.icon}
|
||||||
|
</btrix-popover>`}
|
||||||
</btrix-table-cell>
|
</btrix-table-cell>
|
||||||
<btrix-table-cell class="p-2" rowClickTarget="a">
|
<btrix-table-cell class="p-2" rowClickTarget="a">
|
||||||
<a
|
<a
|
||||||
|
Loading…
Reference in New Issue
Block a user