mirror of https://github.com/halo-dev/halo
Merge branch 'main' into chore/use-ibm-semeru-runtimes
commit
dec7a7f222
|
@ -67,6 +67,7 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: halo-sigs/actions/halo-next-docker-build@main # change the version to specific ref or release tag while the action is stable.
|
- uses: halo-sigs/actions/halo-next-docker-build@main # change the version to specific ref or release tag while the action is stable.
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
with:
|
with:
|
||||||
image-name: ${{ github.event_name == 'release' && 'halo' || 'halo-dev' }}
|
image-name: ${{ github.event_name == 'release' && 'halo' || 'halo-dev' }}
|
||||||
ghcr-token: ${{ secrets.GHCR_TOKEN }}
|
ghcr-token: ${{ secrets.GHCR_TOKEN }}
|
||||||
|
@ -75,3 +76,18 @@ jobs:
|
||||||
push: ${{ github.event_name == 'push' || github.event_name == 'release' }} # we only push to GHCR if the push is to the next branch
|
push: ${{ github.event_name == 'push' || github.event_name == 'release' }} # we only push to GHCR if the push is to the next branch
|
||||||
console-ref: ${{ github.event_name == 'release' && github.ref || 'main' }}
|
console-ref: ${{ github.event_name == 'release' && github.ref || 'main' }}
|
||||||
platforms: linux/amd64,linux/arm64/v8,linux/ppc64le,linux/s390x
|
platforms: linux/amd64,linux/arm64/v8,linux/ppc64le,linux/s390x
|
||||||
|
- uses: halo-sigs/actions/halo-next-docker-build@main
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
with:
|
||||||
|
image-name: halo-dev
|
||||||
|
push: false
|
||||||
|
console-ref: false
|
||||||
|
load: true
|
||||||
|
platforms: ""
|
||||||
|
- name: test
|
||||||
|
run: |
|
||||||
|
sudo curl -L https://github.com/docker/compose/releases/download/v2.23.0/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
|
||||||
|
sudo chmod u+x /usr/local/bin/docker-compose
|
||||||
|
|
||||||
|
docker tag ghcr.io/halo-dev/halo-dev:pr-${{ github.event.number }} ghcr.io/halo-dev/halo-dev:dev
|
||||||
|
cd e2e && ./start.sh
|
||||||
|
|
|
@ -48,6 +48,10 @@ git pull upstream master
|
||||||
git push
|
git push
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### E2E
|
||||||
|
|
||||||
|
Please consider adding some [e2e test cases](e2e/README.md) to make sure the APIs work as expected.
|
||||||
|
|
||||||
### 开发规范
|
### 开发规范
|
||||||
|
|
||||||
请参考 [https://docs.halo.run/developer-guide/core/code-style](https://docs.halo.run/developer-guide/core/code-style),请确保所有代码格式化之后再提交。
|
请参考 [https://docs.halo.run/developer-guide/core/code-style](https://docs.halo.run/developer-guide/core/code-style),请确保所有代码格式化之后再提交。
|
||||||
|
|
|
@ -293,7 +293,6 @@ onMounted(() => {
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
v-model="checkedAll"
|
v-model="checkedAll"
|
||||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@change="handleCheckAllChange"
|
@change="handleCheckAllChange"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -122,7 +122,6 @@ const { operationItems } = useOperationItemExtensionPoint<Attachment>(
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
:checked="selectedAttachments.has(attachment)"
|
:checked="selectedAttachments.has(attachment)"
|
||||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@click="emit('select', attachment)"
|
@click="emit('select', attachment)"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -236,7 +236,6 @@ const handleApproveInBatch = async () => {
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
v-model="checkAll"
|
v-model="checkAll"
|
||||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@change="handleCheckAllChange"
|
@change="handleCheckAllChange"
|
||||||
/>
|
/>
|
||||||
|
@ -375,7 +374,6 @@ const handleApproveInBatch = async () => {
|
||||||
<input
|
<input
|
||||||
v-model="selectedCommentNames"
|
v-model="selectedCommentNames"
|
||||||
:value="comment?.comment?.metadata.name"
|
:value="comment?.comment?.metadata.name"
|
||||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
|
||||||
name="comment-checkbox"
|
name="comment-checkbox"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -240,7 +240,6 @@ watch(
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
v-model="checkedAll"
|
v-model="checkedAll"
|
||||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@change="handleCheckAllChange"
|
@change="handleCheckAllChange"
|
||||||
/>
|
/>
|
||||||
|
@ -308,7 +307,6 @@ watch(
|
||||||
<input
|
<input
|
||||||
v-model="selectedPageNames"
|
v-model="selectedPageNames"
|
||||||
:value="singlePage.page.metadata.name"
|
:value="singlePage.page.metadata.name"
|
||||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -325,7 +325,6 @@ watch(selectedPageNames, (newValue) => {
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
v-model="checkedAll"
|
v-model="checkedAll"
|
||||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@change="handleCheckAllChange"
|
@change="handleCheckAllChange"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -130,7 +130,6 @@ const handleDelete = async () => {
|
||||||
<input
|
<input
|
||||||
v-model="selectedPageNames"
|
v-model="selectedPageNames"
|
||||||
:value="singlePage.page.metadata.name"
|
:value="singlePage.page.metadata.name"
|
||||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -233,7 +233,6 @@ watch(
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
v-model="checkedAll"
|
v-model="checkedAll"
|
||||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@change="handleCheckAllChange"
|
@change="handleCheckAllChange"
|
||||||
/>
|
/>
|
||||||
|
@ -300,7 +299,6 @@ watch(
|
||||||
<input
|
<input
|
||||||
v-model="selectedPostNames"
|
v-model="selectedPostNames"
|
||||||
:value="post.post.metadata.name"
|
:value="post.post.metadata.name"
|
||||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
|
||||||
name="post-checkbox"
|
name="post-checkbox"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -331,7 +331,6 @@ watch(selectedPostNames, (newValue) => {
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
v-model="checkedAll"
|
v-model="checkedAll"
|
||||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@change="handleCheckAllChange"
|
@change="handleCheckAllChange"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -178,7 +178,6 @@ const { startFields, endFields } = useEntityFieldItemExtensionPoint<ListedPost>(
|
||||||
<input
|
<input
|
||||||
v-model="selectedPostNames"
|
v-model="selectedPostNames"
|
||||||
:value="post.post.metadata.name"
|
:value="post.post.metadata.name"
|
||||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
|
||||||
name="post-checkbox"
|
name="post-checkbox"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -167,7 +167,6 @@ onMounted(() => {
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
v-model="checkedAll"
|
v-model="checkedAll"
|
||||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@change="handleCheckAllChange"
|
@change="handleCheckAllChange"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -240,7 +240,6 @@ const { startFields, endFields } = useEntityFieldItemExtensionPoint<Plugin>(
|
||||||
<input
|
<input
|
||||||
v-model="selectedNames"
|
v-model="selectedNames"
|
||||||
:value="plugin.metadata.name"
|
:value="plugin.metadata.name"
|
||||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
|
||||||
name="post-checkbox"
|
name="post-checkbox"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -233,18 +233,11 @@ onMounted(() => {
|
||||||
v-if="!isSuperRole"
|
v-if="!isSuperRole"
|
||||||
v-model="selectedRoleTemplates"
|
v-model="selectedRoleTemplates"
|
||||||
:value="role.metadata.name"
|
:value="role.metadata.name"
|
||||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
:disabled="isSystemReserved"
|
:disabled="isSystemReserved"
|
||||||
@change="handleRoleTemplateSelect"
|
@change="handleRoleTemplateSelect"
|
||||||
/>
|
/>
|
||||||
<input
|
<input v-else type="checkbox" checked disabled />
|
||||||
v-else
|
|
||||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
|
||||||
type="checkbox"
|
|
||||||
checked
|
|
||||||
disabled
|
|
||||||
/>
|
|
||||||
<div class="flex flex-1 flex-col gap-y-3">
|
<div class="flex flex-1 flex-col gap-y-3">
|
||||||
<span class="font-medium text-gray-900">
|
<span class="font-medium text-gray-900">
|
||||||
{{
|
{{
|
||||||
|
|
|
@ -219,7 +219,6 @@ const handleResetForm = () => {
|
||||||
<input
|
<input
|
||||||
v-model="selectedRoleTemplates"
|
v-model="selectedRoleTemplates"
|
||||||
:value="roleTemplate.metadata.name"
|
:value="roleTemplate.metadata.name"
|
||||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@change="handleRoleTemplateSelect"
|
@change="handleRoleTemplateSelect"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -299,7 +299,6 @@ onMounted(() => {
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
v-model="checkedAll"
|
v-model="checkedAll"
|
||||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@change="handleCheckAllChange"
|
@change="handleCheckAllChange"
|
||||||
/>
|
/>
|
||||||
|
@ -412,7 +411,6 @@ onMounted(() => {
|
||||||
<input
|
<input
|
||||||
v-model="selectedUserNames"
|
v-model="selectedUserNames"
|
||||||
:value="user.user.metadata.name"
|
:value="user.user.metadata.name"
|
||||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
|
||||||
name="post-checkbox"
|
name="post-checkbox"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
:disabled="
|
:disabled="
|
||||||
|
|
|
@ -113,6 +113,7 @@
|
||||||
"@rushstack/eslint-patch": "^1.3.2",
|
"@rushstack/eslint-patch": "^1.3.2",
|
||||||
"@tailwindcss/aspect-ratio": "^0.4.2",
|
"@tailwindcss/aspect-ratio": "^0.4.2",
|
||||||
"@tailwindcss/container-queries": "^0.1.0",
|
"@tailwindcss/container-queries": "^0.1.0",
|
||||||
|
"@tailwindcss/forms": "^0.5.7",
|
||||||
"@tsconfig/node18": "^2.0.1",
|
"@tsconfig/node18": "^2.0.1",
|
||||||
"@types/jsdom": "^20.0.1",
|
"@types/jsdom": "^20.0.1",
|
||||||
"@types/lodash.clonedeep": "4.5.7",
|
"@types/lodash.clonedeep": "4.5.7",
|
||||||
|
|
|
@ -225,6 +225,9 @@ importers:
|
||||||
'@tailwindcss/container-queries':
|
'@tailwindcss/container-queries':
|
||||||
specifier: ^0.1.0
|
specifier: ^0.1.0
|
||||||
version: 0.1.0(tailwindcss@3.3.0)
|
version: 0.1.0(tailwindcss@3.3.0)
|
||||||
|
'@tailwindcss/forms':
|
||||||
|
specifier: ^0.5.7
|
||||||
|
version: 0.5.7(tailwindcss@3.3.0)
|
||||||
'@tsconfig/node18':
|
'@tsconfig/node18':
|
||||||
specifier: ^2.0.1
|
specifier: ^2.0.1
|
||||||
version: 2.0.1
|
version: 2.0.1
|
||||||
|
@ -3422,6 +3425,15 @@ packages:
|
||||||
tailwindcss: 3.3.0(postcss@8.4.21)
|
tailwindcss: 3.3.0(postcss@8.4.21)
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@tailwindcss/forms@0.5.7(tailwindcss@3.3.0):
|
||||||
|
resolution: {integrity: sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw==}
|
||||||
|
peerDependencies:
|
||||||
|
tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1'
|
||||||
|
dependencies:
|
||||||
|
mini-svg-data-uri: 1.4.4
|
||||||
|
tailwindcss: 3.3.0(postcss@8.4.21)
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@tanstack/match-sorter-utils@8.7.6:
|
/@tanstack/match-sorter-utils@8.7.6:
|
||||||
resolution: {integrity: sha512-2AMpRiA6QivHOUiBpQAVxjiHAA68Ei23ZUMNaRJrN6omWiSFLoYrxGcT6BXtuzp0Jw4h6HZCmGGIM/gbwebO2A==}
|
resolution: {integrity: sha512-2AMpRiA6QivHOUiBpQAVxjiHAA68Ei23ZUMNaRJrN6omWiSFLoYrxGcT6BXtuzp0Jw4h6HZCmGGIM/gbwebO2A==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
@ -8798,6 +8810,11 @@ packages:
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/mini-svg-data-uri@1.4.4:
|
||||||
|
resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==}
|
||||||
|
hasBin: true
|
||||||
|
dev: true
|
||||||
|
|
||||||
/minimatch@3.1.2:
|
/minimatch@3.1.2:
|
||||||
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
|
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
|
@ -382,7 +382,7 @@ const onVisibleChange = (visible: boolean) => {
|
||||||
ref="globalSearchInput"
|
ref="globalSearchInput"
|
||||||
v-model="keyword"
|
v-model="keyword"
|
||||||
:placeholder="$t('core.components.global_search.placeholder')"
|
:placeholder="$t('core.components.global_search.placeholder')"
|
||||||
class="w-full py-1 text-base outline-none"
|
class="w-full px-0 py-1 text-base outline-none"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
autocorrect="off"
|
autocorrect="off"
|
||||||
spellcheck="false"
|
spellcheck="false"
|
||||||
|
|
|
@ -113,11 +113,18 @@ const inputClasses = {
|
||||||
:placeholder="$t('core.signup.fields.display_name.placeholder')"
|
:placeholder="$t('core.signup.fields.display_name.placeholder')"
|
||||||
:validation-label="$t('core.signup.fields.display_name.placeholder')"
|
:validation-label="$t('core.signup.fields.display_name.placeholder')"
|
||||||
:classes="inputClasses"
|
:classes="inputClasses"
|
||||||
:autofocus="true"
|
|
||||||
type="text"
|
type="text"
|
||||||
validation="required"
|
validation="required"
|
||||||
>
|
>
|
||||||
</FormKit>
|
</FormKit>
|
||||||
|
<FormKit
|
||||||
|
v-model="formState.user.spec.email"
|
||||||
|
:placeholder="$t('core.signup.fields.email.placeholder')"
|
||||||
|
:validation-label="$t('core.signup.fields.email.placeholder')"
|
||||||
|
type="email"
|
||||||
|
name="email"
|
||||||
|
validation="required|email|length:0,100"
|
||||||
|
></FormKit>
|
||||||
<FormKit
|
<FormKit
|
||||||
v-model="formState.password"
|
v-model="formState.password"
|
||||||
name="password"
|
name="password"
|
||||||
|
|
|
@ -4,7 +4,7 @@ const textClassification = {
|
||||||
inner:
|
inner:
|
||||||
"inline-flex items-center w-full relative box-border border border-gray-300 formkit-invalid:border-red-500 h-9 rounded-base overflow-hidden focus-within:border-primary focus-within:shadow-sm w-full sm:max-w-lg transition-all",
|
"inline-flex items-center w-full relative box-border border border-gray-300 formkit-invalid:border-red-500 h-9 rounded-base overflow-hidden focus-within:border-primary focus-within:shadow-sm w-full sm:max-w-lg transition-all",
|
||||||
input:
|
input:
|
||||||
"outline-0 bg-white antialiased resize-none w-full text-black block transition-all appearance-none h-full px-3 text-sm",
|
"bg-white resize-none w-full text-black block transition-all h-full px-3 text-sm",
|
||||||
};
|
};
|
||||||
|
|
||||||
const boxClassification = {
|
const boxClassification = {
|
||||||
|
@ -15,8 +15,7 @@ const boxClassification = {
|
||||||
wrapper:
|
wrapper:
|
||||||
"flex items-center mb-1 cursor-pointer group-[.formkit-fieldset]:px-2",
|
"flex items-center mb-1 cursor-pointer group-[.formkit-fieldset]:px-2",
|
||||||
help: "mb-2 mt-0 px-2",
|
help: "mb-2 mt-0 px-2",
|
||||||
input:
|
input: "form-check-input mr-2 bg-white",
|
||||||
"form-check-input h-4 w-4 mr-2 border border-gray-500 rounded-sm bg-white checked:bg-primary focus:outline-none focus:ring-0 transition duration-200",
|
|
||||||
inner: "flex items-center",
|
inner: "flex items-center",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -105,7 +104,7 @@ const theme: Record<string, Record<string, string>> = {
|
||||||
tagSelect: {
|
tagSelect: {
|
||||||
...textClassification,
|
...textClassification,
|
||||||
inner: `${textClassification.inner} !overflow-visible !h-auto min-h-[2.25rem]`,
|
inner: `${textClassification.inner} !overflow-visible !h-auto min-h-[2.25rem]`,
|
||||||
input: `w-0 flex-grow outline-0 bg-transparent py-1 px-3 block transition-all appearance-none text-sm antialiased`,
|
input: `w-0 flex-grow bg-transparent py-1 px-3 block transition-all text-sm`,
|
||||||
"post-tags-wrapper": "flex w-full items-center",
|
"post-tags-wrapper": "flex w-full items-center",
|
||||||
"post-tags": "flex w-full flex-wrap items-center",
|
"post-tags": "flex w-full flex-wrap items-center",
|
||||||
"post-tag-wrapper": "inline-flex items-center p-1",
|
"post-tag-wrapper": "inline-flex items-center p-1",
|
||||||
|
@ -118,7 +117,7 @@ const theme: Record<string, Record<string, string>> = {
|
||||||
categorySelect: {
|
categorySelect: {
|
||||||
...textClassification,
|
...textClassification,
|
||||||
inner: `${textClassification.inner} !overflow-visible !h-auto min-h-[2.25rem]`,
|
inner: `${textClassification.inner} !overflow-visible !h-auto min-h-[2.25rem]`,
|
||||||
input: `w-0 flex-grow outline-0 bg-transparent py-1 px-3 block transition-all appearance-none text-sm antialiased`,
|
input: `w-0 flex-grow bg-transparent py-1 px-3 block transition-all text-sm`,
|
||||||
"post-categories-wrapper": "flex w-full items-center",
|
"post-categories-wrapper": "flex w-full items-center",
|
||||||
"post-categories": "flex w-full flex-wrap items-center",
|
"post-categories": "flex w-full flex-wrap items-center",
|
||||||
"post-categories-button":
|
"post-categories-button":
|
||||||
|
|
|
@ -28,6 +28,8 @@ core:
|
||||||
placeholder: Username
|
placeholder: Username
|
||||||
display_name:
|
display_name:
|
||||||
placeholder: Display name
|
placeholder: Display name
|
||||||
|
email:
|
||||||
|
placeholder: Email
|
||||||
password:
|
password:
|
||||||
placeholder: Password
|
placeholder: Password
|
||||||
password_confirm:
|
password_confirm:
|
||||||
|
|
|
@ -28,6 +28,8 @@ core:
|
||||||
placeholder: 用户名
|
placeholder: 用户名
|
||||||
display_name:
|
display_name:
|
||||||
placeholder: 名称
|
placeholder: 名称
|
||||||
|
email:
|
||||||
|
placeholder: 电子邮箱
|
||||||
password:
|
password:
|
||||||
placeholder: 密码
|
placeholder: 密码
|
||||||
password_confirm:
|
password_confirm:
|
||||||
|
|
|
@ -28,6 +28,8 @@ core:
|
||||||
placeholder: 用戶名
|
placeholder: 用戶名
|
||||||
display_name:
|
display_name:
|
||||||
placeholder: 名稱
|
placeholder: 名稱
|
||||||
|
email:
|
||||||
|
placeholder: 電子郵箱
|
||||||
password:
|
password:
|
||||||
placeholder: 密碼
|
placeholder: 密碼
|
||||||
password_confirm:
|
password_confirm:
|
||||||
|
|
|
@ -1,3 +1,26 @@
|
||||||
@tailwind base;
|
@tailwind base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
|
/* override @tailwindcss/forms styles */
|
||||||
|
input[type="text"],
|
||||||
|
input[type="password"],
|
||||||
|
input[type="email"],
|
||||||
|
input[type="number"],
|
||||||
|
input[type="url"],
|
||||||
|
input[type="date"],
|
||||||
|
input[type="datetime-local"],
|
||||||
|
input[type="month"],
|
||||||
|
input[type="week"],
|
||||||
|
input[type="time"],
|
||||||
|
input[type="search"],
|
||||||
|
input[type="tel"],
|
||||||
|
input:where(:not([type])),
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
@apply border-none py-0 focus:outline-0 focus:ring-0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"] {
|
||||||
|
@apply rounded-sm border-gray-500;
|
||||||
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ module.exports = {
|
||||||
require("@tailwindcss/aspect-ratio"),
|
require("@tailwindcss/aspect-ratio"),
|
||||||
require("@formkit/themes/tailwindcss"),
|
require("@formkit/themes/tailwindcss"),
|
||||||
require("@tailwindcss/container-queries"),
|
require("@tailwindcss/container-queries"),
|
||||||
|
require("@tailwindcss/forms"),
|
||||||
require("tailwindcss-themer")({
|
require("tailwindcss-themer")({
|
||||||
defaultTheme: {
|
defaultTheme: {
|
||||||
extend: {
|
extend: {
|
||||||
|
|
|
@ -179,7 +179,6 @@ const { copy } = useClipboard({
|
||||||
<input
|
<input
|
||||||
v-model="selectedRoleTemplates"
|
v-model="selectedRoleTemplates"
|
||||||
:value="roleTemplate.metadata.name"
|
:value="roleTemplate.metadata.name"
|
||||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@change="handleRoleTemplateSelect"
|
@change="handleRoleTemplateSelect"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
FROM linuxsuren/api-testing:v0.0.14
|
||||||
|
WORKDIR /workspace
|
||||||
|
COPY testsuite.yaml .
|
||||||
|
CMD [ "atest", "run", "-p", "testsuite.yaml", "--level=debug" ]
|
|
@ -0,0 +1,17 @@
|
||||||
|
Please add the corresponding e2e (aka end-to-end) test cases if you add or update APIs.
|
||||||
|
|
||||||
|
## How to work
|
||||||
|
* Start and watch the [docker-compose](https://docs.docker.com/compose/) via [the script](start.sh)
|
||||||
|
* It has three containers: database, Halo, and testing
|
||||||
|
* Run the e2e testing via [api-testing](https://github.com/LinuxSuRen/api-testing)
|
||||||
|
* It will run the test cases from top to bottom
|
||||||
|
* You can add the necessary asserts to it
|
||||||
|
|
||||||
|
## Run locally
|
||||||
|
Please follow these steps if you want to run the e2e testing locally.
|
||||||
|
|
||||||
|
> Please make sure you have installed docker-compose v2
|
||||||
|
|
||||||
|
* Build project via `./gradlew clean build -x check` in root directory of this repository
|
||||||
|
* Build image via `docker build . -t ghcr.io/halo-dev/halo-dev:dev`
|
||||||
|
* Change the directory to `e2e`, then execute `./start.sh`
|
|
@ -0,0 +1,48 @@
|
||||||
|
version: '3.1'
|
||||||
|
services:
|
||||||
|
testing:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
links:
|
||||||
|
- halo
|
||||||
|
depends_on:
|
||||||
|
halo:
|
||||||
|
condition: service_healthy
|
||||||
|
halo:
|
||||||
|
image: ghcr.io/halo-dev/halo-dev:dev
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:8090/actuator/health/readiness"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
start_period: 30s
|
||||||
|
command:
|
||||||
|
- --spring.r2dbc.url=r2dbc:pool:postgresql://halodb/halo
|
||||||
|
- --spring.r2dbc.username=halo
|
||||||
|
# PostgreSQL 的密码,请保证与下方 POSTGRES_PASSWORD 的变量值一致。
|
||||||
|
- --spring.r2dbc.password=openpostgresql
|
||||||
|
- --spring.sql.init.platform=postgresql
|
||||||
|
# 外部访问地址,请根据实际需要修改
|
||||||
|
# - --halo.external-url=http://localhost:8090/
|
||||||
|
links:
|
||||||
|
- postgresql
|
||||||
|
depends_on:
|
||||||
|
postgresql:
|
||||||
|
condition: service_healthy
|
||||||
|
postgresql:
|
||||||
|
image: postgres:15.4
|
||||||
|
container_name: halodb
|
||||||
|
restart: on-failure:3
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
healthcheck:
|
||||||
|
test: [ "CMD", "pg_isready" ]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
environment:
|
||||||
|
- POSTGRES_PASSWORD=openpostgresql
|
||||||
|
- POSTGRES_USER=halo
|
||||||
|
- POSTGRES_DB=halo
|
||||||
|
- PGUSER=halo
|
|
@ -0,0 +1,31 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
file=$1
|
||||||
|
if [ "$file" == "" ]
|
||||||
|
then
|
||||||
|
file=compose.yaml
|
||||||
|
fi
|
||||||
|
|
||||||
|
docker-compose version
|
||||||
|
docker-compose -f "$file" up --build -d
|
||||||
|
|
||||||
|
while true
|
||||||
|
do
|
||||||
|
docker-compose -f "$file" ps | grep testing
|
||||||
|
if [ $? -eq 1 ]
|
||||||
|
then
|
||||||
|
code=-1
|
||||||
|
docker-compose -f "$file" logs | grep e2e-testing
|
||||||
|
docker-compose -f "$file" logs | grep e2e-testing | grep Usage
|
||||||
|
if [ $? -eq 1 ]
|
||||||
|
then
|
||||||
|
code=0
|
||||||
|
echo "successed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
docker-compose -f "$file" down
|
||||||
|
set -e
|
||||||
|
exit $code
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
|
@ -0,0 +1,86 @@
|
||||||
|
name: halo
|
||||||
|
api: |
|
||||||
|
{{default "http://halo:8090" (env "SERVER")}}/apis
|
||||||
|
param:
|
||||||
|
postName: "{{randAlpha 6}}"
|
||||||
|
items:
|
||||||
|
- name: init
|
||||||
|
request:
|
||||||
|
api: /api.console.halo.run/v1alpha1/system/initialize
|
||||||
|
method: POST
|
||||||
|
header:
|
||||||
|
Content-Type: application/json
|
||||||
|
body: |
|
||||||
|
{
|
||||||
|
"siteTitle": "testing",
|
||||||
|
"username": "admin",
|
||||||
|
"password": "123456",
|
||||||
|
"email": "testing@halo.com",
|
||||||
|
"password_confirm": "123456"
|
||||||
|
}
|
||||||
|
expect:
|
||||||
|
statusCode: 201
|
||||||
|
- name: createPost
|
||||||
|
request:
|
||||||
|
api: /api.console.halo.run/v1alpha1/posts
|
||||||
|
method: POST
|
||||||
|
header:
|
||||||
|
Authorization: "Basic YWRtaW46MTIzNDU2"
|
||||||
|
Content-Type: application/json
|
||||||
|
body: |
|
||||||
|
{
|
||||||
|
"post": {
|
||||||
|
"spec": {
|
||||||
|
"title": "{{.param.postName}}",
|
||||||
|
"slug": "{{.param.postName}}",
|
||||||
|
"template": "",
|
||||||
|
"cover": "",
|
||||||
|
"deleted": false,
|
||||||
|
"publish": false,
|
||||||
|
"pinned": false,
|
||||||
|
"allowComment": true,
|
||||||
|
"visible": "PUBLIC",
|
||||||
|
"priority": 0,
|
||||||
|
"excerpt": {
|
||||||
|
"autoGenerate": true,
|
||||||
|
"raw": ""
|
||||||
|
},
|
||||||
|
"categories": [],
|
||||||
|
"tags": [],
|
||||||
|
"htmlMetas": []
|
||||||
|
},
|
||||||
|
"apiVersion": "content.halo.run/v1alpha1",
|
||||||
|
"kind": "Post",
|
||||||
|
"metadata": {
|
||||||
|
"name": "c31f2192-c992-47b9-86b4-f3fc0605360e",
|
||||||
|
"annotations": {
|
||||||
|
"content.halo.run/preferred-editor": "default"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"raw": "<p>{{.param.postName}}</p>",
|
||||||
|
"content": "<p>{{.param.postName}}</p>",
|
||||||
|
"rawType": "HTML"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- name: listPosts
|
||||||
|
request:
|
||||||
|
api: /api.console.halo.run/v1alpha1/posts?keyword={{.param.postName}}
|
||||||
|
header:
|
||||||
|
Authorization: "Basic YWRtaW46MTIzNDU2"
|
||||||
|
expect:
|
||||||
|
verify:
|
||||||
|
- data.total == 1
|
||||||
|
- name: recyclePost
|
||||||
|
request:
|
||||||
|
api: /api.console.halo.run/v1alpha1/posts/{{(index .listPosts.items 0).post.metadata.name}}/recycle
|
||||||
|
method: PUT
|
||||||
|
header:
|
||||||
|
Authorization: "Basic YWRtaW46MTIzNDU2"
|
||||||
|
- name: recover
|
||||||
|
request:
|
||||||
|
api: /content.halo.run/v1alpha1/posts/{{(index .listPosts.items 0).post.metadata.name}}
|
||||||
|
method: DELETE
|
||||||
|
header:
|
||||||
|
Authorization: "Basic YWRtaW46MTIzNDU2"
|
Loading…
Reference in New Issue