mirror of
https://github.com/flarum/core.git
synced 2025-08-12 11:24:30 +02:00
Compare commits
26 Commits
dk/fix-tim
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
5c901cfba8 | ||
|
be1b5713fa | ||
|
5045254c9f | ||
|
9b302a1029 | ||
|
97dfb50f17 | ||
|
6a940cd34f | ||
|
edd93dad77 | ||
|
2d18d37ba9 | ||
|
b58b3e2224 | ||
|
2c902c6563 | ||
|
a38dc889e9 | ||
|
851907b88c | ||
|
dfa3b47cf3 | ||
|
289ea49cc7 | ||
|
d769ee2b7b | ||
|
6e3051b36a | ||
|
c622070366 | ||
|
21d3e33613 | ||
|
b0d9f10280 | ||
|
d192185d13 | ||
|
6dba5c8e67 | ||
|
34c753040c | ||
|
7c4992c401 | ||
|
a7254773dd | ||
|
1217b11896 | ||
|
7a22527b72 |
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -14,5 +14,6 @@ js/dist/* -diff
|
||||
js/dist/* linguist-generated
|
||||
js/dist-typings/* linguist-generated
|
||||
js/yarn.lock -diff
|
||||
js/package-lock.json -diff
|
||||
|
||||
* text=auto eol=lf
|
||||
|
2
.github/workflows/backend.yml
vendored
2
.github/workflows/backend.yml
vendored
@@ -12,4 +12,4 @@ jobs:
|
||||
with:
|
||||
enable_backend_testing: true
|
||||
|
||||
backend_directory: .
|
||||
backend_directory: .
|
||||
|
4
.github/workflows/frontend.yml
vendored
4
.github/workflows/frontend.yml
vendored
@@ -15,7 +15,9 @@ jobs:
|
||||
enable_typescript: true
|
||||
|
||||
frontend_directory: ./js
|
||||
backend_directory: .
|
||||
js_package_manager: yarn
|
||||
main_git_branch: master
|
||||
|
||||
secrets:
|
||||
bundlewatch_github_token: ${{ secrets.BUNDLEWATCH_GITHUB_TOKEN }}
|
||||
bundlewatch_github_token: ${{ secrets.BUNDLEWATCH_GITHUB_TOKEN }}
|
||||
|
@@ -100,7 +100,8 @@
|
||||
- `last_activity_at, last_seen_at` updated on all API requests (https://github.com/flarum/core/pull/3231).
|
||||
- `RememberMe` access token updated twice in API requests (https://github.com/flarum/core/pull/3233).
|
||||
- Error in `funding` item in `composer.json` bricks the frontend (https://github.com/flarum/core/pull/3239).
|
||||
- Fix escaped quotes in window title (https://github.com/flarum/core/pull/3264)
|
||||
- Escaped quotes in window title (https://github.com/flarum/core/pull/3264)
|
||||
- `schedule:list` command fails due to missing timezone configuration.
|
||||
|
||||
### Deprecated
|
||||
- Unused `evented` utility (https://github.com/flarum/core/pull/3125).
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/// <reference path="../../../src/common/translator-icu-rich.d.ts" />
|
||||
/// <reference path="../../@types/translator-icu-rich.d.ts" />
|
||||
import Modal, { IInternalModalAttrs } from '../../common/components/Modal';
|
||||
export interface ILoadingModalAttrs extends IInternalModalAttrs {
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/// <reference path="../../../src/common/translator-icu-rich.d.ts" />
|
||||
/// <reference path="../../@types/translator-icu-rich.d.ts" />
|
||||
import Modal, { IInternalModalAttrs } from '../../common/components/Modal';
|
||||
import ExtensionReadme from '../models/ExtensionReadme';
|
||||
import type Mithril from 'mithril';
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/// <reference path="../../../src/common/translator-icu-rich.d.ts" />
|
||||
/// <reference path="../../@types/translator-icu-rich.d.ts" />
|
||||
import type Mithril from 'mithril';
|
||||
import type User from '../../common/models/User';
|
||||
import ItemList from '../../common/utils/ItemList';
|
||||
|
2
js/dist-typings/common/Translator.d.ts
vendored
2
js/dist-typings/common/Translator.d.ts
vendored
@@ -1,4 +1,4 @@
|
||||
/// <reference path="../../src/common/translator-icu-rich.d.ts" />
|
||||
/// <reference path="../@types/translator-icu-rich.d.ts" />
|
||||
import { RichMessageFormatter } from '@askvortsov/rich-icu-message-formatter';
|
||||
import { pluralTypeHandler, selectTypeHandler } from '@ultraq/icu-message-formatter';
|
||||
declare type Translations = Record<string, string>;
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import type Mithril from 'mithril';
|
||||
import Component, { ComponentAttrs } from '../Component';
|
||||
export default class ColorPreviewInput extends Component {
|
||||
value?: string;
|
||||
view(vnode: Mithril.Vnode<ComponentAttrs, this>): JSX.Element;
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/// <reference path="../../../src/common/translator-icu-rich.d.ts" />
|
||||
/// <reference path="../../@types/translator-icu-rich.d.ts" />
|
||||
import Modal, { IInternalModalAttrs } from './Modal';
|
||||
import ItemList from '../utils/ItemList';
|
||||
import Stream from '../utils/Stream';
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/// <reference path="../../../src/common/translator-icu-rich.d.ts" />
|
||||
/// <reference path="../../@types/translator-icu-rich.d.ts" />
|
||||
import Modal, { IInternalModalAttrs } from '../../common/components/Modal';
|
||||
import Stream from '../../common/utils/Stream';
|
||||
import Mithril from 'mithril';
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/// <reference path="../../../src/common/translator-icu-rich.d.ts" />
|
||||
/// <reference path="../../@types/translator-icu-rich.d.ts" />
|
||||
import Modal, { IInternalModalAttrs } from '../../common/components/Modal';
|
||||
import ItemList from '../../common/utils/ItemList';
|
||||
import Stream from '../../common/utils/Stream';
|
||||
|
1
js/dist-typings/forum/components/Search.d.ts
vendored
1
js/dist-typings/forum/components/Search.d.ts
vendored
@@ -104,6 +104,7 @@ export default class Search<T extends SearchAttrs = SearchAttrs> extends Compone
|
||||
selectableItems(): JQuery;
|
||||
/**
|
||||
* Get the position of the currently selected search result item.
|
||||
* Returns zero if not found.
|
||||
*/
|
||||
getCurrentNumericIndex(): number;
|
||||
/**
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/// <reference path="../../../src/common/translator-icu-rich.d.ts" />
|
||||
/// <reference path="../../@types/translator-icu-rich.d.ts" />
|
||||
import Modal, { IInternalModalAttrs } from '../../common/components/Modal';
|
||||
import ItemList from '../../common/utils/ItemList';
|
||||
import Stream from '../../common/utils/Stream';
|
||||
|
2
js/dist/admin.js
generated
vendored
2
js/dist/admin.js
generated
vendored
File diff suppressed because one or more lines are too long
2
js/dist/admin.js.LICENSE.txt
generated
vendored
2
js/dist/admin.js.LICENSE.txt
generated
vendored
@@ -48,7 +48,7 @@
|
||||
*/
|
||||
|
||||
/*!
|
||||
* focus-trap 6.7.1
|
||||
* focus-trap 6.7.2
|
||||
* @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
|
2
js/dist/admin.js.map
generated
vendored
2
js/dist/admin.js.map
generated
vendored
File diff suppressed because one or more lines are too long
2
js/dist/forum.js
generated
vendored
2
js/dist/forum.js
generated
vendored
File diff suppressed because one or more lines are too long
2
js/dist/forum.js.LICENSE.txt
generated
vendored
2
js/dist/forum.js.LICENSE.txt
generated
vendored
@@ -48,7 +48,7 @@
|
||||
*/
|
||||
|
||||
/*!
|
||||
* focus-trap 6.7.1
|
||||
* focus-trap 6.7.2
|
||||
* @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
|
2
js/dist/forum.js.map
generated
vendored
2
js/dist/forum.js.map
generated
vendored
File diff suppressed because one or more lines are too long
@@ -3,7 +3,7 @@
|
||||
"name": "@flarum/core",
|
||||
"prettier": "@flarum/prettier-config",
|
||||
"dependencies": {
|
||||
"@askvortsov/rich-icu-message-formatter": "^0.2.3",
|
||||
"@askvortsov/rich-icu-message-formatter": "^0.2.4",
|
||||
"@ultraq/icu-message-formatter": "^0.12.0",
|
||||
"bootstrap": "^3.4.1",
|
||||
"clsx": "^1.1.1",
|
||||
@@ -39,11 +39,12 @@
|
||||
"scripts": {
|
||||
"dev": "webpack --mode development --watch",
|
||||
"build": "webpack --mode production",
|
||||
"analyze": "cross-env ANALYZER=true yarn build",
|
||||
"analyze": "cross-env ANALYZER=true yarn run build",
|
||||
"format": "prettier --write src",
|
||||
"format-check": "prettier --check src",
|
||||
"clean-typings": "npx rimraf dist-typings && mkdir dist-typings",
|
||||
"build-typings": "npm run clean-typings && tsc && [ -e src/@types ] && cp -r src/@types dist-typings/@types",
|
||||
"build-typings": "yarn run clean-typings && [ -e src/@types ] && cp -r src/@types dist-typings/@types && tsc && yarn run post-build-typings",
|
||||
"post-build-typings": "find dist-typings -type f -name '*.d.ts' -print0 | xargs -0 sed -i 's,../src/@types,@types,g'",
|
||||
"check-typings": "tsc --noEmit --emitDeclarationOnly false",
|
||||
"check-typings-coverage": "typescript-coverage-report"
|
||||
},
|
||||
|
26
js/src/@types/translator-icu-rich.d.ts
vendored
Normal file
26
js/src/@types/translator-icu-rich.d.ts
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
declare module '@askvortsov/rich-icu-message-formatter' {
|
||||
type IValues = Record<string, any>;
|
||||
|
||||
type ITypeHandler = (
|
||||
value: string,
|
||||
matches: string,
|
||||
locale: string,
|
||||
values: IValues,
|
||||
format: (message: string, values: IValues) => string
|
||||
) => string;
|
||||
type IRichHandler = (tag: any, values: IValues, contents: string) => any;
|
||||
|
||||
type ValueOrArray<T> = T | ValueOrArray<T>[];
|
||||
type NestedStringArray = ValueOrArray<string>;
|
||||
|
||||
export class RichMessageFormatter {
|
||||
locale: string | null;
|
||||
constructor(locale: string | null, typeHandlers: Record<string, ITypeHandler>, richHandler: IRichHandler);
|
||||
|
||||
format(message: string, values: IValues): string;
|
||||
process(message: string, values: IValues): NestedStringArray;
|
||||
rich(message: string, values: IValues): NestedStringArray;
|
||||
}
|
||||
|
||||
export function mithrilRichHandler(tag: any, values: IValues, contents: string): any;
|
||||
}
|
17
js/src/@types/translator-icu.d.ts
vendored
Normal file
17
js/src/@types/translator-icu.d.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
declare module '@ultraq/icu-message-formatter' {
|
||||
export function pluralTypeHandler(
|
||||
value: string,
|
||||
matches: string,
|
||||
locale: string,
|
||||
values: Record<string, any>,
|
||||
format: (text: string, values: Record<string, any>) => string
|
||||
): string;
|
||||
|
||||
export function selectTypeHandler(
|
||||
value: string,
|
||||
matches: string,
|
||||
locale: string,
|
||||
values: Record<string, any>,
|
||||
format: (text: string, values: Record<string, any>) => string
|
||||
): string;
|
||||
}
|
@@ -5,23 +5,20 @@ import classList from '../utils/classList';
|
||||
import icon from '../helpers/icon';
|
||||
|
||||
export default class ColorPreviewInput extends Component {
|
||||
value?: string;
|
||||
|
||||
view(vnode: Mithril.Vnode<ComponentAttrs, this>) {
|
||||
const { className, ...attrs } = this.attrs;
|
||||
const value = attrs.bidi?.() || attrs.value;
|
||||
const { className, id, ...attrs } = this.attrs;
|
||||
|
||||
attrs.type ||= 'text';
|
||||
|
||||
return (
|
||||
<div className="ColorInput">
|
||||
<input className={classList('FormControl', className)} {...attrs} />
|
||||
<input className={classList('FormControl', className)} id={id} {...attrs} />
|
||||
|
||||
<span className="ColorInput-icon" role="presentation">
|
||||
{icon('fas fa-exclamation-circle')}
|
||||
</span>
|
||||
|
||||
<div className="ColorInput-preview" style={{ '--input-value': value }} role="presentation" />
|
||||
<input className="ColorInput-preview" {...attrs} type="color" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@@ -61,7 +61,7 @@ export default class EditUserModal<CustomAttrs extends IEditUserModalAttrs = IEd
|
||||
fields() {
|
||||
const items = new ItemList();
|
||||
|
||||
if (app.session.user?.canEditCredentials()) {
|
||||
if (this.attrs.user.canEditCredentials()) {
|
||||
items.add(
|
||||
'username',
|
||||
<div className="Form-group">
|
||||
@@ -145,7 +145,7 @@ export default class EditUserModal<CustomAttrs extends IEditUserModalAttrs = IEd
|
||||
}
|
||||
}
|
||||
|
||||
if (app.session.user?.canEditGroups()) {
|
||||
if (this.attrs.user.canEditGroups()) {
|
||||
items.add(
|
||||
'groups',
|
||||
<div className="Form-group EditUserModal-groups">
|
||||
|
@@ -49,7 +49,6 @@ export default class Drawer {
|
||||
* @internal
|
||||
*/
|
||||
resizeHandler = ((e) => {
|
||||
console.log(this, e);
|
||||
if (!e.matches && this.isOpen()) {
|
||||
// Drawer is open but we've made window bigger, so hide it.
|
||||
this.hide();
|
||||
|
@@ -101,7 +101,7 @@ export default class DiscussionComposer extends ComposerBody {
|
||||
.save(data)
|
||||
.then((discussion) => {
|
||||
this.composer.hide();
|
||||
app.discussions.refresh({ deferClear: true });
|
||||
app.discussions.refresh();
|
||||
m.route.set(app.route.discussion(discussion));
|
||||
}, this.loaded.bind(this));
|
||||
}
|
||||
|
@@ -53,7 +53,9 @@ export default class DiscussionPage<CustomAttrs extends IDiscussionPageAttrs = I
|
||||
// page, then we don't want Mithril to redraw the whole page – if it did,
|
||||
// then the pane would redraw which would be slow and would cause problems with
|
||||
// event handlers.
|
||||
if (app.discussions.hasItems()) {
|
||||
// We will also enable the pane if the discussion list is empty but loading,
|
||||
// because the DiscussionComposer refreshes the list and redirects to the new discussion at the same time.
|
||||
if (app.discussions.hasItems() || app.discussions.isLoading()) {
|
||||
app.pane?.enable();
|
||||
app.pane?.hide();
|
||||
}
|
||||
@@ -210,7 +212,7 @@ export default class DiscussionPage<CustomAttrs extends IDiscussionPageAttrs = I
|
||||
record.relationships.discussion.data.id === discussionId
|
||||
)
|
||||
.map((record) => app.store.getById<Post>('posts', record.id))
|
||||
.sort((a?: Post, b?: Post) => (a?.createdAt()?.getTime() ?? 0) - (b?.createdAt()?.getTime() ?? 0))
|
||||
.sort((a?: Post, b?: Post) => (a?.number() ?? 0) - (b?.number() ?? 0))
|
||||
.slice(0, 20);
|
||||
}
|
||||
|
||||
|
@@ -161,6 +161,7 @@ export default class Search<T extends SearchAttrs = SearchAttrs> extends Compone
|
||||
className="Search-clear Button Button--icon Button--link"
|
||||
onclick={this.clear.bind(this)}
|
||||
aria-label={app.translator.trans('core.forum.header.search_clear_button_accessible_label')}
|
||||
type="button"
|
||||
>
|
||||
{icon('fas fa-times-circle')}
|
||||
</button>
|
||||
@@ -324,9 +325,10 @@ export default class Search<T extends SearchAttrs = SearchAttrs> extends Compone
|
||||
|
||||
/**
|
||||
* Get the position of the currently selected search result item.
|
||||
* Returns zero if not found.
|
||||
*/
|
||||
getCurrentNumericIndex(): number {
|
||||
return this.selectableItems().index(this.getItem(this.index));
|
||||
return Math.max(0, this.selectableItems().index(this.getItem(this.index)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -289,7 +289,7 @@ class PostStreamState {
|
||||
|
||||
if (loadIds.length) {
|
||||
return app.store.find('posts', loadIds).then((newPosts) => {
|
||||
return loaded.concat(newPosts).sort((a, b) => a.createdAt() - b.createdAt());
|
||||
return loaded.concat(newPosts).sort((a, b) => a.number() - b.number());
|
||||
});
|
||||
}
|
||||
|
||||
|
1840
js/yarn.lock
1840
js/yarn.lock
File diff suppressed because it is too large
Load Diff
@@ -7,12 +7,26 @@
|
||||
bottom: 8px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&-preview {
|
||||
background-color: var(--input-value);
|
||||
display: inline-block;
|
||||
border-radius: 15%;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
|
||||
// Match both the wrapper div and the div with the background color
|
||||
&, &::-webkit-color-swatch-wrapper, &::-webkit-color-swatch {
|
||||
border: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
// This has to be a separate entry so other browsers
|
||||
// don't ignore the entire CSS rule. Thanks Firefox.
|
||||
&::-moz-color-swatch {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-icon {
|
||||
|
@@ -41,18 +41,23 @@
|
||||
line-height: 1.5em;
|
||||
color: var(--secondary-color);
|
||||
|
||||
&, input, a {
|
||||
&,
|
||||
input,
|
||||
a {
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
}
|
||||
input, a {
|
||||
input,
|
||||
a {
|
||||
color: inherit;
|
||||
}
|
||||
input {
|
||||
font-size: 16px;
|
||||
width: 500px;
|
||||
|
||||
&, &[disabled], &:focus {
|
||||
&,
|
||||
&[disabled],
|
||||
&:focus {
|
||||
background: none;
|
||||
border: 0;
|
||||
padding: 0 20px 0 0;
|
||||
@@ -230,7 +235,8 @@
|
||||
height: 300px;
|
||||
transition: background 0.2s, box-shadow 0.2s;
|
||||
|
||||
&.active, &.fullScreen {
|
||||
&.active,
|
||||
&.fullScreen {
|
||||
background: var(--body-bg);
|
||||
}
|
||||
&.active:not(.fullScreen) {
|
||||
@@ -258,9 +264,16 @@
|
||||
}
|
||||
}
|
||||
.ComposerBody-header {
|
||||
margin-right: 120px;
|
||||
|
||||
.fullScreen & {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.minimized & {
|
||||
overflow: hidden;
|
||||
margin-right: 32px;
|
||||
}
|
||||
}
|
||||
.Composer-content {
|
||||
padding: 20px 20px 0;
|
||||
@@ -279,7 +292,8 @@
|
||||
margin-bottom: -17px;
|
||||
position: relative;
|
||||
|
||||
.minimized &, .fullScreen & {
|
||||
.minimized &,
|
||||
.fullScreen & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -287,14 +301,16 @@
|
||||
float: left;
|
||||
.Avatar--size(64px);
|
||||
|
||||
.minimized &, .fullScreen & {
|
||||
.minimized &,
|
||||
.fullScreen & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.ComposerBody-content {
|
||||
margin-left: 85px;
|
||||
|
||||
.minimized &, .fullScreen & {
|
||||
.minimized &,
|
||||
.fullScreen & {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
@@ -41,7 +41,7 @@ class ListPostsController extends AbstractListController
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $sortFields = ['createdAt'];
|
||||
public $sortFields = ['number', 'createdAt'];
|
||||
|
||||
/**
|
||||
* @var PostFilterer
|
||||
|
@@ -132,7 +132,7 @@ class ShowDiscussionController extends AbstractShowController
|
||||
*/
|
||||
private function loadPostIds(Discussion $discussion, User $actor)
|
||||
{
|
||||
return $discussion->posts()->whereVisibleTo($actor)->orderBy('created_at')->pluck('id')->all();
|
||||
return $discussion->posts()->whereVisibleTo($actor)->orderBy('number')->pluck('id')->all();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,7 +186,7 @@ class ShowDiscussionController extends AbstractShowController
|
||||
{
|
||||
$query = $discussion->posts()->whereVisibleTo($actor);
|
||||
|
||||
$query->orderBy('created_at')->skip($offset)->take($limit)->with($include);
|
||||
$query->orderBy('number')->skip($offset)->take($limit)->with($include);
|
||||
|
||||
$posts = $query->get();
|
||||
|
||||
|
@@ -42,16 +42,29 @@ class DiscussionRepository
|
||||
/**
|
||||
* Get the IDs of discussions which a user has read completely.
|
||||
*
|
||||
* @deprecated 1.3 Use `getReadIdsQuery` instead
|
||||
*
|
||||
* @param User $user
|
||||
* @return array
|
||||
*/
|
||||
public function getReadIds(User $user)
|
||||
{
|
||||
return $this->getReadIdsQuery($user)
|
||||
->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a query containing the IDs of discussions which a user has read completely.
|
||||
*
|
||||
* @param User $user
|
||||
* @return Builder
|
||||
*/
|
||||
public function getReadIdsQuery(User $user): Builder
|
||||
{
|
||||
return Discussion::leftJoin('discussion_user', 'discussion_user.discussion_id', '=', 'discussions.id')
|
||||
->where('discussion_user.user_id', $user->id)
|
||||
->whereColumn('last_read_post_number', '>=', 'last_post_number')
|
||||
->pluck('id')
|
||||
->all();
|
||||
->select('id');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -61,7 +61,7 @@ class UnreadFilterGambit extends AbstractRegexGambit implements FilterInterface
|
||||
protected function constrain(Builder $query, User $actor, bool $negate)
|
||||
{
|
||||
if ($actor->exists) {
|
||||
$readIds = $this->discussions->getReadIds($actor);
|
||||
$readIds = $this->discussions->getReadIdsQuery($actor);
|
||||
|
||||
$query->where(function ($query) use ($readIds, $negate, $actor) {
|
||||
if (! $negate) {
|
||||
|
@@ -21,7 +21,7 @@ class Application
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const VERSION = '1.2.0';
|
||||
const VERSION = '1.3.0-dev';
|
||||
|
||||
/**
|
||||
* The IoC container for the Flarum application.
|
||||
|
@@ -19,6 +19,7 @@
|
||||
<testsuites>
|
||||
<testsuite name="Flarum Integration Tests">
|
||||
<directory suffix="Test.php">./integration</directory>
|
||||
<exclude>./integration/tmp</exclude>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
||||
|
Reference in New Issue
Block a user