mirror of
https://github.com/discourse/discourse.git
synced 2024-11-24 23:48:45 +08:00
DEV: Drop Ember 3 feature flag
This commit is contained in:
parent
2018cd3b62
commit
542cb22fd4
69
.github/workflows/ember-version-enforcement.yml
vendored
69
.github/workflows/ember-version-enforcement.yml
vendored
|
@ -1,69 +0,0 @@
|
|||
# This workflow is designed to stop us accidently committing the lockfile/packagejson symlink changes
|
||||
# which would cause the default Ember version to change.
|
||||
|
||||
name: Ember Version Enforcement
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: yarn
|
||||
- name: Yarn install
|
||||
run: |
|
||||
cd app/assets/javascripts/discourse
|
||||
yarn install
|
||||
- name: "Check default ember version"
|
||||
working-directory: app/assets/javascripts/discourse
|
||||
run: |
|
||||
node -e '
|
||||
const version = require("ember-source/package.json").version;
|
||||
console.log("Ember version is", version);
|
||||
if(version.split(".")[0] !== "5"){
|
||||
console.log(`Ember has unexpectedly been downgraded to version ${version}. If this is intentional, remove this github workflow.`);
|
||||
process.exit(1);
|
||||
}
|
||||
'
|
||||
- name: Downgrade ember
|
||||
run: |
|
||||
script/switch_ember_version 3
|
||||
cd app/assets/javascripts/discourse
|
||||
yarn install
|
||||
- name: "Check upgraded version"
|
||||
working-directory: app/assets/javascripts/discourse
|
||||
run: |
|
||||
node -e '
|
||||
const version = require("ember-source/package.json").version;
|
||||
console.log("Ember version is", version);
|
||||
if(version.split(".")[0] !== "3"){
|
||||
console.log(`Expected Ember 3, but found ${version}`);
|
||||
process.exit(1);
|
||||
}
|
||||
'
|
||||
- name: "Revert ember downgrade"
|
||||
run: |
|
||||
script/switch_ember_version 5
|
||||
- name: "Ensure no diff"
|
||||
run: |
|
||||
if [ ! -z "$(git status --porcelain)" ]; then
|
||||
echo "Working directory was not clean after upgrading/downgrading ember. Perhaps a lockfile is out-of-date. Run this command to re-sync:"
|
||||
echo " script/regen_ember_3_lockfile"
|
||||
echo
|
||||
echo "Current diff:"
|
||||
echo "---------------------------------------------"
|
||||
git -c color.ui=always diff
|
||||
exit 1
|
||||
fi
|
38
.github/workflows/ember-version-lockfiles.yml
vendored
38
.github/workflows/ember-version-lockfiles.yml
vendored
|
@ -1,38 +0,0 @@
|
|||
# This workflow will run on dependabot pull requests to ensure that they update both the ember3 and ember5 lockfiles
|
||||
|
||||
name: Ember Version Lockfiles
|
||||
|
||||
on:
|
||||
- pull_request
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
help_dependabot:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.actor == 'dependabot[bot]' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.head_ref }}
|
||||
- name: Move lockfile to correct location
|
||||
run: |
|
||||
# Dependabot gets confused by the symlinks and dumps the updated lockfile in the root of the repo.
|
||||
# Let's move it back to the correct location.
|
||||
if [[ -f yarn-ember5.lock ]]; then
|
||||
mv yarn-ember5.lock app/assets/javascripts/yarn-ember5.lock
|
||||
fi
|
||||
- name: Update ember3 lockfile
|
||||
run: script/regen_ember_3_lockfile
|
||||
- name: Push changes
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
if [ ! -z "$(git status --porcelain)" ]; then
|
||||
git config --global user.email "build@discourse.org"
|
||||
git config --global user.name "discoursebuild"
|
||||
git add .
|
||||
git commit -m "Update lockfiles for ember version flag"
|
||||
git push
|
||||
fi
|
17
.github/workflows/tests.yml
vendored
17
.github/workflows/tests.yml
vendored
|
@ -22,7 +22,7 @@ permissions:
|
|||
jobs:
|
||||
build:
|
||||
if: github.event_name == 'pull_request' || github.repository != 'discourse/discourse-private-mirror'
|
||||
name: ${{ matrix.target }} ${{ matrix.build_type }}${{ !matrix.updated_ember && ' (Ember 3)' || '' }} # Update fetch-job-id step if changing this
|
||||
name: ${{ matrix.target }} ${{ matrix.build_type }} # Update fetch-job-id step if changing this
|
||||
runs-on: ${{ (matrix.build_type == 'annotations') && 'ubuntu-latest' || 'ubuntu-20.04-8core' }}
|
||||
container: discourse/discourse_test:slim${{ (matrix.build_type == 'frontend' || matrix.build_type == 'system') && '-browsers' || '' }}${{ (matrix.ruby == '3.1') && '-ruby-3.1.0' || '' }}
|
||||
timeout-minutes: 20
|
||||
|
@ -35,7 +35,6 @@ jobs:
|
|||
USES_PARALLEL_DATABASES: ${{ matrix.build_type == 'backend' || matrix.build_type == 'system' }}
|
||||
CAPYBARA_DEFAULT_MAX_WAIT_TIME: 10
|
||||
MINIO_RUNNER_LOG_LEVEL: DEBUG
|
||||
EMBER_VERSION: ${{ (matrix.updated_ember && '5') || '3' }}
|
||||
DISCOURSE_TURBO_RSPEC_RETRY_AND_LOG_FLAKY_TESTS: ${{ (matrix.build_type == 'system' || matrix.build_type == 'backend') && github.ref == 'refs/main/head' }}
|
||||
|
||||
strategy:
|
||||
|
@ -45,7 +44,6 @@ jobs:
|
|||
build_type: [backend, frontend, system, annotations]
|
||||
target: [core, plugins, themes]
|
||||
ruby: ["3.2"]
|
||||
updated_ember: [true]
|
||||
exclude:
|
||||
- build_type: annotations
|
||||
target: plugins
|
||||
|
@ -58,7 +56,6 @@ jobs:
|
|||
include:
|
||||
- build_type: system
|
||||
target: chat
|
||||
updated_ember: true
|
||||
|
||||
steps:
|
||||
- name: Set working directory owner
|
||||
|
@ -299,7 +296,7 @@ jobs:
|
|||
id: fetch-job-id
|
||||
if: always() && steps.check-flaky-spec-report.outputs.exists == 'true'
|
||||
run: |
|
||||
job_id=$(ruby script/get_github_workflow_run_job_id.rb ${{ github.run_id }} ${{ github.run_attempt }} '${{ matrix.target }} ${{ matrix.build_type }}${{ !matrix.updated_ember && ' (Ember 3)' || '' }}')
|
||||
job_id=$(ruby script/get_github_workflow_run_job_id.rb ${{ github.run_id }} ${{ github.run_attempt }} '${{ matrix.target }} ${{ matrix.build_type }}')
|
||||
echo "job_id=$job_id" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Create flaky tests report artifact
|
||||
|
@ -332,7 +329,7 @@ jobs:
|
|||
|
||||
core_frontend_tests:
|
||||
if: github.event_name == 'pull_request' || github.repository != 'discourse/discourse-private-mirror'
|
||||
name: core frontend (${{ matrix.browser }})${{ !matrix.updated_ember && ' (Ember 3)' || '' }}
|
||||
name: core frontend (${{ matrix.browser }})
|
||||
runs-on: ubuntu-20.04-8core
|
||||
container:
|
||||
image: discourse/discourse_test:slim-browsers
|
||||
|
@ -344,10 +341,6 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
browser: ["Chrome", "Firefox ESR", "Firefox Evergreen"]
|
||||
updated_ember: [true]
|
||||
include:
|
||||
- browser: Chrome
|
||||
updated_ember: false
|
||||
|
||||
env:
|
||||
TESTEM_BROWSER: ${{ (startsWith(matrix.browser, 'Firefox') && 'Firefox') || matrix.browser }}
|
||||
|
@ -374,10 +367,6 @@ jobs:
|
|||
path: ${{ steps.yarn-cache-dir.outputs.dir }}
|
||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}-cachev2
|
||||
|
||||
- name: Downgrade Ember
|
||||
if: matrix.updated_ember == false
|
||||
run: script/switch_ember_version 3
|
||||
|
||||
- name: Yarn install
|
||||
working-directory: ./app/assets/javascripts/discourse
|
||||
run: yarn install --frozen-lockfile
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
{{! Remove when legacy modals are dropped (deprecation: discourse.modal-controllers) }}
|
||||
|
||||
<div
|
||||
id={{@id}}
|
||||
class={{concat-class "modal-body" @class}}
|
||||
tabindex="-1"
|
||||
{{did-insert this.didInsert}}
|
||||
{{will-destroy this.willDestroy}}
|
||||
...attributes
|
||||
>
|
||||
{{yield}}
|
||||
</div>
|
|
@ -1,72 +0,0 @@
|
|||
// Remove when legacy modals are dropped (deprecation: discourse.modal-controllers)
|
||||
|
||||
import Component from "@glimmer/component";
|
||||
import { DEBUG } from "@glimmer/env";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { action } from "@ember/object";
|
||||
import { inject as service } from "@ember/service";
|
||||
import $ from "jquery";
|
||||
import { disableImplicitInjections } from "discourse/lib/implicit-injections";
|
||||
|
||||
const LEGACY_ERROR =
|
||||
"d-modal-body should only be used inside a legacy controller-based d-modal. https://meta.discourse.org/t/268057";
|
||||
|
||||
function pick(object, keys) {
|
||||
const result = {};
|
||||
for (const key of keys) {
|
||||
if (key in object) {
|
||||
result[key] = object[key];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@disableImplicitInjections
|
||||
export default class DModalBody extends Component {
|
||||
@service appEvents;
|
||||
@service modal;
|
||||
|
||||
@tracked fixed = false;
|
||||
|
||||
@action
|
||||
didInsert(element) {
|
||||
if (element.closest(".d-modal:not(.d-modal-legacy)")) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(LEGACY_ERROR);
|
||||
if (DEBUG) {
|
||||
throw new Error(LEGACY_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
this.appEvents.trigger("modal-body:clearFlash");
|
||||
|
||||
const fixedParent = element.closest(".d-modal.fixed-modal");
|
||||
if (fixedParent) {
|
||||
this.fixed = true;
|
||||
$(fixedParent).modal("show");
|
||||
this.modal.hidden = false;
|
||||
}
|
||||
|
||||
this.appEvents.trigger(
|
||||
"modal:body-shown",
|
||||
pick(this.args, [
|
||||
"title",
|
||||
"rawTitle",
|
||||
"fixed",
|
||||
"subtitle",
|
||||
"rawSubtitle",
|
||||
"submitOnEnter",
|
||||
"dismissable",
|
||||
"headerClass",
|
||||
"modalClass",
|
||||
"titleAriaElementId",
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
@action
|
||||
willDestroy() {
|
||||
super.willDestroy(...arguments);
|
||||
this.appEvents.trigger("modal:body-dismissed");
|
||||
}
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
{{! Remove when legacy modals are dropped (deprecation: discourse.modal-controllers) }}
|
||||
|
||||
{{! template-lint-disable no-pointer-down-event-binding }}
|
||||
{{! template-lint-disable no-invalid-interactive }}
|
||||
|
||||
<div
|
||||
class={{concat-class
|
||||
this.modalClass
|
||||
this.modalStyle
|
||||
(if this.hasPanels "has-panels")
|
||||
(if @hidden "hidden")
|
||||
"d-modal-legacy"
|
||||
}}
|
||||
id={{if (not-eq this.modalStyle "inline-modal") "discourse-modal"}}
|
||||
data-keyboard="false"
|
||||
aria-modal="true"
|
||||
role="dialog"
|
||||
aria-labelledby={{this.ariaLabelledby}}
|
||||
...attributes
|
||||
{{did-insert this.setupListeners}}
|
||||
{{will-destroy this.cleanupListeners}}
|
||||
{{on "mousedown" this.handleMouseDown}}
|
||||
>
|
||||
<div class="modal-outer-container">
|
||||
<div class="modal-middle-container">
|
||||
<div class="modal-inner-container">
|
||||
<PluginOutlet @name="above-modal-header" @connectorTagName="div" />
|
||||
<div class="modal-header {{this.headerClass}}">
|
||||
{{#if this.dismissable}}
|
||||
<DButton
|
||||
@icon="times"
|
||||
@action={{route-action "closeModal" "initiatedByCloseButton"}}
|
||||
@title="modal.close"
|
||||
class="btn-flat modal-close close"
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
<div class="modal-title-wrapper">
|
||||
{{#if this.title}}
|
||||
<div class="title">
|
||||
<h3 id="discourse-modal-title">{{this.title}}</h3>
|
||||
|
||||
{{#if this.subtitle}}
|
||||
<p class="subtitle">{{this.subtitle}}</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<span id="modal-header-after-title"></span>
|
||||
</div>
|
||||
|
||||
{{#if this.panels}}
|
||||
<ul class="modal-tabs">
|
||||
{{#each this.panels as |panel|}}
|
||||
<ModalTab
|
||||
@panel={{panel}}
|
||||
@panelsLength={{this.panels.length}}
|
||||
@selectedPanel={{@selectedPanel}}
|
||||
@onSelectPanel={{@onSelectPanel}}
|
||||
/>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div
|
||||
id="modal-alert"
|
||||
role="alert"
|
||||
class={{if
|
||||
this.flash
|
||||
(concat-class
|
||||
"alert" (concat "alert-" (or this.flash.messageClass "success"))
|
||||
)
|
||||
}}
|
||||
>
|
||||
{{~this.flash.text~}}
|
||||
</div>
|
||||
|
||||
{{outlet "modalBody"}}
|
||||
|
||||
{{#each this.errors as |error|}}
|
||||
<div class="alert alert-error">
|
||||
<button
|
||||
type="button"
|
||||
class="close"
|
||||
data-dismiss="alert"
|
||||
aria-label={{i18n "modal.dismiss_error"}}
|
||||
>×</button>
|
||||
{{error}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,253 +0,0 @@
|
|||
// Remove when legacy modals are dropped (deprecation: discourse.modal-controllers)
|
||||
|
||||
import Component from "@glimmer/component";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { action } from "@ember/object";
|
||||
import { next, schedule } from "@ember/runloop";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { disableImplicitInjections } from "discourse/lib/implicit-injections";
|
||||
import { bind } from "discourse-common/utils/decorators";
|
||||
import I18n from "discourse-i18n";
|
||||
|
||||
@disableImplicitInjections
|
||||
export default class DModal extends Component {
|
||||
@service appEvents;
|
||||
@service modal;
|
||||
|
||||
@tracked wrapperElement;
|
||||
@tracked modalBodyData = {};
|
||||
@tracked flash;
|
||||
|
||||
get modalStyle() {
|
||||
if (this.args.modalStyle === "inline-modal") {
|
||||
return "inline-modal";
|
||||
} else {
|
||||
return "fixed-modal";
|
||||
}
|
||||
}
|
||||
|
||||
get submitOnEnter() {
|
||||
if ("submitOnEnter" in this.modalBodyData) {
|
||||
return this.modalBodyData.submitOnEnter;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
get dismissable() {
|
||||
if ("dismissable" in this.modalBodyData) {
|
||||
return this.modalBodyData.dismissable;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
get title() {
|
||||
if (this.modalBodyData.title) {
|
||||
return I18n.t(this.modalBodyData.title);
|
||||
} else if (this.modalBodyData.rawTitle) {
|
||||
return this.modalBodyData.rawTitle;
|
||||
} else {
|
||||
return this.args.title;
|
||||
}
|
||||
}
|
||||
|
||||
get subtitle() {
|
||||
if (this.modalBodyData.subtitle) {
|
||||
return I18n.t(this.modalBodyData.subtitle);
|
||||
}
|
||||
|
||||
return this.modalBodyData.rawSubtitle || this.args.subtitle;
|
||||
}
|
||||
|
||||
get headerClass() {
|
||||
return this.modalBodyData.headerClass;
|
||||
}
|
||||
|
||||
get panels() {
|
||||
return this.args.panels;
|
||||
}
|
||||
|
||||
get errors() {
|
||||
return this.args.errors;
|
||||
}
|
||||
|
||||
@action
|
||||
setupListeners(element) {
|
||||
this.appEvents.on("modal:body-shown", this._modalBodyShown);
|
||||
this.appEvents.on("modal-body:flash", this._flash);
|
||||
this.appEvents.on("modal-body:clearFlash", this._clearFlash);
|
||||
document.documentElement.addEventListener(
|
||||
"keydown",
|
||||
this._handleModalEvents
|
||||
);
|
||||
this.wrapperElement = element;
|
||||
}
|
||||
|
||||
@action
|
||||
cleanupListeners() {
|
||||
this.appEvents.off("modal:body-shown", this._modalBodyShown);
|
||||
this.appEvents.off("modal-body:flash", this._flash);
|
||||
this.appEvents.off("modal-body:clearFlash", this._clearFlash);
|
||||
document.documentElement.removeEventListener(
|
||||
"keydown",
|
||||
this._handleModalEvents
|
||||
);
|
||||
}
|
||||
|
||||
get ariaLabelledby() {
|
||||
if (this.modalBodyData.titleAriaElementId) {
|
||||
return this.modalBodyData.titleAriaElementId;
|
||||
} else if (this.args.titleAriaElementId) {
|
||||
return this.args.titleAriaElementId;
|
||||
} else if (this.args.title) {
|
||||
return "discourse-modal-title";
|
||||
}
|
||||
}
|
||||
|
||||
get modalClass() {
|
||||
return this.modalBodyData.modalClass || this.args.modalClass;
|
||||
}
|
||||
|
||||
triggerClickOnEnter(e) {
|
||||
if (!this.submitOnEnter) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// skip when in a form or a textarea element
|
||||
if (
|
||||
e.target.closest("form") ||
|
||||
(document.activeElement && document.activeElement.nodeName === "TEXTAREA")
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@action
|
||||
handleMouseDown(e) {
|
||||
if (!this.dismissable) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
e.target.classList.contains("modal-middle-container") ||
|
||||
e.target.classList.contains("modal-outer-container")
|
||||
) {
|
||||
// Send modal close (which bubbles to ApplicationRoute) if clicked outside.
|
||||
// We do this because some CSS of ours seems to cover the backdrop and makes
|
||||
// it unclickable.
|
||||
return this.args.closeModal?.("initiatedByClickOut");
|
||||
}
|
||||
}
|
||||
|
||||
@bind
|
||||
_modalBodyShown(data) {
|
||||
if (this.isDestroying || this.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.fixed) {
|
||||
this.modal.hidden = false;
|
||||
}
|
||||
|
||||
this.modalBodyData = data;
|
||||
|
||||
next(() => {
|
||||
schedule("afterRender", () => {
|
||||
this._trapTab();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@bind
|
||||
_handleModalEvents(event) {
|
||||
if (this.args.hidden) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.key === "Escape" && this.dismissable) {
|
||||
next(() => this.args.closeModal("initiatedByESC"));
|
||||
}
|
||||
|
||||
if (event.key === "Enter" && this.triggerClickOnEnter(event)) {
|
||||
this.wrapperElement.querySelector(".modal-footer .btn-primary")?.click();
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
if (event.key === "Tab") {
|
||||
this._trapTab(event);
|
||||
}
|
||||
}
|
||||
|
||||
_trapTab(event) {
|
||||
if (this.args.hidden) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const innerContainer = this.wrapperElement.querySelector(
|
||||
".modal-inner-container"
|
||||
);
|
||||
if (!innerContainer) {
|
||||
return;
|
||||
}
|
||||
|
||||
let focusableElements =
|
||||
'[autofocus], a, input, select, textarea, summary, [tabindex]:not([tabindex="-1"])';
|
||||
|
||||
if (!event) {
|
||||
// on first trap we don't allow to focus modal-close
|
||||
// and apply manual focus only if we don't have any autofocus element
|
||||
const autofocusedElement = innerContainer.querySelector("[autofocus]");
|
||||
if (
|
||||
!autofocusedElement ||
|
||||
document.activeElement !== autofocusedElement
|
||||
) {
|
||||
// if there's not autofocus, or the activeElement, is not the autofocusable element
|
||||
// attempt to focus the first of the focusable elements or just the modal-body
|
||||
// to make it possible to scroll with arrow down/up
|
||||
(
|
||||
autofocusedElement ||
|
||||
innerContainer.querySelector(
|
||||
focusableElements + ", button:not(.modal-close)"
|
||||
) ||
|
||||
innerContainer.querySelector(".modal-body")
|
||||
)?.focus();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
focusableElements += ", button:enabled";
|
||||
|
||||
const firstFocusableElement =
|
||||
innerContainer.querySelector(focusableElements);
|
||||
const focusableContent = innerContainer.querySelectorAll(focusableElements);
|
||||
const lastFocusableElement = focusableContent[focusableContent.length - 1];
|
||||
|
||||
if (event.shiftKey) {
|
||||
if (document.activeElement === firstFocusableElement) {
|
||||
lastFocusableElement?.focus();
|
||||
event.preventDefault();
|
||||
}
|
||||
} else {
|
||||
if (document.activeElement === lastFocusableElement) {
|
||||
(
|
||||
innerContainer.querySelector(".modal-close") || firstFocusableElement
|
||||
)?.focus();
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@bind
|
||||
_clearFlash() {
|
||||
this.flash = null;
|
||||
}
|
||||
|
||||
@bind
|
||||
_flash(msg) {
|
||||
this.flash = msg;
|
||||
}
|
||||
}
|
|
@ -10,25 +10,3 @@
|
|||
/>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
|
||||
{{#if this.renderLegacy}}
|
||||
<DModalLegacy
|
||||
@modalClass={{if
|
||||
this.modal.isLegacy
|
||||
(concat-class
|
||||
"modal"
|
||||
"d-modal"
|
||||
this.modal.modalClass
|
||||
(if this.modal.opts.panels "has-tabs")
|
||||
)
|
||||
}}
|
||||
@title={{this.modal.title}}
|
||||
@titleAriaElementId={{this.modal.opts.titleAriaElementId}}
|
||||
@panels={{this.modal.opts.panels}}
|
||||
@selectedPanel={{this.modal.selectedPanel}}
|
||||
@onSelectPanel={{this.modal.onSelectPanel}}
|
||||
@hidden={{this.modal.hidden}}
|
||||
@errors={{this.modal.errors}}
|
||||
@closeModal={{this.closeModal}}
|
||||
/>
|
||||
{{/if}}
|
|
@ -1,7 +1,6 @@
|
|||
import Component from "@glimmer/component";
|
||||
import { action } from "@ember/object";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { EMBER_MAJOR_VERSION } from "discourse/lib/ember-version";
|
||||
|
||||
export default class ModalContainer extends Component {
|
||||
@service modal;
|
||||
|
@ -10,8 +9,4 @@ export default class ModalContainer extends Component {
|
|||
closeModal(data) {
|
||||
this.modal.close(data);
|
||||
}
|
||||
|
||||
get renderLegacy() {
|
||||
return EMBER_MAJOR_VERSION < 4;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ import Component from "@ember/component";
|
|||
import EmberObject from "@ember/object";
|
||||
import Ember from "ember";
|
||||
import { actionModifier } from "./ember-action-modifier";
|
||||
import { EMBER_MAJOR_VERSION } from "./ember-version";
|
||||
|
||||
/**
|
||||
* Classic Ember components (i.e. "@ember/component") rely upon "event
|
||||
|
@ -127,16 +126,13 @@ function rewireClassicComponentEvents(app) {
|
|||
allEventMethods[methodName] = event;
|
||||
}
|
||||
|
||||
const triggerOverrideMethod =
|
||||
EMBER_MAJOR_VERSION < 4 ? "trigger" : "_trigger";
|
||||
|
||||
// Avoid Component.reopen to stop `ember.component.reopen` deprecation warning
|
||||
EmberObject.reopen.call(Component, {
|
||||
/**
|
||||
* @param {string | typeof INTERNAL} name
|
||||
* @param {unknown[]} args
|
||||
*/
|
||||
[triggerOverrideMethod](name, ...args) {
|
||||
_trigger(name, ...args) {
|
||||
if (name === INTERNAL) {
|
||||
if (this.element) {
|
||||
return this._super.call(this, ...args);
|
||||
|
|
|
@ -1,16 +1,9 @@
|
|||
import { tracked } from "@glimmer/tracking";
|
||||
import { getOwner } from "@ember/application";
|
||||
import { action } from "@ember/object";
|
||||
import Service, { inject as service } from "@ember/service";
|
||||
import { dasherize } from "@ember/string";
|
||||
import $ from "jquery";
|
||||
import { CLOSE_INITIATED_BY_MODAL_SHOW } from "discourse/components/d-modal";
|
||||
import { EMBER_MAJOR_VERSION } from "discourse/lib/ember-version";
|
||||
import { disableImplicitInjections } from "discourse/lib/implicit-injections";
|
||||
import deprecated, {
|
||||
withSilencedDeprecations,
|
||||
} from "discourse-common/lib/deprecated";
|
||||
import I18n from "discourse-i18n";
|
||||
import deprecated from "discourse-common/lib/deprecated";
|
||||
|
||||
const LEGACY_OPTS = new Set([
|
||||
"admin",
|
||||
|
@ -23,7 +16,7 @@ const LEGACY_OPTS = new Set([
|
|||
]);
|
||||
|
||||
@disableImplicitInjections
|
||||
class ModalService extends Service {
|
||||
export default class ModalService extends Service {
|
||||
@service dialog;
|
||||
|
||||
@tracked activeModal;
|
||||
|
@ -93,195 +86,3 @@ class ModalService extends Service {
|
|||
this.opts = {};
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all logic below when legacy modals are dropped (deprecation: discourse.modal-controllers)
|
||||
class ModalServiceWithLegacySupport extends ModalService {
|
||||
@service appEvents;
|
||||
|
||||
@tracked name;
|
||||
@tracked selectedPanel;
|
||||
@tracked hidden = true;
|
||||
|
||||
@tracked titleOverride;
|
||||
@tracked modalClassOverride;
|
||||
@tracked onSelectPanel;
|
||||
|
||||
get title() {
|
||||
if (this.titleOverride) {
|
||||
return this.titleOverride;
|
||||
} else if (this.opts.titleTranslated) {
|
||||
return this.opts.titleTranslated;
|
||||
} else if (this.opts.title) {
|
||||
return I18n.t(this.opts.title);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
set title(value) {
|
||||
this.titleOverride = value;
|
||||
}
|
||||
|
||||
get modalClass() {
|
||||
if (!this.isLegacy) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
this.modalClassOverride ||
|
||||
this.opts.modalClass ||
|
||||
`${dasherize(this.name.replace(/^modals\//, "")).toLowerCase()}-modal`
|
||||
);
|
||||
}
|
||||
|
||||
set modalClass(value) {
|
||||
this.modalClassOverride = value;
|
||||
}
|
||||
|
||||
show(modal, opts = {}) {
|
||||
if (typeof modal !== "string") {
|
||||
return super.show(modal, opts);
|
||||
}
|
||||
|
||||
this.close({ initiatedBy: CLOSE_INITIATED_BY_MODAL_SHOW });
|
||||
|
||||
deprecated(
|
||||
`Defining modals using a controller is deprecated. Use the component-based API instead. (modal: ${modal})`,
|
||||
{
|
||||
id: "discourse.modal-controllers",
|
||||
since: "3.1",
|
||||
dropFrom: "3.2",
|
||||
url: "https://meta.discourse.org/t/268057",
|
||||
}
|
||||
);
|
||||
|
||||
const name = modal;
|
||||
const container = getOwner(this);
|
||||
const route = container.lookup("route:application");
|
||||
|
||||
this.opts = opts;
|
||||
|
||||
const controllerName = opts.admin ? `modals/${name}` : name;
|
||||
this.name = controllerName;
|
||||
|
||||
let controller = container.lookup("controller:" + controllerName);
|
||||
const templateName = opts.templateName || dasherize(name);
|
||||
|
||||
const renderArgs = { into: "application", outlet: "modalBody" };
|
||||
if (controller) {
|
||||
renderArgs.controller = controllerName;
|
||||
} else {
|
||||
// use a basic controller
|
||||
renderArgs.controller = "basic-modal-body";
|
||||
controller = container.lookup(`controller:${renderArgs.controller}`);
|
||||
}
|
||||
|
||||
if (opts.addModalBodyView) {
|
||||
renderArgs.view = "modal-body";
|
||||
}
|
||||
|
||||
const modalName = `modal/${templateName}`;
|
||||
const fullName = opts.admin ? `admin/templates/${modalName}` : modalName;
|
||||
|
||||
// Any use of the legacy modal system will trigger Discourse's own deprecation message
|
||||
// so we can silence Ember's message here.
|
||||
withSilencedDeprecations("route-render-template", () => {
|
||||
route.render(fullName, renderArgs);
|
||||
});
|
||||
|
||||
if (opts.panels) {
|
||||
if (controller.actions.onSelectPanel) {
|
||||
this.onSelectPanel = controller.actions.onSelectPanel.bind(controller);
|
||||
}
|
||||
this.selectedPanel = opts.panels[0];
|
||||
}
|
||||
|
||||
controller.set("modal", this);
|
||||
const model = opts.model;
|
||||
if (model) {
|
||||
controller.set("model", model);
|
||||
}
|
||||
if (controller.onShow) {
|
||||
controller.onShow();
|
||||
}
|
||||
controller.set("flashMessage", null);
|
||||
|
||||
return (this.activeController = controller);
|
||||
}
|
||||
|
||||
close(initiatedBy) {
|
||||
if (!this.isLegacy) {
|
||||
super.close(...arguments);
|
||||
}
|
||||
|
||||
const controllerName = this.name;
|
||||
const controller = controllerName
|
||||
? getOwner(this).lookup(`controller:${controllerName}`)
|
||||
: null;
|
||||
|
||||
if (controller?.beforeClose?.() === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
const applicationRoute = getOwner(this).lookup("route:application");
|
||||
|
||||
// Any use of the legacy modal system will trigger Discourse's own deprecation message
|
||||
// so we can silence Ember's message here.
|
||||
withSilencedDeprecations("route-render-template", () => {
|
||||
applicationRoute.render("hide-modal", {
|
||||
into: "application",
|
||||
outlet: "modalBody",
|
||||
});
|
||||
});
|
||||
$(".d-modal.fixed-modal").modal("hide");
|
||||
|
||||
if (controller) {
|
||||
this.appEvents.trigger("modal:closed", {
|
||||
name: controllerName,
|
||||
controller,
|
||||
});
|
||||
|
||||
if (controller.onClose) {
|
||||
controller.onClose({
|
||||
initiatedByCloseButton: initiatedBy === "initiatedByCloseButton",
|
||||
initiatedByClickOut: initiatedBy === "initiatedByClickOut",
|
||||
initiatedByESC: initiatedBy === "initiatedByESC",
|
||||
});
|
||||
}
|
||||
}
|
||||
this.hidden = true;
|
||||
|
||||
this.name =
|
||||
this.selectedPanel =
|
||||
this.modalClassOverride =
|
||||
this.titleOverride =
|
||||
this.onSelectPanel =
|
||||
null;
|
||||
|
||||
super.close();
|
||||
}
|
||||
|
||||
hide() {
|
||||
if (this.isLegacy) {
|
||||
$(".d-modal.fixed-modal").modal("hide");
|
||||
} else {
|
||||
throw "hide/reopen are not supported for component-based modals";
|
||||
}
|
||||
}
|
||||
|
||||
reopen() {
|
||||
if (this.isLegacy) {
|
||||
$(".d-modal.fixed-modal").modal("show");
|
||||
} else {
|
||||
throw "hide/reopen are not supported for component-based modals";
|
||||
}
|
||||
}
|
||||
|
||||
get isLegacy() {
|
||||
return this.name && !this.activeModal;
|
||||
}
|
||||
}
|
||||
|
||||
export default EMBER_MAJOR_VERSION >= 4
|
||||
? ModalService
|
||||
: ModalServiceWithLegacySupport;
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
const EMBER_MAJOR_VERSION = parseInt(
|
||||
require("ember-source/package.json").version.split(".")[0],
|
||||
10
|
||||
);
|
||||
|
||||
module.exports = {
|
||||
"application-template-wrapper": false,
|
||||
"default-async-observers": true,
|
||||
"jquery-integration": EMBER_MAJOR_VERSION < 4,
|
||||
"jquery-integration": false,
|
||||
"template-only-glimmer-components": true,
|
||||
};
|
||||
|
|
|
@ -18,25 +18,8 @@ const withSideWatch = require("./lib/with-side-watch");
|
|||
const RawHandlebarsCompiler = require("discourse-hbr/raw-handlebars-compiler");
|
||||
const crypto = require("crypto");
|
||||
|
||||
const EMBER_MAJOR_VERSION = parseInt(
|
||||
require("ember-source/package.json").version.split(".")[0],
|
||||
10
|
||||
);
|
||||
|
||||
process.env.BROCCOLI_ENABLED_MEMOIZE = true;
|
||||
|
||||
function filterForEmberVersion(tree) {
|
||||
if (EMBER_MAJOR_VERSION < 4) {
|
||||
return tree;
|
||||
}
|
||||
|
||||
return funnel(tree, {
|
||||
// d-modal-legacy includes a named outlet which would cause
|
||||
// a build failure in modern Ember
|
||||
exclude: ["**/components/d-modal-legacy.hbs"],
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = function (defaults) {
|
||||
const discourseRoot = path.resolve("../../../..");
|
||||
const vendorJs = discourseRoot + "/vendor/assets/javascripts/";
|
||||
|
@ -92,21 +75,12 @@ module.exports = function (defaults) {
|
|||
},
|
||||
|
||||
trees: {
|
||||
app: filterForEmberVersion(
|
||||
RawHandlebarsCompiler(
|
||||
withSideWatch("app", { watching: ["../discourse-markdown-it"] })
|
||||
)
|
||||
app: RawHandlebarsCompiler(
|
||||
withSideWatch("app", { watching: ["../discourse-markdown-it"] })
|
||||
),
|
||||
},
|
||||
});
|
||||
|
||||
if (EMBER_MAJOR_VERSION < 4) {
|
||||
// TODO: remove me
|
||||
// Ember 3.28 still has some internal dependency on jQuery being a global,
|
||||
// for the time being we will bring it in vendor.js
|
||||
app.import("node_modules/jquery/dist/jquery.js", { prepend: true });
|
||||
}
|
||||
|
||||
// WARNING: We should only import scripts here if they are not in NPM.
|
||||
app.import(vendorJs + "bootbox.js");
|
||||
app.import(discourseRoot + "/app/assets/javascripts/polyfills.js");
|
||||
|
@ -186,8 +160,7 @@ module.exports = function (defaults) {
|
|||
if (
|
||||
!request.includes("-embroider-implicit") &&
|
||||
// TODO: delete special case for jquery when removing app.import() above
|
||||
((EMBER_MAJOR_VERSION < 4 && request === "jquery") ||
|
||||
request.startsWith("admin/") ||
|
||||
(request.startsWith("admin/") ||
|
||||
request.startsWith("discourse/plugins/") ||
|
||||
request.startsWith("discourse/theme-"))
|
||||
) {
|
||||
|
|
|
@ -26,30 +26,3 @@ define("ember-addons/ember-computed-decorators", [
|
|||
);
|
||||
return decorators;
|
||||
});
|
||||
|
||||
// Based on https://github.com/emberjs/ember-jquery-legacy
|
||||
// The addon has out-of-date dependences, but it's super simple so we can reproduce here instead:
|
||||
define("ember-jquery-legacy", ["exports"], function (exports) {
|
||||
exports.normalizeEvent = function (e) {
|
||||
if (e instanceof Event) {
|
||||
return e;
|
||||
}
|
||||
// __originalEvent is a private escape hatch of Ember's EventDispatcher to allow accessing `originalEvent` without
|
||||
// triggering a deprecation message.
|
||||
return e.__originalEvent || e.originalEvent;
|
||||
};
|
||||
});
|
||||
|
||||
// ember-cached-decorator-polyfill uses a Babel transformation to apply this polyfill in core.
|
||||
// Adding that Babel transformation to themes and plugins will be complex, so we use this to
|
||||
// patch it at runtime. This can be removed once `@glimmer/tracking` is updated to a version
|
||||
// with native `@cached` support.
|
||||
const glimmerTracking = require("@glimmer/tracking");
|
||||
if (glimmerTracking.cached) {
|
||||
// No-op. Can be removed once we're fully upgraded to Ember 4+
|
||||
// Search juice: EMBER_MAJOR_VERSION < 4;
|
||||
} else {
|
||||
Object.defineProperty(glimmerTracking, "cached", {
|
||||
get: () => require("ember-cached-decorator-polyfill").cached,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"postinstall": "./run-patch-package"
|
||||
},
|
||||
"workspaces": [
|
||||
"admin",
|
||||
"bootstrap-json",
|
||||
"deprecation-silencer",
|
||||
"dialog-holder",
|
||||
"discourse",
|
||||
"discourse-common",
|
||||
"discourse-hbr",
|
||||
"discourse-i18n",
|
||||
"discourse-markdown-it",
|
||||
"discourse-plugins",
|
||||
"discourse-widget-hbs",
|
||||
"ember-cli-progress-ci",
|
||||
"ember-production-deprecations",
|
||||
"float-kit",
|
||||
"pretty-text",
|
||||
"select-kit",
|
||||
"theme-transpiler",
|
||||
"truth-helpers"
|
||||
],
|
||||
"resolutions": {
|
||||
"**/unset-value": "2.0.1",
|
||||
"**/ember-source": "3.28.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"patch-package": "^8.0.0",
|
||||
"postinstall-postinstall": "^2.1.0"
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
package-ember5.json
|
1
app/assets/javascripts/package.json
Normal file
1
app/assets/javascripts/package.json
Normal file
|
@ -0,0 +1 @@
|
|||
package-ember5.json
|
File diff suppressed because it is too large
Load Diff
|
@ -1 +0,0 @@
|
|||
yarn-ember5.lock
|
1
app/assets/javascripts/yarn.lock
Normal file
1
app/assets/javascripts/yarn.lock
Normal file
|
@ -0,0 +1 @@
|
|||
yarn-ember5.lock
|
|
@ -157,8 +157,7 @@ class AdminDashboardData
|
|||
:unreachable_themes,
|
||||
:watched_words_check,
|
||||
:google_analytics_version_check,
|
||||
:translation_overrides_check,
|
||||
:ember_version_check
|
||||
:translation_overrides_check
|
||||
|
||||
add_problem_check { sidekiq_check || queue_size_check }
|
||||
end
|
||||
|
@ -382,10 +381,6 @@ class AdminDashboardData
|
|||
nil
|
||||
end
|
||||
|
||||
def ember_version_check
|
||||
I18n.t("dashboard.ember_version_warning") if ENV["EMBER_VERSION"] == "3"
|
||||
end
|
||||
|
||||
def out_of_date_themes
|
||||
old_themes = RemoteTheme.out_of_date_themes
|
||||
return unless old_themes.present?
|
||||
|
|
|
@ -56,17 +56,6 @@ if !args.include?("test") && !args.include?("build") && !args.include?("--proxy"
|
|||
args << PROXY
|
||||
end
|
||||
|
||||
if !["3", "5", nil].include?(ENV["EMBER_VERSION"])
|
||||
raise "Unknown ember version #{ENV["EMBER_VERSION"]}"
|
||||
end
|
||||
|
||||
system(
|
||||
"script/switch_ember_version",
|
||||
ENV["EMBER_VERSION"] || "5",
|
||||
exception: true,
|
||||
chdir: RAILS_ROOT,
|
||||
)
|
||||
|
||||
# Running yarn install in the root directory will also run it for YARN_DIR via a post-install hook
|
||||
exit 1 if !system "yarn", "-s", "install", "--cwd", RAILS_ROOT
|
||||
|
||||
|
|
|
@ -1537,7 +1537,6 @@ en:
|
|||
watched_word_regexp_error: "The regular expression for '%{action}' watched words is invalid. Please check your <a href='%{base_path}/admin/customize/watched_words'>Watched Word settings</a>, or disable the 'watched words regular expressions' site setting."
|
||||
v3_analytics_deprecated: "Your Discourse is currently using Google Analytics 3, which will no longer be supported after July 2023. <a href='https://meta.discourse.org/t/260498'>Upgrade to Google Analytics 4</a> now to continue receiving valuable insights and analytics for your website's performance."
|
||||
category_style_deprecated: "Your Discourse is currently using a deprecated category style which will be removed before the final beta release of Discourse 3.2. Please refer to <a href='https://meta.discourse.org/t/282441'>Moving to a Single Category Style Site Setting</a> for instructions on how to keep your selected category style."
|
||||
ember_version_warning: "Your site is running with the unsupported EMBER_VERSION=3 configuration. This may lead to unexpected issues with themes/plugins. Please remove the EMBER_VERSION configuration from your app.yml file and rebuild. See <a href='https://meta.discourse.org/t/287211'>https://meta.discourse.org/t/287211</a> for more information."
|
||||
back_from_logster_text: "Back to site"
|
||||
|
||||
site_settings:
|
||||
|
|
|
@ -10,13 +10,7 @@ task "assets:precompile:build" do
|
|||
if ENV["SKIP_EMBER_CLI_COMPILE"] != "1"
|
||||
ember_version = ENV["EMBER_VERSION"] || "5"
|
||||
|
||||
raise "Unknown ember version '#{ember_version}'" if !%w[3 5].include?(ember_version)
|
||||
|
||||
if ember_version == "3"
|
||||
puts "Downgrading to Ember 3..."
|
||||
system("script/switch_ember_version", ember_version, exception: true, chdir: Rails.root)
|
||||
system("yarn install", exception: true, chdir: "app/assets/javascripts/discourse")
|
||||
end
|
||||
raise "Unknown ember version '#{ember_version}'" if !%w[5].include?(ember_version)
|
||||
|
||||
compile_command = "CI=1 yarn --cwd app/assets/javascripts/discourse run ember build"
|
||||
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "fileutils"
|
||||
|
||||
# rubocop:disable Discourse/NoChdir
|
||||
Dir.chdir("#{__dir__}/../app/assets/javascripts") do
|
||||
FileUtils.rm("yarn-ember3.lock")
|
||||
FileUtils.cp("yarn-ember5.lock", "yarn-ember3.lock")
|
||||
|
||||
system("#{__dir__}/switch_ember_version", "3", exception: true)
|
||||
|
||||
system "yarn install", exception: true
|
||||
|
||||
system("#{__dir__}/switch_ember_version", "5", exception: true)
|
||||
end
|
|
@ -1,17 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "fileutils"
|
||||
|
||||
v = ARGV[0]
|
||||
|
||||
raise "Unexpected version #{v}" if !%w[3 5].include?(v)
|
||||
|
||||
# rubocop:disable Discourse/NoChdir
|
||||
Dir.chdir("#{__dir__}/../app/assets/javascripts") do
|
||||
FileUtils.rm("package.json")
|
||||
FileUtils.rm("yarn.lock")
|
||||
|
||||
File.symlink("package-ember#{v}.json", "package.json")
|
||||
File.symlink("yarn-ember#{v}.lock", "yarn.lock")
|
||||
end
|
Loading…
Reference in New Issue
Block a user