mirror of https://github.com/halo-dev/halo
feat: add loading state for switch component (#4688)
#### What type of PR is this? /area console /kind feature /milestone 2.10.x #### What this PR does / why we need it: VSwitch 组件支持传入 loading 属性以显示加载状态。 此外,此 PR 为插件启动/停止的开关适配了这个特性用于测试。 <img width="460" alt="image" src="https://github.com/halo-dev/halo/assets/21301288/b78221fe-6b53-4f8c-ba00-6cea2c45b5de"> #### Which issue(s) this PR fixes: Fixes #4687 #### Special notes for your reviewer: 测试插件启动/停止时是否显示加载状态 #### Does this PR introduce a user-facing change? ```release-note Console 端的 VSwitch 组件支持传入 loading 属性以显示加载状态。 ```pull/4680/head
parent
b2d7221316
commit
df22b4b5ea
|
@ -3,10 +3,12 @@ const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
modelValue?: boolean;
|
modelValue?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
loading?: boolean;
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
modelValue: false,
|
modelValue: false,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
|
loading: false,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -16,7 +18,7 @@ const emit = defineEmits<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const handleChange = () => {
|
const handleChange = () => {
|
||||||
if (props.disabled) return;
|
if (props.disabled || props.loading) return;
|
||||||
|
|
||||||
emit("update:modelValue", !props.modelValue);
|
emit("update:modelValue", !props.modelValue);
|
||||||
emit("change", !props.modelValue);
|
emit("change", !props.modelValue);
|
||||||
|
@ -28,13 +30,13 @@ const handleChange = () => {
|
||||||
:class="{
|
:class="{
|
||||||
'bg-gray-200': !modelValue,
|
'bg-gray-200': !modelValue,
|
||||||
'!bg-primary': modelValue,
|
'!bg-primary': modelValue,
|
||||||
'switch-disabled': disabled,
|
'switch-disabled': disabled || loading,
|
||||||
}"
|
}"
|
||||||
aria-checked="false"
|
aria-checked="false"
|
||||||
class="switch-inner"
|
class="switch-inner"
|
||||||
role="switch"
|
role="switch"
|
||||||
type="button"
|
type="button"
|
||||||
:disabled="disabled"
|
:disabled="disabled || loading"
|
||||||
@click="handleChange"
|
@click="handleChange"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
|
@ -45,7 +47,28 @@ const handleChange = () => {
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
class="switch-indicator"
|
class="switch-indicator"
|
||||||
>
|
>
|
||||||
<slot name="icon" />
|
<svg
|
||||||
|
v-if="loading"
|
||||||
|
class="animate-spin"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<circle
|
||||||
|
class="opacity-0"
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="10"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="4"
|
||||||
|
></circle>
|
||||||
|
<path
|
||||||
|
class="opacity-30"
|
||||||
|
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||||
|
fill="currentColor"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
<slot v-else name="icon" />
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,9 +1,25 @@
|
||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import { VSwitch } from "../index";
|
import { VSwitch } from "../index";
|
||||||
import { mount } from "@vue/test-utils";
|
import { mount, shallowMount } from "@vue/test-utils";
|
||||||
|
|
||||||
describe("Switch", () => {
|
describe("Switch", () => {
|
||||||
it("should render", () => {
|
it("should render", () => {
|
||||||
expect(mount(VSwitch)).toBeDefined();
|
expect(mount(VSwitch)).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("emits the correct events when clicked", () => {
|
||||||
|
const wrapper = shallowMount(VSwitch);
|
||||||
|
wrapper.find("button").trigger("click");
|
||||||
|
expect(wrapper.emitted("update:modelValue")).toBeTruthy();
|
||||||
|
expect(wrapper.emitted("change")).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not emit events when disabled or loading", () => {
|
||||||
|
const wrapper = shallowMount(VSwitch, {
|
||||||
|
props: { disabled: true, loading: true },
|
||||||
|
});
|
||||||
|
wrapper.find("button").trigger("click");
|
||||||
|
expect(wrapper.emitted("update:modelValue")).toBeFalsy();
|
||||||
|
expect(wrapper.emitted("change")).toBeFalsy();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -21,7 +21,7 @@ const { changingStatus, changeStatus } = usePluginLifeCycle(plugin);
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<VSwitch
|
<VSwitch
|
||||||
:model-value="plugin.spec.enabled"
|
:model-value="plugin.spec.enabled"
|
||||||
:disabled="changingStatus"
|
:loading="changingStatus"
|
||||||
@click="changeStatus"
|
@click="changeStatus"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue