Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions .github/workflows/end-to-end-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,26 @@ jobs:
run: npm install
- name: Install http-server
run: npm install -g http-server pm2
- name: Build e2e outputs
run: npm run dev:e2e
- name: Build production outputs
run: npm run build

- name: Start up mock server
run: |
pm2 start 'http-server ./test-e2e/example -p 12345'
pm2 start 'http-server ./test-e2e/example -p 12346'

- name: Run tests
- name: Build e2e outputs for chrome
run: npm run dev:e2e
- name: Run tests for Chrome
env:
USE_HEADLESS_PUPPETEER: true
run: npm run test-e2e
- name: Install Firefox for Puppeteer
run: npx puppeteer browsers install firefox
- name: Build firefox e2e outputs
run: npm run dev:e2e-firefox
- name: Run tests for Firefox
env:
USE_HEADLESS_PUPPETEER: true
USE_FIREFOX_PUPPETEER: true
run: npm run test-e2e
- name: Tests ✅
if: ${{ success() }}
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"dev:firefox": "rspack --config=rspack/rspack.dev.firefox.ts --watch",
"dev:safari": "rspack --config=rspack/rspack.dev.safari.ts --watch",
"dev:e2e": "rspack --config=rspack/rspack.e2e.ts",
"dev:e2e-firefox": "rspack --config=rspack/rspack.e2e.firefox.ts",
"analyze": "rspack --config=rspack/rspack.analyze.ts",
"android-firefox": "web-ext run -t firefox-android --firefox-apk org.mozilla.fenix -s dist_dev_firefox --adb-device ",
"build": "rspack --config=rspack/rspack.prod.ts",
Expand Down
19 changes: 19 additions & 0 deletions rspack/rspack.e2e.firefox.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import path from "path"
import manifest from "../src/manifest-firefox"
import { E2E_NAME } from "../src/util/constant/meta"
import generateOption from "./rspack.common"

manifest.name = E2E_NAME
// Fix the crx id for development mode
manifest.key = "clbbddpinhgdejpoepalbfnkogbobfdb"
// The manifest.json is different from Chrome's with add-on ID
manifest.browser_specific_settings = { gecko: { id: 'timer@zhy' } }

const options = generateOption({
outputPath: path.join(__dirname, '..', 'dist_e2e'),
manifest,
mode: "development",
})
options.output = { ...options.output, clean: true }

export default options
1 change: 1 addition & 0 deletions rspack/rspack.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ const options = generateOption({
manifest,
mode: "production",
})
options.output = { ...options.output, clean: true }

export default options
24 changes: 12 additions & 12 deletions src/i18n/element.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import ElementPlus from 'element-plus'
import { type Language } from "element-plus/es/locale"
import { type Language } from "element-plus/lib/locale"
import { type App } from "vue"
import { locale, t } from "."
import calendarMessages from "./message/common/calendar"

const LOCALES: { [locale in timer.Locale]: () => Promise<{ default: Language }> } = {
zh_CN: () => import('element-plus/es/locale/lang/zh-cn'),
zh_TW: () => import('element-plus/es/locale/lang/zh-tw'),
en: () => import('element-plus/es/locale/lang/en'),
ja: () => import('element-plus/es/locale/lang/ja'),
pt_PT: () => import('element-plus/es/locale/lang/pt'),
uk: () => import('element-plus/es/locale/lang/uk'),
es: () => import('element-plus/es/locale/lang/es'),
de: () => import('element-plus/es/locale/lang/de'),
fr: () => import('element-plus/es/locale/lang/fr'),
ru: () => import('element-plus/es/locale/lang/ru'),
ar: () => import('element-plus/es/locale/lang/ar'),
zh_CN: () => import('element-plus/lib/locale/lang/zh-cn'),
zh_TW: () => import('element-plus/lib/locale/lang/zh-tw'),
en: () => import('element-plus/lib/locale/lang/en'),
ja: () => import('element-plus/lib/locale/lang/ja'),
pt_PT: () => import('element-plus/lib/locale/lang/pt'),
uk: () => import('element-plus/lib/locale/lang/uk'),
es: () => import('element-plus/lib/locale/lang/es'),
de: () => import('element-plus/lib/locale/lang/de'),
fr: () => import('element-plus/lib/locale/lang/fr'),
ru: () => import('element-plus/lib/locale/lang/ru'),
ar: () => import('element-plus/lib/locale/lang/ar'),
}

export const initElementLocale = async (app: App) => {
Expand Down
156 changes: 89 additions & 67 deletions src/pages/app/components/SiteManage/SiteManageFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,86 +9,108 @@ import InputFilterItem from "@app/components/common/filter/InputFilterItem"
import { useCategories } from "@app/context"
import { t } from "@app/locale"
import { Connection, Delete, Grid, Plus } from "@element-plus/icons-vue"
import { useState } from "@hooks"
import Flex from "@pages/components/Flex"
import { computed, defineComponent, watch } from "vue"
import { computed, defineComponent, type PropType, watch } from "vue"
import DropdownButton, { type DropdownButtonItem } from "../common/DropdownButton"
import CategoryFilter from "../common/filter/CategoryFilter"
import MultiSelectFilterItem from "../common/filter/MultiSelectFilterItem"
import { ALL_TYPES } from "./common"
import { useSiteManageFilter } from './useSiteManage'

export type FilterOption = {
query?: string
types?: timer.site.Type[]
cateIds?: number[]
}

type BatchOpt = 'change' | 'disassociate' | 'delete'

const _default = defineComponent<{
onCreate: NoArgCallback
onBatchChangeCate: NoArgCallback
onBatchDisassociate: NoArgCallback
onBatchDelete: NoArgCallback
}>(props => {
const { categories } = useCategories()
const filter = useSiteManageFilter()
const _default = defineComponent({
props: {
defaultValue: Object as PropType<FilterOption>,
},
emits: {
change: (_option: FilterOption) => true,
create: () => true,
batchDelete: () => true,
batchChangeCate: () => true,
batchDisassociate: () => true,
genNames: () => true,
},
setup(props, ctx) {
const { categories } = useCategories()

const cateDisabled = computed(() => {
const types = filter.types
return !!types?.length && !types?.includes?.('normal')
})
watch(cateDisabled, () => cateDisabled.value && (filter.cateIds = []))
const defaultOption = props.defaultValue
const [query, setQuery] = useState(defaultOption?.query)
const [types, setTypes] = useState(defaultOption?.types)

watch(categories, () => {
const allCateIds = categories.value?.map(c => c.id) || []
const newVal = filter.cateIds?.filter(cid => allCateIds.includes(cid))
// If selected category is deleted, then reset the value
newVal?.length !== filter.cateIds?.length && (filter.cateIds = newVal)
})
const cateDisabled = computed(() => !!types.value?.length && !types.value?.includes?.('normal'))
watch([cateDisabled], () => cateDisabled.value && setCateIds([]))

const items: DropdownButtonItem<BatchOpt>[] = [{
key: 'change',
label: t(msg => msg.siteManage.cate.batchChange),
icon: Grid,
onClick: props.onBatchChangeCate,
}, {
key: 'disassociate',
label: t(msg => msg.siteManage.cate.batchDisassociate),
icon: Connection,
onClick: props.onBatchDisassociate,
}, {
key: 'delete',
label: t(msg => msg.button.batchDelete),
icon: Delete,
onClick: props.onBatchDelete,
}]
const [cateIds, setCateIds] = useState(defaultOption?.cateIds)

return () => (
<Flex gap={10} justify="space-between">
<Flex gap={10}>
<InputFilterItem
placeholder={`${t(msg => msg.item.host)} / ${t(msg => msg.siteManage.column.alias)}`}
onSearch={val => filter.query = val}
width={200}
/>
<MultiSelectFilterItem
placeholder={t(msg => msg.siteManage.column.type)}
options={ALL_TYPES.map(type => ({ value: type, label: t(msg => msg.siteManage.type[type].name) }))}
defaultValue={filter.types}
onChange={val => filter.types = val as timer.site.Type[]}
/>
<CategoryFilter
disabled={cateDisabled.value}
modelValue={filter.cateIds}
onChange={v => filter.cateIds = v}
/>
</Flex>
<Flex gap={10}>
<DropdownButton items={items} />
<ButtonFilterItem
text={t(msg => msg.button.create)}
icon={Plus}
type="success"
onClick={props.onCreate}
/>
watch(categories, () => {
const allCateIds = categories.value?.map(c => c.id) || []
const newVal = cateIds.value?.filter(cid => allCateIds.includes(cid))
// If selected category is deleted, then reset the value
newVal?.length !== cateIds.value?.length && setCateIds(newVal)
})

watch([query, types, cateIds], () => ctx.emit("change", {
query: query.value,
types: types.value,
cateIds: cateIds.value,
}))

const items: DropdownButtonItem<BatchOpt>[] = [{
key: 'change',
label: t(msg => msg.siteManage.cate.batchChange),
icon: Grid,
onClick: () => ctx.emit('batchChangeCate'),
}, {
key: 'disassociate',
label: t(msg => msg.siteManage.cate.batchDisassociate),
icon: Connection,
onClick: () => ctx.emit('batchDisassociate'),
}, {
key: 'delete',
label: t(msg => msg.button.batchDelete),
icon: Delete,
onClick: () => ctx.emit('batchDelete'),
}]

return () => (
<Flex gap={10} justify="space-between">
<Flex gap={10}>
<InputFilterItem
placeholder={`${t(msg => msg.item.host)} / ${t(msg => msg.siteManage.column.alias)}`}
onSearch={setQuery}
width={200}
/>
<MultiSelectFilterItem
placeholder={t(msg => msg.siteManage.column.type)}
options={ALL_TYPES.map(type => ({ value: type, label: t(msg => msg.siteManage.type[type].name) }))}
defaultValue={types.value}
onChange={val => setTypes(val as timer.site.Type[])}
/>
<CategoryFilter
disabled={cateDisabled.value}
modelValue={cateIds.value}
onChange={setCateIds}
/>
</Flex>
<Flex gap={10}>
<DropdownButton items={items} />
<ButtonFilterItem
text={t(msg => msg.button.create)}
icon={Plus}
type="success"
onClick={() => ctx.emit("create")}
/>
</Flex>
</Flex>
</Flex>
)
)
}
})

export default _default
Loading
Loading