Skip to content

Commit a6490df

Browse files
committed
feat: #200 reset deployments quota each day
1 parent 9e815d7 commit a6490df

File tree

9 files changed

+86
-29
lines changed

9 files changed

+86
-29
lines changed

Diff for: app/Http/Controllers/TeamQuotasController.php

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public function index(Team $team)
1919
'currentUsage' => $quota->currentUsage(),
2020
'maxUsage' => $quota->maxUsage,
2121
'isSoftQuota' => $quota->isSoftQuota,
22+
'resetPeriod' => $quota->resetPeriod,
2223
'almostQuotaReached' => $quota->almostQuotaReached(),
2324
'isIntrinsic' => $key === 'swarms', // Mark swarms as intrinsic
2425
];

Diff for: app/Models/PricingPlan/ItemQuota.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ public function __construct(
1111
public string $name,
1212
public int $maxUsage,
1313
protected Closure $getCurrentUsage,
14-
public bool $isSoftQuota = false
14+
public bool $isSoftQuota = false,
15+
public ?string $resetPeriod = null
1516
) {}
1617

1718
public function ensureQuota(): void

Diff for: app/Models/Team.php

+9-5
Original file line numberDiff line numberDiff line change
@@ -186,25 +186,29 @@ public function quotas(): UsageQuotas
186186
name: 'Nodes',
187187
maxUsage: max($plan->quotas['nodes']['limit'], $override->nodes),
188188
getCurrentUsage: fn () => $this->nodes()->count(),
189-
isSoftQuota: $plan->quotas['nodes']['soft']
189+
isSoftQuota: $plan->quotas['nodes']['soft'],
190+
resetPeriod: $plan->quotas['nodes']['reset_period']
190191
),
191192
new ItemQuota(
192193
name: 'Swarms',
193194
maxUsage: max($plan->quotas['swarms']['limit'], $override->swarms),
194195
getCurrentUsage: fn () => $this->swarms()->count(),
195-
isSoftQuota: $plan->quotas['swarms']['soft']
196+
isSoftQuota: $plan->quotas['swarms']['soft'],
197+
resetPeriod: $plan->quotas['swarms']['reset_period']
196198
),
197199
new ItemQuota(
198200
name: 'Services',
199201
maxUsage: max($plan->quotas['services']['limit'], $override->services),
200202
getCurrentUsage: fn () => $this->services()->count(),
201-
isSoftQuota: $plan->quotas['services']['soft']
203+
isSoftQuota: $plan->quotas['services']['soft'],
204+
resetPeriod: $plan->quotas['services']['reset_period']
202205
),
203206
new ItemQuota(
204207
name: 'Deployments',
205208
maxUsage: max($plan->quotas['deployments']['limit'], $override->deployments),
206-
getCurrentUsage: fn () => $this->deployments()->count(),
207-
isSoftQuota: $plan->quotas['deployments']['soft']
209+
getCurrentUsage: fn () => $this->deployments()->where('created_at', '>=', now()->startOfDay())->count(),
210+
isSoftQuota: $plan->quotas['deployments']['soft'],
211+
resetPeriod: $plan->quotas['deployments']['reset_period']
208212
)
209213
);
210214
}

Diff for: config/billing.php

+18-18
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@
1111
'description' => 'Perfect plan to try the service or host non-critical applications',
1212
'product_id' => env('PADDLE_PLAN_HOBBY_PRODUCT_ID'),
1313
'price_id' => env('PADDLE_PLAN_HOBBY_PRICE_ID'),
14-
'billing_cycle' => 'yearly', // Added billing cycle
14+
'billing_cycle' => 'yearly',
1515
'quotas' => [
16-
'nodes' => ['limit' => 1, 'soft' => false],
17-
'swarms' => ['limit' => 1, 'soft' => false],
18-
'services' => ['limit' => 20, 'soft' => true],
19-
'deployments' => ['limit' => 100, 'soft' => true],
16+
'nodes' => ['limit' => 1, 'soft' => false, 'reset_period' => null],
17+
'swarms' => ['limit' => 1, 'soft' => false, 'reset_period' => null],
18+
'services' => ['limit' => 20, 'soft' => true, 'reset_period' => null],
19+
'deployments' => ['limit' => 100, 'soft' => true, 'reset_period' => 'daily'],
2020
],
2121
],
2222
[
@@ -25,12 +25,12 @@
2525
'description' => 'Need more power or an additional features? This is your choice!',
2626
'product_id' => env('PADDLE_PLAN_STARTUP_PRODUCT_ID'),
2727
'price_id' => env('PADDLE_PLAN_STARTUP_PRICE_ID'),
28-
'billing_cycle' => 'monthly', // Added billing cycle
28+
'billing_cycle' => 'monthly',
2929
'quotas' => [
30-
'nodes' => ['limit' => 5, 'soft' => true],
31-
'swarms' => ['limit' => 1, 'soft' => false],
32-
'services' => ['limit' => 10, 'soft' => true],
33-
'deployments' => ['limit' => 100, 'soft' => true],
30+
'nodes' => ['limit' => 5, 'soft' => true, 'reset_period' => null],
31+
'swarms' => ['limit' => 1, 'soft' => false, 'reset_period' => null],
32+
'services' => ['limit' => 10, 'soft' => true, 'reset_period' => null],
33+
'deployments' => ['limit' => 100, 'soft' => true, 'reset_period' => 'daily'],
3434
],
3535
],
3636
],
@@ -41,10 +41,10 @@
4141
'product_id' => null,
4242
'price_id' => null,
4343
'quotas' => [
44-
'nodes' => ['limit' => 1, 'soft' => false],
45-
'swarms' => ['limit' => 1, 'soft' => false],
46-
'services' => ['limit' => 3, 'soft' => false],
47-
'deployments' => ['limit' => 20, 'soft' => false],
44+
'nodes' => ['limit' => 1, 'soft' => false, 'reset_period' => null],
45+
'swarms' => ['limit' => 1, 'soft' => false, 'reset_period' => null],
46+
'services' => ['limit' => 3, 'soft' => false, 'reset_period' => null],
47+
'deployments' => ['limit' => 20, 'soft' => false, 'reset_period' => 'daily'],
4848
],
4949
],
5050
'selfHostedPlan' => [
@@ -54,10 +54,10 @@
5454
'product_id' => null,
5555
'price_id' => null,
5656
'quotas' => [
57-
'nodes' => ['limit' => 1000, 'soft' => true],
58-
'swarms' => ['limit' => 1, 'soft' => false],
59-
'services' => ['limit' => 5000, 'soft' => true],
60-
'deployments' => ['limit' => 100000, 'soft' => true],
57+
'nodes' => ['limit' => 1000, 'soft' => true, 'reset_period' => null],
58+
'swarms' => ['limit' => 1, 'soft' => false, 'reset_period' => null],
59+
'services' => ['limit' => 5000, 'soft' => true, 'reset_period' => null],
60+
'deployments' => ['limit' => 100000, 'soft' => true, 'reset_period' => 'daily'],
6161
],
6262
],
6363
],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
return new class extends Migration
8+
{
9+
public function up(): void
10+
{
11+
Schema::table('teams', function (Blueprint $table) {
12+
// Change the column type to jsonb
13+
$table->jsonb('quotas_override')->default(json_encode([
14+
'nodes' => 0,
15+
'swarms' => 0,
16+
'services' => 0,
17+
'deployments' => 0,
18+
]))->change();
19+
});
20+
}
21+
22+
public function down(): void
23+
{
24+
Schema::table('teams', function (Blueprint $table) {
25+
// Revert the column type back to json
26+
$table->json('quotas_override')->default(json_encode([
27+
'nodes' => 0,
28+
'swarms' => 0,
29+
'services' => 0,
30+
'deployments' => 0,
31+
]))->change();
32+
});
33+
}
34+
};

Diff for: resources/js/Pages/Nodes/Partials/DockerRegistries.vue

+4-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ const props = defineProps({
1616
const { encrypt } = useCrypto();
1717
1818
const form = useForm({
19-
registries: props.swarm.data.registries,
19+
registries: props.swarm.data.registries.map((registry) => ({
20+
...registry,
21+
password: null,
22+
})),
2023
});
2124
2225
const makeId = (prefix) => prefix + "-" + Math.random().toString(36).slice(2);

Diff for: resources/js/Pages/Nodes/Partials/S3Storages.vue

+4-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ const props = defineProps({
1717
const { encrypt } = useCrypto();
1818
1919
const form = useForm({
20-
s3Storages: props.swarm.data.s3Storages,
20+
s3Storages: props.swarm.data.s3Storages.map((storage) => ({
21+
...storage,
22+
secretKey: null,
23+
})),
2124
});
2225
2326
const addStorage = () => {

Diff for: resources/js/Pages/Teams/Quotas.vue

+13-3
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,12 @@ const quotaDescriptions = {
4646
swarms: "The maximum number of swarms you can create for your team.",
4747
services:
4848
"The maximum number of services you can deploy across all swarms.",
49-
deployments: "The maximum number of deployments you can perform.",
49+
deployments: "The maximum number of deployments you can perform per day.",
5050
};
51+
52+
function getResetPeriodText(quota: ItemQuota): string | null {
53+
return quota.resetPeriod === "daily" ? "Resets daily" : null;
54+
}
5155
</script>
5256

5357
<template>
@@ -116,7 +120,7 @@ const quotaDescriptions = {
116120
</span>
117121
</div>
118122
<div
119-
class="mt-1 text-xs text-gray-500 dark:text-gray-400"
123+
class="mt-1 text-xs text-gray-500 dark:text-gray-400 flex items-center"
120124
>
121125
{{
122126
quotaDescriptions[
@@ -130,14 +134,20 @@ const quotaDescriptions = {
130134
contact
131135
<a
132136
href="mailto:contact@ptah.sh"
133-
class="text-blue-600 hover:text-blue-800"
137+
class="text-blue-600 hover:text-blue-800 ml-1"
134138
>contact@ptah.sh</a
135139
>.
136140
</span>
137141
<span v-if="quota.isIntrinsic">
138142
This limit is set by the system architecture and
139143
cannot be increased.
140144
</span>
145+
<span
146+
v-if="getResetPeriodText(quota)"
147+
class="ml-2 px-2 py-0.5 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded-full font-medium"
148+
>
149+
{{ getResetPeriodText(quota) }}
150+
</span>
141151
</div>
142152
<div class="mt-2">
143153
<div

Diff for: resources/js/types/quotas.ts

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export interface ItemQuota {
44
isSoftQuota: boolean;
55
almostQuotaReached: boolean;
66
isIntrinsic: boolean;
7+
resetPeriod: string;
78
}
89

910
export interface UsageQuotas {

0 commit comments

Comments
 (0)