mirror of
https://github.com/zyycn/codex-proxy-rs.git
synced 2026-11-06 08:06:19 +00:00
Implement end-to-end backup to S3-compatible object storage (Cloudflare R2): admin settings UI, scheduled and manual jobs, records, retention and expiry, download via presigned URL, and delete convergence. - gateway-admin: backup model, schedule/retention policy, daemon worker, storage identity lock and audit - gateway-store: pg_dump staging, S3 client with probe, backup repository - gateway-api: backup settings/records/create/download/delete routes - migrations: fold expiry TTL into 0003_s3_backup.sql (single migration) - frontend: S3 storage, schedule and records cards under settings/backup Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
71 lines
2.1 KiB
Vue
71 lines
2.1 KiB
Vue
<script setup lang="ts">
|
|
import { Check, Minus } from '@lucide/vue'
|
|
import { computed } from 'vue'
|
|
|
|
const props = withDefaults(
|
|
defineProps<{
|
|
indeterminate?: boolean
|
|
disabled?: boolean
|
|
label?: string
|
|
showLabel?: boolean
|
|
}>(),
|
|
{
|
|
indeterminate: false,
|
|
disabled: false,
|
|
label: undefined,
|
|
showLabel: false,
|
|
},
|
|
)
|
|
|
|
const model = defineModel<boolean>({ default: false })
|
|
|
|
const checked = computed(() => model.value || props.indeterminate)
|
|
|
|
const boxClasses = computed(() => [
|
|
'relative inline-flex size-4 shrink-0 items-center justify-center rounded-(--cp-checkbox-radius) border-0 transition-[background-color,box-shadow,color] duration-150',
|
|
props.disabled
|
|
? 'bg-(--cp-disabled-bg) text-(--cp-disabled-icon)'
|
|
: checked.value
|
|
? 'bg-(--cp-info-bg) text-(--cp-info)'
|
|
: 'bg-(--cp-bg-surface) text-transparent shadow-[inset_0_0_0_1px_var(--cp-default-border-hover)]',
|
|
])
|
|
|
|
function toggle() {
|
|
if (props.disabled) {
|
|
return
|
|
}
|
|
|
|
model.value = !model.value
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<button
|
|
type="button"
|
|
class="group inline-flex min-h-4 min-w-4 appearance-none items-center gap-2.5 border-0 bg-transparent p-0 text-[13px] leading-none font-emphasis transition-opacity outline-none focus-visible:ring-2 focus-visible:ring-(--cp-info-border) focus-visible:ring-offset-2 focus-visible:ring-offset-(--cp-bg-surface)"
|
|
:class="disabled ? 'cursor-not-allowed opacity-55' : 'cursor-pointer'"
|
|
role="checkbox"
|
|
:aria-checked="indeterminate ? 'mixed' : model"
|
|
:aria-label="label"
|
|
:disabled="disabled"
|
|
@click="toggle"
|
|
>
|
|
<span :class="boxClasses">
|
|
<Minus
|
|
class="absolute transition-opacity duration-150 size-3"
|
|
:class="[indeterminate ? 'opacity-100' : 'opacity-0']"
|
|
/>
|
|
<Check
|
|
class="absolute transition-opacity duration-150 size-3"
|
|
:class="[!indeterminate && model ? 'opacity-100' : 'opacity-0']"
|
|
/>
|
|
</span>
|
|
<span
|
|
v-if="showLabel && label"
|
|
class="text-[13px] leading-none font-emphasis"
|
|
>
|
|
{{ label }}
|
|
</span>
|
|
</button>
|
|
</template>
|