rework premium workspace pricing

This commit is contained in:
Ruben Fiszel
2023-05-28 12:58:38 +02:00
parent f32a913506
commit 91ad8d0b8d
5 changed files with 197 additions and 261 deletions
+112 -135
View File
@@ -177,26 +177,6 @@
},
"query": "SELECT * from resource_type WHERE name = $1 AND (workspace_id = $2 OR workspace_id = 'admins')"
},
"0473482de2910768dbe1cd4569cf157c91939150ea176f44bcce68eb68dbdeb9": {
"describe": {
"columns": [
{
"name": "usage",
"ordinal": 0,
"type_info": "Int4"
}
],
"nullable": [
false
],
"parameters": {
"Left": [
"Varchar"
]
}
},
"query": "INSERT INTO usage (id, is_workspace, month_, usage) \n VALUES ($1, true, EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date), 0) \n ON CONFLICT (id, is_workspace, month_) DO UPDATE SET usage = usage.usage + 1 \n RETURNING usage.usage"
},
"04a15674cf66f2822085e65ca33ee42b8e7f3f9d63ffac0585a12368d0322252": {
"describe": {
"columns": [
@@ -801,75 +781,6 @@
},
"query": "DELETE FROM queue WHERE schedule_path = $1 AND running = false AND job_kind = $2"
},
"1baf08ea78b84c9836c55975044d072c9d92400a1b1248a61d2d0247ac872fe4": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Left": [
"Varchar",
"Uuid",
"Uuid",
"Varchar",
"Timestamptz",
"Timestamptz",
"Bool",
"Int8",
"Varchar",
"Jsonb",
"Jsonb",
"Text",
"Text",
"Text",
"Bool",
"Varchar",
"Text",
{
"Custom": {
"kind": {
"Enum": [
"script",
"preview",
"flow",
"dependencies",
"flowpreview",
"script_hub",
"identity",
"flowdependencies"
]
},
"name": "job_kind"
}
},
"Varchar",
"Varchar",
"Jsonb",
"Jsonb",
"Bool",
"Bool",
{
"Custom": {
"kind": {
"Enum": [
"python3",
"deno",
"go",
"bash"
]
},
"name": "script_lang"
}
},
"Numeric",
"Varchar",
"Bool",
"Int4",
"Varchar"
]
}
},
"query": "INSERT INTO completed_job AS cj\n ( workspace_id\n , id\n , parent_job\n , created_by\n , created_at\n , started_at\n , duration_ms\n , success\n , script_hash\n , script_path\n , args\n , result\n , logs\n , raw_code\n , raw_lock\n , canceled\n , canceled_by\n , canceled_reason\n , job_kind\n , schedule_path\n , permissioned_as\n , flow_status\n , raw_flow\n , is_flow_step\n , is_skipped\n , language\n , email\n , visible_to_owner\n , mem_peak\n , tag\n )\n VALUES ($1, $2, $3, $4, $5, $6, COALESCE($26, (EXTRACT('epoch' FROM (now())) - EXTRACT('epoch' FROM (COALESCE($6, now()))))*1000), $7, $8, $9,$10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $27, $28, $29, $30)\n ON CONFLICT (id) DO UPDATE SET success = $7, result = $11, logs = concat(cj.logs, $12)"
},
"1bf2ca894246bd716875635b2d0c294a1ce2ed21916097ea165df240f7421a1e": {
"describe": {
"columns": [],
@@ -3721,26 +3632,6 @@
},
"query": "INSERT INTO resource\n (workspace_id, path, value, description, resource_type)\n VALUES ($1, $2, $3, $4, $5)"
},
"8af34c8fd96ccc3c007e211982e60306fee109944c2a053e8c38632992c39983": {
"describe": {
"columns": [
{
"name": "usage",
"ordinal": 0,
"type_info": "Int4"
}
],
"nullable": [
false
],
"parameters": {
"Left": [
"Varchar"
]
}
},
"query": "INSERT INTO usage (id, is_workspace, month_, usage) \n VALUES ($1, false, EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date), 0) \n ON CONFLICT (id, is_workspace, month_) DO UPDATE SET usage = usage.usage + 1 \n RETURNING usage.usage"
},
"8c0131a9cc61f2daa258d49767242bcaab6bb34a977ff7fb0c18aa9202d11f47": {
"describe": {
"columns": [],
@@ -5351,6 +5242,27 @@
},
"query": "SELECT null FROM queue WHERE id = $1 FOR UPDATE"
},
"bd086c56ad3a58163619122641b93b941ef75880eeeab0756d40f68f87760d5b": {
"describe": {
"columns": [
{
"name": "usage",
"ordinal": 0,
"type_info": "Int4"
}
],
"nullable": [
false
],
"parameters": {
"Left": [
"Varchar",
"Bool"
]
}
},
"query": "INSERT INTO usage (id, is_workspace, month_, usage) \n VALUES ($1, $2, EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date), 0) \n ON CONFLICT (id, is_workspace, month_) DO UPDATE SET usage = usage.usage + 1 \n RETURNING usage.usage"
},
"be1de9116b18a40681cb8c5ec7578fd7c5f7ce77f7af63f766c2899d85fe0bef": {
"describe": {
"columns": [
@@ -5762,6 +5674,83 @@
},
"query": "\n SELECT id, flow_status, suspend, script_path\n FROM queue\n WHERE id = ( SELECT parent_job FROM queue WHERE id = $1 UNION ALL SELECT parent_job FROM completed_job WHERE id = $1)\n FOR UPDATE\n "
},
"c8467b5a1a9c915384b7671990111ec548e399a44df6773f48a81d8956aab683": {
"describe": {
"columns": [
{
"name": "duration_ms",
"ordinal": 0,
"type_info": "Int4"
}
],
"nullable": [
false
],
"parameters": {
"Left": [
"Varchar",
"Uuid",
"Uuid",
"Varchar",
"Timestamptz",
"Timestamptz",
"Bool",
"Int8",
"Varchar",
"Jsonb",
"Jsonb",
"Text",
"Text",
"Text",
"Bool",
"Varchar",
"Text",
{
"Custom": {
"kind": {
"Enum": [
"script",
"preview",
"flow",
"dependencies",
"flowpreview",
"script_hub",
"identity",
"flowdependencies"
]
},
"name": "job_kind"
}
},
"Varchar",
"Varchar",
"Jsonb",
"Jsonb",
"Bool",
"Bool",
{
"Custom": {
"kind": {
"Enum": [
"python3",
"deno",
"go",
"bash"
]
},
"name": "script_lang"
}
},
"Numeric",
"Varchar",
"Bool",
"Int4",
"Varchar"
]
}
},
"query": "INSERT INTO completed_job AS cj\n ( workspace_id\n , id\n , parent_job\n , created_by\n , created_at\n , started_at\n , duration_ms\n , success\n , script_hash\n , script_path\n , args\n , result\n , logs\n , raw_code\n , raw_lock\n , canceled\n , canceled_by\n , canceled_reason\n , job_kind\n , schedule_path\n , permissioned_as\n , flow_status\n , raw_flow\n , is_flow_step\n , is_skipped\n , language\n , email\n , visible_to_owner\n , mem_peak\n , tag\n )\n VALUES ($1, $2, $3, $4, $5, $6, COALESCE($26, (EXTRACT('epoch' FROM (now())) - EXTRACT('epoch' FROM (COALESCE($6, now()))))*1000), $7, $8, $9,$10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $27, $28, $29, $30)\n ON CONFLICT (id) DO UPDATE SET success = $7, result = $11, logs = concat(cj.logs, $12) RETURNING duration_ms"
},
"c9d97800eb0ec87df8e8959b283dacb2c6cce422365ed394375641488ceb6b65": {
"describe": {
"columns": [],
@@ -6202,19 +6191,6 @@
},
"query": "SELECT EXISTS(SELECT 1 FROM workspace WHERE id = $1)"
},
"de4c8f42ff846599d6b2b26615a34f0bcbad974edc5f00fb0491475017eebaeb": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Left": [
"Varchar",
"Int4"
]
}
},
"query": "INSERT INTO usage (id, is_workspace, month_, usage) \n VALUES ($1, false, EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date), 0) \n ON CONFLICT (id, is_workspace, month_) DO UPDATE SET usage = usage.usage + $2"
},
"df8f9b2e601b0157759e9507308ea7df562a7a42516be0fcb465b8e34de0f438": {
"describe": {
"columns": [
@@ -6392,6 +6368,20 @@
},
"query": "DELETE FROM completed_job WHERE workspace_id = $1"
},
"e7418515b88d14d1fd79078342963e11422eed9a60e0472c68971f4e8f8735d9": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Left": [
"Varchar",
"Bool",
"Int4"
]
}
},
"query": "INSERT INTO usage (id, is_workspace, month_, usage) \n VALUES ($1, $2, EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date), 0) \n ON CONFLICT (id, is_workspace, month_) DO UPDATE SET usage = usage.usage + $3"
},
"e838b15953b567af2a2da6a4e3a04add5ec2cacabd93171a97c5fc978a64f8aa": {
"describe": {
"columns": [],
@@ -6839,19 +6829,6 @@
},
"query": "SELECT SUM(duration_ms) as duration FROM completed_job WHERE id = ANY($1)"
},
"f67ba6ca3ed802ca41e49a310a4161ea8d81f79021f11f3a9f2b65e93ce6312d": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Left": [
"Varchar",
"Int4"
]
}
},
"query": "INSERT INTO usage (id, is_workspace, month_, usage) \n VALUES ($1, true, EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date), 0) \n ON CONFLICT (id, is_workspace, month_) DO UPDATE SET usage = usage.usage + $2"
},
"f7f2598ac824e9b5719b96b1d1873ad728f7f786c7f447df6cac3e65d5a53bf1": {
"describe": {
"columns": [
+2 -24
View File
@@ -259,37 +259,15 @@ async fn stripe_checkout(
"team" => Some(vec![
stripe::CreateCheckoutSessionLineItems {
quantity: Some(1),
price: Some("price_1MUlrWGU3NdFi9eLE9GBZhoY".to_string()),
price: Some("price_1NCNOgGU3NdFi9eLuG4fZuEP".to_string()),
..Default::default()
},
stripe::CreateCheckoutSessionLineItems {
quantity: None,
price: Some("price_1MUlreGU3NdFi9eLi6sOyvVa".to_string()),
..Default::default()
},
stripe::CreateCheckoutSessionLineItems {
quantity: None,
price: Some("price_1MUlrlGU3NdFi9eLFLggSXZV".to_string()),
..Default::default()
},
stripe::CreateCheckoutSessionLineItems {
quantity: None,
price: Some("price_1MUlr3GU3NdFi9eLbZYFjR9p".to_string()),
price: Some("price_1NCNCpGU3NdFi9eLbiE6Ca42".to_string()),
..Default::default()
},
]),
// "enterprise" => Some(vec![
// stripe::CreateCheckoutSessionLineItems {
// quantity: None,
// price: Some("price_1MSdf6GU3NdFi9eLJFRkntlx".to_string()),
// ..Default::default()
// },
// stripe::CreateCheckoutSessionLineItems {
// quantity: None,
// price: Some("price_1MShsNGU3NdFi9eLJMEZUW8b".to_string()),
// ..Default::default()
// },
// ]),
_ => Err(Error::BadRequest("invalid plan".to_string()))?,
};
params.customer_email = Some(&authed.email);
+7 -16
View File
@@ -351,7 +351,8 @@ pub async fn push<'c, R: rsmq_async::RsmqConnection + Send + 'c>(
Ulid::new().into()
};
if cfg!(feature = "enterprise") {
#[cfg(feature = "enterprise")]
{
let premium_workspace = *CLOUD_HOSTED
&& sqlx::query_scalar!("SELECT premium FROM workspace WHERE id = $1", workspace_id)
.fetch_one(&mut tx)
@@ -365,27 +366,17 @@ pub async fn push<'c, R: rsmq_async::RsmqConnection + Send + 'c>(
job_payload,
JobPayload::Flow(_) | JobPayload::RawFlow { .. }
) {
if !premium_workspace {
sqlx::query_scalar!(
sqlx::query_scalar!(
"INSERT INTO usage (id, is_workspace, month_, usage)
VALUES ($1, false, EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date), 0)
VALUES ($1, $2, EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date), 0)
ON CONFLICT (id, is_workspace, month_) DO UPDATE SET usage = usage.usage + 1
RETURNING usage.usage",
email)
if premium_workspace { workspace_id } else { email },
premium_workspace
)
.fetch_one(&mut tx)
.await
.map_err(|e| Error::InternalErr(format!("updating usage: {e}")))?
} else {
sqlx::query_scalar!(
"INSERT INTO usage (id, is_workspace, month_, usage)
VALUES ($1, true, EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date), 0)
ON CONFLICT (id, is_workspace, month_) DO UPDATE SET usage = usage.usage + 1
RETURNING usage.usage",
workspace_id)
.fetch_one(&mut tx)
.await
.map_err(|e| Error::InternalErr(format!("updating usage: {e}")))?
}
} else if *CLOUD_HOSTED && !premium_workspace {
sqlx::query_scalar!(
"
+33 -43
View File
@@ -67,29 +67,30 @@ pub async fn add_completed_job<R: rsmq_async::RsmqConnection + Clone + Send>(
logs: String,
rsmq: Option<R>,
) -> Result<Uuid, Error> {
let duration =
if queued_job.job_kind == JobKind::Flow || queued_job.job_kind == JobKind::FlowPreview {
let jobs = queued_job.parse_flow_status().map(|s| {
let mut modules = s.modules;
modules.extend([s.failure_module.module_status]);
flatten_jobs(modules)
});
if let Some(jobs) = jobs {
sqlx::query_scalar!(
"SELECT SUM(duration_ms) as duration FROM completed_job WHERE id = ANY($1)",
jobs.as_slice()
)
.fetch_one(db)
.await
.ok()
.flatten()
} else {
tracing::warn!("Could not parse flow status");
None
}
let is_flow =
queued_job.job_kind == JobKind::Flow || queued_job.job_kind == JobKind::FlowPreview;
let duration = if is_flow {
let jobs = queued_job.parse_flow_status().map(|s| {
let mut modules = s.modules;
modules.extend([s.failure_module.module_status]);
flatten_jobs(modules)
});
if let Some(jobs) = jobs {
sqlx::query_scalar!(
"SELECT SUM(duration_ms) as duration FROM completed_job WHERE id = ANY($1)",
jobs.as_slice()
)
.fetch_one(db)
.await
.ok()
.flatten()
} else {
tracing::warn!("Could not parse flow status");
None
};
}
} else {
None
};
let mem_peak = sqlx::query_scalar!("SELECT mem_peak FROM queue WHERE id = $1", &queued_job.id)
.fetch_optional(db)
@@ -99,7 +100,7 @@ pub async fn add_completed_job<R: rsmq_async::RsmqConnection + Clone + Send>(
.flatten();
let mut tx: QueueTransaction<'_, R> = (rsmq, db.begin().await?).into();
let job_id = queued_job.id.clone();
sqlx::query!(
let duration = sqlx::query_scalar!(
"INSERT INTO completed_job AS cj
( workspace_id
, id
@@ -134,7 +135,7 @@ pub async fn add_completed_job<R: rsmq_async::RsmqConnection + Clone + Send>(
)
VALUES ($1, $2, $3, $4, $5, $6, COALESCE($26, (EXTRACT('epoch' FROM (now())) - EXTRACT('epoch' FROM (COALESCE($6, now()))))*1000), $7, $8, $9,\
$10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $27, $28, $29, $30)
ON CONFLICT (id) DO UPDATE SET success = $7, result = $11, logs = concat(cj.logs, $12)",
ON CONFLICT (id) DO UPDATE SET success = $7, result = $11, logs = concat(cj.logs, $12) RETURNING duration_ms",
queued_job.workspace_id,
queued_job.id,
queued_job.parent_job,
@@ -166,7 +167,7 @@ pub async fn add_completed_job<R: rsmq_async::RsmqConnection + Clone + Send>(
mem_peak,
queued_job.tag,
)
.execute(&mut tx)
.fetch_one(&mut tx)
.await
.map_err(|e| Error::InternalErr(format!("Could not add completed job {job_id}: {e}")))?;
@@ -190,36 +191,25 @@ pub async fn add_completed_job<R: rsmq_async::RsmqConnection + Clone + Send>(
}
tx.commit().await?;
if cfg!(enterprise) && duration.unwrap_or(0) > 1000 {
let additional_usage = duration.unwrap() as i32 / 1000;
#[cfg(feature = "enterprise")]
if !is_flow && duration > 1000 {
let additional_usage = duration / 1000;
let w_id = &queued_job.workspace_id;
let premium_workspace = *CLOUD_HOSTED
&& sqlx::query_scalar!("SELECT premium FROM workspace WHERE id = $1", w_id)
.fetch_one(db)
.await
.map_err(|e| Error::InternalErr(format!("fetching if {w_id} is premium: {e}")))?;
if premium_workspace {
let _ = sqlx::query!(
let _ = sqlx::query!(
"INSERT INTO usage (id, is_workspace, month_, usage)
VALUES ($1, true, EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date), 0)
ON CONFLICT (id, is_workspace, month_) DO UPDATE SET usage = usage.usage + $2",
w_id,
VALUES ($1, $2, EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date), 0)
ON CONFLICT (id, is_workspace, month_) DO UPDATE SET usage = usage.usage + $3",
if premium_workspace { w_id } else { &queued_job.email },
premium_workspace,
additional_usage)
.execute(db)
.await
.map_err(|e| Error::InternalErr(format!("updating usage: {e}")));
} else {
sqlx::query!(
"INSERT INTO usage (id, is_workspace, month_, usage)
VALUES ($1, false, EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date), 0)
ON CONFLICT (id, is_workspace, month_) DO UPDATE SET usage = usage.usage + $2",
queued_job.email,
additional_usage)
.execute(db)
.await
.map_err(|e| Error::InternalErr(format!("updating usage: {e}")))?;
}
}
tracing::debug!("Added completed job {}", queued_job.id);
@@ -169,26 +169,18 @@
'<b>1 000</b> free global executions per-user per month'
],
Team: [
`<b>$10/mo</b>, includes 1 user/author + 10k computations`,
`<b>+ $8/mo</b> per extra user/author in the workspace (1 included)`,
`<b>+ $4/mo</b> per extra operators in the workspace.`,
`<b>$0.001</b> per additional computation (10k included)`,
`Google/Github/Microsoft/Gitlab <b>SSO</b>`,
`<b>Unlimited</b> variables/resources/scripts/apps/flows`,
`<b>Support 24/7 with 48h response time</b>`
`<b>$10/mo</b> per seat`,
`Every seat includes <b>10 000</b> executions`,
`Every seat includes either 1 user OR 2 operators`
],
Enterprise: [
`<b>$200/mo</b>, includes 1 user/author + 10k computations`,
`<b>+ $32/mo</b> per extra user/author in the workspace (1 included)`,
`<b>+ $16/mo</b> per extra operators in the workspace.`,
`<b>$0.004</b> per additional computation (10k included)`,
`<b>Dedicated</b> and isolated database and workers available for <b>+400$/mo</b> (EU/US)`,
`<b>Dedicated</b> entire cluster available for <b>+4000$/mo</b> (EU/US)`,
`<b>SAML</b> support`,
`<b>Dedicated</b> and isolated database and workers available (EU/US/Asia)`,
`<b>Dedicated</b> entire cluster available for (EU/US/Asia)`,
`<b>SAML</b> support with group syncing`,
`<b>SLA</b>`,
`<b>Priority Support 24/7 with 3h response time and automation engineer assistance</b>`,
`<b>Design partners for Roadmap</b>`,
`<div class="mt-4">(Self-hosted enterprise licenses also available at 50% discount)</div>`
`<div class="mt-4">Self-hosted licenses also available</div>`
]
}
</script>
@@ -485,29 +477,33 @@
{/if}
{#if plan}
{@const team_factor = plan == 'team' ? 8 : 32}
{@const user_nb = Math.max(0, (users?.filter((x) => !x.operator).length ?? 0) - 1)}
{@const team_factor = plan == 'team' ? 10 : 40}
{@const user_nb = users?.filter((x) => !x.operator)?.length ?? 0}
{@const operator_nb = users?.filter((x) => x.operator)?.length ?? 0}
{@const seats_from_users = Math.ceil(user_nb + operator_nb / 2)}
{@const seats_from_comps = Math.ceil((premium_info?.usage ?? 0) / 10000)}
<div>
Extra seats:
<div class="inline text-2xl font-bold float-right"
>{user_nb} * ${team_factor}
= ${(users?.length ?? 0) * team_factor}/mo</div
>
Authors:
<div class="inline text-2xl font-bold float-right">{user_nb}</div>
<Tooltip
>Actual pricing is calculated on the MAXIMUM number of users in a given billing
period, see the customer portal for more info.</Tooltip
>
</div>
<div>
Extra operators:
<div class="inline text-2xl font-bold float-right"
>{Math.max(0, (users?.filter((x) => x.operator).length ?? 0) - 1)} * ${team_factor /
2} = ${((users?.length ?? 0) * team_factor) / 2}/mo</div
>
Operators:
<div class="inline text-2xl font-bold float-right">{operator_nb}</div>
<Tooltip
>Actual pricing is calculated on the MAXIMUM number of users in a given billing
period, see the customer portal for more info.</Tooltip
>Actual pricing is calculated on the MAXIMUM number of operators in a given
billing period, see the customer portal for more info.</Tooltip
>
</div>
<div>
Seats from authors + operators:
<div class="inline text-2xl font-bold float-right mb-8"
>ceil({user_nb} + {operator_nb}/2) = {seats_from_users}</div
>
</div>
<div>
@@ -517,12 +513,19 @@
</div>
</div>
<div>
Extra computations (above the 10k included) this month:
<div class=" inline text-2xl font-bold float-right"
>{Math.max(0, (premium_info?.usage ?? 0) - 10000)} x {plan == 'team'
? '0.001'
: '0.004'} = ${Math.max(0, (premium_info?.usage ?? 0) - 10000) *
(plan == 'team' ? 0.001 : 0.004)}
Seats from computations:
<div class="inline text-2xl font-bold float-right mb-8"
>ceil({premium_info?.usage ?? 0} / 10 000) = {seats_from_comps}</div
>
</div>
<div>
Total seats:
<div class=" inline text-2xl font-bold float-right">
max({seats_from_comps}, {seats_from_users}) * {team_factor} = ${Math.max(
seats_from_comps,
seats_from_users
) * team_factor}/mo
</div>
</div>
{/if}
@@ -534,7 +537,7 @@
{/if}
</div>
<div class="my-4">
<div class="flex flex-col gap-1 mb-4">
<Slider text="What is a computation ?">
<Alert type="info" title="A computation is 1s of execution">
The single credit-unit is called a "computation". A computation corresponds to a
@@ -556,7 +559,7 @@
{#each Object.entries(plans) as [planTitle, planDesc]}
<div class="box p-4 text-sm flex flex-col h-full overflow-hidden">
<h2 class="mb-4">{planTitle}</h2>
<ul class="list-disc p-4">
<ul class="list-disc text-lg p-4">
{#each planDesc as item}
<li class="mt-2">{@html item}</li>
{/each}
@@ -566,7 +569,7 @@
{#if planTitle == 'Team'}
{#if plan != 'team'}
<div class="mt-4 mx-auto">
<Button href="/api/w/{$workspaceStore}/workspaces/checkout?plan=team"
<Button size="lg" href="/api/w/{$workspaceStore}/workspaces/checkout?plan=team"
>Upgrade to the Team plan</Button
>
</div>
@@ -576,11 +579,8 @@
{:else if planTitle == 'Enterprise'}
{#if plan != 'enterprise'}
<div class="mt-4 mx-auto">
<Button
on:click={() =>
sendUserToast(
'Contact contact@windmill.dev to have your dedicated instance provisioned'
)}>Upgrade to the Enterprise plan</Button
<Button size="lg" href="https://www.windmill.dev/pricing" target="_blank"
>See more</Button
>
</div>
{:else}