fix datepicker for report create/update, fix public_until update

This commit is contained in:
Gregor Vostrak
2025-06-24 16:57:12 +02:00
parent 915204f7a6
commit a45c8a89f6
5 changed files with 66 additions and 13 deletions

View File

@@ -148,6 +148,8 @@ class ReportController extends Controller
$report->share_secret = null; $report->share_secret = null;
$report->public_until = null; $report->public_until = null;
} }
} elseif ($report->is_public && $request->has('public_until')) {
$report->public_until = $request->getPublicUntil();
} }
$report->save(); $report->save();

View File

@@ -15,6 +15,7 @@ import { api } from '@/packages/api/src';
import { Checkbox } from '@/packages/ui/src'; import { Checkbox } from '@/packages/ui/src';
import DatePicker from '@/packages/ui/src/Input/DatePicker.vue'; import DatePicker from '@/packages/ui/src/Input/DatePicker.vue';
import { useNotificationsStore } from '@/utils/notification'; import { useNotificationsStore } from '@/utils/notification';
import { getLocalizedDayJs } from '@/packages/ui/src/utils/time';
const show = defineModel('show', { default: false }); const show = defineModel('show', { default: false });
const saving = ref(false); const saving = ref(false);
@@ -47,10 +48,14 @@ const report = ref({
const { handleApiRequestNotifications } = useNotificationsStore(); const { handleApiRequestNotifications } = useNotificationsStore();
async function submit() { async function submit() {
const { public_until, ...reportProperties } = report.value;
await handleApiRequestNotifications( await handleApiRequestNotifications(
() => () =>
createReportMutation.mutateAsync({ createReportMutation.mutateAsync({
...report.value, ...reportProperties,
public_until: public_until
? getLocalizedDayJs(public_until).utc().format()
: null,
properties: { ...props.properties }, properties: { ...props.properties },
}), }),
'Success', 'Success',
@@ -109,7 +114,10 @@ async function submit() {
(optional) (optional)
</div> </div>
</div> </div>
<DatePicker id="public_until" size="input"></DatePicker> <DatePicker
id="public_until"
v-model="report.public_until"
size="input"></DatePicker>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -13,6 +13,7 @@ import { Checkbox } from '@/packages/ui/src';
import DatePicker from '@/packages/ui/src/Input/DatePicker.vue'; import DatePicker from '@/packages/ui/src/Input/DatePicker.vue';
import { useNotificationsStore } from '@/utils/notification'; import { useNotificationsStore } from '@/utils/notification';
import type { Report } from '@/packages/api/src'; import type { Report } from '@/packages/api/src';
import { getLocalizedDayJs } from '@/packages/ui/src/utils/time';
const show = defineModel('show', { default: false }); const show = defineModel('show', { default: false });
const saving = ref(false); const saving = ref(false);
@@ -64,8 +65,15 @@ watch(
const { handleApiRequestNotifications } = useNotificationsStore(); const { handleApiRequestNotifications } = useNotificationsStore();
async function submit() { async function submit() {
const { public_until, ...reportProperties } = report.value;
await handleApiRequestNotifications( await handleApiRequestNotifications(
() => updateReportMutation.mutateAsync(report.value), () =>
updateReportMutation.mutateAsync({
...reportProperties,
public_until: public_until
? getLocalizedDayJs(public_until).utc().format()
: null,
}),
'Success', 'Success',
'Error', 'Error',
() => { () => {
@@ -118,9 +126,10 @@ async function submit() {
v-if="report.is_public" v-if="report.is_public"
class="flex items-center space-x-4"> class="flex items-center space-x-4">
<InputLabel for="public_until" value="Expires at" /> <InputLabel for="public_until" value="Expires at" />
<DatePicker <DatePicker
id="public_until" id="public_until"
size="input"></DatePicker> v-model="report.public_until"
size="input"></DatePicker>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -30,7 +30,9 @@ const handleChange = (date: DateValue | undefined) => {
return; return;
} }
const dayjs = getLocalizedDayJs(model.value); const dayjs = model.value
? getLocalizedDayJs(model.value)
: getLocalizedDayJs();
model.value = dayjs model.value = dayjs
.year(date.year) .year(date.year)
.month(date.month - 1) // CalendarDate uses 1-based months .month(date.month - 1) // CalendarDate uses 1-based months
@@ -62,12 +64,15 @@ const organization = inject<ComputedRef<Organization>>('organization');
]" ]"
:tabindex="tabindex"> :tabindex="tabindex">
<CalendarIcon <CalendarIcon
:class="[ :class="[
size === 'xs' ? 'h-3 w-3' : size === 'xs'
size === 'sm' ? 'h-3 w-3' : ? 'h-3 w-3'
size === 'lg' ? 'h-4.5 w-4.5' : : size === 'sm'
'h-4 w-4' ? 'h-3 w-3'
]" /> : size === 'lg'
? 'h-4.5 w-4.5'
: 'h-4 w-4',
]" />
<span class="text-center"> <span class="text-center">
{{ {{
model model

View File

@@ -340,6 +340,35 @@ class ReportEndpointTest extends ApiEndpointTestAbstract
); );
} }
public function test_update_endpoint_can_update_public_until_without_changing_secret(): void
{
// Arrange
$data = $this->createUserWithPermission([
'reports:update',
]);
$report = Report::factory()->public()->forOrganization($data->organization)->create();
$secret = $report->share_secret;
$newPublicUntil = Carbon::now()->addDays(30)->toIso8601ZuluString();
Passport::actingAs($data->user);
// Act
$response = $this->putJson(route('api.v1.reports.update', [$data->organization->getKey(), $report->getKey()]), [
'public_until' => $newPublicUntil,
]);
// Assert
$report->refresh();
$this->assertTrue($report->is_public);
$this->assertSame($secret, $report->share_secret);
$this->assertSame($newPublicUntil, $report->public_until->toIso8601ZuluString());
$response->assertStatus(200);
$response->assertJson(fn (AssertableJson $json) => $json
->has('data')
->where('data.is_public', true)
->where('data.shareable_link', $report->getShareableLink())
);
}
public function test_update_endpoint_can_update_the_report_all_properties_set(): void public function test_update_endpoint_can_update_the_report_all_properties_set(): void
{ {
// Arrange // Arrange