mirror of
https://github.com/amir20/dozzle.git
synced 2026-06-23 04:10:12 +00:00
Merge branch 'master' into claude/implement-mcp-go-server-jebjr
This commit is contained in:
@@ -33,7 +33,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: 1.26.0
|
||||
go-version: 1.26.1
|
||||
check-latest: true
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
@@ -63,13 +63,13 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v4
|
||||
- name: Writing certs to file
|
||||
run: |
|
||||
echo "${{ secrets.TTL_KEY }}" > shared_key.pem
|
||||
echo "${{ secrets.TTL_CERT }}" > shared_cert.pem
|
||||
- name: Build
|
||||
uses: docker/bake-action@v6
|
||||
uses: docker/bake-action@v7
|
||||
with:
|
||||
source: .
|
||||
load: true
|
||||
@@ -93,14 +93,14 @@ jobs:
|
||||
packages: write
|
||||
steps:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
|
||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3.7.0
|
||||
uses: docker/login-action@v4.0.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
- name: Log in to the Container registry
|
||||
uses: docker/login-action@v3.7.0
|
||||
uses: docker/login-action@v4.0.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -109,7 +109,7 @@ jobs:
|
||||
uses: actions/checkout@v6
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: |
|
||||
amir20/dozzle
|
||||
@@ -124,7 +124,7 @@ jobs:
|
||||
echo "${{ secrets.TTL_KEY }}" > shared_key.pem
|
||||
echo "${{ secrets.TTL_CERT }}" > shared_cert.pem
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v6.19.2
|
||||
uses: docker/build-push-action@v7.0.0
|
||||
with:
|
||||
push: true
|
||||
context: .
|
||||
|
||||
@@ -18,14 +18,14 @@ jobs:
|
||||
if: ${{ !github.event.repository.fork && !github.event.pull_request.head.repo.fork && (github.event_name == 'push' || github.event.pull_request.head.repo.full_name == 'amir20/dozzle') }}
|
||||
steps:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
|
||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3.7.0
|
||||
uses: docker/login-action@v4.0.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
- name: Log in to the Container registry
|
||||
uses: docker/login-action@v3.7.0
|
||||
uses: docker/login-action@v4.0.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
uses: actions/checkout@v6
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: |
|
||||
amir20/dozzle
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
echo "${{ secrets.TTL_KEY }}" > shared_key.pem
|
||||
echo "${{ secrets.TTL_CERT }}" > shared_cert.pem
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v6.19.2
|
||||
uses: docker/build-push-action@v7.0.0
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "1.26.0"
|
||||
go-version: "1.26.1"
|
||||
check-latest: true
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
@@ -81,12 +81,12 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "1.26.0"
|
||||
go-version: "1.26.1"
|
||||
check-latest: true
|
||||
- name: Generate dependencies
|
||||
run: make fake_assets shared_key.pem shared_cert.pem
|
||||
- name: Stactic checker
|
||||
uses: dominikh/staticcheck-action@v1.4.0
|
||||
uses: dominikh/staticcheck-action@v1.4.1
|
||||
with:
|
||||
install-go: false
|
||||
int-test:
|
||||
@@ -111,11 +111,11 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v4
|
||||
- name: Generate certs
|
||||
run: make shared_key.pem shared_cert.pem
|
||||
- name: Build
|
||||
uses: docker/bake-action@v6
|
||||
uses: docker/bake-action@v7
|
||||
with:
|
||||
source: .
|
||||
load: true
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
# Build assets
|
||||
FROM --platform=$BUILDPLATFORM node:25.7.0-alpine AS node
|
||||
FROM --platform=$BUILDPLATFORM node:25.8.0-alpine AS node
|
||||
|
||||
RUN npm install -g --force corepack && corepack enable
|
||||
|
||||
|
||||
Vendored
+2
-2
@@ -15,8 +15,10 @@ declare module 'vue' {
|
||||
AlertForm: typeof import('./components/Notification/AlertForm.vue')['default']
|
||||
Announcements: typeof import('./components/Announcements.vue')['default']
|
||||
BarChart: typeof import('./components/BarChart.vue')['default']
|
||||
'Carbon:add': typeof import('~icons/carbon/add')['default']
|
||||
'Carbon:caretDown': typeof import('~icons/carbon/caret-down')['default']
|
||||
'Carbon:circleSolid': typeof import('~icons/carbon/circle-solid')['default']
|
||||
'Carbon:close': typeof import('~icons/carbon/close')['default']
|
||||
'Carbon:information': typeof import('~icons/carbon/information')['default']
|
||||
'Carbon:logoKubernetes': typeof import('~icons/carbon/logo-kubernetes')['default']
|
||||
'Carbon:macShift': typeof import('~icons/carbon/mac-shift')['default']
|
||||
@@ -59,7 +61,6 @@ declare module 'vue' {
|
||||
HostList: typeof import('./components/HostList.vue')['default']
|
||||
HostLog: typeof import('./components/HostViewer/HostLog.vue')['default']
|
||||
HostMenu: typeof import('./components/HostMenu.vue')['default']
|
||||
'Ic:baselineFiberNew': typeof import('~icons/ic/baseline-fiber-new')['default']
|
||||
'Ic:sharpKeyboardReturn': typeof import('~icons/ic/sharp-keyboard-return')['default']
|
||||
IndeterminateBar: typeof import('./components/common/IndeterminateBar.vue')['default']
|
||||
'Ion:ellipsisVertical': typeof import('~icons/ion/ellipsis-vertical')['default']
|
||||
@@ -107,7 +108,6 @@ declare module 'vue' {
|
||||
'Mdi:cloudOutline': typeof import('~icons/mdi/cloud-outline')['default']
|
||||
'Mdi:cog': typeof import('~icons/mdi/cog')['default']
|
||||
'Mdi:contentCopy': typeof import('~icons/mdi/content-copy')['default']
|
||||
'Mdi:creation': typeof import('~icons/mdi/creation')['default']
|
||||
'Mdi:docker': typeof import('~icons/mdi/docker')['default']
|
||||
'Mdi:gauge': typeof import('~icons/mdi/gauge')['default']
|
||||
'Mdi:github': typeof import('~icons/mdi/github')['default']
|
||||
|
||||
@@ -57,6 +57,43 @@
|
||||
></div>
|
||||
</fieldset>
|
||||
|
||||
<!-- Custom Headers -->
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend text-lg">
|
||||
{{ $t("notifications.destination-form.headers") }}
|
||||
<span class="text-base-content/60 ml-2 text-sm font-normal">{{
|
||||
$t("notifications.destination-form.headers-hint")
|
||||
}}</span>
|
||||
</legend>
|
||||
<div class="space-y-2">
|
||||
<div v-for="(header, index) in headers" :key="header.key" class="flex items-center gap-2">
|
||||
<input
|
||||
v-model="header.name"
|
||||
type="text"
|
||||
class="input focus:input-primary flex-1 text-base"
|
||||
:placeholder="$t('notifications.destination-form.header-name')"
|
||||
/>
|
||||
<input
|
||||
v-model="header.value"
|
||||
type="text"
|
||||
class="input focus:input-primary flex-1 text-base"
|
||||
:placeholder="$t('notifications.destination-form.header-value')"
|
||||
/>
|
||||
<button type="button" class="btn btn-ghost btn-sm btn-square" @click="headers.splice(index, 1)">
|
||||
<carbon:close />
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-ghost btn-sm"
|
||||
@click="headers.push({ name: '', value: '', key: headerKeyCounter++ })"
|
||||
>
|
||||
<carbon:add />
|
||||
{{ $t("notifications.destination-form.add-header") }}
|
||||
</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<!-- Error -->
|
||||
<div v-if="error" class="alert alert-error">
|
||||
<span>{{ error }}</span>
|
||||
@@ -110,6 +147,12 @@ useFocus(nameInput, { initialValue: true });
|
||||
const webhookUrl = ref(destination?.url ?? "");
|
||||
const payloadFormat = ref<PayloadFormat>(isEditing ? "custom" : "slack");
|
||||
const template = ref(isEditing ? (destination?.template ?? "") : PAYLOAD_TEMPLATES[payloadFormat.value]);
|
||||
let headerKeyCounter = 0;
|
||||
const headers = ref<{ name: string; value: string; key: number }[]>(
|
||||
destination?.headers
|
||||
? Object.entries(destination.headers).map(([name, value]) => ({ name, value, key: headerKeyCounter++ }))
|
||||
: [],
|
||||
);
|
||||
const isTesting = ref(false);
|
||||
const isSaving = ref(false);
|
||||
const error = ref<string | null>(null);
|
||||
@@ -143,6 +186,12 @@ onScopeDispose(() => {
|
||||
templateEditorView?.destroy();
|
||||
});
|
||||
|
||||
function headersToRecord(): Record<string, string> | undefined {
|
||||
const filtered = headers.value.filter((h) => h.name.trim() && h.value.trim());
|
||||
if (filtered.length === 0) return undefined;
|
||||
return Object.fromEntries(filtered.map((h) => [h.name.trim(), h.value.trim()]));
|
||||
}
|
||||
|
||||
const canTest = computed(() => webhookUrl.value.trim().length > 0);
|
||||
|
||||
const isValidUrl = computed(() => {
|
||||
@@ -174,6 +223,7 @@ async function testDestination() {
|
||||
body: JSON.stringify({
|
||||
url: webhookUrl.value.trim(),
|
||||
template: template.value.trim() || undefined,
|
||||
headers: headersToRecord(),
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -198,6 +248,7 @@ async function saveDestination() {
|
||||
type: "webhook",
|
||||
url: webhookUrl.value.trim(),
|
||||
template: template.value.trim() || undefined,
|
||||
headers: headersToRecord(),
|
||||
};
|
||||
|
||||
const url = isEditing
|
||||
|
||||
@@ -19,6 +19,7 @@ export interface Dispatcher {
|
||||
type: string;
|
||||
url?: string;
|
||||
template?: string;
|
||||
headers?: Record<string, string>;
|
||||
prefix?: string;
|
||||
expiresAt?: string;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ The easiest way to set up Dozzle is to use the CLI and mount `docker.sock` file.
|
||||
::: code-group
|
||||
|
||||
```sh
|
||||
docker run -d -v /var/run/docker.sock:/var/run/docker.sock -p 8080:8080 amir20/dozzle:latest
|
||||
docker run -d -v /var/run/docker.sock:/var/run/docker.sock -v dozzle_data:/data -p 8080:8080 amir20/dozzle:latest
|
||||
```
|
||||
|
||||
```yaml [docker-compose.yml]
|
||||
@@ -26,6 +26,7 @@ services:
|
||||
image: amir20/dozzle:latest
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- dozzle_data:/data
|
||||
ports:
|
||||
- 8080:8080
|
||||
environment:
|
||||
@@ -37,6 +38,8 @@ services:
|
||||
#
|
||||
# Uncomment to enable authentication. See https://dozzle.dev/guide/authentication
|
||||
# - DOZZLE_AUTH_PROVIDER=simple
|
||||
volumes:
|
||||
dozzle_data:
|
||||
```
|
||||
|
||||
:::
|
||||
@@ -45,6 +48,9 @@ services:
|
||||
> Dozzle supports actions, such as stopping, starting, and restarting containers, or attaching to container shells. But they are disabled by default for security reasons. To enable them, uncomment the corresponding environment variables.
|
||||
> Dozzle also supports connecting to remote agents to monitor multiple Docker hosts. See [agent](/guide/agent) to learn more.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Dozzle stores notification settings and other data in `/data` inside the container. To persist these settings across container restarts, you need to mount a volume to `/data`. Without this mount, notification settings will be lost when the container is recreated. See the Docker Compose example above for the recommended volume configuration.
|
||||
|
||||
## Docker Swarm
|
||||
|
||||
Dozzle supports running in Swarm mode by deploying it on every node. To run Dozzle in Swarm mode, you can use the following configuration:
|
||||
|
||||
@@ -84,6 +84,8 @@ spec:
|
||||
```
|
||||
|
||||
This configuration creates a service account, a cluster role, and a cluster role binding to allow Dozzle to access the necessary Kubernetes resources. It also creates a deployment for Dozzle and exposes it via a service.
|
||||
> [!WARNING]
|
||||
> When deploying this with any GitOps tool (like Flux CD or Argo CD) in a specific namespace apart from `default`, make sure to change the **namespace** in the **ClusterRoleBinding Subject**
|
||||
|
||||
All other features are supported as well, including authentication, filtering, and more. You can use the same environment variables as you would in Docker to configure Dozzle in Kubernetes.
|
||||
|
||||
|
||||
@@ -36,8 +36,8 @@ require (
|
||||
github.com/yuin/goldmark v1.7.16
|
||||
go.yaml.in/yaml/v3 v3.0.4
|
||||
golang.org/x/crypto v0.48.0
|
||||
golang.org/x/sync v0.19.0
|
||||
google.golang.org/grpc v1.79.1
|
||||
golang.org/x/sync v0.20.0
|
||||
google.golang.org/grpc v1.79.2
|
||||
google.golang.org/protobuf v1.36.11
|
||||
k8s.io/api v0.35.2
|
||||
k8s.io/apimachinery v0.35.2
|
||||
@@ -138,7 +138,7 @@ require (
|
||||
sigs.k8s.io/yaml v1.6.0 // indirect
|
||||
)
|
||||
|
||||
go 1.26.0
|
||||
go 1.26.1
|
||||
|
||||
tool (
|
||||
github.com/air-verse/air
|
||||
|
||||
@@ -446,6 +446,8 @@ golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -516,6 +518,8 @@ google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
|
||||
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.0 h1:6Al3kEFFP9VJhRz3DID6quisgPnTeZVr4lep9kkxdPA=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.0/go.mod h1:QLvsjh0OIR0TYBeiu2bkWGTJBUNQ64st52iWj/yA93I=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.1/go.mod h1:YNKnb2OAApgYn2oYY47Rn7alMr1zWjb2U8Q0aoGWiNc=
|
||||
|
||||
@@ -529,6 +529,7 @@ func (c *Client) UpdateNotificationConfig(ctx context.Context, subscriptions []t
|
||||
Type: d.Type,
|
||||
Url: d.URL,
|
||||
Template: d.Template,
|
||||
Headers: d.Headers,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v6.33.4
|
||||
// protoc v7.34.0
|
||||
// source: rpc.proto
|
||||
|
||||
package pb
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.0
|
||||
// - protoc v6.33.4
|
||||
// - protoc v7.34.0
|
||||
// source: rpc.proto
|
||||
|
||||
package pb
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v6.33.4
|
||||
// protoc v7.34.0
|
||||
// source: types.proto
|
||||
|
||||
package pb
|
||||
@@ -935,6 +935,7 @@ type NotificationDispatcher struct {
|
||||
Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
|
||||
Url string `protobuf:"bytes,4,opt,name=url,proto3" json:"url,omitempty"`
|
||||
Template string `protobuf:"bytes,5,opt,name=template,proto3" json:"template,omitempty"`
|
||||
Headers map[string]string `protobuf:"bytes,6,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@@ -1004,6 +1005,13 @@ func (x *NotificationDispatcher) GetTemplate() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *NotificationDispatcher) GetHeaders() map[string]string {
|
||||
if x != nil {
|
||||
return x.Headers
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_types_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_types_proto_rawDesc = "" +
|
||||
@@ -1092,13 +1100,17 @@ const file_types_proto_rawDesc = "" +
|
||||
"\x13containerExpression\x18\x06 \x01(\tR\x13containerExpression\x12*\n" +
|
||||
"\x10metricExpression\x18\a \x01(\tR\x10metricExpression\x12\x1a\n" +
|
||||
"\bcooldown\x18\b \x01(\x05R\bcooldown\x12\"\n" +
|
||||
"\fsampleWindow\x18\t \x01(\x05R\fsampleWindow\"~\n" +
|
||||
"\fsampleWindow\x18\t \x01(\x05R\fsampleWindow\"\x83\x02\n" +
|
||||
"\x16NotificationDispatcher\x12\x0e\n" +
|
||||
"\x02id\x18\x01 \x01(\x05R\x02id\x12\x12\n" +
|
||||
"\x04name\x18\x02 \x01(\tR\x04name\x12\x12\n" +
|
||||
"\x04type\x18\x03 \x01(\tR\x04type\x12\x10\n" +
|
||||
"\x03url\x18\x04 \x01(\tR\x03url\x12\x1a\n" +
|
||||
"\btemplate\x18\x05 \x01(\tR\btemplate*3\n" +
|
||||
"\btemplate\x18\x05 \x01(\tR\btemplate\x12G\n" +
|
||||
"\aheaders\x18\x06 \x03(\v2-.protobuf.NotificationDispatcher.HeadersEntryR\aheaders\x1a:\n" +
|
||||
"\fHeadersEntry\x12\x10\n" +
|
||||
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
|
||||
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01*3\n" +
|
||||
"\x0fContainerAction\x12\t\n" +
|
||||
"\x05Start\x10\x00\x12\b\n" +
|
||||
"\x04Stop\x10\x01\x12\v\n" +
|
||||
@@ -1117,7 +1129,7 @@ func file_types_proto_rawDescGZIP() []byte {
|
||||
}
|
||||
|
||||
var file_types_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_types_proto_msgTypes = make([]protoimpl.MessageInfo, 13)
|
||||
var file_types_proto_msgTypes = make([]protoimpl.MessageInfo, 14)
|
||||
var file_types_proto_goTypes = []any{
|
||||
(ContainerAction)(0), // 0: protobuf.ContainerAction
|
||||
(*Container)(nil), // 1: protobuf.Container
|
||||
@@ -1133,25 +1145,27 @@ var file_types_proto_goTypes = []any{
|
||||
(*NotificationDispatcher)(nil), // 11: protobuf.NotificationDispatcher
|
||||
nil, // 12: protobuf.Container.LabelsEntry
|
||||
nil, // 13: protobuf.Host.LabelsEntry
|
||||
(*timestamppb.Timestamp)(nil), // 14: google.protobuf.Timestamp
|
||||
(*anypb.Any)(nil), // 15: google.protobuf.Any
|
||||
nil, // 14: protobuf.NotificationDispatcher.HeadersEntry
|
||||
(*timestamppb.Timestamp)(nil), // 15: google.protobuf.Timestamp
|
||||
(*anypb.Any)(nil), // 16: google.protobuf.Any
|
||||
}
|
||||
var file_types_proto_depIdxs = []int32{
|
||||
14, // 0: protobuf.Container.created:type_name -> google.protobuf.Timestamp
|
||||
14, // 1: protobuf.Container.started:type_name -> google.protobuf.Timestamp
|
||||
15, // 0: protobuf.Container.created:type_name -> google.protobuf.Timestamp
|
||||
15, // 1: protobuf.Container.started:type_name -> google.protobuf.Timestamp
|
||||
12, // 2: protobuf.Container.labels:type_name -> protobuf.Container.LabelsEntry
|
||||
2, // 3: protobuf.Container.stats:type_name -> protobuf.ContainerStat
|
||||
14, // 4: protobuf.Container.finished:type_name -> google.protobuf.Timestamp
|
||||
15, // 5: protobuf.LogEvent.message:type_name -> google.protobuf.Any
|
||||
14, // 6: protobuf.LogEvent.timestamp:type_name -> google.protobuf.Timestamp
|
||||
15, // 4: protobuf.Container.finished:type_name -> google.protobuf.Timestamp
|
||||
16, // 5: protobuf.LogEvent.message:type_name -> google.protobuf.Any
|
||||
15, // 6: protobuf.LogEvent.timestamp:type_name -> google.protobuf.Timestamp
|
||||
3, // 7: protobuf.GroupMessage.fragments:type_name -> protobuf.LogFragment
|
||||
14, // 8: protobuf.ContainerEvent.timestamp:type_name -> google.protobuf.Timestamp
|
||||
15, // 8: protobuf.ContainerEvent.timestamp:type_name -> google.protobuf.Timestamp
|
||||
13, // 9: protobuf.Host.labels:type_name -> protobuf.Host.LabelsEntry
|
||||
10, // [10:10] is the sub-list for method output_type
|
||||
10, // [10:10] is the sub-list for method input_type
|
||||
10, // [10:10] is the sub-list for extension type_name
|
||||
10, // [10:10] is the sub-list for extension extendee
|
||||
0, // [0:10] is the sub-list for field type_name
|
||||
14, // 10: protobuf.NotificationDispatcher.headers:type_name -> protobuf.NotificationDispatcher.HeadersEntry
|
||||
11, // [11:11] is the sub-list for method output_type
|
||||
11, // [11:11] is the sub-list for method input_type
|
||||
11, // [11:11] is the sub-list for extension type_name
|
||||
11, // [11:11] is the sub-list for extension extendee
|
||||
0, // [0:11] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_types_proto_init() }
|
||||
@@ -1165,7 +1179,7 @@ func file_types_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_types_proto_rawDesc), len(file_types_proto_rawDesc)),
|
||||
NumEnums: 1,
|
||||
NumMessages: 13,
|
||||
NumMessages: 14,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
||||
@@ -429,6 +429,7 @@ func (s *server) UpdateNotificationConfig(ctx context.Context, req *pb.UpdateNot
|
||||
Type: d.Type,
|
||||
URL: d.Url,
|
||||
Template: d.Template,
|
||||
Headers: d.Headers,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"math"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -86,6 +87,9 @@ func (g *EventGenerator) flushGroup(pendingGroup []*LogEvent) bool {
|
||||
|
||||
func (g *EventGenerator) processBuffer() {
|
||||
var pendingGroup []*LogEvent
|
||||
seenFirst := false
|
||||
var lastOrphanTimestamp int64
|
||||
orphanCount := 0
|
||||
|
||||
loop:
|
||||
for {
|
||||
@@ -95,8 +99,9 @@ loop:
|
||||
break loop
|
||||
}
|
||||
|
||||
// Complex logs are emitted immediately
|
||||
// Complex logs are emitted immediately and always mark seenFirst
|
||||
if !current.IsSimple() {
|
||||
seenFirst = true
|
||||
if !g.flushGroup(pendingGroup) {
|
||||
break loop
|
||||
}
|
||||
@@ -107,6 +112,24 @@ loop:
|
||||
continue
|
||||
}
|
||||
|
||||
// Skip leading simple events without a level that look like orphaned
|
||||
// continuation lines from a group already emitted in a prior fetch.
|
||||
// Only skip if they have a timestamp and are close in time, matching
|
||||
// the group continuation criteria.
|
||||
if !seenFirst && !current.HasLevel() && current.Timestamp > 0 {
|
||||
if lastOrphanTimestamp == 0 || math.Abs(float64(lastOrphanTimestamp-current.Timestamp)) < maxGroupTimeDelta {
|
||||
lastOrphanTimestamp = current.Timestamp
|
||||
orphanCount++
|
||||
continue
|
||||
}
|
||||
}
|
||||
if !seenFirst {
|
||||
if orphanCount > 0 {
|
||||
log.Debug().Int("count", orphanCount).Str("container", g.containerID).Msg("skipped orphaned continuation lines")
|
||||
}
|
||||
seenFirst = true
|
||||
}
|
||||
|
||||
// Simple log - peek ahead to decide grouping
|
||||
next := g.peek()
|
||||
|
||||
@@ -125,7 +148,7 @@ loop:
|
||||
|
||||
pendingGroup = append(pendingGroup, current)
|
||||
|
||||
if next == nil || !next.IsSimple() || !canContinueGroup(pendingGroup[0], next) {
|
||||
if next == nil || !next.IsSimple() || !canContinueGroup(pendingGroup[len(pendingGroup)-1], next) {
|
||||
if !g.flushGroup(pendingGroup) {
|
||||
break loop
|
||||
}
|
||||
@@ -154,32 +177,12 @@ func (g *EventGenerator) nextEvent() *LogEvent {
|
||||
|
||||
// canStartGroup checks if current can start a group with next
|
||||
func canStartGroup(current, next *LogEvent) bool {
|
||||
// Current must have a known level
|
||||
if !current.HasLevel() {
|
||||
return false
|
||||
}
|
||||
// Next must not have its own level (continuation)
|
||||
if next.HasLevel() {
|
||||
return false
|
||||
}
|
||||
// Must be close in time
|
||||
if !current.IsCloseToTime(next) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
return current.HasLevel() && canContinueGroup(current, next)
|
||||
}
|
||||
|
||||
// canContinueGroup checks if next can be added to a group started by first
|
||||
func canContinueGroup(first, next *LogEvent) bool {
|
||||
// Next must not have its own level (continuation)
|
||||
if next.HasLevel() {
|
||||
return false
|
||||
}
|
||||
// Must be close in time to the group leader
|
||||
if !first.IsCloseToTime(next) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
// canContinueGroup checks if next can be appended after prev in a group
|
||||
func canContinueGroup(prev, next *LogEvent) bool {
|
||||
return !next.HasLevel() && prev.IsCloseToTime(next)
|
||||
}
|
||||
|
||||
func (g *EventGenerator) consumeReader() {
|
||||
@@ -220,9 +223,8 @@ func createEvent(message string, streamType StdType) *LogEvent {
|
||||
h := fnv.New32a()
|
||||
h.Write([]byte(message))
|
||||
logEvent := &LogEvent{Id: h.Sum32(), Message: message, Stream: streamType.String(), Type: LogTypeSingle}
|
||||
if index := strings.IndexAny(message, " "); index != -1 {
|
||||
logId := message[:index]
|
||||
if timestamp, err := time.Parse(time.RFC3339Nano, logId); err == nil {
|
||||
if index := strings.IndexByte(message, ' '); index != -1 {
|
||||
if timestamp, err := time.Parse(time.RFC3339Nano, message[:index]); err == nil {
|
||||
logEvent.Timestamp = timestamp.UnixMilli()
|
||||
message = strings.TrimSuffix(message[index+1:], "\n")
|
||||
logEvent.Message = message
|
||||
|
||||
@@ -240,6 +240,114 @@ func TestEventGenerator_MixedLogs(t *testing.T) {
|
||||
assert.Equal(t, LogTypeSingle, event2.Type)
|
||||
}
|
||||
|
||||
func TestEventGenerator_SkipsLeadingOrphanedContinuationLines(t *testing.T) {
|
||||
// Simulate a pagination boundary where orphaned continuation lines
|
||||
// (no level, with timestamp) appear before the first real log entry.
|
||||
// These should be skipped as they belong to a group from a prior fetch.
|
||||
baseTime := "2020-05-13T18:55:37.772853839Z"
|
||||
messages := []string{
|
||||
baseTime + " at line 42", // orphan continuation (no level)
|
||||
baseTime + " in function foo", // orphan continuation (no level)
|
||||
baseTime + " ERROR: Next error", // real entry with level
|
||||
baseTime + " at line 99", // continuation of the real entry
|
||||
}
|
||||
|
||||
reader := &mockLogReader{
|
||||
messages: messages,
|
||||
types: []StdType{STDERR, STDERR, STDERR, STDERR},
|
||||
}
|
||||
|
||||
g := NewEventGenerator(context.Background(), reader, Container{Tty: false})
|
||||
event := <-g.Events
|
||||
|
||||
require.NotNil(t, event, "Expected event to not be nil")
|
||||
assert.Equal(t, LogTypeGroup, event.Type)
|
||||
|
||||
fragments, ok := event.Message.([]LogFragment)
|
||||
require.True(t, ok, "Expected Message to be []LogFragment")
|
||||
assert.Len(t, fragments, 2)
|
||||
assert.Equal(t, "ERROR: Next error", fragments[0].Message)
|
||||
assert.Equal(t, "at line 99", fragments[1].Message)
|
||||
}
|
||||
|
||||
func TestEventGenerator_DoesNotSkipLeadingLevellessLogsWithTimestampGap(t *testing.T) {
|
||||
// Leading lines without levels but far apart in time should NOT be skipped.
|
||||
// They are standalone logs, not orphaned group continuations.
|
||||
messages := []string{
|
||||
"2020-05-13T18:55:37.000Z some log without level",
|
||||
"2020-05-13T18:55:38.000Z another log without level",
|
||||
}
|
||||
|
||||
reader := &mockLogReader{
|
||||
messages: messages,
|
||||
types: []StdType{STDOUT, STDOUT},
|
||||
}
|
||||
|
||||
g := NewEventGenerator(context.Background(), reader, Container{Tty: false})
|
||||
|
||||
// First line is skipped (potential orphan), but the second is too far in time
|
||||
// so it should be emitted.
|
||||
event1 := <-g.Events
|
||||
require.NotNil(t, event1, "Expected event to not be nil")
|
||||
assert.Equal(t, LogTypeSingle, event1.Type)
|
||||
assert.Equal(t, "another log without level", event1.Message)
|
||||
}
|
||||
|
||||
func TestEventGenerator_AllOrphanedLinesProducesNoEvents(t *testing.T) {
|
||||
// If all lines are orphaned continuations, no events should be emitted.
|
||||
baseTime := "2020-05-13T18:55:37.772853839Z"
|
||||
messages := []string{
|
||||
baseTime + " at line 42",
|
||||
baseTime + " in function foo",
|
||||
baseTime + " in function bar",
|
||||
}
|
||||
|
||||
reader := &mockLogReader{
|
||||
messages: messages,
|
||||
types: []StdType{STDERR, STDERR, STDERR},
|
||||
}
|
||||
|
||||
g := NewEventGenerator(context.Background(), reader, Container{Tty: false})
|
||||
event, ok := <-g.Events
|
||||
|
||||
assert.False(t, ok, "Expected channel to be closed with no events")
|
||||
assert.Nil(t, event)
|
||||
}
|
||||
|
||||
func TestEventGenerator_OrphanedLinesFollowedByComplexLog(t *testing.T) {
|
||||
// Orphaned continuation lines should be skipped even when followed by a complex log.
|
||||
baseTime := "2020-05-13T18:55:37.772853839Z"
|
||||
messages := []string{
|
||||
baseTime + " at line 42",
|
||||
baseTime + " in function foo",
|
||||
baseTime + " {\"level\": \"info\", \"message\": \"test\"}",
|
||||
}
|
||||
|
||||
reader := &mockLogReader{
|
||||
messages: messages,
|
||||
types: []StdType{STDERR, STDERR, STDOUT},
|
||||
}
|
||||
|
||||
g := NewEventGenerator(context.Background(), reader, Container{Tty: false})
|
||||
event := <-g.Events
|
||||
|
||||
require.NotNil(t, event, "Expected event to not be nil")
|
||||
assert.Equal(t, LogTypeComplex, event.Type)
|
||||
}
|
||||
|
||||
func TestEventGenerator_DoesNotSkipLeadingLinesWithoutTimestamp(t *testing.T) {
|
||||
// Lines without timestamps (e.g., tty/raw input) should not be skipped
|
||||
// even if they lack a level.
|
||||
input := "some raw output"
|
||||
|
||||
g := NewEventGenerator(context.Background(), makeFakeReader(input, STDOUT), Container{Tty: true})
|
||||
event := <-g.Events
|
||||
|
||||
require.NotNil(t, event, "Expected event to not be nil")
|
||||
assert.Equal(t, input, event.Message)
|
||||
assert.Equal(t, LogTypeSingle, event.Type)
|
||||
}
|
||||
|
||||
func TestEventGenerator_NoGroupingWhenTimestampGap(t *testing.T) {
|
||||
// Messages with different timestamps (too far apart to group)
|
||||
messages := []string{
|
||||
|
||||
@@ -199,8 +199,13 @@ func (l *LogEvent) IsSimple() bool {
|
||||
return l.Type == LogTypeSingle || l.Type == LogTypeGroup
|
||||
}
|
||||
|
||||
// maxGroupTimeDelta is the maximum time difference (in milliseconds) between
|
||||
// consecutive log lines that can be grouped together. Docker can introduce
|
||||
// up to ~30ms of jitter between related log lines (e.g., a stack trace).
|
||||
const maxGroupTimeDelta = 50
|
||||
|
||||
func (l *LogEvent) IsCloseToTime(other *LogEvent) bool {
|
||||
return math.Abs(float64(l.Timestamp-other.Timestamp)) < 10
|
||||
return math.Abs(float64(l.Timestamp-other.Timestamp)) < maxGroupTimeDelta
|
||||
}
|
||||
|
||||
func (l *LogEvent) MessageId() int64 {
|
||||
|
||||
@@ -59,6 +59,7 @@ func (m *Manager) LoadConfig(r io.Reader) error {
|
||||
Type: d.Type,
|
||||
URL: d.URL,
|
||||
Template: d.Template,
|
||||
Headers: d.Headers,
|
||||
APIKey: d.APIKey,
|
||||
Prefix: d.Prefix,
|
||||
ExpiresAt: d.ExpiresAt,
|
||||
@@ -116,6 +117,7 @@ func (m *Manager) HandleNotificationConfig(subscriptions []types.SubscriptionCon
|
||||
Type: dc.Type,
|
||||
URL: dc.URL,
|
||||
Template: dc.Template,
|
||||
Headers: dc.Headers,
|
||||
APIKey: dc.APIKey,
|
||||
Prefix: dc.Prefix,
|
||||
ExpiresAt: dc.ExpiresAt,
|
||||
@@ -137,7 +139,7 @@ func (m *Manager) HandleNotificationConfig(subscriptions []types.SubscriptionCon
|
||||
func createDispatcher(config DispatcherConfig) (dispatcher.Dispatcher, error) {
|
||||
switch config.Type {
|
||||
case "webhook":
|
||||
return dispatcher.NewWebhookDispatcher(config.Name, config.URL, config.Template)
|
||||
return dispatcher.NewWebhookDispatcher(config.Name, config.URL, config.Template, config.Headers)
|
||||
case "cloud":
|
||||
return dispatcher.NewCloudDispatcher(config.Name, config.APIKey, config.Prefix, config.ExpiresAt)
|
||||
default:
|
||||
|
||||
@@ -24,16 +24,18 @@ type WebhookDispatcher struct {
|
||||
URL string
|
||||
Template *template.Template
|
||||
TemplateText string // Original template string for serialization
|
||||
Headers map[string]string
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
// NewWebhookDispatcher creates a new webhook dispatcher
|
||||
// If templateStr is empty, the notification will be marshaled as JSON directly
|
||||
func NewWebhookDispatcher(name, url, templateStr string) (*WebhookDispatcher, error) {
|
||||
func NewWebhookDispatcher(name, url, templateStr string, headers map[string]string) (*WebhookDispatcher, error) {
|
||||
w := &WebhookDispatcher{
|
||||
Name: name,
|
||||
URL: url,
|
||||
TemplateText: templateStr,
|
||||
Headers: headers,
|
||||
client: &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
},
|
||||
@@ -88,6 +90,9 @@ func (w *WebhookDispatcher) SendTest(ctx context.Context, notification types.Not
|
||||
return TestResult{Success: false, Error: fmt.Sprintf("failed to create request: %v", err)}
|
||||
}
|
||||
|
||||
for k, v := range w.Headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("User-Agent", UserAgent)
|
||||
|
||||
|
||||
@@ -152,8 +152,13 @@ func (m *Manager) UpdateSubscription(id int, updates map[string]any) error {
|
||||
SampleWindow: sub.SampleWindow,
|
||||
MetricCooldowns: sub.MetricCooldowns,
|
||||
MetricSampleBuffers: sub.MetricSampleBuffers,
|
||||
TriggeredContainerIDs: sub.TriggeredContainerIDs,
|
||||
}
|
||||
|
||||
// Preserve runtime stats (atomics can't be copied in struct literal)
|
||||
updated.TriggerCount.Store(sub.TriggerCount.Load())
|
||||
updated.LastTriggeredAt.Store(sub.LastTriggeredAt.Load())
|
||||
|
||||
// Apply updates to the clone
|
||||
for key, value := range updates {
|
||||
switch key {
|
||||
@@ -305,6 +310,7 @@ func (m *Manager) Dispatchers() []DispatcherConfig {
|
||||
Type: "webhook",
|
||||
URL: v.URL,
|
||||
Template: v.TemplateText,
|
||||
Headers: v.Headers,
|
||||
})
|
||||
case *dispatcher.CloudDispatcher:
|
||||
result = append(result, DispatcherConfig{
|
||||
|
||||
@@ -160,14 +160,15 @@ func (s *Subscription) CompileExpressions() error {
|
||||
|
||||
// DispatcherConfig represents a dispatcher configuration
|
||||
type DispatcherConfig struct {
|
||||
ID int `json:"id" yaml:"id"`
|
||||
Name string `json:"name" yaml:"name"`
|
||||
Type string `json:"type" yaml:"type"` // "webhook", "cloud"
|
||||
URL string `json:"url,omitempty" yaml:"url,omitempty"`
|
||||
Template string `json:"template,omitempty" yaml:"template,omitempty"` // Go template for custom payload format
|
||||
APIKey string `json:"apiKey,omitempty" yaml:"apiKey,omitempty"` // API key for cloud dispatcher
|
||||
Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"` // API key prefix for cloud dispatcher
|
||||
ExpiresAt *time.Time `json:"expiresAt,omitempty" yaml:"expiresAt,omitempty"`
|
||||
ID int `json:"id" yaml:"id"`
|
||||
Name string `json:"name" yaml:"name"`
|
||||
Type string `json:"type" yaml:"type"` // "webhook", "cloud"
|
||||
URL string `json:"url,omitempty" yaml:"url,omitempty"`
|
||||
Template string `json:"template,omitempty" yaml:"template,omitempty"` // Go template for custom payload format
|
||||
Headers map[string]string `json:"headers,omitempty" yaml:"headers,omitempty"` // Custom HTTP headers
|
||||
APIKey string `json:"apiKey,omitempty" yaml:"apiKey,omitempty"` // API key for cloud dispatcher
|
||||
Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"` // API key prefix for cloud dispatcher
|
||||
ExpiresAt *time.Time `json:"expiresAt,omitempty" yaml:"expiresAt,omitempty"`
|
||||
}
|
||||
|
||||
// Config represents the persisted notification configuration
|
||||
|
||||
@@ -137,7 +137,11 @@ func (h *handler) downloadLogs(w http.ResponseWriter, r *http.Request) {
|
||||
for _, c := range containers {
|
||||
// Create new file in zip for this container's logs
|
||||
fileName := fmt.Sprintf("%s-%s.log", c.containerService.Container.Name, nowFmt)
|
||||
f, err := zw.Create(fileName)
|
||||
f, err := zw.CreateHeader(&zip.FileHeader{
|
||||
Name: fileName,
|
||||
Modified: now,
|
||||
Method: zip.Deflate,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("error creating zip entry for container %s", c.id)
|
||||
return
|
||||
|
||||
@@ -37,13 +37,14 @@ type NotificationRuleResponse struct {
|
||||
}
|
||||
|
||||
type DispatcherResponse struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
URL *string `json:"url,omitempty"`
|
||||
Template *string `json:"template,omitempty"`
|
||||
Prefix *string `json:"prefix,omitempty"`
|
||||
ExpiresAt *time.Time `json:"expiresAt,omitempty"`
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
URL *string `json:"url,omitempty"`
|
||||
Template *string `json:"template,omitempty"`
|
||||
Headers map[string]string `json:"headers,omitempty"`
|
||||
Prefix *string `json:"prefix,omitempty"`
|
||||
ExpiresAt *time.Time `json:"expiresAt,omitempty"`
|
||||
}
|
||||
|
||||
type NotificationRuleInput struct {
|
||||
@@ -69,10 +70,11 @@ type NotificationRuleUpdateInput struct {
|
||||
}
|
||||
|
||||
type DispatcherInput struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
URL *string `json:"url,omitempty"`
|
||||
Template *string `json:"template,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
URL *string `json:"url,omitempty"`
|
||||
Template *string `json:"template,omitempty"`
|
||||
Headers map[string]string `json:"headers,omitempty"`
|
||||
}
|
||||
|
||||
type PreviewInput struct {
|
||||
@@ -92,8 +94,9 @@ type PreviewResult struct {
|
||||
}
|
||||
|
||||
type TestWebhookInput struct {
|
||||
URL string `json:"url"`
|
||||
Template *string `json:"template,omitempty"`
|
||||
URL string `json:"url"`
|
||||
Template *string `json:"template,omitempty"`
|
||||
Headers map[string]string `json:"headers,omitempty"`
|
||||
}
|
||||
|
||||
type TestWebhookResult struct {
|
||||
@@ -142,6 +145,10 @@ func dispatcherConfigToResponse(d *notification.DispatcherConfig) *DispatcherRes
|
||||
if d.Template != "" {
|
||||
template = &d.Template
|
||||
}
|
||||
var headers map[string]string
|
||||
if len(d.Headers) > 0 {
|
||||
headers = d.Headers
|
||||
}
|
||||
var prefix *string
|
||||
if d.Prefix != "" {
|
||||
prefix = &d.Prefix
|
||||
@@ -152,6 +159,7 @@ func dispatcherConfigToResponse(d *notification.DispatcherConfig) *DispatcherRes
|
||||
Type: d.Type,
|
||||
URL: url,
|
||||
Template: template,
|
||||
Headers: headers,
|
||||
Prefix: prefix,
|
||||
ExpiresAt: d.ExpiresAt,
|
||||
}
|
||||
@@ -369,7 +377,7 @@ func (h *handler) createDispatcher(w http.ResponseWriter, r *http.Request) {
|
||||
if input.Template != nil {
|
||||
templateStr = *input.Template
|
||||
}
|
||||
webhook, err := dispatcher.NewWebhookDispatcher(input.Name, url, templateStr)
|
||||
webhook, err := dispatcher.NewWebhookDispatcher(input.Name, url, templateStr, input.Headers)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
@@ -382,13 +390,17 @@ func (h *handler) createDispatcher(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
id := h.hostService.AddDispatcher(d)
|
||||
|
||||
writeJSON(w, http.StatusCreated, &DispatcherResponse{
|
||||
resp := &DispatcherResponse{
|
||||
ID: id,
|
||||
Name: input.Name,
|
||||
Type: input.Type,
|
||||
URL: input.URL,
|
||||
Template: input.Template,
|
||||
})
|
||||
}
|
||||
if len(input.Headers) > 0 {
|
||||
resp.Headers = input.Headers
|
||||
}
|
||||
writeJSON(w, http.StatusCreated, resp)
|
||||
}
|
||||
|
||||
func (h *handler) updateDispatcher(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -415,7 +427,7 @@ func (h *handler) updateDispatcher(w http.ResponseWriter, r *http.Request) {
|
||||
if input.Template != nil {
|
||||
templateStr = *input.Template
|
||||
}
|
||||
webhook, err := dispatcher.NewWebhookDispatcher(input.Name, url, templateStr)
|
||||
webhook, err := dispatcher.NewWebhookDispatcher(input.Name, url, templateStr, input.Headers)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
@@ -428,13 +440,17 @@ func (h *handler) updateDispatcher(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
h.hostService.UpdateDispatcher(id, d)
|
||||
|
||||
writeJSON(w, http.StatusOK, &DispatcherResponse{
|
||||
resp := &DispatcherResponse{
|
||||
ID: id,
|
||||
Name: input.Name,
|
||||
Type: input.Type,
|
||||
URL: input.URL,
|
||||
Template: input.Template,
|
||||
})
|
||||
}
|
||||
if len(input.Headers) > 0 {
|
||||
resp.Headers = input.Headers
|
||||
}
|
||||
writeJSON(w, http.StatusOK, resp)
|
||||
}
|
||||
|
||||
func (h *handler) deleteDispatcher(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -596,7 +612,7 @@ func (h *handler) testWebhook(w http.ResponseWriter, r *http.Request) {
|
||||
templateStr = *input.Template
|
||||
}
|
||||
|
||||
webhook, err := dispatcher.NewWebhookDispatcher("test", input.URL, templateStr)
|
||||
webhook, err := dispatcher.NewWebhookDispatcher("test", input.URL, templateStr, input.Headers)
|
||||
if err != nil {
|
||||
errStr := err.Error()
|
||||
writeJSON(w, http.StatusOK, &TestWebhookResult{
|
||||
|
||||
@@ -240,6 +240,11 @@ notifications:
|
||||
format-custom: Brugerdefineret
|
||||
template: Skabelon
|
||||
template-hint: Go skabelon syntaks
|
||||
headers: Brugerdefinerede Headers
|
||||
headers-hint: Valgfrie HTTP-headers (f.eks. Authorization)
|
||||
header-name: Header-navn
|
||||
header-value: Header-værdi
|
||||
add-header: Tilføj Header
|
||||
test: Test
|
||||
test-success: Test succesfuld
|
||||
cancel: Annuller
|
||||
|
||||
@@ -240,6 +240,11 @@ notifications:
|
||||
format-custom: Benutzerdefiniert
|
||||
template: Vorlage
|
||||
template-hint: Go-Template-Syntax
|
||||
headers: Benutzerdefinierte Header
|
||||
headers-hint: Optionale HTTP-Header (z.B. Authorization)
|
||||
header-name: Header-Name
|
||||
header-value: Header-Wert
|
||||
add-header: Header hinzufügen
|
||||
test: Testen
|
||||
test-success: Test erfolgreich
|
||||
cancel: Abbrechen
|
||||
|
||||
@@ -249,6 +249,11 @@ notifications:
|
||||
format-custom: Custom
|
||||
template: Template
|
||||
template-hint: Go template syntax
|
||||
headers: Custom Headers
|
||||
headers-hint: Optional HTTP headers (e.g., Authorization)
|
||||
header-name: Header name
|
||||
header-value: Header value
|
||||
add-header: Add Header
|
||||
test: Test
|
||||
test-success: Test successful
|
||||
cancel: Cancel
|
||||
|
||||
@@ -240,6 +240,11 @@ notifications:
|
||||
format-custom: Personalizado
|
||||
template: Plantilla
|
||||
template-hint: Sintaxis de plantilla Go
|
||||
headers: Encabezados Personalizados
|
||||
headers-hint: Encabezados HTTP opcionales (ej. Authorization)
|
||||
header-name: Nombre del encabezado
|
||||
header-value: Valor del encabezado
|
||||
add-header: Añadir Encabezado
|
||||
test: Probar
|
||||
test-success: Prueba exitosa
|
||||
cancel: Cancelar
|
||||
|
||||
@@ -240,6 +240,11 @@ notifications:
|
||||
format-custom: Personnalisé
|
||||
template: Modèle
|
||||
template-hint: Syntaxe de modèle Go
|
||||
headers: En-têtes Personnalisés
|
||||
headers-hint: En-têtes HTTP optionnels (ex. Authorization)
|
||||
header-name: Nom de l'en-tête
|
||||
header-value: Valeur de l'en-tête
|
||||
add-header: Ajouter un En-tête
|
||||
test: Tester
|
||||
test-success: Test réussi
|
||||
cancel: Annuler
|
||||
|
||||
@@ -252,6 +252,11 @@ notifications:
|
||||
format-custom: Kustom
|
||||
template: Template
|
||||
template-hint: Sintaks template Go
|
||||
headers: Header Kustom
|
||||
headers-hint: Header HTTP opsional (mis. Authorization)
|
||||
header-name: Nama header
|
||||
header-value: Nilai header
|
||||
add-header: Tambah Header
|
||||
test: Test
|
||||
test-success: Test berhasil
|
||||
cancel: Batal
|
||||
|
||||
@@ -240,6 +240,11 @@ notifications:
|
||||
format-custom: Personalizzato
|
||||
template: Template
|
||||
template-hint: Sintassi template Go
|
||||
headers: Header Personalizzati
|
||||
headers-hint: Header HTTP opzionali (es. Authorization)
|
||||
header-name: Nome header
|
||||
header-value: Valore header
|
||||
add-header: Aggiungi Header
|
||||
test: Test
|
||||
test-success: Test riuscito
|
||||
cancel: Annulla
|
||||
|
||||
@@ -243,6 +243,11 @@ notifications:
|
||||
format-custom: 사용자 정의
|
||||
template: 템플릿
|
||||
template-hint: Go 템플릿 구문
|
||||
headers: 사용자 정의 헤더
|
||||
headers-hint: "선택적 HTTP 헤더 (예: Authorization)"
|
||||
header-name: 헤더 이름
|
||||
header-value: 헤더 값
|
||||
add-header: 헤더 추가
|
||||
test: 테스트
|
||||
test-success: 테스트 성공
|
||||
cancel: 취소
|
||||
|
||||
@@ -241,6 +241,11 @@ notifications:
|
||||
format-custom: Aangepast
|
||||
template: Sjabloon
|
||||
template-hint: Go-sjabloonsyntaxis
|
||||
headers: Aangepaste Headers
|
||||
headers-hint: Optionele HTTP-headers (bijv. Authorization)
|
||||
header-name: Headernaam
|
||||
header-value: Headerwaarde
|
||||
add-header: Header toevoegen
|
||||
test: Testen
|
||||
test-success: Test geslaagd
|
||||
cancel: Annuleren
|
||||
|
||||
@@ -247,6 +247,11 @@ notifications:
|
||||
format-custom: Własny
|
||||
template: Szablon
|
||||
template-hint: Składnia szablonu Go
|
||||
headers: Niestandardowe Nagłówki
|
||||
headers-hint: Opcjonalne nagłówki HTTP (np. Authorization)
|
||||
header-name: Nazwa nagłówka
|
||||
header-value: Wartość nagłówka
|
||||
add-header: Dodaj Nagłówek
|
||||
test: Test
|
||||
test-success: Test zakończony pomyślnie
|
||||
cancel: Anuluj
|
||||
|
||||
@@ -249,6 +249,11 @@ notifications:
|
||||
format-custom: Personalizado
|
||||
template: Modelo
|
||||
template-hint: Sintaxe de modelo Go
|
||||
headers: Cabeçalhos Personalizados
|
||||
headers-hint: Cabeçalhos HTTP opcionais (ex. Authorization)
|
||||
header-name: Nome do cabeçalho
|
||||
header-value: Valor do cabeçalho
|
||||
add-header: Adicionar Cabeçalho
|
||||
test: Testar
|
||||
test-success: Teste bem-sucedido
|
||||
cancel: Cancelar
|
||||
|
||||
@@ -239,6 +239,11 @@ notifications:
|
||||
format-custom: Personalizado
|
||||
template: Template
|
||||
template-hint: Sintaxe de template Go
|
||||
headers: Cabeçalhos Personalizados
|
||||
headers-hint: Cabeçalhos HTTP opcionais (ex. Authorization)
|
||||
header-name: Nome do cabeçalho
|
||||
header-value: Valor do cabeçalho
|
||||
add-header: Adicionar Cabeçalho
|
||||
test: Testar
|
||||
test-success: Teste bem-sucedido
|
||||
cancel: Cancelar
|
||||
|
||||
@@ -240,6 +240,11 @@ notifications:
|
||||
format-custom: Пользовательский
|
||||
template: Шаблон
|
||||
template-hint: Синтаксис шаблона Go
|
||||
headers: Пользовательские Заголовки
|
||||
headers-hint: Необязательные HTTP-заголовки (напр. Authorization)
|
||||
header-name: Имя заголовка
|
||||
header-value: Значение заголовка
|
||||
add-header: Добавить Заголовок
|
||||
test: Тест
|
||||
test-success: Тест успешен
|
||||
cancel: Отмена
|
||||
|
||||
@@ -245,6 +245,11 @@ notifications:
|
||||
format-custom: Po meri
|
||||
template: Predloga
|
||||
template-hint: Sintaksa predloge Go
|
||||
headers: Prilagojene Glave
|
||||
headers-hint: Neobvezne HTTP glave (npr. Authorization)
|
||||
header-name: Ime glave
|
||||
header-value: Vrednost glave
|
||||
add-header: Dodaj Glavo
|
||||
test: Test
|
||||
test-success: Test uspešen
|
||||
cancel: Prekliči
|
||||
|
||||
@@ -240,6 +240,11 @@ notifications:
|
||||
format-custom: Özel
|
||||
template: Şablon
|
||||
template-hint: Go şablon söz dizimi
|
||||
headers: Özel Başlıklar
|
||||
headers-hint: İsteğe bağlı HTTP başlıkları (ör. Authorization)
|
||||
header-name: Başlık adı
|
||||
header-value: Başlık değeri
|
||||
add-header: Başlık Ekle
|
||||
test: Test
|
||||
test-success: Test başarılı
|
||||
cancel: İptal
|
||||
|
||||
@@ -243,6 +243,11 @@ notifications:
|
||||
format-custom: 自訂
|
||||
template: 範本
|
||||
template-hint: Go 範本語法
|
||||
headers: 自訂標頭
|
||||
headers-hint: 選填的 HTTP 標頭(例如 Authorization)
|
||||
header-name: 標頭名稱
|
||||
header-value: 標頭值
|
||||
add-header: 新增標頭
|
||||
test: 測試
|
||||
test-success: 測試成功
|
||||
cancel: 取消
|
||||
|
||||
@@ -240,6 +240,11 @@ notifications:
|
||||
format-custom: 自定义
|
||||
template: 模板
|
||||
template-hint: Go 模板语法
|
||||
headers: 自定义请求头
|
||||
headers-hint: 可选的 HTTP 请求头(如 Authorization)
|
||||
header-name: 请求头名称
|
||||
header-value: 请求头值
|
||||
add-header: 添加请求头
|
||||
test: 测试
|
||||
test-success: 测试成功
|
||||
cancel: 取消
|
||||
|
||||
+8
-8
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "dozzle",
|
||||
"version": "10.0.7",
|
||||
"version": "10.1.0",
|
||||
"description": "Realtime log viewer for docker containers.",
|
||||
"homepage": "https://github.com/amir20/dozzle#readme",
|
||||
"bugs": {
|
||||
"url": "https://github.com/amir20/dozzle/issues"
|
||||
},
|
||||
"packageManager": "pnpm@10.30.3",
|
||||
"packageManager": "pnpm@10.31.0",
|
||||
"type": "module",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -40,7 +40,7 @@
|
||||
"@iconify-json/carbon": "^1.2.19",
|
||||
"@iconify-json/cil": "^1.2.3",
|
||||
"@iconify-json/ic": "^1.2.4",
|
||||
"@iconify-json/material-symbols": "^1.2.59",
|
||||
"@iconify-json/material-symbols": "^1.2.60",
|
||||
"@iconify-json/mdi": "^1.2.3",
|
||||
"@iconify-json/mdi-light": "^1.2.2",
|
||||
"@iconify-json/octicon": "^1.2.21",
|
||||
@@ -73,22 +73,22 @@
|
||||
"unplugin-vue-macros": "^2.14.5",
|
||||
"vite": "7.3.1",
|
||||
"vite-plugin-vue-layouts": "^0.11.0",
|
||||
"vite-svg-loader": "^5.1.0",
|
||||
"vite-svg-loader": "^5.1.1",
|
||||
"vitepress": "1.6.4",
|
||||
"vue": "^3.5.29",
|
||||
"vue-i18n": "^11.2.8",
|
||||
"vue-i18n": "^11.3.0",
|
||||
"vue-router": "^5.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@apache-arrow/esnext-esm": "^21.1.0",
|
||||
"@iconify-json/ion": "^1.2.6",
|
||||
"@iconify-json/material-symbols-light": "^1.2.59",
|
||||
"@iconify-json/material-symbols-light": "^1.2.60",
|
||||
"@iconify-json/ri": "^1.2.10",
|
||||
"@iconify-json/svg-spinners": "^1.2.4",
|
||||
"@pinia/testing": "^1.0.3",
|
||||
"@playwright/test": "^1.58.2",
|
||||
"@types/lodash.debounce": "^4.0.9",
|
||||
"@types/node": "^25.3.3",
|
||||
"@types/node": "^25.3.5",
|
||||
"@vitejs/plugin-vue": "6.0.4",
|
||||
"@vue/compiler-sfc": "^3.5.29",
|
||||
"@vue/test-utils": "^2.4.6",
|
||||
@@ -97,7 +97,7 @@
|
||||
"concurrently": "^9.2.1",
|
||||
"eventsourcemock": "^2.0.0",
|
||||
"jsdom": "^28.1.0",
|
||||
"lint-staged": "^16.3.1",
|
||||
"lint-staged": "^16.3.2",
|
||||
"prettier": "^3.8.1",
|
||||
"prettier-plugin-tailwindcss": "^0.7.2",
|
||||
"simple-git-hooks": "^2.13.1",
|
||||
|
||||
Generated
+124
-95
@@ -45,8 +45,8 @@ importers:
|
||||
specifier: ^1.2.4
|
||||
version: 1.2.4
|
||||
'@iconify-json/material-symbols':
|
||||
specifier: ^1.2.59
|
||||
version: 1.2.59
|
||||
specifier: ^1.2.60
|
||||
version: 1.2.60
|
||||
'@iconify-json/mdi':
|
||||
specifier: ^1.2.3
|
||||
version: 1.2.3
|
||||
@@ -61,7 +61,7 @@ importers:
|
||||
version: 1.2.2
|
||||
'@intlify/unplugin-vue-i18n':
|
||||
specifier: ^11.0.7
|
||||
version: 11.0.7(@vue/compiler-dom@3.5.29)(eslint@9.19.0(jiti@2.6.1))(rollup@4.53.3)(typescript@5.9.3)(vue-i18n@11.2.8(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))
|
||||
version: 11.0.7(@vue/compiler-dom@3.5.29)(eslint@9.19.0(jiti@2.6.1))(rollup@4.53.3)(typescript@5.9.3)(vue-i18n@11.3.0(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))
|
||||
'@lezer/highlight':
|
||||
specifier: ^1.2.3
|
||||
version: 1.2.3
|
||||
@@ -70,7 +70,7 @@ importers:
|
||||
version: 0.5.19(tailwindcss@4.2.1)
|
||||
'@tailwindcss/vite':
|
||||
specifier: 4.2.1
|
||||
version: 4.2.1(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))
|
||||
version: 4.2.1(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))
|
||||
'@vueuse/components':
|
||||
specifier: ^14.2.1
|
||||
version: 14.2.1(vue@3.5.29(typescript@5.9.3))
|
||||
@@ -136,25 +136,25 @@ importers:
|
||||
version: 31.0.0(vue@3.5.29(typescript@5.9.3))
|
||||
unplugin-vue-macros:
|
||||
specifier: ^2.14.5
|
||||
version: 2.14.5(@vueuse/core@14.2.1(vue@3.5.29(typescript@5.9.3)))(esbuild@0.27.1)(rollup@4.53.3)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))(vue-tsc@3.2.5(typescript@5.9.3))(vue@3.5.29(typescript@5.9.3))
|
||||
version: 2.14.5(@vueuse/core@14.2.1(vue@3.5.29(typescript@5.9.3)))(esbuild@0.27.1)(rollup@4.53.3)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))(vue-tsc@3.2.5(typescript@5.9.3))(vue@3.5.29(typescript@5.9.3))
|
||||
vite:
|
||||
specifier: 7.3.1
|
||||
version: 7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2)
|
||||
version: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2)
|
||||
vite-plugin-vue-layouts:
|
||||
specifier: ^0.11.0
|
||||
version: 0.11.0(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))(vue-router@5.0.3(@vue/compiler-sfc@3.5.29)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))
|
||||
version: 0.11.0(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))(vue-router@5.0.3(@vue/compiler-sfc@3.5.29)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))
|
||||
vite-svg-loader:
|
||||
specifier: ^5.1.0
|
||||
version: 5.1.0(vue@3.5.29(typescript@5.9.3))
|
||||
specifier: ^5.1.1
|
||||
version: 5.1.1(vue@3.5.29(typescript@5.9.3))
|
||||
vitepress:
|
||||
specifier: 1.6.4
|
||||
version: 1.6.4(@algolia/client-search@5.23.4)(@types/node@25.3.3)(fuse.js@7.1.0)(lightningcss@1.31.1)(postcss@8.5.6)(react@18.3.1)(search-insights@2.17.3)(sortablejs@1.15.7)(terser@5.39.0)(typescript@5.9.3)
|
||||
version: 1.6.4(@algolia/client-search@5.23.4)(@types/node@25.3.5)(fuse.js@7.1.0)(lightningcss@1.31.1)(postcss@8.5.6)(react@18.3.1)(search-insights@2.17.3)(sortablejs@1.15.7)(terser@5.39.0)(typescript@5.9.3)
|
||||
vue:
|
||||
specifier: ^3.5.29
|
||||
version: 3.5.29(typescript@5.9.3)
|
||||
vue-i18n:
|
||||
specifier: ^11.2.8
|
||||
version: 11.2.8(vue@3.5.29(typescript@5.9.3))
|
||||
specifier: ^11.3.0
|
||||
version: 11.3.0(vue@3.5.29(typescript@5.9.3))
|
||||
vue-router:
|
||||
specifier: ^5.0.3
|
||||
version: 5.0.3(@vue/compiler-sfc@3.5.29)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))
|
||||
@@ -166,8 +166,8 @@ importers:
|
||||
specifier: ^1.2.6
|
||||
version: 1.2.6
|
||||
'@iconify-json/material-symbols-light':
|
||||
specifier: ^1.2.59
|
||||
version: 1.2.59
|
||||
specifier: ^1.2.60
|
||||
version: 1.2.60
|
||||
'@iconify-json/ri':
|
||||
specifier: ^1.2.10
|
||||
version: 1.2.10
|
||||
@@ -184,11 +184,11 @@ importers:
|
||||
specifier: ^4.0.9
|
||||
version: 4.0.9
|
||||
'@types/node':
|
||||
specifier: ^25.3.3
|
||||
version: 25.3.3
|
||||
specifier: ^25.3.5
|
||||
version: 25.3.5
|
||||
'@vitejs/plugin-vue':
|
||||
specifier: 6.0.4
|
||||
version: 6.0.4(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))(vue@3.5.29(typescript@5.9.3))
|
||||
version: 6.0.4(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))(vue@3.5.29(typescript@5.9.3))
|
||||
'@vue/compiler-sfc':
|
||||
specifier: ^3.5.29
|
||||
version: 3.5.29
|
||||
@@ -211,8 +211,8 @@ importers:
|
||||
specifier: ^28.1.0
|
||||
version: 28.1.0
|
||||
lint-staged:
|
||||
specifier: ^16.3.1
|
||||
version: 16.3.1
|
||||
specifier: ^16.3.2
|
||||
version: 16.3.2
|
||||
prettier:
|
||||
specifier: ^3.8.1
|
||||
version: 3.8.1
|
||||
@@ -224,13 +224,13 @@ importers:
|
||||
version: 2.13.1
|
||||
ts-node:
|
||||
specifier: ^10.9.2
|
||||
version: 10.9.2(@types/node@25.3.3)(typescript@5.9.3)
|
||||
version: 10.9.2(@types/node@25.3.5)(typescript@5.9.3)
|
||||
typescript:
|
||||
specifier: ^5.9.3
|
||||
version: 5.9.3
|
||||
vitest:
|
||||
specifier: ^4.0.18
|
||||
version: 4.0.18(@types/node@25.3.3)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2)
|
||||
version: 4.0.18(@types/node@25.3.5)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2)
|
||||
vue-component-type-helpers:
|
||||
specifier: 3.2.5
|
||||
version: 3.2.5
|
||||
@@ -1003,11 +1003,11 @@ packages:
|
||||
'@iconify-json/ion@1.2.6':
|
||||
resolution: {integrity: sha512-JftEXKfjvJNn3SrGeSBrG/waRkjeTpLdMLNLwpAX4NgI14QgJoAeXEh2iZjNPqioAkeIgErX4Bi6mnFwpjk3BQ==}
|
||||
|
||||
'@iconify-json/material-symbols-light@1.2.59':
|
||||
resolution: {integrity: sha512-0dO9tGoHI9aV8Y9J0vI5oH2AsFiN8GrWoCECUqokBqoH/8Y8lpTGzDs2vW1qomNQmiMrqxxvz+u/wkQAVGX2OA==}
|
||||
'@iconify-json/material-symbols-light@1.2.60':
|
||||
resolution: {integrity: sha512-rBdUMsTK9v8BPI5zM9/2eFwX0lHCYyki4FfcaHCnMDk0BcnfvGueEqFP1TyfUGk4peQpmGHR44ZJ0jW2bPAxBA==}
|
||||
|
||||
'@iconify-json/material-symbols@1.2.59':
|
||||
resolution: {integrity: sha512-difuedW4jZyiDDu2SySjPCr+UsM65PRkEg3zUuKz0YRGMkNyBsk3R6j9s/ofP1NaKr2y32XxrzTawmnJZbzOAw==}
|
||||
'@iconify-json/material-symbols@1.2.60':
|
||||
resolution: {integrity: sha512-bmVrnz/9KJNh/j+nO3pyxzo0h8iENIKxv5RASDURhjKdPI53rRcKN7E2Gmwi25k9CBJ+IC6L9l0AGgngeqyRuw==}
|
||||
|
||||
'@iconify-json/mdi-light@1.2.2':
|
||||
resolution: {integrity: sha512-86UV9uyNve8zRFWiPrOrrDp9GDzsZM7plYV/on4VjgLLqXlyriuy541eHZB7LIOzTUyIPVli7QiUpBbTtBhsFw==}
|
||||
@@ -1048,18 +1048,30 @@ packages:
|
||||
vue-i18n:
|
||||
optional: true
|
||||
|
||||
'@intlify/core-base@11.2.8':
|
||||
resolution: {integrity: sha512-nBq6Y1tVkjIUsLsdOjDSJj4AsjvD0UG3zsg9Fyc+OivwlA/oMHSKooUy9tpKj0HqZ+NWFifweHavdljlBLTwdA==}
|
||||
'@intlify/core-base@11.3.0':
|
||||
resolution: {integrity: sha512-NNX5jIwF4TJBe7RtSKDMOA6JD9mp2mRcBHAwt2X+Q8PvnZub0yj5YYXlFu2AcESdgQpEv/5Yx2uOCV/yh7YkZg==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/devtools-types@11.3.0':
|
||||
resolution: {integrity: sha512-G9CNL4WpANWVdUjubOIIS7/D2j/0j+1KJmhBJxHilWNKr9mmt3IjFV3Hq4JoBP23uOoC5ynxz/FHZ42M+YxfGw==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/message-compiler@11.2.8':
|
||||
resolution: {integrity: sha512-A5n33doOjmHsBtCN421386cG1tWp5rpOjOYPNsnpjIJbQ4POF0QY2ezhZR9kr0boKwaHjbOifvyQvHj2UTrDFQ==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/message-compiler@11.3.0':
|
||||
resolution: {integrity: sha512-RAJp3TMsqohg/Wa7bVF3cChRhecSYBLrTCQSj7j0UtWVFLP+6iEJoE2zb7GU5fp+fmG5kCbUdzhmlAUCWXiUJw==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/shared@11.2.8':
|
||||
resolution: {integrity: sha512-l6e4NZyUgv8VyXXH4DbuucFOBmxLF56C/mqh2tvApbzl2Hrhi1aTDcuv5TKdxzfHYmpO3UB0Cz04fgDT9vszfw==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/shared@11.3.0':
|
||||
resolution: {integrity: sha512-LC6P/uay7rXL5zZ5+5iRJfLs/iUN8apu9tm8YqQVmW3Uq3X4A0dOFUIDuAmB7gAC29wTHOS3EiN/IosNSz0eNQ==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/unplugin-vue-i18n@11.0.7':
|
||||
resolution: {integrity: sha512-wswKprS1D8VfnxxVhKxug5wa3MbDSOcCoXOBjnzhMK+6NfP6h6UI8pFqSBIvcW8nPDuzweTc0Sk3PeBCcubfoQ==}
|
||||
engines: {node: '>= 20'}
|
||||
@@ -1623,10 +1635,6 @@ packages:
|
||||
peerDependencies:
|
||||
vite: ^5.2.0 || ^6 || ^7
|
||||
|
||||
'@trysound/sax@0.2.0':
|
||||
resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
|
||||
'@tsconfig/node10@1.0.11':
|
||||
resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==}
|
||||
|
||||
@@ -1690,8 +1698,8 @@ packages:
|
||||
'@types/node@24.10.9':
|
||||
resolution: {integrity: sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw==}
|
||||
|
||||
'@types/node@25.3.3':
|
||||
resolution: {integrity: sha512-DpzbrH7wIcBaJibpKo9nnSQL0MTRdnWttGyE5haGwK86xgMOkFLp7vEyfQPGLOJh5wNYiJ3V9PmUMDhV9u8kkQ==}
|
||||
'@types/node@25.3.5':
|
||||
resolution: {integrity: sha512-oX8xrhvpiyRCQkG1MFchB09f+cXftgIXb3a7UUa4Y3wpmZPw5tyZGTLWhlESOLq1Rq6oDlc8npVU2/9xiCuXMA==}
|
||||
|
||||
'@types/unist@3.0.3':
|
||||
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
|
||||
@@ -3170,8 +3178,8 @@ packages:
|
||||
resolution: {integrity: sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
|
||||
lint-staged@16.3.1:
|
||||
resolution: {integrity: sha512-bqvvquXzFBAlSbluugR4KXAe4XnO/QZcKVszpkBtqLWa2KEiVy8n6Xp38OeUbv/gOJOX4Vo9u5pFt/ADvbm42Q==}
|
||||
lint-staged@16.3.2:
|
||||
resolution: {integrity: sha512-xKqhC2AeXLwiAHXguxBjuChoTTWFC6Pees0SHPwOpwlvI3BH7ZADFPddAdN3pgo3aiKgPUx/bxE78JfUnxQnlg==}
|
||||
engines: {node: '>=20.17'}
|
||||
hasBin: true
|
||||
|
||||
@@ -3614,6 +3622,10 @@ packages:
|
||||
rxjs@7.8.2:
|
||||
resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==}
|
||||
|
||||
sax@1.5.0:
|
||||
resolution: {integrity: sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==}
|
||||
engines: {node: '>=11.0.0'}
|
||||
|
||||
saxes@6.0.0:
|
||||
resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
|
||||
engines: {node: '>=v12.22.7'}
|
||||
@@ -3768,8 +3780,8 @@ packages:
|
||||
resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
svgo@3.3.2:
|
||||
resolution: {integrity: sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==}
|
||||
svgo@3.3.3:
|
||||
resolution: {integrity: sha512-+wn7I4p7YgJhHs38k2TNjy1vCfPIfLIJWR5MnCStsN8WuuTcBnRKcMHQLMM2ijxGZmDoZwNv8ipl5aTTen62ng==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
hasBin: true
|
||||
|
||||
@@ -4052,8 +4064,8 @@ packages:
|
||||
vue: ^3.2.4
|
||||
vue-router: ^4.0.11
|
||||
|
||||
vite-svg-loader@5.1.0:
|
||||
resolution: {integrity: sha512-M/wqwtOEjgb956/+m5ZrYT/Iq6Hax0OakWbokj8+9PXOnB7b/4AxESHieEtnNEy7ZpjsjYW1/5nK8fATQMmRxw==}
|
||||
vite-svg-loader@5.1.1:
|
||||
resolution: {integrity: sha512-RPzcXA/EpKJA0585x58DBgs7my2VfeJ+j2j1EoHY4Zh82Y7hV4cR1fElgy2aZi85+QSrcLLoTStQ5uZjD68u+Q==}
|
||||
peerDependencies:
|
||||
vue: '>=3.2.13'
|
||||
|
||||
@@ -4183,8 +4195,8 @@ packages:
|
||||
vue-component-type-helpers@3.2.5:
|
||||
resolution: {integrity: sha512-tkvNr+bU8+xD/onAThIe7CHFvOJ/BO6XCOrxMzeytJq40nTfpGDJuVjyCM8ccGZKfAbGk2YfuZyDMXM56qheZQ==}
|
||||
|
||||
vue-i18n@11.2.8:
|
||||
resolution: {integrity: sha512-vJ123v/PXCZntd6Qj5Jumy7UBmIuE92VrtdX+AXr+1WzdBHojiBxnAxdfctUFL+/JIN+VQH4BhsfTtiGsvVObg==}
|
||||
vue-i18n@11.3.0:
|
||||
resolution: {integrity: sha512-1J+xDfDJTLhDxElkd3+XUhT7FYSZd2b8pa7IRKGxhWH/8yt6PTvi3xmWhGwhYT5EaXdatui11pF2R6tL73/zPA==}
|
||||
engines: {node: '>= 16'}
|
||||
peerDependencies:
|
||||
vue: ^3.0.0
|
||||
@@ -4931,11 +4943,11 @@ snapshots:
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
|
||||
'@iconify-json/material-symbols-light@1.2.59':
|
||||
'@iconify-json/material-symbols-light@1.2.60':
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
|
||||
'@iconify-json/material-symbols@1.2.59':
|
||||
'@iconify-json/material-symbols@1.2.60':
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
|
||||
@@ -4975,7 +4987,7 @@ snapshots:
|
||||
'@iconify/types': 2.0.0
|
||||
mlly: 1.8.0
|
||||
|
||||
'@intlify/bundle-utils@11.0.7(vue-i18n@11.2.8(vue@3.5.29(typescript@5.9.3)))':
|
||||
'@intlify/bundle-utils@11.0.7(vue-i18n@11.3.0(vue@3.5.29(typescript@5.9.3)))':
|
||||
dependencies:
|
||||
'@intlify/message-compiler': 11.2.8
|
||||
'@intlify/shared': 11.2.8
|
||||
@@ -4987,26 +4999,39 @@ snapshots:
|
||||
source-map-js: 1.2.1
|
||||
yaml-eslint-parser: 1.3.0
|
||||
optionalDependencies:
|
||||
vue-i18n: 11.2.8(vue@3.5.29(typescript@5.9.3))
|
||||
vue-i18n: 11.3.0(vue@3.5.29(typescript@5.9.3))
|
||||
|
||||
'@intlify/core-base@11.2.8':
|
||||
'@intlify/core-base@11.3.0':
|
||||
dependencies:
|
||||
'@intlify/message-compiler': 11.2.8
|
||||
'@intlify/shared': 11.2.8
|
||||
'@intlify/devtools-types': 11.3.0
|
||||
'@intlify/message-compiler': 11.3.0
|
||||
'@intlify/shared': 11.3.0
|
||||
|
||||
'@intlify/devtools-types@11.3.0':
|
||||
dependencies:
|
||||
'@intlify/core-base': 11.3.0
|
||||
'@intlify/shared': 11.3.0
|
||||
|
||||
'@intlify/message-compiler@11.2.8':
|
||||
dependencies:
|
||||
'@intlify/shared': 11.2.8
|
||||
source-map-js: 1.2.1
|
||||
|
||||
'@intlify/message-compiler@11.3.0':
|
||||
dependencies:
|
||||
'@intlify/shared': 11.3.0
|
||||
source-map-js: 1.2.1
|
||||
|
||||
'@intlify/shared@11.2.8': {}
|
||||
|
||||
'@intlify/unplugin-vue-i18n@11.0.7(@vue/compiler-dom@3.5.29)(eslint@9.19.0(jiti@2.6.1))(rollup@4.53.3)(typescript@5.9.3)(vue-i18n@11.2.8(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))':
|
||||
'@intlify/shared@11.3.0': {}
|
||||
|
||||
'@intlify/unplugin-vue-i18n@11.0.7(@vue/compiler-dom@3.5.29)(eslint@9.19.0(jiti@2.6.1))(rollup@4.53.3)(typescript@5.9.3)(vue-i18n@11.3.0(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.9.1(eslint@9.19.0(jiti@2.6.1))
|
||||
'@intlify/bundle-utils': 11.0.7(vue-i18n@11.2.8(vue@3.5.29(typescript@5.9.3)))
|
||||
'@intlify/bundle-utils': 11.0.7(vue-i18n@11.3.0(vue@3.5.29(typescript@5.9.3)))
|
||||
'@intlify/shared': 11.2.8
|
||||
'@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.2.8)(@vue/compiler-dom@3.5.29)(vue-i18n@11.2.8(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))
|
||||
'@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.2.8)(@vue/compiler-dom@3.5.29)(vue-i18n@11.3.0(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))
|
||||
'@rollup/pluginutils': 5.3.0(rollup@4.53.3)
|
||||
'@typescript-eslint/scope-manager': 8.42.0
|
||||
'@typescript-eslint/typescript-estree': 8.42.0(typescript@5.9.3)
|
||||
@@ -5017,7 +5042,7 @@ snapshots:
|
||||
unplugin: 2.3.11
|
||||
vue: 3.5.29(typescript@5.9.3)
|
||||
optionalDependencies:
|
||||
vue-i18n: 11.2.8(vue@3.5.29(typescript@5.9.3))
|
||||
vue-i18n: 11.3.0(vue@3.5.29(typescript@5.9.3))
|
||||
transitivePeerDependencies:
|
||||
- '@vue/compiler-dom'
|
||||
- eslint
|
||||
@@ -5025,14 +5050,14 @@ snapshots:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
'@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.2.8)(@vue/compiler-dom@3.5.29)(vue-i18n@11.2.8(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))':
|
||||
'@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.2.8)(@vue/compiler-dom@3.5.29)(vue-i18n@11.3.0(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@babel/parser': 7.29.0
|
||||
optionalDependencies:
|
||||
'@intlify/shared': 11.2.8
|
||||
'@vue/compiler-dom': 3.5.29
|
||||
vue: 3.5.29(typescript@5.9.3)
|
||||
vue-i18n: 11.2.8(vue@3.5.29(typescript@5.9.3))
|
||||
vue-i18n: 11.3.0(vue@3.5.29(typescript@5.9.3))
|
||||
|
||||
'@isaacs/cliui@8.0.2':
|
||||
dependencies:
|
||||
@@ -5430,14 +5455,12 @@ snapshots:
|
||||
postcss-selector-parser: 6.0.10
|
||||
tailwindcss: 4.2.1
|
||||
|
||||
'@tailwindcss/vite@4.2.1(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))':
|
||||
'@tailwindcss/vite@4.2.1(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))':
|
||||
dependencies:
|
||||
'@tailwindcss/node': 4.2.1
|
||||
'@tailwindcss/oxide': 4.2.1
|
||||
tailwindcss: 4.2.1
|
||||
vite: 7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2)
|
||||
|
||||
'@trysound/sax@0.2.0': {}
|
||||
vite: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2)
|
||||
|
||||
'@tsconfig/node10@1.0.11': {}
|
||||
|
||||
@@ -5500,7 +5523,7 @@ snapshots:
|
||||
dependencies:
|
||||
undici-types: 7.16.0
|
||||
|
||||
'@types/node@25.3.3':
|
||||
'@types/node@25.3.5':
|
||||
dependencies:
|
||||
undici-types: 7.18.2
|
||||
|
||||
@@ -5551,15 +5574,15 @@ snapshots:
|
||||
|
||||
'@ungap/structured-clone@1.3.0': {}
|
||||
|
||||
'@vitejs/plugin-vue@5.2.4(vite@5.4.21(@types/node@25.3.3)(lightningcss@1.31.1)(terser@5.39.0))(vue@3.5.29(typescript@5.9.3))':
|
||||
'@vitejs/plugin-vue@5.2.4(vite@5.4.21(@types/node@25.3.5)(lightningcss@1.31.1)(terser@5.39.0))(vue@3.5.29(typescript@5.9.3))':
|
||||
dependencies:
|
||||
vite: 5.4.21(@types/node@25.3.3)(lightningcss@1.31.1)(terser@5.39.0)
|
||||
vite: 5.4.21(@types/node@25.3.5)(lightningcss@1.31.1)(terser@5.39.0)
|
||||
vue: 3.5.29(typescript@5.9.3)
|
||||
|
||||
'@vitejs/plugin-vue@6.0.4(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))(vue@3.5.29(typescript@5.9.3))':
|
||||
'@vitejs/plugin-vue@6.0.4(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))(vue@3.5.29(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@rolldown/pluginutils': 1.0.0-rc.2
|
||||
vite: 7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2)
|
||||
vite: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2)
|
||||
vue: 3.5.29(typescript@5.9.3)
|
||||
|
||||
'@vitest/expect@4.0.18':
|
||||
@@ -5571,13 +5594,13 @@ snapshots:
|
||||
chai: 6.2.1
|
||||
tinyrainbow: 3.0.3
|
||||
|
||||
'@vitest/mocker@4.0.18(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))':
|
||||
'@vitest/mocker@4.0.18(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))':
|
||||
dependencies:
|
||||
'@vitest/spy': 4.0.18
|
||||
estree-walker: 3.0.3
|
||||
magic-string: 0.30.21
|
||||
optionalDependencies:
|
||||
vite: 7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2)
|
||||
vite: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2)
|
||||
|
||||
'@vitest/pretty-format@4.0.18':
|
||||
dependencies:
|
||||
@@ -5739,12 +5762,12 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- vue
|
||||
|
||||
'@vue-macros/devtools@0.4.1(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))':
|
||||
'@vue-macros/devtools@0.4.1(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))':
|
||||
dependencies:
|
||||
sirv: 3.0.1
|
||||
vue: 3.5.29(typescript@5.9.3)
|
||||
optionalDependencies:
|
||||
vite: 7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2)
|
||||
vite: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2)
|
||||
transitivePeerDependencies:
|
||||
- typescript
|
||||
|
||||
@@ -7150,7 +7173,7 @@ snapshots:
|
||||
lightningcss-win32-arm64-msvc: 1.31.1
|
||||
lightningcss-win32-x64-msvc: 1.31.1
|
||||
|
||||
lint-staged@16.3.1:
|
||||
lint-staged@16.3.2:
|
||||
dependencies:
|
||||
commander: 14.0.3
|
||||
listr2: 9.0.5
|
||||
@@ -7583,6 +7606,8 @@ snapshots:
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
sax@1.5.0: {}
|
||||
|
||||
saxes@6.0.0:
|
||||
dependencies:
|
||||
xmlchars: 2.2.0
|
||||
@@ -7744,15 +7769,15 @@ snapshots:
|
||||
dependencies:
|
||||
has-flag: 4.0.0
|
||||
|
||||
svgo@3.3.2:
|
||||
svgo@3.3.3:
|
||||
dependencies:
|
||||
'@trysound/sax': 0.2.0
|
||||
commander: 7.2.0
|
||||
css-select: 5.1.0
|
||||
css-tree: 2.3.1
|
||||
css-what: 6.1.0
|
||||
csso: 5.0.5
|
||||
picocolors: 1.1.1
|
||||
sax: 1.5.0
|
||||
|
||||
symbol-tree@3.2.4: {}
|
||||
|
||||
@@ -7829,14 +7854,14 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- typescript
|
||||
|
||||
ts-node@10.9.2(@types/node@25.3.3)(typescript@5.9.3):
|
||||
ts-node@10.9.2(@types/node@25.3.5)(typescript@5.9.3):
|
||||
dependencies:
|
||||
'@cspotcode/source-map-support': 0.8.1
|
||||
'@tsconfig/node10': 1.0.11
|
||||
'@tsconfig/node12': 1.0.11
|
||||
'@tsconfig/node14': 1.0.3
|
||||
'@tsconfig/node16': 1.0.4
|
||||
'@types/node': 25.3.3
|
||||
'@types/node': 25.3.5
|
||||
acorn: 8.14.1
|
||||
acorn-walk: 8.3.4
|
||||
arg: 4.1.3
|
||||
@@ -7935,12 +7960,12 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@vueuse/core': 14.2.1(vue@3.5.29(typescript@5.9.3))
|
||||
|
||||
unplugin-combine@1.2.1(esbuild@0.27.1)(rollup@4.53.3)(unplugin@1.16.1)(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2)):
|
||||
unplugin-combine@1.2.1(esbuild@0.27.1)(rollup@4.53.3)(unplugin@1.16.1)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2)):
|
||||
optionalDependencies:
|
||||
esbuild: 0.27.1
|
||||
rollup: 4.53.3
|
||||
unplugin: 1.16.1
|
||||
vite: 7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2)
|
||||
vite: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2)
|
||||
|
||||
unplugin-icons@23.0.1(@vue/compiler-sfc@3.5.29):
|
||||
dependencies:
|
||||
@@ -7983,7 +8008,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- vue
|
||||
|
||||
unplugin-vue-macros@2.14.5(@vueuse/core@14.2.1(vue@3.5.29(typescript@5.9.3)))(esbuild@0.27.1)(rollup@4.53.3)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))(vue-tsc@3.2.5(typescript@5.9.3))(vue@3.5.29(typescript@5.9.3)):
|
||||
unplugin-vue-macros@2.14.5(@vueuse/core@14.2.1(vue@3.5.29(typescript@5.9.3)))(esbuild@0.27.1)(rollup@4.53.3)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))(vue-tsc@3.2.5(typescript@5.9.3))(vue@3.5.29(typescript@5.9.3)):
|
||||
dependencies:
|
||||
'@vue-macros/better-define': 1.11.4(vue@3.5.29(typescript@5.9.3))
|
||||
'@vue-macros/boolean-prop': 0.5.5(vue@3.5.29(typescript@5.9.3))
|
||||
@@ -7998,7 +8023,7 @@ snapshots:
|
||||
'@vue-macros/define-render': 1.6.6(vue@3.5.29(typescript@5.9.3))
|
||||
'@vue-macros/define-slots': 1.2.6(vue@3.5.29(typescript@5.9.3))
|
||||
'@vue-macros/define-stylex': 0.2.3(vue@3.5.29(typescript@5.9.3))
|
||||
'@vue-macros/devtools': 0.4.1(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))
|
||||
'@vue-macros/devtools': 0.4.1(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))
|
||||
'@vue-macros/export-expose': 0.3.5(vue@3.5.29(typescript@5.9.3))
|
||||
'@vue-macros/export-props': 0.6.5(vue@3.5.29(typescript@5.9.3))
|
||||
'@vue-macros/export-render': 0.3.5(vue@3.5.29(typescript@5.9.3))
|
||||
@@ -8015,7 +8040,7 @@ snapshots:
|
||||
'@vue-macros/short-vmodel': 1.5.5(vue@3.5.29(typescript@5.9.3))
|
||||
'@vue-macros/volar': 0.30.15(typescript@5.9.3)(vue-tsc@3.2.5(typescript@5.9.3))(vue@3.5.29(typescript@5.9.3))
|
||||
unplugin: 1.16.1
|
||||
unplugin-combine: 1.2.1(esbuild@0.27.1)(rollup@4.53.3)(unplugin@1.16.1)(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))
|
||||
unplugin-combine: 1.2.1(esbuild@0.27.1)(rollup@4.53.3)(unplugin@1.16.1)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))
|
||||
unplugin-vue-define-options: 1.5.5(vue@3.5.29(typescript@5.9.3))
|
||||
vue: 3.5.29(typescript@5.9.3)
|
||||
transitivePeerDependencies:
|
||||
@@ -8071,33 +8096,36 @@ snapshots:
|
||||
'@types/unist': 3.0.3
|
||||
vfile-message: 4.0.2
|
||||
|
||||
vite-plugin-vue-layouts@0.11.0(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))(vue-router@5.0.3(@vue/compiler-sfc@3.5.29)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3)):
|
||||
vite-plugin-vue-layouts@0.11.0(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))(vue-router@5.0.3(@vue/compiler-sfc@3.5.29)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3)):
|
||||
dependencies:
|
||||
debug: 4.4.0
|
||||
fast-glob: 3.3.3
|
||||
vite: 7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2)
|
||||
vite: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2)
|
||||
vue: 3.5.29(typescript@5.9.3)
|
||||
vue-router: 5.0.3(@vue/compiler-sfc@3.5.29)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
vite-svg-loader@5.1.0(vue@3.5.29(typescript@5.9.3)):
|
||||
vite-svg-loader@5.1.1(vue@3.5.29(typescript@5.9.3)):
|
||||
dependencies:
|
||||
svgo: 3.3.2
|
||||
debug: 4.4.3
|
||||
svgo: 3.3.3
|
||||
vue: 3.5.29(typescript@5.9.3)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
vite@5.4.21(@types/node@25.3.3)(lightningcss@1.31.1)(terser@5.39.0):
|
||||
vite@5.4.21(@types/node@25.3.5)(lightningcss@1.31.1)(terser@5.39.0):
|
||||
dependencies:
|
||||
esbuild: 0.25.10
|
||||
postcss: 8.5.6
|
||||
rollup: 4.52.4
|
||||
optionalDependencies:
|
||||
'@types/node': 25.3.3
|
||||
'@types/node': 25.3.5
|
||||
fsevents: 2.3.3
|
||||
lightningcss: 1.31.1
|
||||
terser: 5.39.0
|
||||
|
||||
vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2):
|
||||
vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2):
|
||||
dependencies:
|
||||
esbuild: 0.27.1
|
||||
fdir: 6.5.0(picomatch@4.0.3)
|
||||
@@ -8106,7 +8134,7 @@ snapshots:
|
||||
rollup: 4.53.3
|
||||
tinyglobby: 0.2.15
|
||||
optionalDependencies:
|
||||
'@types/node': 25.3.3
|
||||
'@types/node': 25.3.5
|
||||
fsevents: 2.3.3
|
||||
jiti: 2.6.1
|
||||
lightningcss: 1.31.1
|
||||
@@ -8114,7 +8142,7 @@ snapshots:
|
||||
tsx: 4.19.2
|
||||
yaml: 2.8.2
|
||||
|
||||
vitepress@1.6.4(@algolia/client-search@5.23.4)(@types/node@25.3.3)(fuse.js@7.1.0)(lightningcss@1.31.1)(postcss@8.5.6)(react@18.3.1)(search-insights@2.17.3)(sortablejs@1.15.7)(terser@5.39.0)(typescript@5.9.3):
|
||||
vitepress@1.6.4(@algolia/client-search@5.23.4)(@types/node@25.3.5)(fuse.js@7.1.0)(lightningcss@1.31.1)(postcss@8.5.6)(react@18.3.1)(search-insights@2.17.3)(sortablejs@1.15.7)(terser@5.39.0)(typescript@5.9.3):
|
||||
dependencies:
|
||||
'@docsearch/css': 3.8.2
|
||||
'@docsearch/js': 3.8.2(@algolia/client-search@5.23.4)(react@18.3.1)(search-insights@2.17.3)
|
||||
@@ -8123,7 +8151,7 @@ snapshots:
|
||||
'@shikijs/transformers': 2.5.0
|
||||
'@shikijs/types': 2.5.0
|
||||
'@types/markdown-it': 14.1.2
|
||||
'@vitejs/plugin-vue': 5.2.4(vite@5.4.21(@types/node@25.3.3)(lightningcss@1.31.1)(terser@5.39.0))(vue@3.5.29(typescript@5.9.3))
|
||||
'@vitejs/plugin-vue': 5.2.4(vite@5.4.21(@types/node@25.3.5)(lightningcss@1.31.1)(terser@5.39.0))(vue@3.5.29(typescript@5.9.3))
|
||||
'@vue/devtools-api': 7.7.2
|
||||
'@vue/shared': 3.5.18
|
||||
'@vueuse/core': 12.8.2(typescript@5.9.3)
|
||||
@@ -8132,7 +8160,7 @@ snapshots:
|
||||
mark.js: 8.11.1
|
||||
minisearch: 7.1.2
|
||||
shiki: 2.5.0
|
||||
vite: 5.4.21(@types/node@25.3.3)(lightningcss@1.31.1)(terser@5.39.0)
|
||||
vite: 5.4.21(@types/node@25.3.5)(lightningcss@1.31.1)(terser@5.39.0)
|
||||
vue: 3.5.29(typescript@5.9.3)
|
||||
optionalDependencies:
|
||||
postcss: 8.5.6
|
||||
@@ -8163,10 +8191,10 @@ snapshots:
|
||||
- typescript
|
||||
- universal-cookie
|
||||
|
||||
vitest@4.0.18(@types/node@25.3.3)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2):
|
||||
vitest@4.0.18(@types/node@25.3.5)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2):
|
||||
dependencies:
|
||||
'@vitest/expect': 4.0.18
|
||||
'@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))
|
||||
'@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2))
|
||||
'@vitest/pretty-format': 4.0.18
|
||||
'@vitest/runner': 4.0.18
|
||||
'@vitest/snapshot': 4.0.18
|
||||
@@ -8183,10 +8211,10 @@ snapshots:
|
||||
tinyexec: 1.0.2
|
||||
tinyglobby: 0.2.15
|
||||
tinyrainbow: 3.0.3
|
||||
vite: 7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2)
|
||||
vite: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.39.0)(tsx@4.19.2)(yaml@2.8.2)
|
||||
why-is-node-running: 2.3.0
|
||||
optionalDependencies:
|
||||
'@types/node': 25.3.3
|
||||
'@types/node': 25.3.5
|
||||
jsdom: 28.1.0
|
||||
transitivePeerDependencies:
|
||||
- jiti
|
||||
@@ -8207,10 +8235,11 @@ snapshots:
|
||||
|
||||
vue-component-type-helpers@3.2.5: {}
|
||||
|
||||
vue-i18n@11.2.8(vue@3.5.29(typescript@5.9.3)):
|
||||
vue-i18n@11.3.0(vue@3.5.29(typescript@5.9.3)):
|
||||
dependencies:
|
||||
'@intlify/core-base': 11.2.8
|
||||
'@intlify/shared': 11.2.8
|
||||
'@intlify/core-base': 11.3.0
|
||||
'@intlify/devtools-types': 11.3.0
|
||||
'@intlify/shared': 11.3.0
|
||||
'@vue/devtools-api': 6.6.4
|
||||
vue: 3.5.29(typescript@5.9.3)
|
||||
|
||||
|
||||
@@ -111,4 +111,5 @@ message NotificationDispatcher {
|
||||
string type = 3;
|
||||
string url = 4;
|
||||
string template = 5;
|
||||
map<string, string> headers = 6;
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ type DispatcherConfig struct {
|
||||
Type string
|
||||
URL string
|
||||
Template string
|
||||
Headers map[string]string
|
||||
APIKey string
|
||||
Prefix string
|
||||
ExpiresAt *time.Time
|
||||
|
||||
Reference in New Issue
Block a user