@appscode/design-system 2.17.87 → 2.17.91-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/vue-components/index.ts +18 -0
- package/vue-components/styles/base/utilities/_grid.scss +22 -0
- package/vue-components/styles/base/utilities/_typography.scss +30 -0
- package/vue-components/styles/components/_badge-tags.scss +10 -8
- package/vue-components/styles/components/charts/_recoverable-window.scss +15 -0
- package/vue-components/v3/button/SegmentedControl.vue +64 -0
- package/vue-components/v3/cards/ConfirmNameCard.vue +201 -0
- package/vue-components/v3/cards/DetailCard.vue +58 -0
- package/vue-components/v3/cards/RadioCard.vue +162 -0
- package/vue-components/v3/cards/StatCard.vue +50 -0
- package/vue-components/v3/cards/SummaryCard.vue +176 -0
- package/vue-components/v3/cards/TableCard.vue +61 -0
- package/vue-components/v3/charts/RecoverableWindow.vue +240 -0
- package/vue-components/v3/charts/RecoverableWindowTimeline.vue +953 -0
- package/vue-components/v3/charts/ScheduledMarker.vue +18 -0
- package/vue-components/v3/charts/TimelineTrack.vue +405 -0
- package/vue-components/v3/charts/timeline.ts +142 -0
- package/vue-components/v3/charts/types.ts +51 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
interface Props {
|
|
3
|
+
label: string;
|
|
4
|
+
value?: string | number;
|
|
5
|
+
suffix?: string;
|
|
6
|
+
progress?: number;
|
|
7
|
+
progressColor?: "success" | "info" | "warning" | "danger";
|
|
8
|
+
modifierClasses?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
withDefaults(defineProps<Props>(), {
|
|
12
|
+
value: "",
|
|
13
|
+
suffix: "",
|
|
14
|
+
progressColor: "success",
|
|
15
|
+
modifierClasses: "",
|
|
16
|
+
});
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<div class="is-flex is-flex-direction-column gap-8 p-12 b-1 is-rounded-8 bg-white is-clipped" :class="modifierClasses">
|
|
21
|
+
<div class="is-flex is-justify-content-space-between is-align-items-flex-start gap-8">
|
|
22
|
+
<p class="heading has-text-grey mb-0 tracking-normal">{{ label }}</p>
|
|
23
|
+
<slot name="badge" />
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<div class="is-flex-grow-1">
|
|
27
|
+
<slot>
|
|
28
|
+
<p class="is-flex is-flex-wrap-wrap is-align-items-baseline gap-4">
|
|
29
|
+
<strong class="text-code font-28">{{ value }}</strong>
|
|
30
|
+
<span v-if="suffix" class="has-text-grey">{{ suffix }}</span>
|
|
31
|
+
</p>
|
|
32
|
+
</slot>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<progress
|
|
36
|
+
v-if="progress !== undefined"
|
|
37
|
+
class="progress height-6 mb-0"
|
|
38
|
+
:class="`is-${progressColor}`"
|
|
39
|
+
:value="progress"
|
|
40
|
+
max="100"
|
|
41
|
+
/>
|
|
42
|
+
|
|
43
|
+
<div
|
|
44
|
+
v-if="$slots.footer"
|
|
45
|
+
class="is-flex is-justify-content-space-between is-align-items-center gap-8 text-xs has-text-grey"
|
|
46
|
+
>
|
|
47
|
+
<slot name="footer" />
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
</template>
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import HeroiconsClipboardDocumentCheck from "~icons/heroicons/clipboard-document-check";
|
|
3
|
+
|
|
4
|
+
interface SummaryItem {
|
|
5
|
+
// unique key; also used for the `item-<key>` slot
|
|
6
|
+
key?: string;
|
|
7
|
+
label: string;
|
|
8
|
+
value?: string | number;
|
|
9
|
+
// muted text shown after the value, e.g. "/ 20m SLA target"
|
|
10
|
+
suffix?: string;
|
|
11
|
+
// colors the value (and the tile for "warning" / "danger")
|
|
12
|
+
type?: "default" | "success" | "warning" | "danger";
|
|
13
|
+
// render the value in monospace font
|
|
14
|
+
mono?: boolean;
|
|
15
|
+
modifierClasses?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface Props {
|
|
19
|
+
title?: string;
|
|
20
|
+
// shown as a tag at the top right, e.g. "Workflow ID: #pitr-wf-94022"
|
|
21
|
+
tag?: string;
|
|
22
|
+
items?: SummaryItem[];
|
|
23
|
+
// items per row on desktop
|
|
24
|
+
columns?: 1 | 2 | 3 | 4;
|
|
25
|
+
showIcon?: boolean;
|
|
26
|
+
modifierClasses?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
withDefaults(defineProps<Props>(), {
|
|
30
|
+
title: "",
|
|
31
|
+
tag: "",
|
|
32
|
+
items: () => [],
|
|
33
|
+
columns: 3,
|
|
34
|
+
showIcon: true,
|
|
35
|
+
modifierClasses: "",
|
|
36
|
+
});
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<template>
|
|
40
|
+
<div class="summary-card" :class="modifierClasses">
|
|
41
|
+
<div
|
|
42
|
+
v-if="title || tag || $slots.header"
|
|
43
|
+
class="sc-header is-flex is-justify-content-space-between is-align-items-center is-flex-wrap-wrap gap-8"
|
|
44
|
+
>
|
|
45
|
+
<slot name="header">
|
|
46
|
+
<h5 class="sc-title is-flex is-align-items-center gap-12 mb-0">
|
|
47
|
+
<slot name="icon">
|
|
48
|
+
<HeroiconsClipboardDocumentCheck v-if="showIcon" class="sc-icon" />
|
|
49
|
+
</slot>
|
|
50
|
+
{{ title }}
|
|
51
|
+
</h5>
|
|
52
|
+
<span v-if="tag" class="sc-tag">{{ tag }}</span>
|
|
53
|
+
</slot>
|
|
54
|
+
</div>
|
|
55
|
+
|
|
56
|
+
<div class="sc-grid" :style="{ '--sc-columns': columns }">
|
|
57
|
+
<div
|
|
58
|
+
v-for="(item, idx) in items"
|
|
59
|
+
:key="item.key ?? idx"
|
|
60
|
+
class="sc-item"
|
|
61
|
+
:class="[`is-${item.type ?? 'default'}`, item.modifierClasses]"
|
|
62
|
+
>
|
|
63
|
+
<p class="sc-label mb-4">{{ item.label }}</p>
|
|
64
|
+
<slot :name="`item-${item.key ?? idx}`" :item="item">
|
|
65
|
+
<p class="sc-value mb-0" :class="{ 'is-mono': item.mono }">
|
|
66
|
+
{{ item.value }}
|
|
67
|
+
<span v-if="item.suffix" class="sc-suffix">{{ item.suffix }}</span>
|
|
68
|
+
</p>
|
|
69
|
+
</slot>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
</template>
|
|
74
|
+
|
|
75
|
+
<style scoped lang="scss">
|
|
76
|
+
.summary-card {
|
|
77
|
+
--sc-mono: "Inconsolata", monospace;
|
|
78
|
+
|
|
79
|
+
padding: 24px 28px;
|
|
80
|
+
border: 1px solid $color-border-light;
|
|
81
|
+
border-radius: 12px;
|
|
82
|
+
background-color: $slate-95;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.sc-header {
|
|
86
|
+
margin-bottom: 20px;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.sc-title {
|
|
90
|
+
font-size: 18px;
|
|
91
|
+
font-weight: 600;
|
|
92
|
+
text-transform: uppercase;
|
|
93
|
+
color: $color-heading;
|
|
94
|
+
|
|
95
|
+
.sc-icon {
|
|
96
|
+
flex-shrink: 0;
|
|
97
|
+
width: 20px;
|
|
98
|
+
height: 20px;
|
|
99
|
+
color: $success;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.sc-tag {
|
|
104
|
+
padding: 4px 12px;
|
|
105
|
+
border-radius: 4px;
|
|
106
|
+
font-family: var(--sc-mono);
|
|
107
|
+
font-size: 14px;
|
|
108
|
+
color: $color-label;
|
|
109
|
+
background-color: $slate-90;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.sc-grid {
|
|
113
|
+
display: grid;
|
|
114
|
+
grid-template-columns: repeat(var(--sc-columns), minmax(0, 1fr));
|
|
115
|
+
gap: 24px;
|
|
116
|
+
|
|
117
|
+
@media (max-width: 768px) {
|
|
118
|
+
grid-template-columns: minmax(0, 1fr);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.sc-item {
|
|
123
|
+
padding: 16px 18px;
|
|
124
|
+
border: 1px solid $color-border;
|
|
125
|
+
border-radius: 8px;
|
|
126
|
+
background-color: $white-100;
|
|
127
|
+
|
|
128
|
+
&.is-success .sc-value {
|
|
129
|
+
color: $success;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
&.is-warning {
|
|
133
|
+
border-color: $yellow-80;
|
|
134
|
+
background-color: $yellow-80;
|
|
135
|
+
|
|
136
|
+
.sc-label,
|
|
137
|
+
.sc-value {
|
|
138
|
+
color: $yellow-40;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
&.is-danger {
|
|
143
|
+
border-color: $red-90;
|
|
144
|
+
background-color: $red-95;
|
|
145
|
+
|
|
146
|
+
.sc-label,
|
|
147
|
+
.sc-value {
|
|
148
|
+
color: $danger;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.sc-label {
|
|
154
|
+
font-size: 14px;
|
|
155
|
+
font-weight: 500;
|
|
156
|
+
text-transform: uppercase;
|
|
157
|
+
color: $color-label;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.sc-value {
|
|
161
|
+
font-size: 16px;
|
|
162
|
+
font-weight: 600;
|
|
163
|
+
color: $color-heading;
|
|
164
|
+
|
|
165
|
+
&.is-mono {
|
|
166
|
+
font-family: var(--sc-mono);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.sc-suffix {
|
|
171
|
+
margin-left: 8px;
|
|
172
|
+
font-size: 14px;
|
|
173
|
+
font-weight: 400;
|
|
174
|
+
color: $color-label;
|
|
175
|
+
}
|
|
176
|
+
</style>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<script setup lang="ts" generic="Row extends object">
|
|
2
|
+
import { computed } from "vue";
|
|
3
|
+
import type { AcTableCol } from "../../types/table";
|
|
4
|
+
import AcTable from "../table/Table.vue";
|
|
5
|
+
import TableRow from "../table/TableRow.vue";
|
|
6
|
+
import TableCell from "../table/TableCell.vue";
|
|
7
|
+
|
|
8
|
+
const props = withDefaults(
|
|
9
|
+
defineProps<{
|
|
10
|
+
title: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
columns: { key: string; label: string }[];
|
|
13
|
+
rows: Row[];
|
|
14
|
+
isLoaderActive?: boolean;
|
|
15
|
+
modifierClasses?: string;
|
|
16
|
+
}>(),
|
|
17
|
+
{
|
|
18
|
+
description: "",
|
|
19
|
+
isLoaderActive: false,
|
|
20
|
+
modifierClasses: "",
|
|
21
|
+
},
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
const tableHeaders = computed<AcTableCol[]>(() =>
|
|
25
|
+
props.columns.map(({ label }) => ({ name: label, type: "string", priority: 0 })),
|
|
26
|
+
);
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<template>
|
|
30
|
+
<div class="b-1 is-rounded-8 bg-white" :class="modifierClasses">
|
|
31
|
+
<div class="p-20 is-flex is-justify-content-space-between is-align-items-flex-start gap-16">
|
|
32
|
+
<div>
|
|
33
|
+
<h5>{{ title }}</h5>
|
|
34
|
+
<p v-if="description" class="has-text-grey">{{ description }}</p>
|
|
35
|
+
</div>
|
|
36
|
+
<slot name="actions" />
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<AcTable
|
|
40
|
+
:table-headers="tableHeaders"
|
|
41
|
+
:is-loader-active="isLoaderActive"
|
|
42
|
+
:is-table-empty="!rows.length"
|
|
43
|
+
table-style=""
|
|
44
|
+
>
|
|
45
|
+
<TableRow v-for="(row, index) in rows" :key="index">
|
|
46
|
+
<TableCell v-for="column in columns" :key="column.key" class="pt-12 pb-12">
|
|
47
|
+
<slot :name="`cell-${column.key}`" :row="row" :value="row[column.key as keyof Row]">{{
|
|
48
|
+
row[column.key as keyof Row]
|
|
49
|
+
}}</slot>
|
|
50
|
+
</TableCell>
|
|
51
|
+
</TableRow>
|
|
52
|
+
</AcTable>
|
|
53
|
+
|
|
54
|
+
<div
|
|
55
|
+
v-if="$slots.footer"
|
|
56
|
+
class="is-flex is-justify-content-space-between is-align-items-center gap-8 pl-20 pr-20 pb-12"
|
|
57
|
+
>
|
|
58
|
+
<slot name="footer" />
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</template>
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, watch } from "vue";
|
|
3
|
+
|
|
4
|
+
import AcButton from "../button/Button.vue";
|
|
5
|
+
import AcSegmentedControl from "../button/SegmentedControl.vue";
|
|
6
|
+
import ScheduledMarker from "./ScheduledMarker.vue";
|
|
7
|
+
import TimelineTrack from "./TimelineTrack.vue";
|
|
8
|
+
import PhArrowClockwise from "~icons/ph/arrow-clockwise";
|
|
9
|
+
|
|
10
|
+
import type { RecoveryPoint, RecoveryTrack, TimeRangeOption, TimelineHover } from "./types";
|
|
11
|
+
import { DAY_MS, axisTicks, defaultRangeOptions, formatTime, parseDuration, toMs, type TimeDomain } from "./timeline";
|
|
12
|
+
|
|
13
|
+
interface Props {
|
|
14
|
+
title?: string;
|
|
15
|
+
description?: string;
|
|
16
|
+
tracks: RecoveryTrack[];
|
|
17
|
+
now?: string | number;
|
|
18
|
+
loading?: boolean;
|
|
19
|
+
editableRanges?: boolean;
|
|
20
|
+
footnote?: string;
|
|
21
|
+
labelWidth?: string;
|
|
22
|
+
modifierClasses?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
26
|
+
title: "Recoverable Window",
|
|
27
|
+
description: "",
|
|
28
|
+
now: undefined,
|
|
29
|
+
loading: false,
|
|
30
|
+
editableRanges: false,
|
|
31
|
+
footnote: "",
|
|
32
|
+
labelWidth: "150px",
|
|
33
|
+
modifierClasses: "",
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const emit = defineEmits<{
|
|
37
|
+
(e: "refresh"): void;
|
|
38
|
+
(e: "hover", payload: TimelineHover): void;
|
|
39
|
+
(e: "leave"): void;
|
|
40
|
+
(e: "select", point: RecoveryPoint): void;
|
|
41
|
+
}>();
|
|
42
|
+
|
|
43
|
+
const range = defineModel<string>("range", { default: "" });
|
|
44
|
+
const ranges = defineModel<TimeRangeOption[]>("ranges", { default: () => defaultRangeOptions });
|
|
45
|
+
|
|
46
|
+
const rangeLabels = computed<string[]>({
|
|
47
|
+
get: () => ranges.value.map((option) => option.label),
|
|
48
|
+
set: (labels) => {
|
|
49
|
+
ranges.value = labels.map((label, index) => ({
|
|
50
|
+
label,
|
|
51
|
+
durationMs: parseDuration(label) ?? ranges.value[index]?.durationMs ?? DAY_MS,
|
|
52
|
+
}));
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
watch(
|
|
57
|
+
ranges,
|
|
58
|
+
(options) => {
|
|
59
|
+
if (!options.some((option) => option.label === range.value)) range.value = options[0]?.label ?? "";
|
|
60
|
+
},
|
|
61
|
+
{ immediate: true },
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const nowMs = computed(() => toMs(props.now) ?? Date.now());
|
|
65
|
+
|
|
66
|
+
const domain = computed<TimeDomain>(() => {
|
|
67
|
+
const selected = ranges.value.find((option) => option.label === range.value) ?? ranges.value[0];
|
|
68
|
+
const durationMs = selected?.durationMs ?? DAY_MS;
|
|
69
|
+
return { start: nowMs.value - durationMs, end: nowMs.value, durationMs };
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const ticks = computed(() => axisTicks(domain.value));
|
|
73
|
+
|
|
74
|
+
const nowLabel = computed(() => `now (${formatTime(nowMs.value)} Local Time)`);
|
|
75
|
+
|
|
76
|
+
const gridStyle = computed(() => ({ "--rw-label-width": props.labelWidth }));
|
|
77
|
+
</script>
|
|
78
|
+
|
|
79
|
+
<template>
|
|
80
|
+
<div class="rw-card p-20 b-1 is-rounded-8 bg-white" :class="modifierClasses">
|
|
81
|
+
<div class="is-flex is-justify-content-space-between is-align-items-flex-start gap-16 mb-20">
|
|
82
|
+
<div>
|
|
83
|
+
<h5 class="mb-4">{{ title }}</h5>
|
|
84
|
+
<p v-if="description" class="text-sm has-text-grey mb-0">{{ description }}</p>
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
<div class="is-flex is-align-items-center gap-8">
|
|
88
|
+
<slot name="actions" />
|
|
89
|
+
<ac-segmented-control v-model:options="rangeLabels" v-model="range" :editable="editableRanges" />
|
|
90
|
+
<ac-button
|
|
91
|
+
icon-class="unplugin-icon"
|
|
92
|
+
modifier-classes="is-tinny is-white b-1"
|
|
93
|
+
tooltip="Refresh"
|
|
94
|
+
@click="emit('refresh')"
|
|
95
|
+
>
|
|
96
|
+
<template #icon>
|
|
97
|
+
<PhArrowClockwise />
|
|
98
|
+
</template>
|
|
99
|
+
</ac-button>
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<div class="rw-grid" :class="{ 'rw-grid--loading': loading }" :style="gridStyle">
|
|
104
|
+
<template v-for="track in tracks" :key="track.key">
|
|
105
|
+
<div class="is-flex is-align-items-center gap-8">
|
|
106
|
+
<span class="rw-dot" :class="`rw-dot--${track.status ?? 'success'}`" />
|
|
107
|
+
<span class="text-sm">{{ track.label }}</span>
|
|
108
|
+
</div>
|
|
109
|
+
<timeline-track
|
|
110
|
+
:track="track"
|
|
111
|
+
:domain="domain"
|
|
112
|
+
@hover="emit('hover', $event)"
|
|
113
|
+
@leave="emit('leave')"
|
|
114
|
+
@select="emit('select', $event)"
|
|
115
|
+
/>
|
|
116
|
+
</template>
|
|
117
|
+
|
|
118
|
+
<div />
|
|
119
|
+
<div class="rw-axis">
|
|
120
|
+
<span v-for="tick in ticks" :key="tick.time" class="rw-axis-tick" :style="{ left: `${tick.offset}%` }">
|
|
121
|
+
{{ tick.label }}
|
|
122
|
+
</span>
|
|
123
|
+
<span class="rw-axis-now">
|
|
124
|
+
<span class="rw-dot rw-dot--danger" />
|
|
125
|
+
{{ nowLabel }}
|
|
126
|
+
</span>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
|
|
130
|
+
<div
|
|
131
|
+
class="rw-footer mt-12 pt-12 is-flex is-justify-content-space-between is-align-items-center is-flex-wrap-wrap gap-8"
|
|
132
|
+
>
|
|
133
|
+
<div class="is-flex is-flex-wrap-wrap is-align-items-center gap-16">
|
|
134
|
+
<slot name="legend">
|
|
135
|
+
<span class="rw-legend-item"><i class="rw-swatch rw-swatch--pitr" />Any point recoverable (PITR)</span>
|
|
136
|
+
<span class="rw-legend-item"><i class="rw-swatch rw-swatch--verified" />Verified Snapshot</span>
|
|
137
|
+
<span class="rw-legend-item"><i class="rw-swatch rw-swatch--failed" />Failed run (logged)</span>
|
|
138
|
+
<span class="rw-legend-item"><scheduled-marker class="rw-swatch rw-swatch--scheduled" />Next scheduled</span>
|
|
139
|
+
</slot>
|
|
140
|
+
</div>
|
|
141
|
+
<span v-if="footnote" class="text-code text-xs has-text-grey">{{ footnote }}</span>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
</template>
|
|
145
|
+
|
|
146
|
+
<style lang="scss" scoped>
|
|
147
|
+
@import "../../styles/components/charts/recoverable-window";
|
|
148
|
+
|
|
149
|
+
.rw-grid {
|
|
150
|
+
display: grid;
|
|
151
|
+
grid-template-columns: var(--rw-label-width) 1fr;
|
|
152
|
+
column-gap: 16px;
|
|
153
|
+
row-gap: 14px;
|
|
154
|
+
align-items: center;
|
|
155
|
+
|
|
156
|
+
&--loading {
|
|
157
|
+
opacity: 0.5;
|
|
158
|
+
pointer-events: none;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.rw-dot {
|
|
163
|
+
width: 8px;
|
|
164
|
+
height: 8px;
|
|
165
|
+
border-radius: 50%;
|
|
166
|
+
flex-shrink: 0;
|
|
167
|
+
background-color: $rw-dot-success;
|
|
168
|
+
|
|
169
|
+
&--warning {
|
|
170
|
+
background-color: $rw-dot-warning;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
&--danger {
|
|
174
|
+
background-color: $rw-dot-danger;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.rw-axis {
|
|
179
|
+
position: relative;
|
|
180
|
+
height: 18px;
|
|
181
|
+
font-size: 12px;
|
|
182
|
+
color: $rw-axis-text;
|
|
183
|
+
|
|
184
|
+
.rw-axis-tick {
|
|
185
|
+
position: absolute;
|
|
186
|
+
transform: translateX(-50%);
|
|
187
|
+
font-family: monospace;
|
|
188
|
+
white-space: nowrap;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.rw-axis-now {
|
|
192
|
+
position: absolute;
|
|
193
|
+
right: 0;
|
|
194
|
+
display: inline-flex;
|
|
195
|
+
align-items: center;
|
|
196
|
+
gap: 6px;
|
|
197
|
+
font-family: monospace;
|
|
198
|
+
color: $rw-failed;
|
|
199
|
+
white-space: nowrap;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.rw-footer {
|
|
204
|
+
border-top: 1px solid $rw-rail-border;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.rw-legend-item {
|
|
208
|
+
display: inline-flex;
|
|
209
|
+
align-items: center;
|
|
210
|
+
gap: 6px;
|
|
211
|
+
font-size: 12px;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.rw-swatch {
|
|
215
|
+
width: 12px;
|
|
216
|
+
height: 12px;
|
|
217
|
+
border-radius: 2px;
|
|
218
|
+
display: inline-block;
|
|
219
|
+
|
|
220
|
+
&--pitr {
|
|
221
|
+
background-color: $rw-pitr-legend;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
&--verified {
|
|
225
|
+
background-color: $rw-snapshot;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
&--failed {
|
|
229
|
+
background-color: $rw-failed;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
&--scheduled {
|
|
233
|
+
width: 10px;
|
|
234
|
+
height: 14px;
|
|
235
|
+
border-radius: 0;
|
|
236
|
+
background-color: transparent;
|
|
237
|
+
color: $rw-scheduled;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
</style>
|