diff --git a/.bowerrc b/.bowerrc deleted file mode 100644 index 959e1696e7..0000000000 --- a/.bowerrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "directory": "bower_components", - "analytics": false -} diff --git a/.eslintrc.js b/.eslintrc.js index 33d24c6746..855a39f3a5 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -14,6 +14,9 @@ module.exports = { env: { browser: true }, + globals: { + basicContext: false + }, rules: { /* Possible Errors */ @@ -122,6 +125,8 @@ module.exports = { 'require-yield': 2, 'template-curly-spacing': 2, + 'ember/no-jquery': 'error', + // Temporarily turn these off 'ember/avoid-leaking-state-in-ember-objects': 'off', 'ember/closure-actions': 'off', diff --git a/.github_changelog_generator b/.github_changelog_generator new file mode 100644 index 0000000000..195b3ef5d4 --- /dev/null +++ b/.github_changelog_generator @@ -0,0 +1 @@ +since-tag=v2.3.1 diff --git a/.travis.yml b/.travis.yml index 30c95ba09e..f36d343aba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,11 +47,9 @@ jobs: before_install: - curl -o- -L https://yarnpkg.com/install.sh | bash - export PATH=$HOME/.yarn/bin:$PATH - - yarn global add bower install: - yarn install --ignore-engines - - bower install script: - node_modules/.bin/ember try:one $EMBER_TRY_SCENARIO --skip-cleanup=true --- node_modules/.bin/ember test --filter="Ember Debug" diff --git a/CHANGELOG.md b/CHANGELOG.md index a5a1c50291..2523959eb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,65 @@ +# Change Log + +## [Unreleased](https://github.com/emberjs/ember-inspector/tree/HEAD) + +[Full Changelog](https://github.com/emberjs/ember-inspector/compare/v3.0.0...HEAD) + +**Fixed bugs:** + +- "Cannot read property 'outlets' of undefined" On Ember 3.1-beta.1 [\#770](https://github.com/emberjs/ember-inspector/issues/770) +- Data tab not working [\#739](https://github.com/emberjs/ember-inspector/issues/739) + +**Merged pull requests:** + +- Bump minor version to 3.1.0 [\#769](https://github.com/emberjs/ember-inspector/pull/769) ([teddyzeenny](https://github.com/teddyzeenny)) +- Remove jQuery from app [\#768](https://github.com/emberjs/ember-inspector/pull/768) ([rwwagner90](https://github.com/rwwagner90)) + +## [v3.0.0](https://github.com/emberjs/ember-inspector/tree/v3.0.0) (2018-03-08) +[Full Changelog](https://github.com/emberjs/ember-inspector/compare/v2.3.1...v3.0.0) + +**Implemented enhancements:** + +- Test against all supported Ember versions with ember-try [\#763](https://github.com/emberjs/ember-inspector/issues/763) + +**Fixed bugs:** + +- Empty mixins break component selector [\#752](https://github.com/emberjs/ember-inspector/issues/752) +- Make View Tree support Glimmer components [\#750](https://github.com/emberjs/ember-inspector/issues/750) +- Not visible in Chromium 62 or Vivaldi 1.12 [\#734](https://github.com/emberjs/ember-inspector/issues/734) + +**Closed issues:** + +- Remove ember\_debug/addons/ember-new-computed [\#758](https://github.com/emberjs/ember-inspector/issues/758) +- Consider dropping Ember 1.x support / `ember-new-computed` [\#745](https://github.com/emberjs/ember-inspector/issues/745) +- \[feature discussion\] ability to configure value for "Hide Empty Model Types" [\#741](https://github.com/emberjs/ember-inspector/issues/741) +- Can not build current master [\#736](https://github.com/emberjs/ember-inspector/issues/736) +- Support Firefox 57.0 \("Quantum"\) [\#735](https://github.com/emberjs/ember-inspector/issues/735) +- Illegal invocation when using View tree. [\#718](https://github.com/emberjs/ember-inspector/issues/718) +- Compatibility with new modules API \(Ember 2.16\) [\#707](https://github.com/emberjs/ember-inspector/issues/707) + +**Merged pull requests:** + +- Fix text field assertion [\#767](https://github.com/emberjs/ember-inspector/pull/767) ([rwwagner90](https://github.com/rwwagner90)) +- Add branches to build in Travis CI [\#766](https://github.com/emberjs/ember-inspector/pull/766) ([teddyzeenny](https://github.com/teddyzeenny)) +- Fix inspector reset on client app's reset and destroy [\#765](https://github.com/emberjs/ember-inspector/pull/765) ([teddyzeenny](https://github.com/teddyzeenny)) +- Bump version to 3.0.0 [\#764](https://github.com/emberjs/ember-inspector/pull/764) ([teddyzeenny](https://github.com/teddyzeenny)) +- Ember 3.0, dep updates, testing updates, and codemods [\#762](https://github.com/emberjs/ember-inspector/pull/762) ([rwwagner90](https://github.com/rwwagner90)) +- Remove computedPolyfill [\#761](https://github.com/emberjs/ember-inspector/pull/761) ([rwwagner90](https://github.com/rwwagner90)) +- Remove getTemplate stuff [\#760](https://github.com/emberjs/ember-inspector/pull/760) ([rwwagner90](https://github.com/rwwagner90)) +- WIP [\#759](https://github.com/emberjs/ember-inspector/pull/759) ([rwwagner90](https://github.com/rwwagner90)) +- Fix file paths displayed in the Routes tab [\#757](https://github.com/emberjs/ember-inspector/pull/757) ([omarhamdan](https://github.com/omarhamdan)) +- Add Documentation + Minor Cleanup [\#755](https://github.com/emberjs/ember-inspector/pull/755) ([omarhamdan](https://github.com/omarhamdan)) +- Allow for empty mixins [\#753](https://github.com/emberjs/ember-inspector/pull/753) ([XuluWarrior](https://github.com/XuluWarrior)) +- ember-qunit-codemod [\#751](https://github.com/emberjs/ember-inspector/pull/751) ([rwwagner90](https://github.com/rwwagner90)) +- Start converting to module imports [\#749](https://github.com/emberjs/ember-inspector/pull/749) ([rwwagner90](https://github.com/rwwagner90)) +- Fix loading main outlet [\#748](https://github.com/emberjs/ember-inspector/pull/748) ([rwwagner90](https://github.com/rwwagner90)) +- Drop ember-new-computed [\#746](https://github.com/emberjs/ember-inspector/pull/746) ([jacobq](https://github.com/jacobq)) +- UI Tweaks to Match Latest Inspectors [\#744](https://github.com/emberjs/ember-inspector/pull/744) ([nummi](https://github.com/nummi)) +- Update Inspect Views Icon [\#743](https://github.com/emberjs/ember-inspector/pull/743) ([nummi](https://github.com/nummi)) +- preserve model type hiding [\#742](https://github.com/emberjs/ember-inspector/pull/742) ([efx](https://github.com/efx)) +- Bump patch version to 2.3.1 [\#738](https://github.com/emberjs/ember-inspector/pull/738) ([teddyzeenny](https://github.com/teddyzeenny)) +- Avoid error in some environments [\#638](https://github.com/emberjs/ember-inspector/pull/638) ([pablobm](https://github.com/pablobm)) + # Ember Inspector Changelog ## Ember Inspector 2.3.1 @@ -285,3 +347,6 @@ * Added a hint to refresh the page when the Inspector is open after a few promises were created and uncaught. * [BUGFIX] Error message about file:// protocol should only be shown on Chrome * [BUGFIX] Add missing ember.prod.js file in vendors + + +\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* \ No newline at end of file diff --git a/HISTORY.md b/HISTORY.md new file mode 100644 index 0000000000..a86f99fa96 --- /dev/null +++ b/HISTORY.md @@ -0,0 +1,283 @@ +# Ember Inspector Changelog + +## Ember Inspector 2.3.0 + +* [FEATURE] View tree filter support [#720](https://github.com/emberjs/ember-inspector/pull/720) +* [IMPROVEMENT] Sort object inspector properties [#622](https://github.com/emberjs/ember-inspector/pull/622) +* [BUGFIX] Fix the Ember Application's query selector [#730](https://github.com/emberjs/ember-inspector/pull/730) +* [BUGFIX] Fix late Iframe detection in Chrome [#729](https://github.com/emberjs/ember-inspector/pull/729) +* [INTERNAL] Update README and `package.json` to match recent updates [#724](https://github.com/emberjs/ember-inspector/pull/724) +* [INTERNAL] Fix compressed `dist` directory [#722](https://github.com/emberjs/ember-inspector/pull/722) + +## Ember Inspector 2.2.0 + +* [IMPROVEMENT] Rewrite the FF addon as a FF WebExtension [#715](https://github.com/emberjs/ember-inspector/pull/715) +* [BUGFIX] Fix `event` variable name [#714](https://github.com/emberjs/ember-inspector/pull/714) + +## Ember Inspector 2.1.1 + +* [BUGFIX] Only call Mixin#toString on Ember > 2.11 [#708](https://github.com/emberjs/ember-inspector/pull/708) +* [BUGFIX] Fix unloading a record in the data tab [#709](https://github.com/emberjs/ember-inspector/pull/709) + +## Ember Inspector 2.0.4 + +* [BUGFIX] Account for components that are appended manually [#610](https://github.com/emberjs/ember-inspector/pull/610) +* [BUGFIX] Only list sub-routes if they are defined [#612](https://github.com/emberjs/ember-inspector/pull/612) + +## Ember Inspector 2.0.3 + +* [BUGFIX] Fall back to memory caching if local storage is inaccessible [#592](https://github.com/emberjs/ember-inspector/pull/592) +* [BUGFIX] Update outlet and template Glimmer code to match 2.9.beta-3 [#607](https://github.com/emberjs/ember-inspector/pull/607) + +## Ember Inspector 2.0.2 + +* [BUGFIX] Rebuild columns when schema changes [#589](https://github.com/emberjs/ember-inspector/pull/589) +* [BUGFIX] Update to new way to get the root element in Glimmer [#588](https://github.com/emberjs/ember-inspector/pull/588) + +## Ember Inspector 2.0.1 + +* [BUGFIX] Disable source map for ember_debug.js [#583](https://github.com/emberjs/ember-inspector/pull/583) + +## Ember Inspector 2.0.0 + +* [FEATURE] Added the ability to resize and toggle columns [#574](https://github.com/emberjs/ember-inspector/pull/574) +* [IMPROVEMENT] Added Glimmer 2 support [#579](https://github.com/emberjs/ember-inspector/pull/579) +* [IMPROVEMENT] Current route only checkbox persists between refreshes now [#568](https://github.com/emberjs/ember-inspector/pull/568) +* [DOC] Fix typo in install instructions [#576](https://github.com/emberjs/ember-inspector/pull/576) +* [DOC] Remove `grunt version` command from README [#540](https://github.com/emberjs/ember-inspector/pull/540) +* [BUGFIX] The bookmarklet's `load_inspector.js` should not include ES6 [#546](https://github.com/emberjs/ember-inspector/pull/546) +* [BUGFIX] Fix deprecated `window.postMessage` usage [#555](https://github.com/emberjs/ember-inspector/pull/555) +* [INTERNAL] Upgrade Ember 1.12 -> Ember and Ember CLI 2.6 [#563](https://github.com/emberjs/ember-inspector/pull/563) +* [INTERNAL] Use smoke-and-mirrors for lazy rendering [#563](https://github.com/emberjs/ember-inspector/pull/563) +* [INTERNAL] Replace obsolete Broccoli plugins with "broccoli-funnel" [#571](https://github.com/emberjs/ember-inspector/pull/571) +* [INTERNAL] Update ESLint and enable more rules [#572](https://github.com/emberjs/ember-inspector/pull/572) +* [INTERNAL] Update build dependencies [#573](https://github.com/emberjs/ember-inspector/pull/573) [#578](https://github.com/emberjs/ember-inspector/pull/578) +* [INTERNAL] Remove `list-view` in order to upgrade Ember [#543](https://github.com/emberjs/ember-inspector/pull/543) +* [INTERNAL] Remove `dist-config.js` from index files [#542](https://github.com/emberjs/ember-inspector/pull/542) +* [INTERNAL] Lock down jQuery version [#512](https://github.com/emberjs/ember-inspector/pull/512) +* [INTERNAL] Upgrade babel-eslint [#515](https://github.com/emberjs/ember-inspector/pull/515) +* [INTERNAL] remove duplicate key from eslintrc [#517](https://github.com/emberjs/ember-inspector/pull/517) +* [INTERNAL] Port Gruntfile tasks to `grunt-jpm` to build a valid xpi for Firefox [#519](https://github.com/emberjs/ember-inspector/pull/519) + +## Ember Inspector 1.10.0 + +* [IMPROVEMENT] Add [DEV] to the tab name for the inspector development version [#527](https://github.com/emberjs/ember-inspector/pull/527) +* [BUGFIX] Fix PDF documents not opening on latest Chrome [#533](https://github.com/emberjs/ember-inspector/pull/533) +* [INTERNAL] Publish multiple versions of the inspector to support all Ember versions [#535](https://github.com/emberjs/ember-inspector/pull/535) +* [INTERNAL] Lock Ember version at 0.0.0 -> 2.6.0 and start supporting a new version at 2.7.0 + +## Ember Inspector 1.9.5 + +* [BUGFIX] filter out null/undefined nodes [#510](https://github.com/emberjs/ember-inspector/pull/510) +* [BUGFIX] Fix websocket adapter ES6 conversion [#505](https://github.com/emberjs/ember-inspector/pull/505) + +## Ember Inspector 1.9.4 + +* [BUGFIX] Launch inspector if document ready state is `interactive` [#500](https://github.com/emberjs/ember-inspector/pull/500) +* [BUGFIX] [Ember 2.2] Use the new `resolveRegistration` to remove the deprecation warning [#499](https://github.com/emberjs/ember-inspector/pull/499) [#497](https://github.com/emberjs/ember-inspector/pull/497) +* [BUGFIX] [Ember 2.2] Fix the view tree: use `scope.getSelf` when available to get the controller [#496](https://github.com/emberjs/ember-inspector/pull/496) +* [INTERNAL] Tweak Firefox skeleton again for 44 and later [#491](https://github.com/emberjs/ember-inspector/pull/491) + +## Ember Inspector 1.9.3 + +* [BUGFIX] Make sure we only reopen the app once [#482](https://github.com/emberjs/ember-inspector/pull/482) +* [BUGFIX] Save `_super` before reopening [#481](https://github.com/emberjs/ember-inspector/pull/481) +* [BUGFIX] Prevent errors when document.documentElement.dataset is not present [#475](https://github.com/emberjs/ember-inspector/pull/475) +* [BUGFIX] [Ember 2.1] Prevent deprecation for initializer arguments [#476](https://github.com/emberjs/ember-inspector/pull/476) +* [BUGFIX] [Ember 2.1] Update getState and getLocals for compatibility with canary [#467](https://github.com/emberjs/ember-inspector/pull/467) + +## Ember Inspector 1.9.2 + +* [BUGFIX] Don't assume Ember.View exists (for Ember 2.0+) [#469](https://github.com/emberjs/ember-inspector/pull/469) +* [IMPROVEMENT] Update Firefox skeleton for path change in Firefox 44+ [#470](https://github.com/emberjs/ember-inspector/pull/470) + +## Ember Inspector 1.9.1 + +* [BUGFIX] Fix value of this after ES6 refactor [#450](https://github.com/emberjs/ember-inspector/pull/450) + +## Ember Inspector 1.9.0 + +* [IMPROVEMENT] Speed up source map computation in deprecations pane [#439](https://github.com/emberjs/ember-inspector/pull/439) +* [BUGFIX] Fix resolver and Ember.View errors in Ember 2.0 canary [#440](https://github.com/emberjs/ember-inspector/pull/440) +* [BUGFIX] Fix components not being detected inside {{each}} helper [#428](https://github.com/emberjs/ember-inspector/pull/428) +* [BUGFIX] Fix "object could not be cloned" error when prototype extensions are disabled [#435](https://github.com/emberjs/ember-inspector/pull/435) +* [BUGFIX] Tomster should be not hidden if the Ember app contains an iframe [#436](https://github.com/emberjs/ember-inspector/pull/436) +* [BUGFIX] Guard against renderNode.lastResult being null +[#437](https://github.com/emberjs/ember-inspector/pull/437) +* [BUGFIX] Fix object inspector toggle button being hidden when the object inspector is expanded. +[#438](https://github.com/emberjs/ember-inspector/pull/438) +* [BUGFIX] Prevent deprecations for Ember.keys on Ember 2.0.0 [#426](https://github.com/emberjs/ember-inspector/pull/426) +* [INTERNAL] Rewrite the entire build process to targets all platforms in the same build [#374](https://github.com/emberjs/ember-inspector/pull/374) +* [INTERNAL] Refactor all the code to use ES6 [#368](https://github.com/emberjs/ember-inspector/pull/368), [#370](https://github.com/emberjs/ember-inspector/pull/370), [#372](https://github.com/emberjs/ember-inspector/pull/372), +[#376](https://github.com/emberjs/ember-inspector/pull/376) +, +[#387](https://github.com/emberjs/ember-inspector/pull/387) +* [INTERNAL] Update the README deployment steps [#442](https://github.com/emberjs/ember-inspector/pull/442) +* [INTERNAL] Use a new eslint config (eslint-config-ember) [#371](https://github.com/emberjs/ember-inspector/pull/371) +* [INTERNAL] Fix the build commands in README [#385](https://github.com/emberjs/ember-inspector/pull/385) +* [INTERNAL] Add CODE_OF_CONDUCT.md + +## Ember Inspector 1.8.3 + +* [BUGFIX] Fix routes pane for Ember >= 1.13 [#399](https://github.com/emberjs/ember-inspector/pull/399) +* [BUGFIX] Fix sending view model to console [#412](https://github.com/emberjs/ember-inspector/pull/412) +* [BUGFIX] Guard against renderNode not being rendered yet [#417](https://github.com/emberjs/ember-inspector/pull/417) + +## Ember Inspector 1.8.2 + +* [IMPROVEMENT] Add support for Ember Data >= 1.0.0-beta.19 [#383](https://github.com/emberjs/ember-inspector/pull/383) +* [IMPROVEMENT] Add support for Ember >= 1.13.0 [#393](https://github.com/emberjs/ember-inspector/pull/393) + - Rename `Ember.Debug` to `Ember.EmberInspectorDebugger` + - Remove calls to `Ember.View.addMutationListener` + - Use the container's view registry instead of `Ember.View.views` + +## Ember Inspector 1.8.1 + +* [IMPROVEMENT] Remove new CP syntax deprecation warning [#362](https://github.com/emberjs/ember-inspector/pull/362) + +## Ember Inspector 1.8.0 + +* [IMPROVEMENT] The view tree now supports glimmer [#357](https://github.com/emberjs/ember-inspector/pull/357) +* [IMPROVEMENT] Catch errors triggered by the inspector and show them as warnings [#343](https://github.com/emberjs/ember-inspector/pull/343) +* [IMPROVEMENT] Handle and display errors caused by CP calculation in the object inspector [#342](https://github.com/emberjs/ember-inspector/pull/342) +* [IMPROVEMENT] Stop deprecation logging in console and add one warning [#347](https://github.com/emberjs/ember-inspector/pull/347) +* [IMPROVEMENT] Speed up the deprecations tab and source map computation [#358](https://github.com/emberjs/ember-inspector/pull/358) +* [BUGFIX] Include ember-new-computed in ember-debug to remove CP syntax deprecations [#352](https://github.com/emberjs/ember-inspector/pull/352) +* [INTERNAL] Tests now use async/await instead of async test helpers [#340](https://github.com/emberjs/ember-inspector/pull/340) +* [INTERNAL] Use new CP syntax [#337](https://github.com/emberjs/ember-inspector/pull/337) +* [INTERNAL] Add eslint [#340](https://github.com/emberjs/ember-inspector/pull/340) +* [INTERNAL] Use broccoli-es6modules (esperanto) to transpile ember-debug [#328](https://github.com/emberjs/ember-inspector/pull/328) +* [INTERNAL] Upgrade to ember-cli 0.2 and qunit 2.0 syntax [#330](https://github.com/emberjs/ember-inspector/pull/330) [#332](https://github.com/emberjs/ember-inspector/pull/332) [#293](https://github.com/emberjs/ember-inspector/pull/293) +* [INTERNAL] Upgrade to Ember 1.10 [#329](https://github.com/emberjs/ember-inspector/pull/329) + +## Ember Inspector 1.7.3 + +* [BUGFIX] Don't assume prototype extensions are enabled +* [BUGFIX] Descriptor is no longer exposed on the Ember global +* [BUGFIX] Handle case where container type no longer exists after reload + +## Ember Inspector 1.7.2 + +* [BUGFIX] Fixed error when `define` is defined but `requireModule` is not +* [BUGFIX] Fixed Ember 1.11 resolver bug that broke the routes tab +* [BUGFIX] Only destroy the promise assembler if it exists +* [BUGFIX] Use the new Ember load hook if available +* [BUGFIX] Fixed issue with deferred apps getting mistakenly detected +* [BUGFIX] ObjectInspector is not destroyed last on app reset +* [BUGFIX] Use registry.resolve for latest Ember +* Add grunt-cli to package.json +* Do not minify code for FF addon + +## Ember Inspector 1.7.1 + +* [BUGFIX] Fix the inspector for Ember < 1.4 + +## Ember Inspector 1.7.0 + +* [FEATURE] Added a new deprecations tab +* [FEATURE] The inspector now works in tests +* [FEATURE] Inspector state is now preserved across reloads +* [IMPROVEMENT] Fixed object naming to account for module based names +* [IMPROVEMENT] Moved the project to ember-cli +* [IMPROVEMENT] Added a date picker to the object inspector +* [IMPROVEMENT] Migrated to the new chrome extension options dialog +* [BUGFIX] The data tab now detects models using pod structure +* [BUGFIX] Prevent duplicate model types in the data tab +* [BUGFIX] Improved startup so the inspector launches before the app +* [BUGFIX] We now store `instrumentWithStack` in session storage for reloads +* [BUGFIX] Ember.Debug as a namespace was changing inspected object names +* [BUGFIX] The render performance tab now fails silently on render errors +* [BUGFIX] Nested components no longer cause wrong views to be listed +* [BUGFIX] Guarded against `event.data`in window messages being null +* Use Ember's `ViewUtils` to get the `BoundingClientRect` +* Ensured last Firefox addon-sdk is used +* Added warning to the README about the use of window messages + +## Ember Inspector 1.6.4 + +* [BUGFIX] Check type of EMBER_INSPECTOR_CONFIG + +## Ember Inspector 1.6.3 + +* Use the new `Ember.libraries` api for newer Ember versions + +## Ember Inspector 1.6.2 + +* Add dist directories to npm + +## Ember Inspector 1.6.1 + +* [BUGFIX] Used general dot replacement in regex expressions to support nested routes +* Used `document.defaultView.eval` to support FF >= 34 +* Added npm `prepublish` hook + +## Ember Inspector 1.6.0 + +* [FEATURE] Added new "Container" tab +* [FEATURE] Added `EmberInspector.inspect(obj)` to send objects to the inspector +* [FEATURE] Views generated by `each` helper are now shown by default +* [FEATURE] Added a link to Github issues +* [FEATURE] Object inspector can now drill into arrays +* [FEATURE] Added support for dates in the object inspector +* [IMPROVEMENT] Main nav is now resizable +* [IMPROVEMENT] Performance improvement by making promise tracing opt-in +* [IMPROVEMENT] Model types are now sorted alphabetically +* [IMPROVEMENT] Separated regular tabs from advanced tabs +* [IMPROVEMENT] Detecting the application view no longer depends on `ember-application` class +* [BUGFIX] `null` values now show up as "null" in the object inspector +* [BUGFIX] Empty values in the object inspector should be editable +* [BUGFIX] Support views without a controller +* [BUGFIX] Firefox Tomster script no longer conflicts with WYSIWYGs +* [BUGFIX] Fixed issue with toolbar and expanding the object inspector +* [BUGFIX] Removed 404 image errors from tests + +## Ember Inspector 1.5.0 + +* [IMPROVEMENT] Redesigned the UI to be more consistent with Chrome dev tools +* [IMPROVEMENT] Improved "appeared" performance by instrumenting out of band +* [BUGFIX] Fixed compatibility issue between promise inspection and Ember >= 1.7 +* [BUGFIX] Fixed view highlighting after metal-views upgrade +* [BUGFIX] Fixed conflict between injecting Tomster script and file upload libraries + +## Ember Inspector 1.4.0 + +* [FEATURE] Added bookmark option to support all browsers +* [FEATURE] Added support for multiple iframes +* [FEATURE] Added optional Tomster to Firefox +* [FEATURE] Added "display current route" option to the routes tab +* [IMPROVEMENT] Removed redundant prefixes from class names in the view tree +* [IMPROVEMENT] Added search field to the render performance tab +* [BUGFIX] Fixed current route match when resource same as route name +* [BUGFIX] Fixed bug where a maximum of one namespace was assumed +* [BUGFIX] Fixed render perf tab for apps with prototype extensions disabled +* [BUGFIX] Routes tab no longer instantiates controllers +* `data-ember-extension` is now only added to the HTML tag (instead of the body). + +## Ember Inspector 1.3.1 + +* [IMPROVEMENT] Better view names in the render performance tab +* [IMPROVEMENT] Object inspector now skips properties ending with `Binding` +* [IMPROVEMENT] Removed several `Ember.View` private props from the Object Inspector +* [BUGFIX] Fixed hierarchy issue in render perf tree causing duplication of views +* [BUGFIX] Fixed scrollbar in render performance tab on OS X +* [BUGFIX] Object inspector should not assume all `_debugInfo` props exist + +## Ember Inspector 1.3.0 + +* [FEATURE] Added new "Render Performance" tab +* [FEATURE] Added new column "Duration" to the view tree +* [BUGFIX] Fixed bug with editing json strings in the object inspector +* [BUGFIX] Fixed permission denied exception on Firefox >= 30 +* Removed dummy URLs created by Ember for error and loading routes +* Removed methods from the object inspector + +## Ember Inspector 1.2.0 + +* [FEATURE] Add info tab that shows a list of libraries used and their versions +* [FEATURE] Add a Tomster icon to Chrome bar on any page with an Ember app (opt-in in chrome://extensions -> Ember Inspector -> options) +* [FEATURE] Promise chains can now be collapsed / expanded. Fulfilled promises are collapsed by default. Rejected and pending are expanded. +* Replaced $E button with "Stack trace" when the promise rejects with an instance of `Error`. +* Added support for async loading of Ember (such as requirejs) +* Added a hint to refresh the page when the Inspector is open after a few promises were created and uncaught. +* [BUGFIX] Error message about file:// protocol should only be shown on Chrome +* [BUGFIX] Add missing ember.prod.js file in vendors diff --git a/README.md b/README.md index 9e388b4ee2..6d1401bf93 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ OR: - Clone the repository - cd into the repo directory -- run `yarn install && bower install` +- run `yarn install` - run `yarn global add ember-cli` - run `yarn build` to build the `dist` directory - Visit `chrome://extensions` in Chrome @@ -30,7 +30,7 @@ OR: - Clone the repository - cd into the repo directory -- run `yarn install && bower install` +- run `yarn install` - run `yarn global add ember-cli` - run `yarn build` to build the `dist` directory - Visit `about:debugging` in Firefox @@ -41,7 +41,7 @@ OR: - Clone the repository - cd into the repo directory -- run `yarn install && bower install` +- run `yarn install` - run `yarn global add ember-cli` - run `yarn build` to build the `dist` directory - Visit `chrome://extensions` in Opera @@ -69,7 +69,7 @@ javascript: (function() { var s = document.createElement('script'); s.src = 'htt ## Building and Testing: -Run `yarn install && yarn global add ember-cli && yarn global add bower && bower install && grunt-cli` to install the required modules. +Run `yarn install && yarn global add ember-cli && grunt-cli` to install the required modules. - `yarn build` to build the files in the `dist` directory - `yarn watch` To watch the files and re-build in `dist` when anything changes (useful during development). diff --git a/app/adapters/web-extension.js b/app/adapters/web-extension.js index 64219e24d2..b1c65bd842 100644 --- a/app/adapters/web-extension.js +++ b/app/adapters/web-extension.js @@ -16,6 +16,8 @@ export default BasicAdapter.extend({ this._connect(); this._handleReload(); this._injectDebugger(); + this._setThemeColors(); + return this._super(...arguments); }, @@ -55,6 +57,17 @@ export default BasicAdapter.extend({ this.onResourceAdded(); }, + _setThemeColors() { + // Remove old theme colors to ensure switching themes works + document.body.classList.remove('theme--light', 'theme--dark'); + + let theme = 'theme--light'; + if (chrome.devtools.panels.themeName === 'dark') { + theme = 'theme--dark'; + } + document.body.classList.add(theme); + }, + onResourceAdded(/*callback*/) {}, willReload() { diff --git a/app/components/component-tree-item.js b/app/components/component-tree-item.js new file mode 100644 index 0000000000..85f3d51ecc --- /dev/null +++ b/app/components/component-tree-item.js @@ -0,0 +1,14 @@ +import { computed } from '@ember/object'; +import Component from '@ember/component'; +import { htmlSafe } from '@ember/string'; + +export default Component.extend({ + item: null, + tagName: '', + + labelStyle: computed('item.parentCount', function() { + let expanderOffset = this.get('item.hasChildren') ? 12 : 0; + let padding = this.get('item.parentCount') * 20 - expanderOffset + 25; + return htmlSafe(`padding-left: ${padding}px;`); + }) +}); diff --git a/app/components/date-property-field.js b/app/components/date-property-field.js index 8c6afa1014..dc655e1297 100644 --- a/app/components/date-property-field.js +++ b/app/components/date-property-field.js @@ -16,7 +16,7 @@ export default DatePicker.extend({ }, openDatePicker: on('didInsertElement', function() { - once(this.$(), 'click'); + once(this.element, 'click'); }), keyUp(e) { diff --git a/app/components/drag-handle.js b/app/components/drag-handle.js index dd4cb1779e..ac200a8ce5 100644 --- a/app/components/drag-handle.js +++ b/app/components/drag-handle.js @@ -1,4 +1,3 @@ -import $ from 'jquery'; import { equal } from '@ember/object/computed'; import Component from '@ember/component'; import { computed } from '@ember/object'; @@ -51,32 +50,18 @@ export default Component.extend({ 'on-drag'() {}, startDragging() { - let $container = this.$().parent(); - let $containerOffsetLeft = $container.offset().left; - let $containerOffsetRight = $containerOffsetLeft + $container.width(); - let namespace = `drag-${this.get('elementId')}`; - - this.sendAction('action', true); + let namespace = `drag-${this.elementId}`; - $('body').on(`mousemove.${namespace}`, e => { - let position = this.get('isLeft') ? - e.pageX - $containerOffsetLeft : - $containerOffsetRight - e.pageX; + this.setIsDragging(true); - position -= this.get('left'); - if (position >= this.get('minWidth') && position <= this.get('maxWidth')) { - this.set('position', position); - this.get('on-drag')(position); - } - }) - .on(`mouseup.${namespace} mouseleave.${namespace}`, () => { - this.stopDragging(); - }); + document.body.addEventListener(`mousemove.${namespace}`, this._mouseMoveHandler); + document.body.addEventListener(`mouseup.${namespace} mouseleave.${namespace}`, this.stopDragging); }, stopDragging() { - this.sendAction('action', false); - $('body').off(`.drag-${this.get('elementId')}`); + this.setIsDragging(false); + document.body.removeEventListener(`.drag-${this.elementId}`, this._mouseMoveHandler); + document.body.removeEventListener(`.drag-${this.elementId}`, this.stopDragging); }, willDestroyElement() { @@ -97,5 +82,21 @@ export default Component.extend({ string = ''; } return htmlSafe(string); - }) + }), + + _mouseMoveHandler(e) { + let $container = this.element.parentNode; + let $containerOffsetLeft = $container.offset().left; + let $containerOffsetRight = $containerOffsetLeft + $container.width(); + + let position = this.get('isLeft') ? + e.pageX - $containerOffsetLeft : + $containerOffsetRight - e.pageX; + + position -= this.get('left'); + if (position >= this.get('minWidth') && position <= this.get('maxWidth')) { + this.set('position', position); + this.get('on-drag')(position); + } + } }); diff --git a/app/components/draggable-column.js b/app/components/draggable-column.js index 79e56a1c68..7fc4b80e80 100644 --- a/app/components/draggable-column.js +++ b/app/components/draggable-column.js @@ -9,16 +9,15 @@ export default Component.extend({ tagName: '', // Prevent wrapping in a div side: 'left', minWidth: 60, - setIsDragging: 'setIsDragging', /** * Injected `layout` service. Used to broadcast * changes the layout of the app. * - * @property layout + * @property layoutService * @type {Service} */ - layout: service(), + layoutService: service('layout'), /** * Trigger that the application dimensions have changed due to @@ -28,14 +27,10 @@ export default Component.extend({ * @method triggerResize */ triggerResize() { - this.get('layout').trigger('resize', { source: 'draggable-column' }); + this.get('layoutService').trigger('resize', { source: 'draggable-column' }); }, actions: { - setIsDragging(isDragging) { - this.sendAction('setIsDragging', isDragging); - }, - /** * Action called whenever the draggable column has been * resized. diff --git a/app/components/main-content.js b/app/components/main-content.js index 82ea6032e4..488d3ef80c 100644 --- a/app/components/main-content.js +++ b/app/components/main-content.js @@ -1,6 +1,5 @@ import Component from '@ember/component'; import { schedule } from '@ember/runloop'; -import $ from 'jquery'; import { inject as service } from '@ember/service'; import { task, timeout } from 'ember-concurrency'; @@ -16,9 +15,7 @@ export default Component.extend({ layoutService: service('layout'), didInsertElement() { - $(window).on(`resize.view-${this.get('elementId')}`, () => { - this.get('updateHeightDebounce').perform(); - }); + window.addEventListener(`resize.view-${this.elementId}`, this._performUpdateHeight); schedule('afterRender', this, this.updateHeight); return this._super(...arguments); }, @@ -35,6 +32,10 @@ export default Component.extend({ this.updateHeight(); }).restartable(), + _performUpdateHeight() { + this.get('updateHeightDebounce').perform(); + }, + /** * Update the layout's `contentHeight` property. * This will cause the layout service to trigger @@ -47,11 +48,11 @@ export default Component.extend({ * @method updateHeight */ updateHeight() { - this.get('layoutService').updateContentHeight(this.$().height()); + this.get('layoutService').updateContentHeight(this.element.clientHeight); }, willDestroyElement() { - $(window).off(`.view-${this.get('elementId')}`); + window.removeEventListener(`.view-${this.elementId}`, this._performUpdateHeight); return this._super(...arguments); } }); diff --git a/app/components/mixin-property.js b/app/components/mixin-property.js index 27954c2dc1..92af19ceb3 100644 --- a/app/components/mixin-property.js +++ b/app/components/mixin-property.js @@ -1,6 +1,6 @@ import { computed } from '@ember/object'; import Component from '@ember/component'; -import { equal, alias } from '@ember/object/computed'; +import { equal, alias, and } from '@ember/object/computed'; export default Component.extend({ isEdit: false, @@ -17,19 +17,31 @@ export default Component.extend({ txtValue: null, dateValue: null, - isCalculated: computed('model.value.type', function() { - return this.get('model.value.type') !== 'type-descriptor'; + isCalculated: computed('valueType', function() { + return this.get('valueType') !== 'type-descriptor'; }), - isEmberObject: equal('model.value.type', 'type-ember-object'), + valueType: alias('model.value.type'), + + isService: alias('model.isService'), + + isOverridden: alias('model.overridden'), + + isEmberObject: equal('valueType', 'type-ember-object'), isComputedProperty: alias('model.value.computed'), - isFunction: equal('model.value.type', 'type-function'), + isFunction: equal('valueType', 'type-function'), + + isArray: equal('valueType', 'type-array'), - isArray: equal('model.value.type', 'type-array'), + isDate: equal('valueType', 'type-date'), - isDate: equal('model.value.type', 'type-date'), + isDepsExpanded: false, + + hasDependentKeys: and('model.dependentKeys.length', 'isCalculated'), + + showDependentKeys: and('isDepsExpanded', 'hasDependentKeys'), _parseTextValue(value) { let parsedValue; @@ -48,6 +60,9 @@ export default Component.extend({ }, actions: { + toggleDeps() { + this.toggleProperty('isDepsExpanded'); + }, valueClick() { if (this.get('isEmberObject') || this.get('isArray')) { this.get('mixin').send('digDeeper', this.get('model')); @@ -64,7 +79,7 @@ export default Component.extend({ } let value = this.get('model.value.inspect'); - let type = this.get('model.value.type'); + let type = this.get('valueType'); if (type === 'type-string') { value = `"${value}"`; } diff --git a/app/components/property-field.js b/app/components/property-field.js index 0e117400f8..74b2bd5011 100644 --- a/app/components/property-field.js +++ b/app/components/property-field.js @@ -12,7 +12,7 @@ export default TextField.extend({ properyComponent: null, didInsertElement() { - this.$().select(); + this.element.select(); return this._super(...arguments); }, diff --git a/app/components/record-item.js b/app/components/record-item.js index d7d79ba8e1..76ea9a6bb4 100644 --- a/app/components/record-item.js +++ b/app/components/record-item.js @@ -5,7 +5,7 @@ import { isEmpty } from '@ember/utils'; const COLOR_MAP = { red: '#ff2717', blue: '#174fff', - green: '#006400' + green: '#009900' }; export default Component.extend({ diff --git a/app/components/resizable-column.js b/app/components/resizable-column.js index 6781862581..a776627edc 100644 --- a/app/components/resizable-column.js +++ b/app/components/resizable-column.js @@ -12,7 +12,7 @@ export default Component.extend({ didInsertElement() { if (!this.get('width')) { - this.set('width', this.$().width()); + this.set('width', this.element.clientWidth); } } }); diff --git a/app/components/search-field.js b/app/components/search-field.js new file mode 100644 index 0000000000..f9108ca8c1 --- /dev/null +++ b/app/components/search-field.js @@ -0,0 +1,10 @@ +import Component from '@ember/component'; + +export default Component.extend({ + actions: { + clear() { + this.element.querySelector('input').focus(); + this.set('value', ''); + } + } +}); diff --git a/app/components/x-list.js b/app/components/x-list.js index ec4fcd6466..bfe553149c 100644 --- a/app/components/x-list.js +++ b/app/components/x-list.js @@ -1,9 +1,8 @@ import Component from '@ember/component'; import { run, scheduleOnce } from '@ember/runloop'; -import $ from 'jquery'; import { task, timeout } from 'ember-concurrency'; import ResizableColumns from 'ember-inspector/libs/resizable-columns'; -import LocalStorageService from "ember-inspector/services/storage/local"; +import LocalStorageService from 'ember-inspector/services/storage/local'; import { inject as service } from '@ember/service'; import { readOnly, reads } from '@ember/object/computed'; @@ -27,12 +26,12 @@ export default Component.extend({ /** * Layout service used to listen to changes to the application - * layout such as resizing of the main nav or object inspecto. + * layout such as resizing of the main nav or object inspector. * - * @property layout + * @property layoutService * @type {Service} */ - layout: service(), + layoutService: service('layout'), /** * Indicate the table's header's height in pixels. @@ -140,8 +139,8 @@ export default Component.extend({ this.onResize = () => { this.get('debounceColumnWidths').perform(); }; - $(window).on(`resize.${this.get('elementId')}`, this.onResize); - this.get('layout').on('resize', this.onResize); + window.addEventListener(`resize.${this.get('elementId')}`, this.onResize); + this.get('layoutService').on('resize', this.onResize); return this._super(...arguments); }, @@ -164,12 +163,19 @@ export default Component.extend({ arr.push({ name, title: name, - fun: run.bind(this, this.toggleColumnVisibility, id) + fn: run.bind(this, this.toggleColumnVisibility, id) }); return arr; }, []); - this.$('.list__header').contextMenu(menu, { triggerOn: 'contextmenu' }); + this.showBasicContext = (e) => { + basicContext.show(menu, e); + }; + + const listHeader = this.element.querySelector('.list__header'); + if (listHeader) { + listHeader.addEventListener('contextmenu', this.showBasicContext); + } }, /** @@ -183,7 +189,10 @@ export default Component.extend({ */ toggleColumnVisibility(id) { this.resizableColumns.toggleVisibility(id); - this.$('.list__header').contextMenu('destroy'); + const listHeader = this.element.querySelector('.list__header'); + if (listHeader) { + listHeader.removeEventListener('contextmenu', this.showBasicContext); + } this.setupContextMenu(); }, @@ -195,7 +204,7 @@ export default Component.extend({ * @property debounceColumnWidths * @type {Object} Ember Concurrency task */ - debounceColumnWidths: task(function * () { + debounceColumnWidths: task(function* () { yield timeout(100); this.resizableColumns.setTableWidth(this.getTableWidth()); }).restartable(), @@ -207,9 +216,12 @@ export default Component.extend({ * @method willDestroyElement */ willDestroyElement() { - $(window).off(`.${this.get('elementId')}`); - this.$('.list__header').contextMenu('destroy'); - this.get('layout').off('resize', this.onResize); + window.removeEventListener(`.${this.elementId}`, this.onResize); + const listHeader = this.element.querySelector('.list__header'); + if (listHeader) { + listHeader.removeEventListener('contextmenu', this.showBasicContext); + } + this.get('layoutService').off('resize', this.onResize); return this._super(...arguments); }, @@ -220,7 +232,7 @@ export default Component.extend({ * @return {Number} The width in pixels */ getTableWidth() { - return this.$('.list__table-container').innerWidth(); + return this.element.querySelector('.list__table-container').clientWidth; }, /** diff --git a/app/controllers/component-tree.js b/app/controllers/component-tree.js new file mode 100644 index 0000000000..77cebefccc --- /dev/null +++ b/app/controllers/component-tree.js @@ -0,0 +1,228 @@ +import { + get, + computed +} from '@ember/object'; +import Controller, { + inject as controller +} from '@ember/controller'; +import searchMatch from 'ember-inspector/utils/search-match'; +import { + notEmpty, +} from '@ember/object/computed'; +import { + isEmpty +} from '@ember/utils'; + +import ComponentViewItem from 'ember-inspector/models/component-view-item'; + +/** + * Takes the `viewTree` from `view-debug`'s `sendTree()` method, and recursively + * flattens it into an array of `ComponentViewItem` objects + * @param {string} searchValue The value of the search box + * @param {*} treeNode The node in the viewTree + * @param {ComponentViewItem} parent The parent `ComponentViewItem` + * @param {number} parentCount The component hierarchy depth + * @param {boolean} parentMatched Whether the parent node is initially set to display + * @param {Array} list The accumulator, gets mutated in each call + */ +const flattenSearchTree = ( + searchValue, + treeNode, + parent, + parentCount, + parentMatched, + list +) => { + let activeSearch = !isEmpty(searchValue); + let searchMatched = activeSearch ? + searchMatch(get(treeNode, 'value.name'), searchValue) : + true; + + let viewItem = ComponentViewItem.create({ + view: treeNode.value, + parent, + parentCount, + searchMatched, + activeSearch, + expanded: !activeSearch, + hasChildren: treeNode.children.length > 0, + }); + + // remember if there is no active search, searchMatched will be true + let shouldAddItem = searchMatched || parentMatched; + if (shouldAddItem) { + list.push(viewItem); + } + + let newParentCount = shouldAddItem ? parentCount + 1 : 0; + + treeNode.children.forEach(child => { + flattenSearchTree( + searchValue, + child, + viewItem, + newParentCount, + shouldAddItem, + list + ); + }); + return list; +}; + +export default Controller.extend({ + application: controller(), + pinnedObjectId: null, + inspectingViews: false, + components: true, + options: { + components: true, + }, + + /** + * Bound to the search field to filter the component list. + * + * @property searchValue + * @type {String} + * @default '' + */ + searchValue: '', + + activeSearch: notEmpty('searchValue'), + + /** + * The final list that the `{{vertical-collection}}` renders + * is created in three stages: + * 1. The `viewArray` is recalculated When the controller's `viewTree` is set by the route, or when + * a user updates the search box. + * 2. The `filteredArray` CP takes the `viewArray` and caches the expanded state for each item. + * This keeps the tree from suddenly re-expanding if the `viewTree` updates after users have + * collapsed some nodes. + * 3. Once the list is rendered, when users expand/collapse a node that action directly + * toggles the `expanded` property on each item, which makes `visible` recompute. + * + * This could probably happen in one big function, but for the time being its split in the + * interest of clarity rather than performance (even if the extra CPs might avoid doing some extra + * work when users expand/contract tree nodes) + */ + displayedList: computed('filteredArray.@each.visible', function () { + return this.get('filteredArray').filterBy('visible'); + }), + + filteredArray: computed('viewArray.[]', function () { + let viewArray = this.get('viewArray'); + let expandedStateCache = this.get('expandedStateCache'); + viewArray.forEach(viewItem => { + let cachedExpansion = expandedStateCache[viewItem.view.objectId]; + if (cachedExpansion !== undefined) { + viewItem.set('expanded', cachedExpansion); + } else { + expandedStateCache[viewItem.view.objectId] = viewItem.expanded; + } + }); + + return viewArray; + }), + + viewArray: computed('viewTree', 'searchValue', function () { + let tree = this.get('viewTree'); + if (!tree) { + return []; + } + return flattenSearchTree(this.get('searchValue'), tree, null, 0, false, []); + }), + + expandedStateCache: null, //set on init + + init() { + this._super(...arguments); + this.set('expandedStateCache', {}); + }, + + expandToNode(objectId) { + let node = this.get('filteredArray').find(item => item.get('id') === objectId); + if (node) { + node.expandParents(); + } + }, + + actions: { + previewLayer({ + view: { + objectId, + elementId, + renderNodeId + } + }) { + // We are passing all of objectId, elementId, and renderNodeId to support post-glimmer 1, post-glimmer 2, and root for + // post-glimmer 2 + this.get('port').send('view:previewLayer', { + objectId, + renderNodeId, + elementId, + }); + }, + + hidePreview() { + this.get('port').send('view:hidePreview'); + }, + + toggleViewInspection() { + this.get('port').send('view:inspectViews', { + inspect: !this.get('inspectingViews'), + }); + }, + + sendObjectToConsole(objectId) { + this.get('port').send('objectInspector:sendToConsole', { + objectId, + }); + }, + + expandAll() { + this.expandedStateCache = {}; + this.get('filteredArray').forEach((item) => { + item.set('expanded', true); + this.expandedStateCache[item.view.objectId] = true; + }); + }, + + collapseAll() { + this.expandedStateCache = {}; + this.get('filteredArray').forEach((item) => { + item.set('expanded', false); + this.expandedStateCache[item.view.objectId] = false; + }); + }, + + toggleExpanded(item) { + item.toggleProperty('expanded'); + this.expandedStateCache[item.view.objectId] = item.get('expanded'); + }, + + inspect(objectId) { + if (objectId) { + this.set('pinnedObjectId', objectId); + this.expandToNode(objectId); + this.get('port').send('objectInspector:inspectById', { + objectId, + }); + } + }, + + scrollToElement(elementId) { + this.get('port').send('view:scrollToElement', { + elementId + }); + }, + + inspectElement({ + objectId, + elementId + }) { + this.get('port').send('view:inspectElement', { + objectId, + elementId, + }); + }, + }, +}); diff --git a/app/controllers/container-type.js b/app/controllers/container-type.js index bd7c1b96c0..fcef33fd2b 100644 --- a/app/controllers/container-type.js +++ b/app/controllers/container-type.js @@ -9,7 +9,7 @@ export default Controller.extend({ sortProperties: ['name'], - searchVal: debounceComputed('search', 300), + searchValue: debounceComputed('search', 300), search: null, diff --git a/app/controllers/deprecations.js b/app/controllers/deprecations.js index 3294947180..5611fc11f3 100644 --- a/app/controllers/deprecations.js +++ b/app/controllers/deprecations.js @@ -13,10 +13,12 @@ export default Controller.extend({ */ application: controller(), search: null, - searchVal: debounceComputed('search', 300), + searchValue: debounceComputed('search', 300), + filtered: filter('model', function(item) { return searchMatch(get(item, 'message'), this.get('search')); }).property('model.@each.message', 'search'), + actions: { openResource(item) { this.get('adapter').openResource(item.fullSource, item.line); diff --git a/app/controllers/promise-tree.js b/app/controllers/promise-tree.js index 31a7f3921f..207de41325 100644 --- a/app/controllers/promise-tree.js +++ b/app/controllers/promise-tree.js @@ -70,15 +70,15 @@ export default Controller.extend({ isPendingFilter: equal('filter', 'pending'), isFulfilledFilter: equal('filter', 'fulfilled'), - search: null, + searchValue: null, effectiveSearch: null, - searchChanged: observer('search', function() { + searchChanged: observer('searchValue', function() { debounce(this, this.notifyChange, 500); }), notifyChange() { - this.set('effectiveSearch', this.get('search')); + this.set('effectiveSearch', this.get('searchValue')); next(() => { this.notifyPropertyChange('model'); }); diff --git a/app/controllers/records.js b/app/controllers/records.js index 55c87a5a37..64db0a8089 100644 --- a/app/controllers/records.js +++ b/app/controllers/records.js @@ -8,11 +8,11 @@ import { dasherize } from '@ember/string'; export default Controller.extend({ application: controller(), - queryParams: ['filterValue', 'search'], + queryParams: ['filterValue', 'searchValue'], columns: readOnly('modelType.columns'), - search: '', + searchValue: '', filters: computed(() => []), @@ -21,7 +21,7 @@ export default Controller.extend({ noFilterValue: none('filterValue'), modelChanged: observer('model', function() { - this.set('search', ''); + this.set('searchValue', ''); }), recordToString(record) { @@ -72,8 +72,8 @@ export default Controller.extend({ return { columns }; }), - filtered: computed('search', 'model.@each.columnValues', 'model.@each.filterValues', 'filterValue', function() { - let search = this.get('search'); + filtered: computed('searchValue', 'model.@each.columnValues', 'model.@each.filterValues', 'filterValue', function() { + let search = this.get('searchValue'); let filter = this.get('filterValue'); return this.get('model').filter(item => { // check filters diff --git a/app/controllers/render-tree.js b/app/controllers/render-tree.js index bfcc43100d..cc551bbc0f 100644 --- a/app/controllers/render-tree.js +++ b/app/controllers/render-tree.js @@ -68,7 +68,7 @@ export default Controller.extend({ // bound to the input field, updates the `search` property // 300ms after changing - searchField: debounceComputed('search', 300), + searchValue: debounceComputed('search', 300), // model filtered based on this value search: '', diff --git a/app/controllers/view-tree.js b/app/controllers/view-tree.js index 6e9885ea12..c717e1cb7c 100644 --- a/app/controllers/view-tree.js +++ b/app/controllers/view-tree.js @@ -1,4 +1,3 @@ -import { on } from '@ember/object/evented'; import { observer, get } from '@ember/object'; import Controller, { inject as controller } from '@ember/controller'; import searchMatch from 'ember-inspector/utils/search-match'; @@ -17,11 +16,11 @@ export default Controller.extend({ /** * Bound to the search field to filter the component list. * - * @property searchText + * @property searchValue * @type {String} * @default '' */ - searchText: '', + searchValue: '', /** * The filtered view list. @@ -30,12 +29,12 @@ export default Controller.extend({ * @type {Array} */ filteredList: filter('model', function(item) { - return searchMatch(get(item, 'value.name'), this.get('searchText')); - }).property('model.[]', 'searchText'), + return searchMatch(get(item, 'value.name'), this.get('searchValue')); + }).property('model.[]', 'searchValue'), - optionsChanged: on('init', observer('options.components', function() { + optionsChanged: observer('options.components', function() { this.port.send('view:setOptions', { options: this.get('options') }); - })), + }), actions: { previewLayer({ value: { objectId, elementId, renderNodeId } }) { diff --git a/app/models/component-view-item.js b/app/models/component-view-item.js new file mode 100644 index 0000000000..9da81d1e58 --- /dev/null +++ b/app/models/component-view-item.js @@ -0,0 +1,56 @@ +import EmberObject, { computed } from '@ember/object'; +import { reads } from '@ember/object/computed'; + +/** + * ComponentViewItem is used to represent the flattened nodes in the component tree + */ +export default EmberObject.extend({ + /** + * The Ember View object this item represents + */ + view: null, + + /** + * A reference to the parent `ComponentViewItem`, null at the root of the tree + */ + parent: null, + + /** + * Used to set indentation levels later + */ + parentCount: 0, + expanded: true, + hasChildren: true, + searchMatched: false, + + /** + * If the user has typed text into the search box (used to calculate visibility) + */ + activeSearch: false, + + id: reads('view.objectId'), + + expandParents() { + let parent = this.get('parent'); + if (parent) { + parent.set('expanded', true); + parent.expandParents(); + } + }, + + visible: computed( + 'parent.{visible,expanded}', + 'searchMatched', + 'activeSearch', + function() { + let parent = this.get('parent'); + let showNodeInHierarchy = + parent && parent.get('expanded') && parent.get('visible'); + if (this.get('activeSearch')) { + return this.get('searchMatched') || showNodeInHierarchy; + } else { + return !parent || showNodeInHierarchy; + } + } + ), +}); diff --git a/app/router.js b/app/router.js index e1b3e6c557..7a404e04bf 100644 --- a/app/router.js +++ b/app/router.js @@ -9,6 +9,7 @@ const Router = EmberRouter.extend({ Router.map(function() { this.route('app-detected', { path: '/', resetNamespace: true }, function() { this.route('view-tree', { path: '/', resetNamespace: true }); + this.route('component-tree', { resetNamespace: true }); this.route('route-tree', { resetNamespace: true }); this.route('data', { resetNamespace: true }, function() { diff --git a/app/routes/application.js b/app/routes/application.js index af7d516b42..b4f71e3c20 100644 --- a/app/routes/application.js +++ b/app/routes/application.js @@ -3,6 +3,7 @@ import Route from '@ember/routing/route'; import { inject as service } from '@ember/service'; import { schedule } from '@ember/runloop'; import Ember from "ember"; + const { NativeArray } = Ember; @@ -77,24 +78,24 @@ export default Route.extend({ * Service used to broadcast changes to the application's layout * such as toggling of the object inspector. * - * @property layout + * @property layoutService * @type {Service} */ - layout: service(), + layoutService: service('layout'), actions: { expandInspector() { this.set("controller.inspectorExpanded", true); // Broadcast that tables have been resized (used by `x-list`). schedule('afterRender', () => { - this.get('layout').trigger('resize', { source: 'object-inspector' }); + this.get('layoutService').trigger('resize', { source: 'object-inspector' }); }); }, toggleInspector() { this.toggleProperty("controller.inspectorExpanded"); // Broadcast that tables have been resized (used by `x-list`). schedule('afterRender', () => { - this.get('layout').trigger('resize', { source: 'object-inspector' }); + this.get('layoutService').trigger('resize', { source: 'object-inspector' }); }); }, inspectObject(objectId) { diff --git a/app/routes/component-tree.js b/app/routes/component-tree.js new file mode 100644 index 0000000000..73d590121b --- /dev/null +++ b/app/routes/component-tree.js @@ -0,0 +1,43 @@ +import TabRoute from "ember-inspector/routes/tab"; + +export default TabRoute.extend({ + setupController() { + this._super(...arguments); + this.get('port').on('view:viewTree', this, this.setViewTree); + this.get('port').on('view:stopInspecting', this, this.stopInspecting); + this.get('port').on('view:startInspecting', this, this.startInspecting); + this.get('port').on('view:inspectDOMElement', this, this.inspectDOMElement); + this.get('port').on('view:inspectComponent', this, this.inspectComponent); + this.get('port').send('view:setOptions', { options: this.get('controller.options') }); + this.get('port').send('view:getTree'); + }, + + deactivate() { + this.get('port').off('view:viewTree', this, this.setViewTree); + this.get('port').off('view:stopInspecting', this, this.stopInspecting); + this.get('port').off('view:startInspecting', this, this.startInspecting); + this.get('port').off('view:inspectDOMElement', this, this.inspectDOMElement); + this.get('port').off('view:inspectComponent', this, this.inspectComponent); + + }, + + setViewTree(options) { + this.set('controller.viewTree', options.tree); + }, + + startInspecting() { + this.set('controller.inspectingViews', true); + }, + + stopInspecting() { + this.set('controller.inspectingViews', false); + }, + + inspectComponent({ viewId }) { + this.get('controller').send('inspect', viewId); + }, + + inspectDOMElement({ elementSelector }) { + this.get('port.adapter').inspectDOMElement(elementSelector); + } +}); diff --git a/app/routes/view-tree.js b/app/routes/view-tree.js index d7319736c1..98c2aa74c7 100644 --- a/app/routes/view-tree.js +++ b/app/routes/view-tree.js @@ -12,6 +12,7 @@ export default TabRoute.extend({ this.get('port').on('view:stopInspecting', this, this.stopInspecting); this.get('port').on('view:startInspecting', this, this.startInspecting); this.get('port').on('view:inspectDOMElement', this, this.inspectDOMElement); + this.get('port').send('view:setOptions', { options: this.get('controller.options') }); this.get('port').send('view:getTree'); }, diff --git a/app/styles/app.scss b/app/styles/app.scss index 5a604e5166..6366a14791 100644 --- a/app/styles/app.scss +++ b/app/styles/app.scss @@ -23,6 +23,8 @@ } @import "base"; +@import "colors"; +@import "component_tree"; @import "context_menu"; @import "drag_handle"; @import "dropdown"; diff --git a/app/styles/base.scss b/app/styles/base.scss index 3066cf49af..5deb108ecc 100644 --- a/app/styles/base.scss +++ b/app/styles/base.scss @@ -1,3 +1,9 @@ +:root { + --font-sans-serif: -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Cantarell', 'Oxygen', 'Ubuntu', 'Helvetica Neue', helvetica, arial, sans-serif; + --font-monospace: 'SF Mono', Menlo, Monaco, monospace; +} + + h1, h2, h3, h4, h5, h6 { margin: 0; padding: 0; @@ -10,8 +16,8 @@ html, body { } body, input { - font-family: -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Cantarell', 'Oxygen', 'Ubuntu', 'Helvetica Neue', helvetica, arial, sans-serif; - color: #333; + font-family: var(--font-sans-serif); + color: var(--base26); } body, div, nav { @@ -24,5 +30,5 @@ a { } code { - font-family: Menlo, Monaco, monospace; + font-family: var(--font-monospace); } diff --git a/app/styles/colors.scss b/app/styles/colors.scss new file mode 100644 index 0000000000..fd42e7b873 --- /dev/null +++ b/app/styles/colors.scss @@ -0,0 +1,111 @@ +.theme--light { + --base00: #ffffff; + --base01: #f3f3f3; + --base03: #ededed; + --base05: #dedede; + --base06: #d1d1d1; + --base07: #cccccc; + --base08: #cacaca; + --base10: #b4b4b4; + --base11: #b3b3b3; + --base12: #b2b2b2; + --base13: #aaaaaa; + --base14: #a3a3a3; + --base15: #999999; + --base16: #888888; + --base17: #777777; + --base18: #737373; + --base19: #6e6e6e; + --base20: #676767; + --base21: #555555; + --base22: #505050; + --base23: #444444; + --base24: #404040; + --base25: #3d3d3d; + --base26: #333333; + --base27: #303030; + --base28: #222222; + --base29: #000000; + --base30: #bcbcbc; + --base31: #464646; + --base32: #d6d6d6; + --base33: #666666; + --base34: #cecece; + --base35: #f5f5f5; + --base36: #e7e7e7; + --spec00: #fffec2; + --spec01: #ffffee; + --spec02: #ff0000; + --spec03: #f23818; + --spec04: #990099; + --spec05: #990000; + --spec06: #6e68c6; + --spec07: #4281eb; + --spec08: #3879d9; + --spec09: #2b7fb3; + --spec10: #000099; + --spec11: #3F81EE; + --spec12: #7c027c; + --spec13: #4977d2; + --spec14: #ecf1fa; + --spec15: #cd61a7; + --spec16: #7fb56d; + --spec17: #328509; + --spec18: #9c0f9c; +} + +.theme--dark { + --base00: #242424; + --base01: #242424; + --base03: #121212; + --base05: #212121; + --base06: #2E2E2E; + --base07: #333333; + --base08: #353535; + --base10: #4B4B4B; + --base11: #4C4C4C; + --base12: #4D4D4D; + --base13: #555555; + --base14: #5C5C5C; + --base15: #666666; + --base16: #777777; + --base17: #888888; + --base18: #8C8C8C; + --base19: #919191; + --base20: #989898; + --base21: #AAAAAA; + --base22: #AFAFAF; + --base23: #BBBBBB; + --base24: #BFBFBF; + --base25: #C2C2C2; + --base26: #CCCCCC; + --base27: #CFCFCF; + --base28: #DDDDDD; + --base29: #FFFFFF; + --base30: #434343; + --base31: #B9B9B9; + --base32: #292929; + --base33: #999999; + --base34: #313131; + --base35: #0A0A0A; + --base36: #181818; + --spec00: #00013D; + --spec01: #000011; + --spec02: #00FFFF; + --spec03: #0DC7E7; + --spec04: #66FF66; + --spec05: #66FFFF; + --spec06: #919739; + --spec07: #BD7E14; + --spec08: #C78626; + --spec09: #D4804C; + --spec10: #FFFF66; + --spec11: #C07E11; + --spec12: #83FD83; + --spec13: #B6882D; + --spec14: #130E05; + --spec15: #cd61a7; + --spec16: #7fb56d; + --spec17: #328509; + --spec18: #9c0f9c; +} diff --git a/app/styles/component_tree.scss b/app/styles/component_tree.scss new file mode 100644 index 0000000000..52c813f525 --- /dev/null +++ b/app/styles/component_tree.scss @@ -0,0 +1,99 @@ +.component-tree-item { + position: relative; + display: flex; + min-height: 18px; + align-items: center; + margin: 3px 3px 0 3px; + border-radius: 4px; + font-size: 12px; + color: var(--base21); + +} + +.component-tree-item--component { + color: var(--spec12); + + &:hover { + background-color: var(--spec14); + + .component-tree-item__view-element { opacity: 1; } + } +} + +.component-tree-item__view-element { + display: flex; + align-items: center; + height: 100%; + padding: 0; + border: 0; + background: transparent; + + &:focus { outline: none; } +} + +.component-tree-item__tag { + display: flex; + cursor: default; +} + .component-tree-item--component .component-tree-item__tag { + cursor: pointer; + } + +.component-tree-item__bracket::before { + content: '{{'; + color: var(--base14); +} +.component-tree-item__bracket::after { + content: '}}'; + color: var(--base14); +} + +.component-tree-item__expand { + display: inline-block; + border: 0; + padding: 0 2px; + cursor: pointer; + background: transparent; + + &:focus { outline: none; } + + svg { + transition-property: transform; + transition-duration: 0.1s; + } + + &.collapsed svg { + transform: rotate(-90deg); + } +} + +.component-tree-item__view-element { + display: inline-block; + margin-left: 10px; + opacity: 0; + cursor: pointer; + + polygon, rect, path { fill: var(--base28); } +} + + +/** + * Modifier + */ + +.component-tree-item--selected { + color: var(--base00); + background: var(--spec13); + &:hover { background: var(--spec13); } + + .component-tree-item__bracket::before, + .component-tree-item__bracket::after { + color: var(--base14); + } + + .component-tree-item__expand, + .component-tree-item__view-element { + opacity: 1; + polygon, rect, path { fill: var(--base00); } + } +} diff --git a/app/styles/drag_handle.scss b/app/styles/drag_handle.scss index 275e89318c..14885cfb40 100644 --- a/app/styles/drag_handle.scss +++ b/app/styles/drag_handle.scss @@ -25,7 +25,7 @@ height: 100%; margin-left: 3px; width: 1px; - border-left: 1px solid #A3A3A3; + border-left: 1px solid var(--base30); pointer-events: none; } diff --git a/app/styles/dropdown.scss b/app/styles/dropdown.scss index a9e1e79131..63488c1aa6 100644 --- a/app/styles/dropdown.scss +++ b/app/styles/dropdown.scss @@ -6,20 +6,22 @@ .dropdown { position: relative; flex: auto; + height: 28px; } .dropdown__select { - -webkit-appearance: none; box-sizing: border-box; display: block; width: 100%; - height: 18px; - padding: 0 15px 0 5px; + height: 100%; + margin: 0; + padding: 0 16px 0 5px; font-size: 12px; - color: rgb(48, 48, 48); - text-shadow: rgba(255, 255, 255, 0.75) 0 1px 0; + color: var(--base31); border: 0; background-color: transparent; + -moz-appearance: none; + -webkit-appearance: none; } .dropdown__select:focus { @@ -28,13 +30,9 @@ .dropdown__arrow { position: absolute; - right: 4px; - top: 7px; - background-image: url(images/arrow_down.svg); - background-size: 100%; + right: 5px; + top: 9px; opacity: 0.7; - width: 7px; - height: 7px; - display: inline-block; + width: 6px; pointer-events: none; } diff --git a/app/styles/error_page.scss b/app/styles/error_page.scss index 1a3d225680..86de69c8a4 100644 --- a/app/styles/error_page.scss +++ b/app/styles/error_page.scss @@ -15,13 +15,13 @@ .error-page { padding: 10px; - background: #ededed; + background: var(--base03); position: absolute; top: 0; left: 0; width: 100%; min-height: 100%; - color: #505050; + color: var(--base22); -moz-box-sizing: border-box; box-sizing: border-box; } @@ -32,14 +32,14 @@ padding: 25px; -moz-box-sizing: border-box; box-sizing: border-box; - background: #ffffff; - border: solid 1px #d1d1d1; + background: var(--base00); + border: 1px solid var(--base06); border-radius: 5px; margin: auto; } .error-page__content a { - color: #f23818; + color: var(--spec03); text-decoration: none; } @@ -49,7 +49,7 @@ padding-top: 15px; padding-bottom: 30px; margin-bottom: 10px; - border-bottom: solid 1px #d1d1d1; + border-bottom: 1px solid var(--base06); position: relative; } @@ -58,6 +58,7 @@ width: 128px; height: 89px; background: url("images/fishy_tomster.png") left center no-repeat; + background-size: 128px 89px; position: absolute; right: 0px; bottom: 0px; @@ -82,7 +83,7 @@ .error-page__list { padding-left: 16px; padding-bottom: 5px; - border-bottom: solid 1px #d1d1d1;; + border-bottom: 1px solid var(--base06); } .error-page__list li { diff --git a/app/styles/external_link.scss b/app/styles/external_link.scss index 82b74a4075..2931736172 100644 --- a/app/styles/external_link.scss +++ b/app/styles/external_link.scss @@ -9,7 +9,7 @@ position: absolute; right: -12px; bottom: 10px; - background-image: url('images/external_link.svg'); + background-image: url('svg/external_link.svg'); background-size: 100%; } } diff --git a/app/styles/list.scss b/app/styles/list.scss index 367d6bd7de..201ceb3166 100644 --- a/app/styles/list.scss +++ b/app/styles/list.scss @@ -3,7 +3,7 @@ font-size: 11px; height: 100%; box-sizing: border-box; - background: white; + background: var(--base00); overflow: hidden; } @@ -32,12 +32,12 @@ text-align: left; user-select: none; - border-bottom: 1px solid #cacaca; + border-bottom: 1px solid var(--base08); height: 30px; .list__row { - background: #fff; + background: var(--base00); } .list__cell { @@ -55,10 +55,10 @@ .list:not(.list_no-alternate-color) .list__content { .list__row { - background: #f3f3f3; + background: var(--base03); &:nth-of-type(2n) { - background: #fff; + background: var(--base00); } } } @@ -200,7 +200,7 @@ top: 0px; font-size: 75%; - color: #737373; + color: var(--base18); } } diff --git a/app/styles/mixin.scss b/app/styles/mixin.scss index aa87925e0a..32b4c602c0 100644 --- a/app/styles/mixin.scss +++ b/app/styles/mixin.scss @@ -6,69 +6,59 @@ or a mixin the object extends */ +$mixin-left-padding: 22px; + .mixin__name { - margin-top: -1px; - padding: 2px 2px 2px 5px; - border-top: 1px solid #bdbdbd; - border-bottom: 1px solid #bdbdbd; - background-color: #f0f0f0; + position: -webkit-sticky; + position: sticky; + top: 0; + padding: 4px 2px 4px $mixin-left-padding; + border-bottom: 1px solid var(--base34); + background-color: var(--base35); cursor: default; user-select: none; + color: var(--base28); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + z-index: 1; } .mixin__name:active { - background-color: #ccc; - border-top: 1px solid #b2b2b2; - border-bottom: 1px solid #b2b2b2; + background-color: var(--base36); } - .mixin_props_no .mixin__name:before { - opacity: 0; - } +.mixin__name--no-props { + color: var(--base17); +} - .mixin.ember-mixin .mixin__name { - color: #888; - } +.mixin_props_no .mixin__name:before { + opacity: 0; +} .mixin__name:before { + position: absolute; + top: 5px; + left: 6px; content: "\25B6"; - color: #737373; - margin-right: 4px; - position: relative; - top: -1px; - font-size: 75%; + color: var(--base18); + margin-right: 5px; + font-size: 90%; + transform: rotate(0deg); + transition: all 0.1s; } - .mixin_state_expanded .mixin__name { - border-bottom: 1px solid #bdbdbd; - } - .mixin_state_expanded .mixin__name:before { - content: "\25BC"; - } - - .mixin.ember-mixin .mixin__name:before { - color: #aaa; + transform: rotate(90deg); } -.mixin__name_errors { - background-color: #fff; - - &:active{ - background-color: #fff; - } -} - - .mixin__properties { - margin: 5px; list-style-type: none; - padding: 0; + border-bottom: 1px solid var(--base34); + margin: 0; + padding: 3px 0 5px 0; font-size: 12px; - font-family: Menlo, Monaco, monospace; + font-family: var(--font-monospace); } .mixin__property { @@ -79,24 +69,64 @@ display: flex; flex-direction: row; align-items: center; + min-height: 19px; + padding-top: 1px; + padding-bottom: 1px; + + .mixin__cp-toggle { + width: $mixin-left-padding; + outline: none; + + svg { + transition: all 0.2s; + transform: + rotate(-90deg) + translateY(1px); + } + } + .mixin__cp-toggle--expanded { + svg { + transform: rotate(0deg); + } + } } +/* Errors */ + .mixin__error { margin-right: 3px; padding: 0px 20px; - color: red; + color: var(--spec02); } -.mixin__property button { - border: none; - background: none; - margin: 0; - padding: 0; +.mixin__name--errors { + background-color: var(--base00); + + &:active{ + background-color: var(--base00); + } } -.mixin__property button img, .mixin__property span.pad { - margin-right: 3px; - width: 20px; +/* Buttons */ + +.mixin__property { + button { + border: none; + background: none; + margin: 0; + padding: 0; + } + + .pad { width: $mixin-left-padding; } + + .mixin__calc-btn svg { + path, circle { fill: var(--spec18); } + } + + .mixin__send-btn { + opacity: 0; + padding-right: 6px; + } } .mixin__property-overridden-by { @@ -104,7 +134,7 @@ } .mixin__property-name { - color: #909; + color: var(--base26); } .mixin__property-value { @@ -117,33 +147,23 @@ .mixin__property-value-txt { flex: 1; - border: solid 1px #ccc; - /*border: none;*/ - box-shadow: 2px 2px 2px #888; - /*box-shadow: none;*/ + border: 1px solid var(--base17); outline: none; + color: var(--base26); + font-size: 12px; + background: var(--base01); } -.mixin__calc-btn_calculated { - opacity: 0.4; -} - -.mixin__send-btn { - width: 20px; - opacity: 0; -} - - .mixin__property-value-separator { margin-right: 5px; } .mixin__property .type-function { - color: #999; + color: var(--base15); } .mixin__property .type-object { - color: #999; + color: var(--base20); } .mixin__property .type-ember-object, @@ -151,20 +171,19 @@ cursor: pointer; } -.mixin__property-calculated-value { - flex: 1; - color: #999; -} - -.mixin__property .type-null, .mixin__property .type-boolean { - color: #009; +.mixin__property .type-null, +.mixin__property .type-boolean { + color: var(--spec10); } .mixin__property .type-descriptor { cursor: pointer; - color: #900; + color: var(--spec05); } +.mixin__property .type-service { + color: var(--spec17); +} .mixin__property_state_overridden { @@ -173,22 +192,22 @@ .mixin__property:not(.mixin__property_state_overridden):hover { - background-color: #ffe; + background-color: var(--base01); } .mixin__property_state_overridden:hover .mixin__property-overridden-by { position: absolute; - background-color: rgba(255, 255, 255, 0.95); + background-color: var(--spec01); right: 0; display: inline; text-decoration: none; } .mixin__property:not(.mixin__property_state_overridden):hover .mixin__send-btn { - opacity: 1; -} + opacity: 1; -.mixin__property:not(.mixin__property_state_overridden):hover .mixin__send-btn:active { - opacity: 0.5; + &:active { + opacity: 0.5; + } } diff --git a/app/styles/nav.scss b/app/styles/nav.scss index c51efefbd8..8a0b57f6f0 100644 --- a/app/styles/nav.scss +++ b/app/styles/nav.scss @@ -3,22 +3,17 @@ === Navigation lists and links */ -.nav__title { - padding: 3px 5px; - line-height: 11px; - height: 15px; -} -.nav__title h3 { +.nav__title h1 { white-space: nowrap; - display: inline-block; + height: 22px; text-overflow: ellipsis; overflow: hidden; - color: #6e6e6e; - text-shadow: rgba(255, 255, 255, 0.75) 0 1px 0; - float: left; - padding: 0; - margin: 0; + color: var(--base19); + line-height: 22px; + text-shadow: var(--base05) 0 1px 0; + padding: 0 5px; + margin: 2px 0 0 0; } /* List */ @@ -33,24 +28,22 @@ .nav li { display: block; - margin-top: 2px; } .nav li svg { - position: absolute; - top: 50%; - left: 14px; - margin-top: -10px; + flex-shrink: 0; + margin-right: 7px; + width: 22px; + height: 22px; } /* List anchor */ .nav li > a { display: block; - height: 18px; - line-height: 18px; - margin-top: 1px; - padding: 2px 5px; + height: 22px; + line-height: 22px; + padding: 0 5px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; @@ -66,7 +59,7 @@ .nav li > a path, .nav li > a rect, .nav li > a circle { - fill: #222; + fill: var(--base28); } .nav li > a:focus { @@ -74,38 +67,43 @@ } .nav li > a.active { - color: #fff; - text-shadow: 0 1px 0 rgba(0,0,0, 0.33); - background: #3879D9; + color: var(--base00); + background: var(--spec11); } .nav li > a.active polygon, .nav li > a.active path, .nav li > a.active rect, .nav li > a.active circle { - fill: #fff; + fill: var(--base00); } .app.inactive .nav li > a.active { - background: #b4b4b4; + background: var(--base10); } /* Custom navs */ .nav--main li > a { - position: relative; - height: 33px; - padding-left: 40px; - color: #333; - line-height: 33px; + display: flex; + align-items: center; + height: 38px; + padding-left: 12px; + color: var(--base26); + line-height: 38px; +} + +.nav--main .pill { + margin-left: 5px; } -.nav.nav--main .nav__title { - padding-left: 15px; +.nav.nav--main .nav__title h1 { + padding-left: 14px; } -/* Custom nav title */ +/* Flip path on Promises icon */ -.nav__title--middle { - line-height: 21px; +.promises-icon-circle { + transform: scaleX(-1); + transform-origin: 18px; } diff --git a/app/styles/notice.scss b/app/styles/notice.scss index 6e350c4bc8..d1df4ead3b 100644 --- a/app/styles/notice.scss +++ b/app/styles/notice.scss @@ -7,5 +7,4 @@ margin-top: 20px; font-size: 14px; text-align: center; - text-shadow: rgba(255, 255, 255, 0.75) 0 1px 0; } diff --git a/app/styles/object_inspector.scss b/app/styles/object_inspector.scss index ef97da814f..8ce81cd21a 100644 --- a/app/styles/object_inspector.scss +++ b/app/styles/object_inspector.scss @@ -6,6 +6,98 @@ */ .object-trail { + margin-bottom: 4px; margin-left: 39px; word-break: break-all; } + +.mixin__property-dependency-list { + position: relative; + margin-bottom: 5px; + margin-top: 2px; + padding-top: 2px; + + & > svg { + position: absolute; + top: -4px; + left: 28px; + width: 19px; + height: 10px; + } + + ul { + list-style: none; + margin: 0; + padding: 0; + } +} + +.mixin__property-dependency-item { + position: relative; + margin-bottom: 2px; + margin-left: 55px; + font-size: 11px; + color: var(--base21); + + &::before { + content: ''; + position: absolute; + top: -5px; + left: -9px; + width: 1px; + height: 8px; + background-color: var(--base16); + } + + svg { + position: absolute; + bottom: 2px; + left: -13px; + + ellipse { + stroke: var(--base16); + fill: var(--base00); + } + } +} + +.mixin__property-dependency-item:first-child::before { display: none; } + +.mixin__property-icon-container { + width: $mixin-left-padding; +} + +.mixin__property-icon { + display: inline-block; + width: 17px; + height: 17px; + border-radius: 3px; + color: #fff; + font-size: 13px; + line-height: 17px; + font-family: var(--font-monospace); + text-align: center; + user-select: none; + -webkit-user-select: none; +} + +.mixin__property-icon--service { + background-color: var(--spec16); + &::before { + content: "S"; + } +} + +.mixin__property-icon--computed { + background-color: var(--spec15); + &::before { + content: "C"; + } +} + +.mixin__property-icon--property { + background-color: var(--base11); + &::before { + content: "P"; + } +} \ No newline at end of file diff --git a/app/styles/pill.scss b/app/styles/pill.scss index 392feac8f3..35a7693c8a 100644 --- a/app/styles/pill.scss +++ b/app/styles/pill.scss @@ -12,24 +12,24 @@ padding: 2px 6px; line-height: 12px; background: transparent; - text-shadow: rgba(255, 255, 255, 0.5) 0 1px 0; border-radius: 8px; vertical-align: middle; - background: rgba(0, 0, 0, 0.3); + background: var(--base11); } -.pill_text_clear { - text-shadow: none; - font-weight: bold; +a.active > .pill { + background: var(--base21); } -.pill_not-clickable { +.pill--not-clickable { cursor: inherit; } -/** MODIFIER: SIZE = SMALL **/ -.pill_size_small { +.pill--small { + padding: 2px 4px; font-size: 10px; +} - padding: 2px 4px; +.pill--bold { + font-weight: bold; } diff --git a/app/styles/send_to_console.scss b/app/styles/send_to_console.scss index 9b163acb0f..5e8518d49a 100644 --- a/app/styles/send_to_console.scss +++ b/app/styles/send_to_console.scss @@ -23,7 +23,7 @@ } .send-to-console:hover { - border-bottom: solid 1px rgb(43, 127, 179); + border-bottom: 1px solid var(--spec09); } .send-to-console:active { @@ -42,7 +42,7 @@ .send-trace-to-console:hover { - color: black; + color: var(--base29); } .send-trace-to-console:active { diff --git a/app/styles/sidebar_toggle.scss b/app/styles/sidebar_toggle.scss index e3ec844b13..7b799e13a6 100644 --- a/app/styles/sidebar_toggle.scss +++ b/app/styles/sidebar_toggle.scss @@ -6,11 +6,18 @@ .sidebar-toggle { position: absolute; - top: 2px; + top: 0; + max-height: 27px; } + .toolbar__icon-button.sidebar-toggle { + margin-right: 0; + padding-right: 6px; + background: var(--base00); + } + .sidebar-toggle--right { - right: -6px; + right: 0; } .sidebar-toggle--left { diff --git a/app/styles/split.scss b/app/styles/split.scss index c7307d7d59..8a0644625d 100644 --- a/app/styles/split.scss +++ b/app/styles/split.scss @@ -39,28 +39,28 @@ flex: none; flex-direction: column; box-sizing: border-box; - padding: 1px 2px; - min-height: 23px; - line-height: 20px; - border-color: #cacaca; + border-color: var(--base32); } .split__panel__hd { + min-height: 29px; border-bottom-width: 1px; border-bottom-style: solid; - background: #fff; + background: var(--base00); } .split__panel__bd { - background: #fff; + background: var(--base00); flex: auto; overflow: auto; } .split__panel__ft { + justify-content: center; + height: 23px; border-top-width: 1px; border-top-style: solid; - background: #F3F3F3; + background: var(--base01); } /* Fix visibility issue with phantomjs test runner @@ -75,7 +75,7 @@ /* Custom panels */ .split__panel--sidebar-1 .split__panel__bd { - background: #F3F3F3; + background: var(--base01); } .split__panel--sidebar-1 > .split__panel__ft { @@ -83,7 +83,7 @@ } .split__panel--sidebar-2 .split__panel__bd { - background: #f3f3f3; + background: var(--base01); } /* Fix main list-view scrolling */ diff --git a/app/styles/toolbar.scss b/app/styles/toolbar.scss index 11e95750d4..8057e7b641 100644 --- a/app/styles/toolbar.scss +++ b/app/styles/toolbar.scss @@ -1,23 +1,23 @@ +$toolbar-height: 28px; + .toolbar { - display: -webkit-flex; display: flex; - -webkit-flex-direction: row; flex-direction: row; align-items: center; + min-height: $toolbar-height; } .toolbar > * { - -webkit-flex: none; flex: none; } + /** Toolbar Title ============= */ .toolbar__title { - -webkit-flex: auto; flex: auto; font-weight: 700; white-space: nowrap; @@ -31,19 +31,21 @@ */ .toolbar__icon-button { - display: inline-block; - width: 32px; - height: 20px; - margin-left: 0; - padding: 0; - vertical-align: top; + display: flex; + align-items: center; + height: $toolbar-height; + margin-right: 2px; + margin-left: 2px; + padding: 0 2px; border: 0 transparent none; - background-color: rgba(0, 0, 0, 0); - background: white; + vertical-align: top; + background: transparent; } +/* if first item in toolbar, create extra clickable space */ .toolbar__icon-button:first-child { - margin-left: -2px; + margin-left: 0; + padding-left: 10px; } .toolbar__icon-button:focus { @@ -51,19 +53,19 @@ } .toolbar__icon-button .svg-stroke { - stroke: rgb(103,103,103); + stroke: var(--base20); } .toolbar__icon-button .svg-fill { - fill: rgb(103,103,103); + fill: var(--base20); } .toolbar__icon-button:hover .svg-stroke { - stroke: rgb(64,64,64); + stroke: var(--base24); } .toolbar__icon-button:hover .svg-fill { - fill: rgb(64,64,64); + fill: var(--base24); } .toolbar__icon-button:active { @@ -72,11 +74,11 @@ /* active (highlighted) */ .toolbar__icon-button.active .svg-stroke { - stroke: #4281eb; + stroke: var(--spec07); } .toolbar__icon-button.active .svg-fill { - fill: #4281eb; + fill: var(--spec07); } /* disabled */ @@ -89,24 +91,47 @@ } .toolbar__icon-button.disabled .svg-stroke { - stroke: #cacaca; + stroke: var(--base08); } .toolbar__icon-button.disabled .svg-fill { - fill: #cacaca; + fill: var(--base08); } + + /** Toolbar Checkboxes ================== */ .toolbar__checkbox { - margin: auto 6px auto 0; - height: auto; - line-height: 20px; + height: 100%; white-space: nowrap; overflow: hidden; + margin-right: 4px; + margin-left: 4px; +} + +.toolbar__checkbox label { + display: block; + height: 100%; + line-height: $toolbar-height; +} + +.toolbar__checkbox input { + margin: 0; +} + +/* if first item in toolbar, create extra clickable space */ + +.toolbar__checkbox:first-child { + margin-left: 0; +} + +.toolbar__checkbox:first-child label { + margin-left: 0; + padding-left: 8px; } /** @@ -120,14 +145,14 @@ position: relative; cursor: default; display: inline-block; - margin-right: 6px; - padding: 2px 6px; - line-height: 12px; - background: transparent; - text-shadow: rgba(255, 255, 255, 0.5) 0 1px 0; + margin-left: 2px; + margin-right: 2px; + padding: 0 6px; + background: var(--base03); border: none; - border-radius: 8px; + border-radius: 2px; vertical-align: middle; + color: var(--base26); } .toolbar__radio:active, @@ -135,21 +160,27 @@ .toolbar__radio:focus, .toolbar__radio.active { outline: none; - color: white; - text-shadow: rgba(0, 0, 0, 0.4) 0 1px 0; } +.toolbar__radio--first { + margin-left: 4px; +} + +.toolbar__radio--last { + margin-right: 4px; +} .toolbar__radio:hover { - background: rgba(0, 0, 0, 0.2); + background: var(--base06); } .toolbar__radio:active { - background: rgba(0, 0, 0, 0.5); + background: var(--base00); } .toolbar__radio.active { - background: rgba(0, 0, 0, 0.3); + color: var(--base00); + background: var(--spec11); } /** @@ -158,23 +189,22 @@ */ .toolbar__search { - margin-right: 6px; + position: relative; + margin-right: 4px; + margin-left: 4px; } .toolbar__search input { - -moz-box-sizing: border-box; box-sizing: border-box; - border: 1px solid #b3b3b3; - border-radius: 2px; - margin: auto 0; - padding: 0 3px; + width: 175px; + height: $toolbar-height - 7; margin: 0; - -webkit-appearance: none; + border: 1px solid var(--base07); + border-radius: 3px; + padding: 0 15px 0 4px; font-size: 12px; - background-color: #FFF; - height: 20px; + background-color: var(--base00); line-height: normal; - width: 179px; } .toolbar__search input:focus { @@ -185,6 +215,18 @@ width: 150px; } +.toolbar__search-clear-button { + position: absolute; + top: 3px; + right: 0; + width: auto; + height: auto; + + svg { + path { fill: var(--base33); } + } +} + /** Toolbar Divider =============== @@ -193,8 +235,9 @@ .toolbar .divider { display: inline-block; width: 1px; - height: 16px; + height: $toolbar-height - 10px; position: relative; - margin-right: 6px; - background-color: #cacaca; + margin-right: 4px; + margin-left: 4px; + background-color: var(--base08); } diff --git a/app/styles/warning.scss b/app/styles/warning.scss index 99aca515bc..65965f9629 100644 --- a/app/styles/warning.scss +++ b/app/styles/warning.scss @@ -2,7 +2,7 @@ display: flex; flex-direction: row; justify-content: flex-start; - background: #FFFEC2; + background: var(--spec00); font-size: 11px; padding: 0; } @@ -21,9 +21,9 @@ .warning__close { font-weight: 200; - color: #6E68C6; + color: var(--spec06); text-decoration: underline; - background: #FFFEC2; + background: var(--spec00); border: hidden; cursor: pointer; padding: 0; diff --git a/app/templates/-main.hbs b/app/templates/-main.hbs index c72d7ff9ba..2a41901db6 100644 --- a/app/templates/-main.hbs +++ b/app/templates/-main.hbs @@ -1,7 +1,8 @@
{{#draggable-column - width=navWidth - classes="split__panel split__panel--sidebar-1"}} + width=navWidth + classes="split__panel split__panel--sidebar-1" + setIsDragging=(route-action 'setIsDragging')}}
{{iframe-picker}}
@@ -20,7 +21,7 @@ {{outlet "toolbar"}} {{#unless inspectorExpanded}} {{sidebar-toggle action="toggleInspector" side="right" - isExpanded=false classNames="toolbar__icon-button"}} + isExpanded=false classNames="toolbar__icon-button"}} {{/unless}}
diff --git a/app/templates/application.hbs b/app/templates/application.hbs index 348eaa3506..ca65b959ad 100644 --- a/app/templates/application.hbs +++ b/app/templates/application.hbs @@ -7,27 +7,29 @@ {{#if inspectorExpanded}} {{#draggable-column - side="right" - width=inspectorWidth - classes="split__panel"}} - {{object-inspector application=this model=mixinStack mixinDetails=mixinDetails toggleInspector="toggleInspector"}} + side="right" + width=inspectorWidth + classes="split__panel" + setIsDragging=(route-action 'setIsDragging')}} + {{object-inspector application=this model=mixinStack mixinDetails=mixinDetails + toggleInspector="toggleInspector"}} {{/draggable-column}} {{/if}} {{else}} {{#not-detected description="Ember application"}} -
  • This is not an Ember application.
  • -
  • You are using an old version of Ember (< rc5).
  • - {{#if isChrome}} -
  • You are using the file:// protocol (instead of http://), in which case: -
      -
    • Visit the URL: chrome://extensions.
    • -
    • Find the Ember Inspector.
    • -
    • Make sure "Allow access to file URLs" is checked.
    • -
    -
  • - {{/if}} +
  • This is not an Ember application.
  • +
  • You are using an old version of Ember (< rc5).
  • + {{#if isChrome}} +
  • You are using the file:// protocol (instead of http://), in which case: +
      +
    • Visit the URL: chrome://extensions.
    • +
    • Find the Ember Inspector.
    • +
    • Make sure "Allow access to file URLs" is checked.
    • +
    +
  • + {{/if}} {{/not-detected}} {{/if}} {{/x-app}} diff --git a/app/templates/component-tree-toolbar.hbs b/app/templates/component-tree-toolbar.hbs new file mode 100644 index 0000000000..4b979b5758 --- /dev/null +++ b/app/templates/component-tree-toolbar.hbs @@ -0,0 +1,21 @@ +
    + + +
    + + + + + +
    + + +
    diff --git a/app/templates/component-tree.hbs b/app/templates/component-tree.hbs new file mode 100644 index 0000000000..50852bca6c --- /dev/null +++ b/app/templates/component-tree.hbs @@ -0,0 +1,14 @@ +
    + {{#vertical-collection displayedList estimateHeight=20 as |item i|}} +
    + {{component-tree-item + item=item + pinnedObjectId=pinnedObjectId + toggleExpanded=(action "toggleExpanded" item) + inspect=(action "inspect") + scrollToElement=(action "scrollToElement") + sendObjectToConsole=(action "sendObjectToConsole")}} +
    + {{/vertical-collection}} +
    \ No newline at end of file diff --git a/app/templates/components/clear-button.hbs b/app/templates/components/clear-button.hbs index 30f5f14ec7..bfa28c192f 100644 --- a/app/templates/components/clear-button.hbs +++ b/app/templates/components/clear-button.hbs @@ -1,6 +1 @@ - - - - - - +{{svg-jar "clear-2" width="13px" height="13px"}} \ No newline at end of file diff --git a/app/templates/components/component-tree-item.hbs b/app/templates/components/component-tree-item.hbs new file mode 100644 index 0000000000..799f5c96fc --- /dev/null +++ b/app/templates/components/component-tree-item.hbs @@ -0,0 +1,27 @@ +
    + {{#if item.hasChildren}} + + {{/if}} + + + {{item.view.name}} + + + {{#if item.view.isComponent}} + + {{/if}} +
    diff --git a/app/templates/components/deprecation-item.hbs b/app/templates/components/deprecation-item.hbs index ad72a754fb..fb81d8e2c7 100644 --- a/app/templates/components/deprecation-item.hbs +++ b/app/templates/components/deprecation-item.hbs @@ -1,7 +1,7 @@ {{#list.cell class="list__cell_main js-deprecation-main-cell" title=model.message}}
    - {{model.count}} + {{model.count}} {{model.message}} {{#if model.url}} diff --git a/app/templates/components/draggable-column.hbs b/app/templates/components/draggable-column.hbs index 2a9bd3f728..d558135d8d 100644 --- a/app/templates/components/draggable-column.hbs +++ b/app/templates/components/draggable-column.hbs @@ -2,4 +2,9 @@ {{yield}} {{/resizable-column}} -{{drag-handle side=side position=width minWidth=minWidth action="setIsDragging" on-drag=(action "didDrag")}} +{{drag-handle + minWidth=minWidth + on-drag=(action "didDrag") + position=width + setIsDragging=setIsDragging + side=side}} diff --git a/app/templates/components/iframe-picker.hbs b/app/templates/components/iframe-picker.hbs index a2903d3ce5..ab66cf21ee 100644 --- a/app/templates/components/iframe-picker.hbs +++ b/app/templates/components/iframe-picker.hbs @@ -4,5 +4,5 @@ {{/each}} - + {{svg-jar "dropdown-arrow" class="dropdown__arrow"}} diff --git a/app/templates/components/mixin-details.hbs b/app/templates/components/mixin-details.hbs index 55be88564b..67e546524e 100644 --- a/app/templates/components/mixin-details.hbs +++ b/app/templates/components/mixin-details.hbs @@ -1,53 +1,146 @@ {{#if model.errors.length}} -
    -

    - Errors - - Trace in the console - -

    -
    - {{#each model.errors as |error|}} -
    - Error while computing: {{error.property}} +
    +

    + Errors + + Trace in the console + +

    +
    + {{#each model.errors as |error|}} +
    + Error while computing: {{error.property}} +
    + {{/each}}
    - {{/each}}
    -
    {{/if}} + {{#each model.mixins as |item|}} {{#mixin-detail model=item mixinDetails=this as |mixin|}}
    {{#if mixin.model.properties.length}}

    {{mixin.model.name}}

    {{else}} -

    {{mixin.model.name}}

    +

    {{mixin.model.name}}

    {{/if}} {{#if mixin.isExpanded}}
      {{#each mixin.sortedProperties as |prop|}} {{#mixin-property model=prop mixin=mixin as |property|}} -
    • - {{#if property.model.value.computed}} - +
    • + + {{#if property.hasDependentKeys}} + {{else}} - + {{/if}} - {{property.model.name}}: + + + {{#if property.isService}} + + + + {{else if property.isComputedProperty}} + + + + {{else}} + + + + {{/if}} + + + + {{#if property.isService}} + + {{property.model.name}} + + {{else}} + {{#if property.hasDependentKeys}} + + {{property.model.name}} + + {{else}} + {{property.model.name}} + {{/if}} + {{/if}} + + + : + + {{#unless property.isEdit}} - {{property.model.value.inspect}} + {{#if (and property.isComputedProperty (not property.isCalculated))}} + + {{else}} + + {{property.model.value.inspect}} + + {{/if}} {{else}} {{#unless property.isDate}} - {{property-field value=property.txtValue finished-editing="finishedEditing" save-property="saveProperty" propertyComponent=property - class="mixin__property-value-txt js-object-property-value-txt"}} + {{property-field + value=property.txtValue + finished-editing="finishedEditing" + save-property="saveProperty" + propertyComponent=property + class="mixin__property-value-txt js-object-property-value-txt"}} {{else}} - {{date-property-field value=property.dateValue format="YYYY-MM-DD" - class="mixin__property-value-txt js-object-property-value-date" onSelection=(action "dateSelected" target=property) cancel=(action "finishedEditing" target=property)}} + {{date-property-field + value=property.dateValue + format="YYYY-MM-DD" + class="mixin__property-value-txt js-object-property-value-date" + onSelection=(action "dateSelected" target=property) + cancel=(action "finishedEditing" target=property)}} {{/unless}} {{/unless}} - (Overridden by {{property.model.overridden}}) - -
    • + + (Overridden by {{property.model.overridden}}) + + + + + {{#if property.showDependentKeys}} +
    • + {{svg-jar "dependent-key-connection" width="20px" height="10px"}} +
        + {{#each property.model.dependentKeys as |depKey index|}} +
      • + {{svg-jar "dependent-key-bullet" width="9px" height="9px"}} + + {{depKey}} + +
      • + {{/each}} +
      +
    • + {{/if}} {{/mixin-property}} {{else}}
    • No Properties
    • diff --git a/app/templates/components/not-detected.hbs b/app/templates/components/not-detected.hbs index 9da0409940..099bcc1f0f 100644 --- a/app/templates/components/not-detected.hbs +++ b/app/templates/components/not-detected.hbs @@ -21,7 +21,7 @@
    If you're still having trouble, please file an issue on the Ember Inspector's -
    GitHub page. + GitHub page.
    diff --git a/app/templates/components/object-inspector.hbs b/app/templates/components/object-inspector.hbs index 99208a8a14..c2ef2c0348 100644 --- a/app/templates/components/object-inspector.hbs +++ b/app/templates/components/object-inspector.hbs @@ -4,14 +4,10 @@ isExpanded=true class="toolbar__icon-button sidebar-toggle--far-left"}}
    -
    + {{model.firstObject.name}} diff --git a/app/templates/components/promise-item.hbs b/app/templates/components/promise-item.hbs index 98aa7e352b..22f1b5eb01 100644 --- a/app/templates/components/promise-item.hbs +++ b/app/templates/components/promise-item.hbs @@ -13,7 +13,7 @@
    {{/list.cell}} {{#list.cell}} -
    {{state}}
    +
    {{state}}
    {{/list.cell}} {{#list.cell class="js-promise-value"}} {{#if hasValue}} diff --git a/app/templates/components/reload-button.hbs b/app/templates/components/reload-button.hbs index f67ffeb417..3905c01ab4 100644 --- a/app/templates/components/reload-button.hbs +++ b/app/templates/components/reload-button.hbs @@ -1,7 +1 @@ - - - +{{svg-jar "reload" width="13px" height="13px"}} \ No newline at end of file diff --git a/app/templates/components/render-item.hbs b/app/templates/components/render-item.hbs index d766e667a0..0560d1bb00 100644 --- a/app/templates/components/render-item.hbs +++ b/app/templates/components/render-item.hbs @@ -6,7 +6,7 @@ {{/list.cell}} {{#list.cell class="list__cell_value_numeric"}} - {{ms-to-time model.duration}} + {{ms-to-time model.duration}} {{/list.cell}} {{#list.cell class="list__cell_value_numeric js-render-profile-timestamp"}} {{readableTime}} diff --git a/app/templates/components/search-field.hbs b/app/templates/components/search-field.hbs new file mode 100644 index 0000000000..0a6cf24f1e --- /dev/null +++ b/app/templates/components/search-field.hbs @@ -0,0 +1,6 @@ +{{input value=value type="text" placeholder="Search"}} +{{#if value}} + +{{/if}} \ No newline at end of file diff --git a/app/templates/components/view-item.hbs b/app/templates/components/view-item.hbs index 62fc6db6d3..4e6bc79bbc 100644 --- a/app/templates/components/view-item.hbs +++ b/app/templates/components/view-item.hbs @@ -45,5 +45,5 @@ {{/list.cell}} {{#list.cell class="list__cell_size_small list__cell_value_numeric"}} - {{ms-to-time model.value.duration}} + {{ms-to-time model.value.duration}} {{/list.cell}} diff --git a/app/templates/components/x-list.hbs b/app/templates/components/x-list.hbs index 2130c00f81..09535f9acb 100644 --- a/app/templates/components/x-list.hbs +++ b/app/templates/components/x-list.hbs @@ -8,15 +8,15 @@ {{/each}} - - {{#each columns key="id" as |column|}} - {{#x-list-cell - tagName="th" - class="js-header-column"}} - {{column.name}} - {{/x-list-cell}} - {{/each}} - + + {{#each columns key="id" as |column|}} + {{#x-list-cell + tagName="th" + class="js-header-column"}} + {{column.name}} + {{/x-list-cell}} + {{/each}} +
    @@ -39,12 +39,13 @@ {{#each columns key="id" as |column|}} {{#unless (eq column columns.lastObject)}} {{drag-handle - side="left" + faded=true left=column.left - position=(one-way column.width) minWidth=minWidth maxWidth=column.maxWidth on-drag=(action "didResize" column.id) - faded=true}} + position=(one-way column.width) + setIsDragging=setIsDragging + side="left"}} {{/unless}} {{/each}} diff --git a/app/templates/container-type-toolbar.hbs b/app/templates/container-type-toolbar.hbs index 046ac69ffb..461d0844b6 100644 --- a/app/templates/container-type-toolbar.hbs +++ b/app/templates/container-type-toolbar.hbs @@ -1,7 +1,9 @@
    {{reload-button action="reload" classNames="toolbar__icon-button js-reload-container-btn"}} + +
    diff --git a/app/templates/container-type.hbs b/app/templates/container-type.hbs index 76ec086988..ab906fc079 100644 --- a/app/templates/container-type.hbs +++ b/app/templates/container-type.hbs @@ -1,4 +1,8 @@ -{{#x-list name="container-instance-list" schema=(hash columns=null) headerHeight=0 as |list|}} +{{#x-list + headerHeight=0 + name="container-instance-list" + schema=(hash columns=null) + setIsDragging=(route-action 'setIsDragging') as |list|}} {{#list.vertical-collection filtered estimateHeight=30 itemClass="js-instance-row" as |content index|}} {{#list.cell class="list__cell_main" clickable=content.inspectable}} diff --git a/app/templates/container-types.hbs b/app/templates/container-types.hbs index 943e5cdebf..19040a91c3 100644 --- a/app/templates/container-types.hbs +++ b/app/templates/container-types.hbs @@ -1,12 +1,13 @@
    {{#draggable-column - width=180 - classes="split__panel split__panel--sidebar-2 nav"}} + width=180 + classes="split__panel split__panel--sidebar-2 nav" + setIsDragging=(route-action 'setIsDragging')}}
      diff --git a/app/templates/deprecations-toolbar.hbs b/app/templates/deprecations-toolbar.hbs index ca835ab49b..c925521ea5 100644 --- a/app/templates/deprecations-toolbar.hbs +++ b/app/templates/deprecations-toolbar.hbs @@ -1,7 +1,9 @@
      {{clear-button action="clear" classNames="toolbar__icon-button js-clear-deprecations-btn"}} + +
      diff --git a/app/templates/deprecations.hbs b/app/templates/deprecations.hbs index 91653cfc24..8274966469 100644 --- a/app/templates/deprecations.hbs +++ b/app/templates/deprecations.hbs @@ -1,20 +1,26 @@ -{{#x-list name="deprecation-list" schema=(hash columns=null) headerHeight=0 class="js-deprecations list_no-alternate-color" as |list|}} +{{#x-list + class="js-deprecations list_no-alternate-color" + headerHeight=0 + name="deprecation-list" + schema=(hash columns=null) + setIsDragging=(route-action 'setIsDragging') as |list|}} {{#if filtered.length}} - {{#each filtered as |content|}} - {{deprecation-item - model=content - openResource=(action "openResource") - traceSource=(action "traceSource") - traceDeprecations=(action "traceDeprecations") - class="deprecation-item" - list=list - }} - {{/each}} + {{#each filtered as |content|}} + {{deprecation-item + model=content + openResource=(action "openResource") + traceSource=(action "traceSource") + traceDeprecations=(action "traceDeprecations") + class="deprecation-item" + list=list + }} + {{/each}} {{else}}
      -

      No deprecations have been detected. Try reloading to catch the deprecations that were logged before you opened the inspector.

      +

      No deprecations have been detected. Try reloading to catch the deprecations that were logged before you opened + the inspector.

      {{/if}} diff --git a/app/templates/info.hbs b/app/templates/info.hbs index 453e4e2f0a..05956a691a 100644 --- a/app/templates/info.hbs +++ b/app/templates/info.hbs @@ -1,4 +1,7 @@ -{{#x-list name="info-list" schema=(schema-for "info-list") as |list|}} +{{#x-list + name="info-list" + schema=(schema-for "info-list") + setIsDragging=(route-action 'setIsDragging') as |list|}} {{#each model as |library|}} diff --git a/app/templates/model-types-toolbar.hbs b/app/templates/model-types-toolbar.hbs index fe77c73762..b414522d1c 100644 --- a/app/templates/model-types-toolbar.hbs +++ b/app/templates/model-types-toolbar.hbs @@ -1,5 +1,8 @@
      - {{input type="checkbox" checked=hideEmptyModelTypes id="options-hideEmptyModelTypes"}} +
      diff --git a/app/templates/model-types.hbs b/app/templates/model-types.hbs index 44b7c9e62a..99a9ad0faf 100644 --- a/app/templates/model-types.hbs +++ b/app/templates/model-types.hbs @@ -1,7 +1,10 @@
      - {{#draggable-column width=navWidth classes="split__panel split__panel--sidebar-2 nav"}} + {{#draggable-column + width=navWidth + classes="split__panel split__panel--sidebar-2 nav" + setIsDragging=(route-action 'setIsDragging')}}
      - +
        {{#each sorted as |modelType|}}
      • diff --git a/app/templates/nav.hbs b/app/templates/nav.hbs index 1cf373ea9a..6e2683eaac 100644 --- a/app/templates/nav.hbs +++ b/app/templates/nav.hbs @@ -1,116 +1,61 @@
      {{else}} - {{#x-list name="render-tree" schema=(schema-for "render-tree") class="js-render-tree" headerHeight=headerHeight as |list|}} + {{#x-list + class="js-render-tree" + headerHeight=headerHeight + name="render-tree" + schema=(schema-for "render-tree") + setIsDragging=(route-action 'setIsDragging') as |list|}} {{#each filtered as |item|}} {{render-item model=item search=search list=list}} diff --git a/app/templates/route-tree-toolbar.hbs b/app/templates/route-tree-toolbar.hbs index a907f74acc..0f4c733a3f 100644 --- a/app/templates/route-tree-toolbar.hbs +++ b/app/templates/route-tree-toolbar.hbs @@ -1,5 +1,8 @@
      - {{input type="checkbox" checked=options.hideRoutes id="options-hideRoutes"}} +
      diff --git a/app/templates/route-tree.hbs b/app/templates/route-tree.hbs index a3bdb08fc4..6606b59945 100644 --- a/app/templates/route-tree.hbs +++ b/app/templates/route-tree.hbs @@ -1,4 +1,8 @@ -{{#x-list name="route-tree" schema=(schema-for "route-tree") as |list|}} +{{#x-list + name="route-tree" + schema=(schema-for "route-tree") + setIsDragging=(route-action 'setIsDragging') +as |list|}} {{#list.vertical-collection filtered as |content|}} {{route-item diff --git a/app/templates/view-tree-toolbar.hbs b/app/templates/view-tree-toolbar.hbs index c72e5d2165..899397521e 100644 --- a/app/templates/view-tree-toolbar.hbs +++ b/app/templates/view-tree-toolbar.hbs @@ -1,22 +1,20 @@
      -
      +
      - {{input type="checkbox" checked=options.components id="options-components"}} +
      diff --git a/app/templates/view-tree.hbs b/app/templates/view-tree.hbs index 34d01e534e..7cf69cba24 100644 --- a/app/templates/view-tree.hbs +++ b/app/templates/view-tree.hbs @@ -1,14 +1,18 @@ -{{#x-list name="view-tree" schema=(schema-for "view-tree") as |list|}} +{{#x-list + name="view-tree" + schema=(schema-for "view-tree") + setIsDragging=(route-action 'setIsDragging') as |list|}} {{#list.vertical-collection filteredList as |content index|}} - + {{view-item - model=content - inspect=(action "inspect") - inspectElement=(action "inspectElement") - sendModelToConsole=(action "sendModelToConsole") - sendObjectToConsole=(action "sendObjectToConsole") - list=list - }} + model=content + inspect=(action "inspect") + inspectElement=(action "inspectElement") + sendModelToConsole=(action "sendModelToConsole") + sendObjectToConsole=(action "sendObjectToConsole") + list=list + }} {{/list.vertical-collection}} {{/x-list}} diff --git a/bower.json b/bower.json deleted file mode 100644 index cf901578bf..0000000000 --- a/bower.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "ember-inspector", - "dependencies": { - "moment": "~2.8.4", - "animation-frame": "~0.2.4", - "contextMenu": "~1.4.0" - } -} diff --git a/ember-cli-build.js b/ember-cli-build.js index 504335fd3c..5d37b3e854 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -22,6 +22,12 @@ const map = stew.map; const options = { fingerprint: { enabled: false + }, + + svgJar: { + sourceDirs: [ + 'public/assets/svg' + ] } }; @@ -48,8 +54,9 @@ module.exports = function(defaults) { const env = process.env.EMBER_ENV; app.import('vendor/babel-polyfill.js', { prepend: true }); - app.import('bower_components/contextMenu/contextMenu.js'); - app.import('bower_components/contextMenu/contextMenu.css'); + app.import('node_modules/basiccontext/dist/basicContext.min.css'); + app.import('node_modules/basiccontext/dist/themes/default.min.css'); + app.import('node_modules/basiccontext/dist/basicContext.min.js'); // Ember Debug diff --git a/ember_debug/object-inspector.js b/ember_debug/object-inspector.js index c9acf9dfee..3c542d2c8a 100644 --- a/ember_debug/object-inspector.js +++ b/ember_debug/object-inspector.js @@ -232,7 +232,6 @@ export default EmberObject.extend(PortMixin, { if (this.canSend(object)) { let details = this.mixinsForObject(object); - this.sendMessage('updateObject', { parentObject: objectId, property, @@ -342,7 +341,11 @@ export default EmberObject.extend(PortMixin, { // for more details. if (compareVersion(VERSION, '2.11.0') !== -1) { if (!name && typeof mixin.toString === 'function') { - name = mixin.toString(); + try { + name = mixin.toString(); + } catch (e) { + name = '(Unable to convert Object to string)'; + } } } if (!name) { @@ -468,7 +471,25 @@ function addProperties(properties, hash) { continue; } let options = { isMandatorySetter: isMandatorySetter(hash, prop) }; + + if (typeof hash[prop] === 'object' && hash[prop] !== null) { + options.isService = hash[prop].type === 'service'; + if (!options.isService) { + if (hash[prop].constructor) { + options.isService = hash[prop].constructor.isServiceFactory; + } + } + } + if (isComputed(hash[prop])) { + options.dependentKeys = (hash[prop]._dependentKeys || []).map((key) => key.toString()); + if (!options.isService) { + if (typeof hash[prop]._getter === 'function') { + options.code = Function.prototype.toString.call(hash[prop]._getter); + } else { + options.code = ''; + } + } options.readOnly = hash[prop]._readOnly; } replaceProperty(properties, prop, hash[prop], options); @@ -493,6 +514,10 @@ function replaceProperty(properties, name, value, options) { let prop = { name, value: inspectValue(value) }; prop.isMandatorySetter = options.isMandatorySetter; prop.readOnly = options.readOnly; + prop.dependentKeys = options.dependentKeys || []; + let hasServiceFootprint = prop.value && typeof prop.value.inspect === 'string' ? prop.value.inspect.includes('@service:') : false; + prop.isService = options.isService || hasServiceFootprint; + prop.code = options.code; properties.push(prop); } diff --git a/ember_debug/view-debug.js b/ember_debug/view-debug.js index a85896603b..ec8a6eda59 100644 --- a/ember_debug/view-debug.js +++ b/ember_debug/view-debug.js @@ -77,6 +77,14 @@ export default EmberObject.extend(PortMixin, { this.stopInspecting(); } }, + + scrollToElement({ elementId }) { + let el = document.querySelector(`#${elementId}`); + if (el) { + el.scrollIntoView(); + } + }, + inspectElement({ objectId, elementId }) { if (objectId) { this.inspectViewElement(objectId); @@ -226,6 +234,7 @@ export default EmberObject.extend(PortMixin, { let view = this.get('objectInspector').sentObjects[viewElem.id]; if (view instanceof Component) { this.get('objectInspector').sendObject(view); + this.sendMessage('inspectComponent', { viewId: viewElem.id }); } } this.stopInspecting(); diff --git a/package.json b/package.json index 521b2ab0fc..a671d09358 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-inspector", - "version": "3.0.0", + "version": "3.1.0", "description": "Extends developer tools to allow you to better inspect your Ember.js apps.", "license": "MIT", "author": "Tilde, Inc.", @@ -36,6 +36,7 @@ "aws-sdk": "^2.3.3", "babel-eslint": "^8.2.2", "babel-plugin-transform-es2015-modules-amd": "^6.24.0", + "basiccontext": "^3.5.1", "broccoli-asset-rev": "^2.4.5", "broccoli-babel-transpiler": "^6.0.0", "broccoli-concat": "^3.0.1", @@ -54,7 +55,7 @@ "ember-cli-htmlbars": "^2.0.3", "ember-cli-htmlbars-inline-precompile": "^1.0.2", "ember-cli-inject-live-reload": "^1.4.1", - "ember-cli-moment-shim": "3.5.0", + "ember-cli-moment-shim": "^3.6.0", "ember-cli-qunit": "^4.3.2", "ember-cli-sass": "^7.1.7", "ember-cli-shims": "^1.2.0", @@ -66,8 +67,10 @@ "ember-native-dom-helpers": "^0.4.2", "ember-pikaday": "^2.2.2", "ember-resolver": "^4.0.0", + "ember-route-action-helper": "^2.0.6", "ember-source": "~3.0.0", "ember-source-channel-url": "^1.0.1", + "ember-svg-jar": "^1.1.1", "ember-truth-helpers": "2.0.0", "ember-try": "^1.0.0-beta.1", "eslint-plugin-ember": "^5.0.0", @@ -80,6 +83,7 @@ "js-string-escape": "^1.0.0", "loader.js": "^4.2.3", "mkdirp": "^0.5.1", + "qunit-dom": "^0.6.2", "rimraf": "^2.5.2", "yauzl": "^2.4.1" }, diff --git a/public/assets/images/arrow_down.svg b/public/assets/images/arrow_down.svg index 46da0494a1..cc7ffabc39 100644 --- a/public/assets/images/arrow_down.svg +++ b/public/assets/images/arrow_down.svg @@ -1,52 +1,3 @@ - - - - - - - image/svg+xml - - - - - - - + + diff --git a/public/assets/images/calculate.svg b/public/assets/images/calculate.svg deleted file mode 100755 index 7fe298b836..0000000000 --- a/public/assets/images/calculate.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/public/assets/images/external_link.svg b/public/assets/images/external_link.svg deleted file mode 100644 index 8e05e1b374..0000000000 --- a/public/assets/images/external_link.svg +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - diff --git a/public/assets/images/fishy_tomster.png b/public/assets/images/fishy_tomster.png index bd16ea8818..fd4b7d4192 100644 Binary files a/public/assets/images/fishy_tomster.png and b/public/assets/images/fishy_tomster.png differ diff --git a/public/assets/svg/arrow-back.svg b/public/assets/svg/arrow-back.svg new file mode 100644 index 0000000000..58ff40f2e4 --- /dev/null +++ b/public/assets/svg/arrow-back.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/public/assets/svg/calculate.svg b/public/assets/svg/calculate.svg new file mode 100755 index 0000000000..1958000a85 --- /dev/null +++ b/public/assets/svg/calculate.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/assets/svg/chevron-down.svg b/public/assets/svg/chevron-down.svg new file mode 100644 index 0000000000..1fa36f1584 --- /dev/null +++ b/public/assets/svg/chevron-down.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/assets/svg/chevron-right.svg b/public/assets/svg/chevron-right.svg new file mode 100644 index 0000000000..cea127cdc0 --- /dev/null +++ b/public/assets/svg/chevron-right.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/assets/svg/clear-2.svg b/public/assets/svg/clear-2.svg new file mode 100644 index 0000000000..004e8de23a --- /dev/null +++ b/public/assets/svg/clear-2.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/assets/svg/clear.svg b/public/assets/svg/clear.svg new file mode 100644 index 0000000000..1a64a5a254 --- /dev/null +++ b/public/assets/svg/clear.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/public/assets/svg/dependent-key-bullet.svg b/public/assets/svg/dependent-key-bullet.svg new file mode 100644 index 0000000000..09923134a7 --- /dev/null +++ b/public/assets/svg/dependent-key-bullet.svg @@ -0,0 +1,3 @@ + diff --git a/public/assets/svg/dependent-key-connection.svg b/public/assets/svg/dependent-key-connection.svg new file mode 100644 index 0000000000..c4c255aa87 --- /dev/null +++ b/public/assets/svg/dependent-key-connection.svg @@ -0,0 +1,3 @@ + diff --git a/public/assets/svg/disclosure-triangle.svg b/public/assets/svg/disclosure-triangle.svg new file mode 100644 index 0000000000..bb2f84a318 --- /dev/null +++ b/public/assets/svg/disclosure-triangle.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/assets/svg/dropdown-arrow.svg b/public/assets/svg/dropdown-arrow.svg new file mode 100644 index 0000000000..15562a27ce --- /dev/null +++ b/public/assets/svg/dropdown-arrow.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/public/assets/svg/external_link.svg b/public/assets/svg/external_link.svg new file mode 100644 index 0000000000..aa605f396e --- /dev/null +++ b/public/assets/svg/external_link.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/assets/svg/eye.svg b/public/assets/svg/eye.svg new file mode 100644 index 0000000000..c3850a6328 --- /dev/null +++ b/public/assets/svg/eye.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/public/assets/svg/inspect.svg b/public/assets/svg/inspect.svg new file mode 100644 index 0000000000..c4faea3d1b --- /dev/null +++ b/public/assets/svg/inspect.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/public/assets/svg/nav-components.svg b/public/assets/svg/nav-components.svg new file mode 100644 index 0000000000..1abb9e5114 --- /dev/null +++ b/public/assets/svg/nav-components.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/public/assets/svg/nav-container.svg b/public/assets/svg/nav-container.svg new file mode 100644 index 0000000000..16006bcbc1 --- /dev/null +++ b/public/assets/svg/nav-container.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/public/assets/svg/nav-data.svg b/public/assets/svg/nav-data.svg new file mode 100644 index 0000000000..3c45889742 --- /dev/null +++ b/public/assets/svg/nav-data.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/public/assets/svg/nav-deprecations.svg b/public/assets/svg/nav-deprecations.svg new file mode 100644 index 0000000000..912242c038 --- /dev/null +++ b/public/assets/svg/nav-deprecations.svg @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/public/assets/svg/nav-info.svg b/public/assets/svg/nav-info.svg new file mode 100644 index 0000000000..9258bf96d7 --- /dev/null +++ b/public/assets/svg/nav-info.svg @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/public/assets/svg/nav-promises.svg b/public/assets/svg/nav-promises.svg new file mode 100644 index 0000000000..c39637295b --- /dev/null +++ b/public/assets/svg/nav-promises.svg @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/public/assets/svg/nav-render-performance.svg b/public/assets/svg/nav-render-performance.svg new file mode 100644 index 0000000000..badc9e1c03 --- /dev/null +++ b/public/assets/svg/nav-render-performance.svg @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/public/assets/svg/nav-route-tree.svg b/public/assets/svg/nav-route-tree.svg new file mode 100644 index 0000000000..78f4326ff8 --- /dev/null +++ b/public/assets/svg/nav-route-tree.svg @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/public/assets/svg/nav-view-tree.svg b/public/assets/svg/nav-view-tree.svg new file mode 100644 index 0000000000..7936b51a1e --- /dev/null +++ b/public/assets/svg/nav-view-tree.svg @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/public/assets/svg/reload.svg b/public/assets/svg/reload.svg new file mode 100644 index 0000000000..b9724a1640 --- /dev/null +++ b/public/assets/svg/reload.svg @@ -0,0 +1,3 @@ + + + diff --git a/tests/acceptance/component-tree-test.js b/tests/acceptance/component-tree-test.js new file mode 100644 index 0000000000..a4cac1ef8c --- /dev/null +++ b/tests/acceptance/component-tree-test.js @@ -0,0 +1,303 @@ +import { + visit, + fillIn, + findAll, + click, + triggerEvent, +} from '@ember/test-helpers'; +import { run } from '@ember/runloop'; +import { module, test } from 'qunit'; +import { setupApplicationTest } from 'ember-qunit'; +import wait from 'ember-test-helpers/wait'; + +let port; + +module('Component Tab', function(hooks) { + setupApplicationTest(hooks); + + hooks.beforeEach(function() { + port = this.owner.lookup('port:main'); + }); + + function textFor(selector, context) { + return context.querySelector(selector).textContent.trim(); + } + + let treeId = 0; + function viewNodeFactory(props) { + if (!props.template) { + props.template = props.name; + } + let obj = { + value: props, + children: [], + treeId: ++treeId, + }; + return obj; + } + + function viewTreeFactory(tree) { + let children = tree.children; + delete tree.children; + let viewNode = viewNodeFactory(tree); + if (children) { + for (let i = 0; i < children.length; i++) { + viewNode.children.push(viewTreeFactory(children[i])); + } + } + return viewNode; + } + + function defaultViewTree() { + return viewTreeFactory({ + name: 'application', + isVirtual: false, + isComponent: false, + objectId: 'applicationView', + viewClass: 'App.ApplicationView', + completeViewClass: 'App.ApplicationView', + duration: 10, + controller: { + name: 'App.ApplicationController', + completeName: 'App.ApplicationController', + objectId: 'applicationController', + }, + children: [ + { + name: 'todos', + isVirtual: false, + isComponent: false, + viewClass: 'App.TodosView', + completeViewClass: 'App.TodosView', + duration: 1, + objectId: 'todosView', + model: { + name: 'TodosArray', + completeName: 'TodosArray', + objectId: 'todosArray', + type: 'type-ember-object', + }, + controller: { + name: 'App.TodosController', + completeName: 'App.TodosController', + objectId: 'todosController', + }, + children: [ + { + completeViewClass: 'todo-list', + isComponent: true, + name: 'todo-list', + objectId: 'ember392', + tagName: 'section', + template: 'app/templates/components/todo-list', + viewClass: 'todo-list', + children: [ + { + completeViewClass: 'todo-item', + isComponent: true, + name: 'todo-item', + objectId: 'ember267', + tagName: 'li', + template: 'app/templates/components/todo-item', + viewClass: 'todo-item', + }, + ], + }, + ], + }, + ], + }); + } + + test('It should correctly display the component tree', async function(assert) { + let viewTree = defaultViewTree(); + + await visit('/component-tree'); + run(() => { + port.trigger('view:viewTree', { tree: viewTree }); + }); + await wait(); + + let treeNodes = findAll('.component-tree-item'); + assert.equal(treeNodes.length, 4, 'expected some tree nodes'); + + let expandedNodes = findAll('.component-tree-item .expanded'); + assert.equal(expandedNodes.length, 3, 'all nodes should be expanded except the leaf node'); + + let templateNames = []; + + [...treeNodes].forEach(function(node) { + templateNames.push(textFor('code', node)); + }); + + assert.deepEqual( + templateNames, + ['application', 'todos', 'todo-list', 'todo-item'], + 'expected names for all views/components' + ); + }); + + test('It allows users to expand and collapse nodes', async function(assert) { + let viewTree = defaultViewTree(); + + await visit('/component-tree'); + run(() => { + port.trigger('view:viewTree', { tree: viewTree }); + }); + await wait(); + + let treeNodes = findAll('.component-tree-item'); + assert.equal(treeNodes.length, 4, 'expected some tree nodes'); + + let expanders = findAll('.component-tree-item__expand'); + let expanderEl = expanders[expanders.length - 1]; + await click(expanderEl); + + treeNodes = findAll('.component-tree-item'); + assert.equal(treeNodes.length, 3, 'the last node should be hidden'); + + }); + + test('It should filter the view tree using the search text', async function(assert) { + let viewTree = defaultViewTree(); + + await visit('/component-tree'); + run(() => { + port.trigger('view:viewTree', { tree: viewTree }); + }); + await wait(); + + let treeNodes = findAll('.component-tree-item'); + assert.equal(treeNodes.length, 4, 'expected some tree nodes'); + + await fillIn('.js-filter-views input', 'todo-'); + treeNodes = findAll('.component-tree-item'); + assert.equal(treeNodes.length, 2, 'expected filtered tree nodes'); + + let visibleComponentNames = []; + [...treeNodes].forEach(function(node) { + visibleComponentNames.push(textFor('code', node)); + }); + + assert.deepEqual( + visibleComponentNames, + ['todo-list', 'todo-item'], + 'expected names for all views/components' + ); + }); + + test("It should clear the search filter when the clear button is clicked", async function(assert) { + let viewTree = defaultViewTree(); + + await visit('/component-tree'); + run(() => { + port.trigger('view:viewTree', { tree: viewTree }); + }); + await wait(); + + let treeNodes = findAll('.component-tree-item'); + assert.equal(treeNodes.length, 4, 'expected all tree nodes'); + + await fillIn('.js-filter-views input', 'xxxxxx'); + treeNodes = findAll('.component-tree-item'); + assert.equal(treeNodes.length, 0, 'expected filtered tree nodes'); + + await click('.js-search-field-clear-button'); + treeNodes = findAll('.component-tree-item'); + assert.equal(treeNodes.length, 4, 'expected all tree nodes'); + }); + + test('It should update the view tree when the port triggers a change, preserving the expanded state of existing nodes', async function(assert) { + let viewTree = defaultViewTree(); + + await visit('/component-tree'); + run(() => port.trigger('view:viewTree', { tree: viewTree })); + await wait(); + + let expanders = findAll('.component-tree-item__expand'); + let expanderEl = expanders[expanders.length - 1]; + await click(expanderEl); + + let treeNodes = findAll('.component-tree-item'); + assert.equal(treeNodes.length, 3, 'the last node should be hidden'); + + viewTree = defaultViewTree(); // resend the same view tree + run(() => port.trigger('view:viewTree', { tree: viewTree })); + await wait(); + + assert.dom('.component-tree-item').exists({ count: 3 }, 'the last node should still be hidden'); + }); + + test('Previewing / showing a view on the client', async function(assert) { + let messageSent = null; + port.reopen({ + send(name, message) { + messageSent = { name, message }; + }, + }); + + await visit('/component-tree'); + let viewTree = defaultViewTree(); + viewTree.children = []; + run(() => port.trigger('view:viewTree', { tree: viewTree })); + await wait(); + await triggerEvent('.component-tree-item', 'mouseenter'); + assert.equal( + messageSent.name, + 'view:previewLayer', + 'Client asked to preview layer' + ); + assert.equal( + messageSent.message.objectId, + 'applicationView', + 'Client sent correct id to preview layer' + ); + await triggerEvent('.component-tree-item', 'mouseleave'); + assert.equal( + messageSent.name, + 'view:hidePreview', + 'Client asked to hide preview' + ); + }); + + test('Scrolling an element into view', async function(assert) { + let messageSent = null; + port.reopen({ + send(name, message) { + messageSent = { name, message }; + }, + }); + + await visit('/component-tree'); + let viewTree = defaultViewTree(); + run(() => port.trigger('view:viewTree', { tree: viewTree })); + await wait(); + + await click('.component-tree-item__view-element'); + assert.equal( + messageSent.name, + 'view:scrollToElement', + 'Client asked to scroll element into view' + ); + }); + + test('Inspects the component in the object inspector on click', async function(assert) { + let messageSent = null; + port.reopen({ + send(name, message) { + messageSent = { name, message }; + } + }); + + await visit('/component-tree'); + let tree = defaultViewTree(); + run(() => { + port.trigger('view:viewTree', { tree }); + }); + await wait(); + + await click('.component-tree-item--component code'); + assert.equal(messageSent.name, 'objectInspector:inspectById'); + assert.equal(messageSent.message.objectId, 'ember392'); + }); +}); diff --git a/tests/acceptance/container-test.js b/tests/acceptance/container-test.js index 6690994bca..7be09d78fc 100644 --- a/tests/acceptance/container-test.js +++ b/tests/acceptance/container-test.js @@ -62,10 +62,10 @@ module('Container Tab', function(hooks) { await visit('/container-types'); let rows = findAll('.js-container-type'); assert.equal(rows.length, 2); - assert.equal(findAll('.js-container-type-name')[0].textContent.trim(), 'controller'); - assert.equal(findAll('.js-container-type-count')[0].textContent.trim(), '2'); - assert.equal(findAll('.js-container-type-name')[1].textContent.trim(), 'route'); - assert.equal(findAll('.js-container-type-count')[1].textContent.trim(), '5'); + assert.dom(findAll('.js-container-type-name')[0]).hasText('controller'); + assert.dom(findAll('.js-container-type-count')[0]).hasText('2'); + assert.dom(findAll('.js-container-type-name')[1]).hasText('route'); + assert.dom(findAll('.js-container-type-count')[1]).hasText('5'); }); @@ -91,8 +91,8 @@ module('Container Tab', function(hooks) { rows = findAll('.js-container-instance-list-item'); - assert.equal(rows[0].textContent.trim(), 'first'); - assert.equal(rows[1].textContent.trim(), 'second'); + assert.dom(rows[0]).hasText('first'); + assert.dom(rows[1]).hasText('second'); name = null; message = null; @@ -107,7 +107,39 @@ module('Container Tab', function(hooks) { rows = findAll('.js-container-instance-list-item'); assert.equal(rows.length, 1); - assert.equal(rows[0].textContent.trim(), 'first'); + assert.dom(rows[0]).hasText('first'); + }); + + test("It should clear the search filter when the clear button is clicked", async function(assert) { + let instances = getInstances(); + + port.reopen({ + send(n, m) { + name = n; + message = m; + if (name === 'container:getTypes') { + this.trigger('container:types', { types: getTypes() }); + } + + if (name === 'container:getInstances' && message.containerType === 'controller') { + this.trigger('container:instances', { instances, status: 200 }); + } + } + }); + + await visit('/container-types/controller'); + let rows; + + rows = findAll('.js-container-instance-list-item'); + assert.equal(rows.length, 2, 'expected all rows'); + + await fillIn('.js-container-instance-search input', 'xxxxx'); + rows = findAll('.js-container-instance-list-item'); + assert.equal(rows.length, 0, 'expected filtered rows'); + + await click('.js-search-field-clear-button'); + rows = findAll('.js-container-instance-list-item'); + assert.equal(rows.length, 2, 'expected all rows'); }); test("Successfully redirects if the container type is not found", async function(assert) { @@ -154,14 +186,14 @@ module('Container Tab', function(hooks) { await visit('/container-types/controller'); - assert.equal(findAll('.js-container-type').length, 0); - assert.equal(findAll('.js-container-instance-list-item').length, 0); + assert.dom('.js-container-type').doesNotExist(); + assert.dom('.js-container-instance-list-item').doesNotExist(); types = getTypes(); instances = getInstances(); await click('.js-reload-container-btn'); - assert.equal(findAll('.js-container-type').length, 2); - assert.equal(findAll('.js-container-instance-list-item').length, 2); + assert.dom('.js-container-type').exists({ count: 2 }); + assert.dom('.js-container-instance-list-item').exists({ count: 2 }); }); }); diff --git a/tests/acceptance/data-test.js b/tests/acceptance/data-test.js index c2050e99e2..68ed69bb6b 100644 --- a/tests/acceptance/data-test.js +++ b/tests/acceptance/data-test.js @@ -93,20 +93,20 @@ module('Data Tab', function(hooks) { test('Model types are successfully listed and bound', async function t(assert) { await visit('/data/model-types'); - assert.equal(findAll('.js-model-type').length, 2); + assert.dom('.js-model-type').exists({ count: 2 }); // they should be sorted alphabetically - assert.equal(findAll('.js-model-type-name')[0].textContent.trim(), 'App.Comment'); - assert.equal(findAll('.js-model-type-name')[1].textContent.trim(), 'App.Post'); + assert.dom(findAll('.js-model-type-name')[0]).hasText('App.Comment'); + assert.dom(findAll('.js-model-type-name')[1]).hasText('App.Post'); - assert.equal(findAll('.js-model-type-count')[0].textContent.trim(), 1); - assert.equal(findAll('.js-model-type-count')[1].textContent.trim(), 2); + assert.dom(findAll('.js-model-type-count')[0]).hasText('1'); + assert.dom(findAll('.js-model-type-count')[1]).hasText('2'); await triggerPort(this, 'data:modelTypesUpdated', { modelTypes: [ modelTypeFactory({ name: 'App.Post', count: 3 }) ] }); - assert.equal(findAll('.js-model-type-count')[1].textContent.trim(), 3); + assert.dom(findAll('.js-model-type-count')[1]).hasText('3'); }); test('Records are successfully listed and bound', async function t(assert) { @@ -115,24 +115,24 @@ module('Data Tab', function(hooks) { await click(findAll('.js-model-type a')[1]); let columns = findAll('.js-header-column'); - assert.equal(columns[0].textContent.trim(), 'Id'); - assert.equal(columns[1].textContent.trim(), 'Title'); - assert.equal(columns[2].textContent.trim(), 'Body'); + assert.dom(columns[0]).hasText('Id'); + assert.dom(columns[1]).hasText('Title'); + assert.dom(columns[2]).hasText('Body'); let recordRows = findAll('.js-record-list-item'); assert.equal(recordRows.length, 2); let firstRow = recordRows[0]; let firstRowColumns = firstRow.querySelectorAll('.js-record-column'); - assert.equal(firstRowColumns[0].textContent.trim(), 1); - assert.equal(firstRowColumns[1].textContent.trim(), 'My Post'); - assert.equal(firstRowColumns[2].textContent.trim(), 'This is my first post'); + assert.dom(firstRowColumns[0]).hasText('1'); + assert.dom(firstRowColumns[1]).hasText('My Post'); + assert.dom(firstRowColumns[2]).hasText('This is my first post'); let secondRow = recordRows[1]; let secondRowColumns = secondRow.querySelectorAll('.js-record-column'); - assert.equal(secondRowColumns[0].textContent.trim(), 2); - assert.equal(secondRowColumns[1].textContent.trim(), 'Hello'); - assert.equal(secondRowColumns[2].textContent.trim(), ''); + assert.dom(secondRowColumns[0]).hasText('2'); + assert.dom(secondRowColumns[1]).hasText('Hello'); + assert.dom(secondRowColumns[2]).hasText(''); await triggerPort(this, 'data:recordsAdded', { records: [recordFactory({ objectId: 'new-post', id: 3, title: 'Added Post', body: 'I am new here' })] @@ -140,9 +140,9 @@ module('Data Tab', function(hooks) { let addedRow = findAll('.js-record-list-item')[2]; let addedRowColumns = addedRow.querySelectorAll('.js-record-column'); - assert.equal(addedRowColumns[0].textContent.trim(), 3); - assert.equal(addedRowColumns[1].textContent.trim(), 'Added Post'); - assert.equal(addedRowColumns[2].textContent.trim(), 'I am new here'); + assert.dom(addedRowColumns[0]).hasText('3'); + assert.dom(addedRowColumns[1]).hasText('Added Post'); + assert.dom(addedRowColumns[2]).hasText('I am new here'); await triggerPort(this, 'data:recordsUpdated', { records: [recordFactory({ objectId: 'new-post', id: 3, title: 'Modified Post', body: 'I am no longer new' })] @@ -151,9 +151,9 @@ module('Data Tab', function(hooks) { let rows = findAll('.js-record-list-item'); let modifiedRow = rows[rows.length - 1]; let modifiedRowColumns = modifiedRow.querySelectorAll('.js-record-column'); - assert.equal(modifiedRowColumns[0].textContent.trim(), 3); - assert.equal(modifiedRowColumns[1].textContent.trim(), 'Modified Post'); - assert.equal(modifiedRowColumns[2].textContent.trim(), 'I am no longer new'); + assert.dom(modifiedRowColumns[0]).hasText('3'); + assert.dom(modifiedRowColumns[1]).hasText('Modified Post'); + assert.dom(modifiedRowColumns[2]).hasText('I am no longer new'); await triggerPort(this, 'data:recordsRemoved', { index: 2, @@ -161,11 +161,11 @@ module('Data Tab', function(hooks) { }); await wait(); - assert.equal(findAll('.js-record-list-item').length, 2); + assert.dom('.js-record-list-item').exists({ count: 2 }); rows = findAll('.js-record-list-item'); let lastRow = rows[rows.length - 1]; let lastRowColumns = lastRow.querySelectorAll('.js-record-column'); - assert.equal(lastRowColumns[0].textContent.trim(), 2, 'Records successfully removed.'); + assert.dom(lastRowColumns[0]).hasText('2', 'Records successfully removed.'); }); test('Filtering records', async function t(assert) { @@ -182,7 +182,7 @@ module('Data Tab', function(hooks) { rows = findAll('.js-record-list-item'); assert.equal(rows.length, 1); - assert.equal(findAll('.js-record-column', rows[0])[0].textContent.trim(), '2'); + assert.dom(findAll('.js-record-column', rows[0])[0]).hasText('2'); }); test('Searching records', async function t(assert) { @@ -197,13 +197,13 @@ module('Data Tab', function(hooks) { rows = findAll('.js-record-list-item'); assert.equal(rows.length, 1); - assert.equal(findAll('.js-record-column', rows[0])[0].textContent.trim(), '2'); + assert.dom(findAll('.js-record-column', rows[0])[0]).hasText('2'); await fillIn('.js-records-search input', 'my first post'); rows = findAll('.js-record-list-item'); assert.equal(rows.length, 1); - assert.equal(findAll('.js-record-column', rows[0])[0].textContent.trim(), '1'); + assert.dom(findAll('.js-record-column', rows[0])[0]).hasText('1'); await fillIn('.js-records-search input', ''); @@ -211,12 +211,29 @@ module('Data Tab', function(hooks) { assert.equal(rows.length, 2); }); + test("It should clear the search filter when the clear button is clicked", async function(assert) { + await visit('/data/model-types'); + await click(findAll('.js-model-type a')[1]); + + let rows = findAll('.js-record-list-item'); + assert.equal(rows.length, 2); + + await fillIn('.js-records-search input', 'Hello'); + + rows = findAll('.js-record-list-item'); + assert.equal(rows.length, 1); + + await click('.js-search-field-clear-button'); + rows = findAll('.js-record-list-item'); + assert.equal(rows.length, 2); + }); + test('Columns successfully updated when switching model types', async function t(assert) { await visit('/data/model-types/App.Post/records'); let columns = findAll('.js-header-column'); - assert.equal(columns[columns.length - 1].textContent.trim(), 'Body'); + assert.dom(columns[columns.length - 1]).hasText('Body'); await visit('/data/model-types/App.Comment/records'); columns = findAll('.js-header-column'); - assert.equal(columns[columns.length - 1].textContent.trim(), 'Content'); + assert.dom(columns[columns.length - 1]).hasText('Content'); }); }); diff --git a/tests/acceptance/deprecation-test.js b/tests/acceptance/deprecation-test.js index 719ce2adec..f57487bbb4 100644 --- a/tests/acceptance/deprecation-test.js +++ b/tests/acceptance/deprecation-test.js @@ -1,4 +1,4 @@ -import { visit, find, findAll, click } from '@ember/test-helpers'; +import { visit, findAll, fillIn, click } from '@ember/test-helpers'; import { module, test } from 'qunit'; import { setupApplicationTest } from 'ember-qunit'; @@ -71,10 +71,10 @@ module('Deprecation Tab', function(hooks) { await visit('/deprecations'); - assert.notOk(find('.js-deprecation-source'), 'no sources'); - assert.equal(findAll('.js-deprecation-message')[0].textContent.trim(), 'Deprecation 1', 'message shown'); - assert.equal(findAll('.js-deprecation-count')[0].textContent.trim(), 2, 'Count correct'); - assert.ok(find('.js-deprecation-full-trace'), 'Full trace button shown'); + assert.dom('.js-deprecation-source').doesNotExist('no sources'); + assert.dom(findAll('.js-deprecation-message')[0]).hasText('Deprecation 1', 'message shown'); + assert.dom(findAll('.js-deprecation-count')[0]).hasText('2', 'Count correct'); + assert.dom('.js-deprecation-full-trace').exists('Full trace button shown'); await click('.js-full-trace-deprecations-btn'); assert.equal(name, 'deprecation:sendStackTraces'); @@ -96,16 +96,16 @@ module('Deprecation Tab', function(hooks) { await visit('/deprecations'); - assert.equal(find('.js-deprecation-message').textContent.trim(), 'Deprecation 1', 'message shown'); - assert.equal(find('.js-deprecation-count').textContent.trim(), 2, 'Count correct'); - assert.notOk(find('.js-deprecation-full-trace'), 'Full trace button not shown'); + assert.dom('.js-deprecation-message').hasText('Deprecation 1', 'message shown'); + assert.dom('.js-deprecation-count').hasText('2', 'Count correct'); + assert.dom('.js-deprecation-full-trace').doesNotExist('Full trace button not shown'); let sources = findAll('.js-deprecation-source'); assert.equal(sources.length, 2, 'shows all sources'); assert.notOk(sources[0].querySelector('.js-deprecation-source-link'), 'source not clickable'); - assert.equal(sources[0].querySelector('.js-deprecation-source-text').textContent.trim(), 'path-to-file.js:1'); + assert.dom(sources[0].querySelector('.js-deprecation-source-text')).hasText('path-to-file.js:1'); assert.notOk(sources[1].querySelector('.js-deprecation-source-link'), 'source not clickable'); - assert.equal(sources[1].querySelector('.js-deprecation-source-text').textContent.trim(), 'path-to-second-file.js:2'); + assert.dom(sources[1].querySelector('.js-deprecation-source-text')).hasText('path-to-second-file.js:2'); await click('.js-trace-deprecations-btn', sources[0]); @@ -142,16 +142,16 @@ module('Deprecation Tab', function(hooks) { await visit('/deprecations'); - assert.equal(find('.js-deprecation-message').textContent.trim(), 'Deprecation 1', 'message shown'); - assert.equal(find('.js-deprecation-count').textContent.trim(), 2, 'Count correct'); - assert.notOk(find('.js-deprecation-full-trace'), 'Full trace button not shown'); + assert.dom('.js-deprecation-message').hasText('Deprecation 1', 'message shown'); + assert.dom('.js-deprecation-count').hasText('2', 'Count correct'); + assert.dom('.js-deprecation-full-trace').doesNotExist('Full trace button not shown'); let sources = findAll('.js-deprecation-source'); assert.equal(sources.length, 2, 'shows all sources'); assert.notOk(sources[0].querySelector('.js-deprecation-source-text'), 'source clickable'); - assert.equal(sources[0].querySelector('.js-deprecation-source-link').textContent.trim(), 'path-to-file.js:1'); + assert.dom(sources[0].querySelector('.js-deprecation-source-link')).hasText('path-to-file.js:1'); assert.notOk(sources[1].querySelector('.js-deprecation-source-text'), 'source clickable'); - assert.equal(sources[1].querySelector('.js-deprecation-source-link').textContent.trim(), 'path-to-second-file.js:2'); + assert.dom(sources[1].querySelector('.js-deprecation-source-link')).hasText('path-to-second-file.js:2'); openResourceArgs = false; await click('.js-deprecation-source-link', sources[0]); @@ -174,4 +174,30 @@ module('Deprecation Tab', function(hooks) { assert.equal(message.deprecation.message, 'Deprecation 1'); assert.equal(message.deprecation.sources.length, 1); }); + + test("It should clear the search filter when the clear button is clicked", async function(assert) { + port.reopen({ + send(name) { + if (name === 'deprecation:watch') { + port.trigger('deprecation:deprecationsAdded', { + deprecations: deprecationsWithSource() + }); + } + return this._super(...arguments); + } + }); + + await visit('/deprecations'); + + let sources = findAll('.js-deprecation-source'); + assert.equal(sources.length, 2, 'shows all sources'); + + await fillIn('.js-deprecations-search input', 'xxxx'); + sources = findAll('.js-deprecation-source'); + assert.equal(sources.length, 0, 'sources filtered'); + + await click('.js-search-field-clear-button'); + sources = findAll('.js-deprecation-source'); + assert.equal(sources.length, 2, 'show all sources'); + }); }); diff --git a/tests/acceptance/info-test.js b/tests/acceptance/info-test.js index 5c6e713c41..ec4ea6bf42 100644 --- a/tests/acceptance/info-test.js +++ b/tests/acceptance/info-test.js @@ -29,11 +29,11 @@ module('Info Tab', function(hooks) { let libraries = findAll('.js-library-row'); assert.equal(libraries.length, 3, "The correct number of libraries is displayed"); - assert.equal(libraries[0].querySelector('.js-lib-name').textContent.trim(), 'Ember Inspector', 'Ember Inspector is added automatically'); - assert.equal(libraries[0].querySelector('.js-lib-version').textContent.trim(), '9.9.9'); - assert.equal(libraries[1].querySelector('.js-lib-name').textContent.trim(), 'Ember'); - assert.equal(libraries[1].querySelector('.js-lib-version').textContent.trim(), '1.0'); - assert.equal(libraries[2].querySelector('.js-lib-name').textContent.trim(), 'Handlebars'); - assert.equal(libraries[2].querySelector('.js-lib-version').textContent.trim(), '2.1'); + assert.dom(libraries[0].querySelector('.js-lib-name')).hasText('Ember Inspector', 'Ember Inspector is added automatically'); + assert.dom(libraries[0].querySelector('.js-lib-version')).hasText('9.9.9'); + assert.dom(libraries[1].querySelector('.js-lib-name')).hasText('Ember'); + assert.dom(libraries[1].querySelector('.js-lib-version')).hasText('1.0'); + assert.dom(libraries[2].querySelector('.js-lib-name')).hasText('Handlebars'); + assert.dom(libraries[2].querySelector('.js-lib-version')).hasText('2.1'); }); }); diff --git a/tests/acceptance/object-inspector-test.js b/tests/acceptance/object-inspector-test.js index da1608c52b..d5b6285458 100644 --- a/tests/acceptance/object-inspector-test.js +++ b/tests/acceptance/object-inspector-test.js @@ -89,9 +89,12 @@ module('Object Inspector', function(hooks) { await triggerPort(this, 'objectInspector:updateObject', obj); - assert.equal(find('.js-object-name').textContent, 'My Object'); - assert.equal(find('.js-object-detail-name').textContent, 'Own Properties'); - assert.ok(find('.js-object-detail').classList.contains('mixin_state_expanded'), 'The "Own Properties" detail is expanded by default'); + assert.dom('.js-object-name').hasText('My Object'); + assert.dom('.js-object-detail-name').hasText('Own Properties'); + assert.dom('.js-object-detail').hasClass( + 'mixin_state_expanded', + 'The "Own Properties" detail is expanded by default' + ); }); test("Object details", async function (assert) { @@ -99,30 +102,29 @@ module('Object Inspector', function(hooks) { await triggerPort(this, 'objectInspector:updateObject', objectToInspect()); - assert.equal(find('.js-object-name').textContent, 'My Object'); + assert.dom('.js-object-name').hasText('My Object'); let [firstDetail, secondDetail] = findAll('.js-object-detail'); - assert.equal(firstDetail.querySelector('.js-object-detail-name').textContent, 'First Detail'); - assert.notOk(firstDetail.classList.contains('mixin_state_expanded'), 'Detail not expanded by default'); + assert.dom(firstDetail.querySelector('.js-object-detail-name')).hasText('First Detail'); + assert.dom(firstDetail).hasNoClass('mixin_state_expanded', 'Detail not expanded by default'); await click('.js-object-detail-name', firstDetail); - assert.ok(firstDetail.classList.contains('mixin_state_expanded'), 'Detail expands on click.'); - assert.notOk(secondDetail.classList.contains('mixin_state_expanded'), 'Second detail does not expand.'); + assert.dom(firstDetail).hasClass('mixin_state_expanded', 'Detail expands on click.'); + assert.dom(secondDetail).hasNoClass('mixin_state_expanded', 'Second detail does not expand.'); assert.equal(firstDetail.querySelectorAll('.js-object-property').length, 1); - assert.equal(firstDetail.querySelector('.js-object-property-name').textContent, 'numberProperty'); - assert.equal(firstDetail.querySelector('.js-object-property-value').textContent, '1'); - + assert.dom(firstDetail.querySelector('.js-object-property-name')).hasText('numberProperty'); + assert.dom(firstDetail.querySelector('.js-object-property-value')).hasText('1'); await click(firstDetail.querySelector('.js-object-detail-name')); - assert.notOk(firstDetail.classList.contains('mixin_state_expanded'), 'Expanded detail minimizes on click.'); + assert.dom(firstDetail).hasNoClass('mixin_state_expanded', 'Expanded detail minimizes on click.'); await click(secondDetail.querySelector('.js-object-detail-name')); - assert.ok(secondDetail.classList.contains('mixin_state_expanded')); + assert.dom(secondDetail).hasClass('mixin_state_expanded'); assert.equal(secondDetail.querySelectorAll('.js-object-property').length, 2); - assert.equal(secondDetail.querySelectorAll('.js-object-property-name')[0].textContent, 'objectProperty'); - assert.equal(secondDetail.querySelectorAll('.js-object-property-value')[0].textContent, 'Ember Object Name'); - assert.equal(secondDetail.querySelectorAll('.js-object-property-name')[1].textContent, 'stringProperty'); - assert.equal(secondDetail.querySelectorAll('.js-object-property-value')[1].textContent, 'String Value'); + assert.dom(secondDetail.querySelectorAll('.js-object-property-name')[0]).hasText('objectProperty'); + assert.dom(secondDetail.querySelectorAll('.js-object-property-value')[0]).hasText('Ember Object Name'); + assert.dom(secondDetail.querySelectorAll('.js-object-property-name')[1]).hasText('stringProperty'); + assert.dom(secondDetail.querySelectorAll('.js-object-property-value')[1]).hasText('String Value'); }); test("Digging deeper into objects", async function (assert) { @@ -159,17 +161,17 @@ module('Object Inspector', function(hooks) { await triggerPort(this, 'objectInspector:updateObject', nestedObject); - assert.equal(find('.js-object-name').textContent, 'My Object', 'Title stays as the initial object.'); - assert.equal(find('.js-object-trail').textContent, '.objectProperty', 'Nested property shows below title'); - assert.equal(find('.js-object-detail-name').textContent, 'Nested Detail'); + assert.dom('.js-object-name').hasText('My Object', 'Title stays as the initial object.'); + assert.dom('.js-object-trail').hasText('.objectProperty', 'Nested property shows below title'); + assert.dom('.js-object-detail-name').hasText('Nested Detail'); await click('.js-object-detail-name'); - assert.ok(find('.js-object-detail').classList.contains('mixin_state_expanded')); - assert.equal(find('.js-object-property-name').textContent, 'nestedProp'); - assert.equal(find('.js-object-property-value').textContent, 'Nested Prop'); + assert.dom('.js-object-detail').hasClass('mixin_state_expanded'); + assert.dom('.js-object-property-name').hasText('nestedProp'); + assert.dom('.js-object-property-value').hasText('Nested Prop'); await click('.js-object-inspector-back'); - assert.notOk(find('.js-object-trail'), 0); + assert.dom('.js-object-trail').doesNotExist(0); }); test("Computed properties", async function (assert) { @@ -207,7 +209,138 @@ module('Object Inspector', function(hooks) { mixinIndex: 0 }); - assert.equal(find('.js-object-property-value').textContent, 'Computed value'); + assert.dom('.js-object-property-value').hasText('Computed value'); + }); + + test("Service highlight", async function(assert) { + await visit('/'); + + let obj = { + name: 'My Object', + objectId: 'myObject', + details: [{ + name: 'Detail', + properties: [{ + name: 'serviceProp', + isService: true, + value: { + inspect: '', + computed: true + } + }] + }] + }; + + await triggerPort(this, 'objectInspector:updateObject', obj); + await click('.js-object-detail-name'); + + assert.equal(findAll('.mixin__property--group').length, 1); + assert.equal(findAll('.mixin__property-icon--service').length, 1); + assert.equal(findAll('.js-property-name-service').length, 1); + assert.equal(findAll('.mixin__property-dependency-list').length, 0); + assert.equal(findAll('.mixin__property-dependency-item').length, 0); + assert.equal(findAll('.mixin__property-dependency-item > .mixin__property-dependency-name').length, 0); + }); + + test("Computed properties no dependency", async function (assert) { + await visit('/'); + + let obj = { + name: 'My Object', + objectId: 'myObject', + details: [{ + name: 'Detail', + properties: [{ + name: 'computedProp', + dependentKeys: [], + value: { + inspect: '', + type: 'type-descriptor', + computed: true + } + }] + }] + }; + + await triggerPort(this, 'objectInspector:updateObject', obj); + await click('.js-object-detail-name'); + await click('.js-calculate'); + + assert.equal(name, 'objectInspector:calculate'); + assert.deepEqual(message, { objectId: 'myObject', property: 'computedProp', mixinIndex: 0 }); + await triggerPort(this, 'objectInspector:updateProperty', { + objectId: 'myObject', + property: 'computedProp', + value: { + inspect: 'Computed value', + computed: 'foo-bar' + }, + mixinIndex: 0 + }); + + assert.equal(findAll('.mixin__property--group').length, 0); + + await click('.mixin__property-icon--computed'); + + assert.equal(findAll('.mixin__property-dependency-list').length, 0); + assert.equal(findAll('.mixin__property-dependency-item').length, 0); + assert.equal(findAll('.mixin__property-dependency-item > .mixin__property-dependency-name').length, 0); + + await click('.mixin__property-icon--computed'); + + assert.equal(findAll('.mixin__property-dependency-list').length, 0); + assert.equal(findAll('.mixin__property-dependency-item').length, 0); + assert.equal(findAll('.mixin__property-dependency-item > .mixin__property-dependency-name').length, 0); + }); + + test("Computed properties dependency expand", async function (assert) { + await visit('/'); + + let obj = { + name: 'My Object', + objectId: 'myObject', + details: [{ + name: 'Detail', + properties: [{ + name: 'computedProp', + dependentKeys: ['foo.@each.bar'], + value: { + inspect: '', + type: 'type-descriptor', + computed: true + } + }] + }] + }; + await triggerPort(this, 'objectInspector:updateObject', obj); + await click('.js-object-detail-name'); + await click('.js-calculate'); + + assert.equal(name, 'objectInspector:calculate'); + assert.deepEqual(message, { objectId: 'myObject', property: 'computedProp', mixinIndex: 0 }); + await triggerPort(this, 'objectInspector:updateProperty', { + objectId: 'myObject', + property: 'computedProp', + value: { + inspect: 'Computed value', + computed: 'foo-bar' + }, + mixinIndex: 0 + }); + + assert.equal(findAll('.mixin__property--group').length, 1); + + await click('.mixin__property-icon--computed'); + + assert.equal(findAll('.mixin__property-dependency-list').length, 1); + assert.equal(findAll('.mixin__property-dependency-item').length, 1); + assert.equal(findAll('.mixin__property-dependency-item > .mixin__property-dependency-name').length, 1); + + await click('.mixin__property-icon--computed'); + + assert.equal(findAll('.mixin__property-dependency-list').length, 0); + assert.equal(findAll('.mixin__property-dependency-item').length, 0); + assert.equal(findAll('.mixin__property-dependency-item > .mixin__property-dependency-name').length, 0); }); test("Properties are bound to the application properties", async function (assert) { @@ -232,7 +365,7 @@ module('Object Inspector', function(hooks) { }; await triggerPort(this, 'objectInspector:updateObject', obj); - assert.equal(find('.js-object-property-value').textContent, 'Teddy'); + assert.dom('.js-object-property-value').hasText('Teddy'); await triggerPort(this, 'objectInspector:updateProperty', { objectId: 'object-id', mixinIndex: 0, @@ -267,7 +400,7 @@ module('Object Inspector', function(hooks) { } }); - assert.equal(find('.js-object-property-value').textContent, 'Joey'); + assert.dom('.js-object-property-value').hasText('Joey'); }); test("Stringified json should not get double parsed", async function (assert) { @@ -370,12 +503,12 @@ module('Object Inspector', function(hooks) { }; await triggerPort(this, 'objectInspector:updateObject', obj); await click('.js-object-property-value'); - assert.notOk(find('.js-object-property-value-txt')); + assert.dom('.js-object-property-value-txt').doesNotExist(); let valueElements = findAll('.js-object-property-value'); await click(valueElements[valueElements.length - 1]); - assert.ok(find('.js-object-property-value-txt')); + assert.dom('.js-object-property-value-txt').exists(); }); test("Dropping an object due to destruction", async function (assert) { @@ -392,10 +525,10 @@ module('Object Inspector', function(hooks) { await triggerPort(this, 'objectInspector:updateObject', obj); - assert.equal(find('.js-object-name').textContent.trim(), 'My Object'); + assert.dom('.js-object-name').hasText('My Object'); await triggerPort(this, 'objectInspector:droppedObject', { objectId: 'myObject' }); - assert.notOk(find('.js-object-name')); + assert.dom('.js-object-name').doesNotExist(); }); test("Date fields are editable", async function (assert) { @@ -450,9 +583,9 @@ module('Object Inspector', function(hooks) { await visit('/'); await triggerPort(this, 'objectInspector:updateObject', obj); - assert.equal(find('.js-object-name').textContent, 'My Object'); - assert.equal(findAll('.js-object-inspector-errors').length, 1); - assert.equal(findAll('.js-object-inspector-error').length, 2); + assert.dom('.js-object-name').hasText('My Object'); + assert.dom('.js-object-inspector-errors').exists({ count: 1 }); + assert.dom('.js-object-inspector-error').exists({ count: 2 }); await click('.js-send-errors-to-console'); @@ -466,13 +599,13 @@ module('Object Inspector', function(hooks) { ] }); - assert.ok(find('.js-object-inspector-error')); + assert.dom('.js-object-inspector-error').exists(); await triggerPort(this, 'objectInspector:updateErrors', { objectId: '1', errors: [] }); - assert.notOk(find('.js-object-inspector-errors')); + assert.dom('.js-object-inspector-errors').doesNotExist(); }); }); diff --git a/tests/acceptance/promise-test.js b/tests/acceptance/promise-test.js index 7ea8386421..14e7b947e1 100644 --- a/tests/acceptance/promise-test.js +++ b/tests/acceptance/promise-test.js @@ -1,4 +1,4 @@ -import { visit, find, findAll, click } from '@ember/test-helpers'; +import { visit, find, findAll, fillIn, click } from '@ember/test-helpers'; import { module, test } from 'qunit'; import { setupApplicationTest } from 'ember-qunit'; import { triggerPort } from '../helpers/trigger-port'; @@ -51,8 +51,8 @@ module('Promise Tab', function(hooks) { promises: [] }); - assert.notOk(find('.js-promise-tree'), "no promise list"); - assert.ok(find('.js-page-refresh'), "page refresh hint seen"); + assert.dom('.js-promise-tree').doesNotExist("no promise list"); + assert.dom('.js-page-refresh').exists("page refresh hint seen"); await click('.js-page-refresh-btn'); @@ -68,16 +68,16 @@ module('Promise Tab', function(hooks) { ] }); - assert.ok(find('.js-promise-tree'), 'promise tree is seen after being populated'); - assert.equal(findAll('.js-promise-tree-item').length, 1, '1 promise item can be seen'); - assert.notOk(find('.js-page-refresh'), 'page refresh hint hidden'); + assert.dom('.js-promise-tree').exists('promise tree is seen after being populated'); + assert.dom('.js-promise-tree-item').exists({ count: 1 }, '1 promise item can be seen'); + assert.dom('.js-page-refresh').doesNotExist('page refresh hint hidden'); // make sure clearing does not show the refresh hint await click('.js-clear-promises-btn'); - assert.ok(find('.js-promise-tree'), 'promise-tree can be seen'); - assert.notOk(find('.js-promise-tree-item'), 'promise items cleared'); - assert.notOk(find('.js-page-refresh'), 'page refresh hint hidden'); + assert.dom('.js-promise-tree').exists('promise-tree can be seen'); + assert.dom('.js-promise-tree-item').doesNotExist('promise items cleared'); + assert.dom('.js-page-refresh').doesNotExist('page refresh hint hidden'); }); test("Pending promise", async function(assert) { @@ -94,10 +94,10 @@ module('Promise Tab', function(hooks) { }); await wait(); - assert.equal(findAll('.js-promise-tree-item').length, 1); + assert.dom('.js-promise-tree-item').exists({ count: 1 }); let row = find('.js-promise-tree-item'); - assert.equal(row.querySelector('.js-promise-label').textContent.trim(), 'Promise 1'); - assert.equal(row.querySelector('.js-promise-state').textContent.trim(), 'Pending'); + assert.dom(row.querySelector('.js-promise-label')).hasText('Promise 1'); + assert.dom(row.querySelector('.js-promise-state')).hasText('Pending'); }); @@ -123,12 +123,12 @@ module('Promise Tab', function(hooks) { }); await wait(); - assert.equal(findAll('.js-promise-tree-item').length, 1); + assert.dom('.js-promise-tree-item').exists({ count: 1 }); let row = find('.js-promise-tree-item'); - assert.equal(row.querySelector('.js-promise-label').textContent.trim(), 'Promise 1'); - assert.equal(row.querySelector('.js-promise-state').textContent.trim(), 'Fulfilled'); - assert.equal(row.querySelector('.js-promise-value').textContent.trim(), 'value'); - assert.equal(row.querySelector('.js-promise-time').textContent.trim(), '10.00ms'); + assert.dom(row.querySelector('.js-promise-label')).hasText('Promise 1'); + assert.dom(row.querySelector('.js-promise-state')).hasText('Fulfilled'); + assert.dom(row.querySelector('.js-promise-value')).hasText('value'); + assert.dom(row.querySelector('.js-promise-time')).hasText('10.00ms'); }); @@ -153,12 +153,12 @@ module('Promise Tab', function(hooks) { ] }); - assert.equal(findAll('.js-promise-tree-item').length, 1); + assert.dom('.js-promise-tree-item').exists({ count: 1 }); let row = find('.js-promise-tree-item'); - assert.equal(row.querySelector('.js-promise-label').textContent.trim(), 'Promise 1'); - assert.equal(row.querySelector('.js-promise-state').textContent.trim(), 'Rejected'); - assert.equal(row.querySelector('.js-promise-value').textContent.trim(), 'reason'); - assert.equal(row.querySelector('.js-promise-time').textContent.trim(), '20.00ms'); + assert.dom(row.querySelector('.js-promise-label')).hasText('Promise 1'); + assert.dom(row.querySelector('.js-promise-state')).hasText('Rejected'); + assert.dom(row.querySelector('.js-promise-value')).hasText('reason'); + assert.dom(row.querySelector('.js-promise-time')).hasText('20.00ms'); }); test("Chained promises", async function(assert) { @@ -181,12 +181,12 @@ module('Promise Tab', function(hooks) { let rows = findAll('.js-promise-tree-item'); assert.equal(rows.length, 1, 'Collpased by default'); - assert.equal(rows[0].querySelector('.js-promise-label').textContent.trim(), 'Parent'); + assert.dom(rows[0].querySelector('.js-promise-label')).hasText('Parent'); await click(rows[0].querySelector('.js-promise-label')); rows = findAll('.js-promise-tree-item'); assert.equal(rows.length, 2, 'Chain now expanded'); - assert.equal(rows[1].querySelector('.js-promise-label').textContent.trim(), 'Child'); + assert.dom(rows[1].querySelector('.js-promise-label')).hasText('Child'); }); test("Can trace promise when there is a stack", async function(assert) { @@ -210,7 +210,7 @@ module('Promise Tab', function(hooks) { promises: [generatePromise({ guid: 1, hasStack: false })] }); - assert.notOk(find('.js-trace-promise-btn')); + assert.dom('.js-trace-promise-btn').doesNotExist(); }); test("Toggling promise trace option", async function(assert) { @@ -241,7 +241,7 @@ module('Promise Tab', function(hooks) { }); let row = find('.js-promise-tree-item'); - assert.equal(find('.js-send-to-console-btn').textContent.trim(), 'Stack trace'); + assert.dom('.js-send-to-console-btn').hasText('Stack trace'); await click(row.querySelector('.js-send-to-console-btn')); assert.equal(name, 'promise:sendValueToConsole'); @@ -291,4 +291,25 @@ module('Promise Tab', function(hooks) { assert.equal(name, 'objectInspector:inspectById'); assert.deepEqual(message, { objectId: 100 }); }); + + test("It should clear the search filter when the clear button is clicked", async function(assert) { + await visit('/promise-tree'); + + await triggerPort(this, 'promise:promisesUpdated', { + promises: [ + generatePromise({ + guid: 1, + label: 'Promise 1', + state: 'created' + }) + ] + }); + await wait(); + + assert.dom('.js-promise-tree-item').exists({ count: 1 }); + await fillIn('.js-promise-search input', 'xxxxx'); + assert.dom('.js-promise-tree-item').doesNotExist(); + await click('.js-search-field-clear-button'); + assert.dom('.js-promise-tree-item').exists({ count: 1 }); + }); }); diff --git a/tests/acceptance/render-tree-test.js b/tests/acceptance/render-tree-test.js index f01b0cc7ea..122c8a5414 100644 --- a/tests/acceptance/render-tree-test.js +++ b/tests/acceptance/render-tree-test.js @@ -1,4 +1,4 @@ -import { visit, find, findAll, click, fillIn } from '@ember/test-helpers'; +import { visit, findAll, click, fillIn } from '@ember/test-helpers'; import { module, test } from 'qunit'; import { setupApplicationTest } from 'ember-qunit'; @@ -51,8 +51,8 @@ module('Render Tree Tab', function(hooks) { await visit('/render-tree'); - assert.notOk(find('.js-render-tree'), "no render tree"); - assert.ok(find('.js-render-tree-empty'), "Message about empty render tree shown"); + assert.dom('.js-render-tree').doesNotExist("no render tree"); + assert.dom('.js-render-tree-empty').exists("Message about empty render tree shown"); }); test("Renders the list correctly", async function(assert) { @@ -68,26 +68,26 @@ module('Render Tree Tab', function(hooks) { await visit('/render-tree'); - assert.ok(find('.js-render-tree')); + assert.dom('.js-render-tree').exists(); let rows = findAll('.js-render-profile-item'); assert.equal(rows.length, 2, "Two rows are rendered initially"); - assert.equal(rows[0].querySelector('.js-render-profile-name').textContent.trim(), "First View Rendering"); - assert.equal(rows[0].querySelector('.js-render-profile-duration').textContent.trim(), "476.87ms"); - assert.equal(rows[0].querySelector('.js-render-profile-timestamp').textContent.trim(), "13:16:22:715"); + assert.dom(rows[0].querySelector('.js-render-profile-name')).hasText('First View Rendering'); + assert.dom(rows[0].querySelector('.js-render-profile-duration')).hasText('476.87ms'); + assert.dom(rows[0].querySelector('.js-render-profile-timestamp')).hasText('13:16:22:715'); - assert.equal(rows[1].querySelector('.js-render-profile-name').textContent.trim(), "Second View Rendering"); - assert.equal(rows[1].querySelector('.js-render-profile-duration').textContent.trim(), "10.00ms"); - assert.equal(rows[1].querySelector('.js-render-profile-timestamp').textContent.trim(), "13:16:22:759"); + assert.dom(rows[1].querySelector('.js-render-profile-name')).hasText('Second View Rendering'); + assert.dom(rows[1].querySelector('.js-render-profile-duration')).hasText('10.00ms'); + assert.dom(rows[1].querySelector('.js-render-profile-timestamp')).hasText('13:16:22:759'); await click('.js-render-main-cell', rows[0]); rows = findAll('.js-render-profile-item'); assert.equal(rows.length, 3, "Child is shown below the parent"); - assert.equal(rows[1].querySelector('.js-render-profile-name').textContent.trim(), "Child view"); - assert.equal(rows[1].querySelector('.js-render-profile-duration').textContent.trim(), "0.36ms"); - assert.equal(rows[1].querySelector('.js-render-profile-timestamp').textContent.trim(), "13:16:22:581"); + assert.dom(rows[1].querySelector('.js-render-profile-name')).hasText('Child view'); + assert.dom(rows[1].querySelector('.js-render-profile-duration')).hasText('0.36ms'); + assert.dom(rows[1].querySelector('.js-render-profile-timestamp')).hasText('13:16:22:581'); await click('.js-render-main-cell', rows[0]); @@ -111,15 +111,15 @@ module('Render Tree Tab', function(hooks) { let rows = findAll('.js-render-profile-item'); assert.equal(rows.length, 2, "Two rows are rendered initially"); - assert.equal(rows[0].querySelector('.js-render-profile-name').textContent.trim(), "First View Rendering"); - assert.equal(rows[1].querySelector('.js-render-profile-name').textContent.trim(), "Second View Rendering"); + assert.dom(rows[0].querySelector('.js-render-profile-name')).hasText('First View Rendering'); + assert.dom(rows[1].querySelector('.js-render-profile-name')).hasText('Second View Rendering'); await fillIn('.js-render-profiles-search input', 'first'); rows = findAll('.js-render-profile-item'); assert.equal(rows.length, 2, "The first parent is rendered with the child"); - assert.equal(rows[0].querySelector('.js-render-profile-name').textContent.trim(), "First View Rendering"); - assert.equal(rows[1].querySelector('.js-render-profile-name').textContent.trim(), "Child view"); + assert.dom(rows[0].querySelector('.js-render-profile-name')).hasText('First View Rendering'); + assert.dom(rows[1].querySelector('.js-render-profile-name')).hasText('Child view'); // Minimize to hide child view await click('.js-render-main-cell'); @@ -129,13 +129,38 @@ module('Render Tree Tab', function(hooks) { rows = findAll('.js-render-profile-item'); assert.equal(rows.length, 2, "filter is reset"); - assert.equal(rows[0].querySelector('.js-render-profile-name').textContent.trim(), "First View Rendering"); - assert.equal(rows[1].querySelector('.js-render-profile-name').textContent.trim(), "Second View Rendering"); + assert.dom(rows[0].querySelector('.js-render-profile-name')).hasText('First View Rendering'); + assert.dom(rows[1].querySelector('.js-render-profile-name')).hasText('Second View Rendering'); await fillIn('.js-render-profiles-search input', 'Second'); rows = findAll('.js-render-profile-item'); assert.equal(rows.length, 1, "The second row is the only one showing"); - assert.equal(rows[0].querySelector('.js-render-profile-name').textContent.trim(), "Second View Rendering"); + assert.dom(rows[0].querySelector('.js-render-profile-name')).hasText('Second View Rendering'); + }); + + test("It should clear the search filter when the clear button is clicked", async function(assert) { + port.reopen({ + send(n/*, m*/) { + if (n === 'render:watchProfiles') { + this.trigger('render:profilesAdded', { + profiles: generateProfiles() + }); + } + } + }); + + await visit('/render-tree'); + + let rows = findAll('.js-render-profile-item'); + assert.equal(rows.length, 2, "expected all rows"); + + await fillIn('.js-render-profiles-search input', 'xxxxxx'); + rows = findAll('.js-render-profile-item'); + assert.equal(rows.length, 0, 'expected filtered rows'); + + await click('.js-search-field-clear-button'); + rows = findAll('.js-render-profile-item'); + assert.equal(rows.length, 2, 'expected all rows'); }); }); diff --git a/tests/acceptance/view-tree-test.js b/tests/acceptance/view-tree-test.js index c70aceb632..30bf12e38a 100644 --- a/tests/acceptance/view-tree-test.js +++ b/tests/acceptance/view-tree-test.js @@ -240,6 +240,27 @@ module('View Tree Tab', function(hooks) { ], 'expected title tips'); }); + test("It should clear the search filter when the clear button is clicked", async function(assert) { + let viewTree = defaultViewTree(); + + await visit('/'); + run(() => { + port.trigger('view:viewTree', { tree: viewTree }); + }); + await wait(); + + let treeNodes = findAll('.js-view-tree-item'); + assert.equal(treeNodes.length, 3, 'expected all tree nodes'); + + await fillIn('.js-filter-views input', 'post'); + treeNodes = findAll('.js-view-tree-item'); + assert.equal(treeNodes.length, 1, 'expected filtered tree nodes'); + + await click('.js-search-field-clear-button'); + treeNodes = findAll('.js-view-tree-item'); + assert.equal(treeNodes.length, 3, 'expected all tree nodes'); + }); + test("It should update the view tree when the port triggers a change", async function(assert) { assert.expect(4); let treeNodes, viewTree = defaultViewTree(); @@ -251,7 +272,7 @@ module('View Tree Tab', function(hooks) { treeNodes = findAll('.js-view-tree-item'); assert.equal(treeNodes.length, 3); let viewControllersEls = findAll('.js-view-controller'); - assert.equal(viewControllersEls[viewControllersEls.length - 1].textContent.trim(), 'App.CommentsController'); + assert.dom(viewControllersEls[viewControllersEls.length - 1]).hasText('App.CommentsController'); viewTree = defaultViewTree(); viewTree.children.splice(0, 1); @@ -261,7 +282,7 @@ module('View Tree Tab', function(hooks) { treeNodes = findAll('.js-view-tree-item'); assert.equal(treeNodes.length, 2); viewControllersEls = findAll('.js-view-controller'); - assert.equal(viewControllersEls[viewControllersEls.length - 1].textContent.trim(), 'App.SomeController'); + assert.dom(viewControllersEls[viewControllersEls.length - 1]).hasText('App.SomeController'); }); test("Previewing / showing a view on the client", async function(assert) { diff --git a/tests/ember_debug/object-inspector-test.js b/tests/ember_debug/object-inspector-test.js index b586011b51..f39ab4f886 100644 --- a/tests/ember_debug/object-inspector-test.js +++ b/tests/ember_debug/object-inspector-test.js @@ -4,6 +4,7 @@ import Component from '@ember/component'; import { run } from '@ember/runloop'; import { guidFor } from '@ember/object/internals'; import EmberObject, { computed } from '@ember/object'; +import Service from '@ember/service'; import Ember from 'ember'; import { module, test } from 'qunit'; import { settings as nativeDomHelpersSettings } from 'ember-native-dom-helpers'; @@ -368,6 +369,44 @@ module('Ember Debug - Object Inspector', function(hooks) { assert.ok(message.details[4].name !== 'MixinToSkip', 'Correctly skips properties'); }); + + test("Service should be successfully tagged as service on serialization", function(assert) { + let inspectedService = Service.extend({ + fooBoo() { + return true; + } + }).create(); + + let inspected = EmberObject.extend({ + service: inspectedService + }).create(); + + objectInspector.sendObject(inspected); + + let serializedServiceProperty = message.details[1].properties[0]; + + assert.equal(serializedServiceProperty.isService, true); + }); + + test("Computed property dependent keys and code should be successfully serialized", function(assert) { + let compuedFn = function() { + return this.get("foo") + this.get("bar"); + }; + + let inspected = EmberObject.extend({ + foo: true, + bar: false, + fooAndBar: computed("foo", "bar", compuedFn) + }).create(); + + objectInspector.sendObject(inspected); + let serializedComputedProperty = message.details[1].properties[2]; + + assert.equal(serializedComputedProperty.code, compuedFn.toString()); + assert.equal(serializedComputedProperty.dependentKeys[0], "foo"); + assert.equal(serializedComputedProperty.dependentKeys[1], "bar"); + }); + test('Read Only Computed properties mush have a readOnly property', function(assert) { let inspected = EmberObject.extend({ readCP: computed(function() {}).property().readOnly(), diff --git a/tests/ember_debug/view-debug-test.js b/tests/ember_debug/view-debug-test.js index 5355cc1840..33cf13bb7e 100644 --- a/tests/ember_debug/view-debug-test.js +++ b/tests/ember_debug/view-debug-test.js @@ -174,15 +174,15 @@ module('Ember Debug - View', function(hooks) { let previewDiv = find('[data-label=preview-div]'); assert.ok(isVisible(previewDiv)); - assert.notOk(find('[data-label=layer-component]'), 'Component layer not shown on outlet views'); - assert.equal(previewDiv.querySelector('[data-label=layer-controller]').textContent, 'App.ApplicationController'); - assert.equal(previewDiv.querySelector('[data-label=layer-model]').textContent, 'Application model'); + assert.dom('[data-label=layer-component]').doesNotExist('Component layer not shown on outlet views'); + assert.dom(previewDiv.querySelector('[data-label=layer-controller]')).hasText('App.ApplicationController'); + assert.dom(previewDiv.querySelector('[data-label=layer-model]')).hasText('Application model'); let layerDiv = find('[data-label=layer-div]'); await triggerEvent(layerDiv, 'mouseup'); assert.ok(isVisible(layerDiv)); - assert.equal(layerDiv.querySelector('[data-label=layer-model]').textContent, 'Application model'); + assert.dom(layerDiv.querySelector('[data-label=layer-model]')).hasText('Application model'); await click(layerDiv.querySelector('[data-label=layer-controller]')); let controller = this.owner.lookup('controller:application'); @@ -249,7 +249,10 @@ module('Ember Debug - View', function(hooks) { await visit('/simple'); - assert.ok(rootElement.classList.contains('ember-application'), 'The rootElement has the .ember-application CSS class'); + assert.dom(rootElement).hasClass( + 'ember-application', + 'The rootElement has the .ember-application CSS class' + ); rootElement.classList.remove('ember-application'); // Restart the inspector diff --git a/yarn.lock b/yarn.lock index ffd1f1be86..118dda3ca3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -129,6 +129,10 @@ "@types/acorn" "*" source-map "^0.6.1" +abab@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e" + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -147,12 +151,22 @@ accepts@~1.3.4: mime-types "~2.1.16" negotiator "0.6.1" +acorn-globals@^1.0.4: + version "1.0.9" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-1.0.9.tgz#55bb5e98691507b74579d0513413217c380c54cf" + dependencies: + acorn "^2.1.0" + acorn-jsx@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" dependencies: acorn "^3.0.4" +acorn@^2.1.0, acorn@^2.4.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-2.7.0.tgz#ab6e7d9d886aaca8b085bc3312b79a198433f0e7" + acorn@^3.0.4: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" @@ -1199,6 +1213,10 @@ basic-auth@~2.0.0: dependencies: safe-buffer "5.1.1" +basiccontext@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/basiccontext/-/basiccontext-3.5.1.tgz#e1f512d447c8c19c48d0a616f77a725d6b181ee0" + bcrypt-pbkdf@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" @@ -1284,6 +1302,10 @@ body@^5.1.0: raw-body "~1.1.0" safe-json-parse "~1.0.1" +boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + boom@2.x.x: version "2.10.1" resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" @@ -1432,6 +1454,17 @@ broccoli-builder@^0.18.8: rsvp "^3.0.17" silent-error "^1.0.1" +broccoli-caching-writer@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" + dependencies: + broccoli-kitchen-sink-helpers "^0.2.5" + broccoli-plugin "1.1.0" + debug "^2.1.1" + rimraf "^2.2.8" + rsvp "^3.0.17" + walk-sync "^0.2.5" + broccoli-caching-writer@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-3.0.3.tgz#0bd2c96a9738d6a6ab590f07ba35c5157d7db476" @@ -1452,6 +1485,19 @@ broccoli-clean-css@^1.1.0: inline-source-map-comment "^1.0.5" json-stable-stringify "^1.0.0" +broccoli-concat@^2.2.0: + version "2.3.8" + resolved "https://registry.yarnpkg.com/broccoli-concat/-/broccoli-concat-2.3.8.tgz#590cdcc021bb905b6c121d87c2d1d57df44a2a48" + dependencies: + broccoli-caching-writer "^2.3.1" + broccoli-kitchen-sink-helpers "^0.3.1" + broccoli-stew "^1.3.3" + fast-sourcemap-concat "^1.0.1" + fs-extra "^0.30.0" + lodash.merge "^4.3.0" + lodash.omit "^4.1.0" + lodash.uniq "^4.2.0" + broccoli-concat@^3.0.1, broccoli-concat@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/broccoli-concat/-/broccoli-concat-3.2.2.tgz#86ffdc52606eb590ba9f6b894c5ec7a016f5b7b9" @@ -1561,16 +1607,16 @@ broccoli-funnel@^2.0.0, broccoli-funnel@^2.0.1: symlink-or-copy "^1.0.0" walk-sync "^0.3.1" -broccoli-kitchen-sink-helpers@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.3.1.tgz#77c7c18194b9664163ec4fcee2793444926e0c06" +broccoli-kitchen-sink-helpers@^0.2.5, broccoli-kitchen-sink-helpers@~0.2.0: + version "0.2.9" + resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" dependencies: glob "^5.0.10" mkdirp "^0.5.1" -broccoli-kitchen-sink-helpers@~0.2.0: - version "0.2.9" - resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" +broccoli-kitchen-sink-helpers@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.3.1.tgz#77c7c18194b9664163ec4fcee2793444926e0c06" dependencies: glob "^5.0.10" mkdirp "^0.5.1" @@ -1621,7 +1667,7 @@ broccoli-middleware@^1.0.0: handlebars "^4.0.4" mime "^1.2.11" -broccoli-persistent-filter@^1.0.3, broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.4.0, broccoli-persistent-filter@^1.4.2, broccoli-persistent-filter@^1.4.3: +broccoli-persistent-filter@^1.0.3, broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.2.0, broccoli-persistent-filter@^1.4.0, broccoli-persistent-filter@^1.4.2, broccoli-persistent-filter@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/broccoli-persistent-filter/-/broccoli-persistent-filter-1.4.3.tgz#3511bc52fc53740cda51621f58a28152d9911bc1" dependencies: @@ -1639,6 +1685,15 @@ broccoli-persistent-filter@^1.0.3, broccoli-persistent-filter@^1.1.5, broccoli-p symlink-or-copy "^1.0.1" walk-sync "^0.3.1" +broccoli-plugin@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" + dependencies: + promise-map-series "^0.2.1" + quick-temp "^0.1.3" + rimraf "^2.3.4" + symlink-or-copy "^1.0.1" + broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli-plugin@^1.2.1, broccoli-plugin@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.3.0.tgz#bee704a8e42da08cb58e513aaa436efb7f0ef1ee" @@ -1703,13 +1758,32 @@ broccoli-stew@^1.2.0, broccoli-stew@^1.3.2, broccoli-stew@^1.3.3, broccoli-stew@ symlink-or-copy "^1.1.8" walk-sync "^0.3.0" -broccoli-string-replace@^0.1.1: +broccoli-string-replace@^0.1.1, broccoli-string-replace@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/broccoli-string-replace/-/broccoli-string-replace-0.1.2.tgz#1ed92f85680af8d503023925e754e4e33676b91f" dependencies: broccoli-persistent-filter "^1.1.5" minimatch "^3.0.3" +broccoli-svg-optimizer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/broccoli-svg-optimizer/-/broccoli-svg-optimizer-1.0.2.tgz#b12e84e65912f3134939cbf766c3fa0b4d0d92d9" + dependencies: + broccoli-persistent-filter "^1.2.0" + json-stable-stringify "^1.0.1" + rsvp "^3.2.1" + svgo "^0.6.6" + +broccoli-symbolizer@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/broccoli-symbolizer/-/broccoli-symbolizer-0.5.0.tgz#c666d4158ff4484263daaee9a6284d684b6eb3a2" + dependencies: + broccoli-concat "^2.2.0" + broccoli-persistent-filter "^1.2.0" + cheerio "^0.20.0" + json-stable-stringify "^1.0.1" + lodash "^4.13.1" + broccoli-uglify-sourcemap@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-2.0.2.tgz#f4a73112f1f56b46043e2e89cba5ce7762cddeb3" @@ -1951,6 +2025,18 @@ charm@^1.0.0: dependencies: inherits "^2.0.1" +cheerio@^0.20.0: + version "0.20.0" + resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.20.0.tgz#5c710f2bab95653272842ba01c6ea61b3545ec35" + dependencies: + css-select "~1.2.0" + dom-serializer "~0.1.0" + entities "~1.1.1" + htmlparser2 "~3.8.1" + lodash "^4.1.0" + optionalDependencies: + jsdom "^7.0.2" + chokidar@1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" @@ -1970,6 +2056,12 @@ circular-json@^0.3.1: version "0.3.3" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" +clap@^1.0.9: + version "1.2.3" + resolved "https://registry.yarnpkg.com/clap/-/clap-1.2.3.tgz#4f36745b32008492557f46412d66d50cb99bce51" + dependencies: + chalk "^1.1.3" + class-utils@^0.3.5: version "0.3.6" resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" @@ -2075,6 +2167,12 @@ co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" +coa@~1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.4.tgz#a9ef153660d6a86a8bdec0289a5c684d217432fd" + dependencies: + q "^1.1.2" + code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" @@ -2104,7 +2202,7 @@ colors@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" -colors@^1.1.2: +colors@^1.1.2, colors@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" @@ -2351,6 +2449,36 @@ crypto-random-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" +css-select@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" + dependencies: + boolbase "~1.0.0" + css-what "2.1" + domutils "1.5.1" + nth-check "~1.0.1" + +css-what@2.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" + +csso@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/csso/-/csso-2.0.0.tgz#178b43a44621221c27756086f531e02f42900ee8" + dependencies: + clap "^1.0.9" + source-map "^0.5.3" + +cssom@0.3.x, "cssom@>= 0.3.0 < 0.4.0": + version "0.3.2" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.2.tgz#b8036170c79f07a90ff2f16e22284027a243848b" + +"cssstyle@>= 0.2.29 < 0.3.0": + version "0.2.37" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-0.2.37.tgz#541097234cb2513c83ceed3acddc27ff27987d54" + dependencies: + cssom "0.3.x" + currently-unhandled@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" @@ -2556,6 +2684,34 @@ doctrine@^2.1.0: dependencies: esutils "^2.0.2" +dom-serializer@0, dom-serializer@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" + dependencies: + domelementtype "~1.1.1" + entities "~1.1.1" + +domelementtype@1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2" + +domelementtype@~1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b" + +domhandler@2.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.3.0.tgz#2de59a0822d5027fabff6f032c2b25a2a8abe738" + dependencies: + domelementtype "1" + +domutils@1.5, domutils@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" + dependencies: + dom-serializer "0" + domelementtype "1" + dot-prop@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" @@ -2729,20 +2885,20 @@ ember-cli-lodash-subset@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/ember-cli-lodash-subset/-/ember-cli-lodash-subset-2.0.1.tgz#20cb68a790fe0fde2488ddfd8efbb7df6fe766f2" -ember-cli-moment-shim@3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/ember-cli-moment-shim/-/ember-cli-moment-shim-3.5.0.tgz#7ea8d42b0a04c767258287b30447681e52fba0c4" +ember-cli-moment-shim@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/ember-cli-moment-shim/-/ember-cli-moment-shim-3.6.0.tgz#a6ce858e99b285eb9c539c8cebb698435f8d043a" dependencies: broccoli-funnel "^2.0.0" broccoli-merge-trees "^2.0.0" broccoli-source "^1.1.0" broccoli-stew "^1.5.0" chalk "^1.1.3" - ember-cli-babel "^6.8.2" + ember-cli-babel "^6.6.0" ember-cli-import-polyfill "^0.2.0" exists-sync "^0.0.4" lodash.defaults "^4.2.0" - moment "^2.18.1" + moment "^2.19.3" moment-timezone "^0.5.13" ember-cli-node-assets@^0.2.2: @@ -2955,6 +3111,19 @@ ember-export-application-global@^2.0.0: dependencies: ember-cli-babel "^6.0.0-beta.7" +ember-factory-for-polyfill@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/ember-factory-for-polyfill/-/ember-factory-for-polyfill-1.3.1.tgz#b446ed64916d293c847a4955240eb2c993b86eae" + dependencies: + ember-cli-version-checker "^2.1.0" + +ember-getowner-polyfill@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ember-getowner-polyfill/-/ember-getowner-polyfill-2.2.0.tgz#38e7dccbcac69d5ec694000329ec0b2be651d2b2" + dependencies: + ember-cli-version-checker "^2.1.0" + ember-factory-for-polyfill "^1.3.1" + ember-load-initializers@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ember-load-initializers/-/ember-load-initializers-1.0.0.tgz#4919eaf06f6dfeca7e134633d8c05a6c9921e6e7" @@ -3025,6 +3194,13 @@ ember-rfc176-data@^0.3.0, ember-rfc176-data@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.1.tgz#6a5a4b8b82ec3af34f3010965fa96b936ca94519" +ember-route-action-helper@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/ember-route-action-helper/-/ember-route-action-helper-2.0.6.tgz#1d50454350d7112be326ab44058f06cf291d5fd9" + dependencies: + ember-cli-babel "^6.8.1" + ember-getowner-polyfill "^2.0.0" + ember-router-generator@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee" @@ -3055,6 +3231,22 @@ ember-source@~3.0.0: jquery "^3.2.1" resolve "^1.3.3" +ember-svg-jar@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ember-svg-jar/-/ember-svg-jar-1.1.1.tgz#d95d4c335ed98984ba4c5808280404a5968b78b3" + dependencies: + broccoli-caching-writer "^2.3.1" + broccoli-funnel "^1.0.1" + broccoli-merge-trees "^1.1.1" + broccoli-string-replace "^0.1.2" + broccoli-svg-optimizer "^1.0.2" + broccoli-symbolizer "^0.5.0" + cheerio "^0.20.0" + ember-cli-babel "^6.6.0" + lodash "^4.13.1" + mkdirp "^0.5.1" + path-posix "^1.0.0" + ember-truth-helpers@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ember-truth-helpers/-/ember-truth-helpers-2.0.0.tgz#f3e2eef667859197f1328bb4f83b0b35b661c1ac" @@ -3145,6 +3337,10 @@ ensure-posix-path@^1.0.0, ensure-posix-path@^1.0.1, ensure-posix-path@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz#a65b3e42d0b71cfc585eb774f9943c8d9b91b0c2" +entities@1.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.0.0.tgz#b2987aa3821347fcde642b24fdfc9e4fb712bf26" + entities@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" @@ -3170,6 +3366,17 @@ escape-string-regexp@1.0.5, escape-string-regexp@^1.0.0, escape-string-regexp@^1 version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" +escodegen@^1.6.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.9.1.tgz#dbae17ef96c8e4bedb1356f4504fa4cc2f7cb7e2" + dependencies: + esprima "^3.1.3" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + eslint-plugin-ember@^5.0.0: version "5.0.3" resolved "https://registry.yarnpkg.com/eslint-plugin-ember/-/eslint-plugin-ember-5.0.3.tgz#9f5e2048ab3ddc1548d4d17bf318cf1bb5cf37f1" @@ -3246,6 +3453,10 @@ esprima@^2.6.0: version "2.7.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" +esprima@^3.1.3, esprima@~3.1.0: + version "3.1.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + esprima@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" @@ -3258,10 +3469,6 @@ esprima@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.0.0.tgz#53cf247acda77313e551c3aa2e73342d3fb4f7d9" -esprima@~3.1.0: - version "3.1.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" - esquery@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.0.tgz#cfba8b57d7fba93f17298a8a006a04cda13d80fa" @@ -3275,7 +3482,7 @@ esrecurse@^4.1.0: estraverse "^4.1.0" object-assign "^4.0.1" -estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" @@ -4463,6 +4670,16 @@ hosted-git-info@^2.1.4, hosted-git-info@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" +htmlparser2@~3.8.1: + version "3.8.3" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.8.3.tgz#996c28b191516a8be86501a7d79757e5c70c1068" + dependencies: + domelementtype "1" + domhandler "2.3" + domutils "1.5" + entities "1.0" + readable-stream "1.1" + http-cache-semantics@3.8.1: version "3.8.1" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" @@ -5026,10 +5243,37 @@ js-yaml@~2.0.5: argparse "~ 0.1.11" esprima "~ 1.0.2" +js-yaml@~3.6.0: + version "3.6.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.6.1.tgz#6e5fe67d8b205ce4d22fad05b7781e8dadcc4b30" + dependencies: + argparse "^1.0.7" + esprima "^2.6.0" + jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" +jsdom@^7.0.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-7.2.2.tgz#40b402770c2bda23469096bee91ab675e3b1fc6e" + dependencies: + abab "^1.0.0" + acorn "^2.4.0" + acorn-globals "^1.0.4" + cssom ">= 0.3.0 < 0.4.0" + cssstyle ">= 0.2.29 < 0.3.0" + escodegen "^1.6.1" + nwmatcher ">= 1.3.7 < 2.0.0" + parse5 "^1.5.1" + request "^2.55.0" + sax "^1.1.4" + symbol-tree ">= 3.1.0 < 4.0.0" + tough-cookie "^2.2.0" + webidl-conversions "^2.0.0" + whatwg-url-compat "~0.6.5" + xml-name-validator ">= 2.0.1 < 3.0.0" + jsesc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" @@ -5689,7 +5933,7 @@ lodash@^4.0.0, lodash@^4.14.0, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.5.1, lod version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" -lodash@^4.2.0, lodash@^4.6.1: +lodash@^4.1.0, lodash@^4.13.1, lodash@^4.2.0, lodash@^4.6.1: version "4.17.5" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" @@ -6032,7 +6276,7 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@0.5, mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1: +mkdirp@0.5, mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: @@ -6069,10 +6313,14 @@ moment-timezone@^0.5.13: dependencies: moment ">= 2.9.0" -moment@2.x, "moment@>= 2.9.0", moment@^2.18.1: +moment@2.x: version "2.20.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.20.1.tgz#d6eb1a46cbcc14a2b2f9434112c1ff8907f313fd" +"moment@>= 2.9.0", moment@^2.19.3: + version "2.22.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.1.tgz#529a2e9bf973f259c9643d237fda84de3a26e8ad" + morgan@^1.8.1: version "1.9.0" resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.9.0.tgz#d01fa6c65859b76fcf31b3cb53a3821a311d8051" @@ -6331,10 +6579,20 @@ npm-run-path@^2.0.0: gauge "~2.7.3" set-blocking "~2.0.0" +nth-check@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.1.tgz#9929acdf628fc2c41098deab82ac580cf149aae4" + dependencies: + boolbase "~1.0.0" + number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" +"nwmatcher@>= 1.3.7 < 2.0.0": + version "1.4.4" + resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.4.tgz#2285631f34a95f0d0395cd900c96ed39b58f346e" + oauth-sign@~0.8.0, oauth-sign@~0.8.1, oauth-sign@~0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" @@ -6419,7 +6677,7 @@ optimist@^0.6.1: minimist "~0.0.1" wordwrap "~0.0.2" -optionator@^0.8.2: +optionator@^0.8.1, optionator@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" dependencies: @@ -6556,6 +6814,10 @@ parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" +parse5@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94" + parsejson@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/parsejson/-/parsejson-0.0.3.tgz#ab7e3759f209ece99437973f7d0f1f64ae0e64ab" @@ -6812,6 +7074,13 @@ quick-temp@^0.1.0, quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quic rimraf "^2.5.4" underscore.string "~3.3.4" +qunit-dom@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/qunit-dom/-/qunit-dom-0.6.2.tgz#0b37012cbbc838f09eba760b3d39924ad5ccbccb" + dependencies: + broccoli-funnel "^2.0.0" + broccoli-merge-trees "^2.0.0" + qunit@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/qunit/-/qunit-2.5.0.tgz#64cbe30a1193ef02edc5b278efcdf1d0bae96b22" @@ -6891,6 +7160,15 @@ read@1, read@1.0.7: dependencies: mute-stream "~0.0.4" +readable-stream@1.1: + version "1.1.13" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.13.tgz#f6eef764f514c89e2b9e23146a75ba106756d23e" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + readable-stream@^1.0.27-1: version "1.1.14" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" @@ -7191,6 +7469,33 @@ request@2.81.0: tunnel-agent "^0.6.0" uuid "^3.0.0" +request@^2.55.0: + version "2.85.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.85.0.tgz#5a03615a47c61420b3eb99b7dba204f83603e1fa" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.6.0" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.1" + forever-agent "~0.6.1" + form-data "~2.3.1" + har-validator "~5.0.3" + hawk "~6.0.2" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.17" + oauth-sign "~0.8.2" + performance-now "^2.1.0" + qs "~6.5.1" + safe-buffer "^5.1.1" + stringstream "~0.0.5" + tough-cookie "~2.3.3" + tunnel-agent "^0.6.0" + uuid "^3.1.0" + request@~2.79.0: version "2.79.0" resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" @@ -7310,7 +7615,7 @@ rollup@^0.51.6: version "0.51.8" resolved "https://registry.yarnpkg.com/rollup/-/rollup-0.51.8.tgz#58bd0b642885f4770b5f93cc64f14e4233c2236d" -rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.3.3, rsvp@^3.5.0: +rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.5.0: version "3.6.2" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" @@ -7397,7 +7702,7 @@ sax@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" -sax@>=0.6.0: +sax@>=0.6.0, sax@^1.1.4, sax@~1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" @@ -7698,7 +8003,7 @@ source-map@0.4.x, source-map@^0.4.2, source-map@^0.4.4: dependencies: amdefine ">=0.0.4" -source-map@^0.5.0, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1: +source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -7928,6 +8233,22 @@ supports-color@^5.2.0: dependencies: has-flag "^3.0.0" +svgo@^0.6.6: + version "0.6.6" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.6.6.tgz#b340889036f20f9b447543077d0f5573ed044c08" + dependencies: + coa "~1.0.1" + colors "~1.1.2" + csso "~2.0.0" + js-yaml "~3.6.0" + mkdirp "~0.5.1" + sax "~1.2.1" + whet.extend "~0.9.9" + +"symbol-tree@>= 3.1.0 < 4.0.0": + version "3.2.2" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" + symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.1.8.tgz#cabe61e0010c1c023c173b25ee5108b37f4b4aa3" @@ -8126,6 +8447,12 @@ to-utf8@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/to-utf8/-/to-utf8-0.0.1.tgz#d17aea72ff2fba39b9e43601be7b3ff72e089852" +tough-cookie@^2.2.0: + version "2.3.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" + dependencies: + punycode "^1.4.1" + tough-cookie@~2.2.0: version "2.2.2" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.2.2.tgz#c83a1830f4e5ef0b93ef2a3488e724f8de016ac7" @@ -8136,6 +8463,10 @@ tough-cookie@~2.3.0, tough-cookie@~2.3.3: dependencies: punycode "^1.4.1" +tr46@~0.0.1: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + "traverse@>=0.3.0 <0.4": version "0.3.9" resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" @@ -8430,7 +8761,7 @@ walk-sync@0.3.2, walk-sync@^0.3.0, walk-sync@^0.3.1, walk-sync@^0.3.2: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" -walk-sync@^0.2.7: +walk-sync@^0.2.5, walk-sync@^0.2.7: version "0.2.7" resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" dependencies: @@ -8470,6 +8801,10 @@ wcwidth@^1.0.1: dependencies: defaults "^1.0.3" +webidl-conversions@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-2.0.1.tgz#3bf8258f7d318c7443c36f2e169402a1a6703506" + websocket-driver@>=0.5.1: version "0.7.0" resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" @@ -8481,6 +8816,12 @@ websocket-extensions@>=0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" +whatwg-url-compat@~0.6.5: + version "0.6.5" + resolved "https://registry.yarnpkg.com/whatwg-url-compat/-/whatwg-url-compat-0.6.5.tgz#00898111af689bb097541cd5a45ca6c8798445bf" + dependencies: + tr46 "~0.0.1" + when@3.6.4: version "3.6.4" resolved "https://registry.yarnpkg.com/when/-/when-3.6.4.tgz#473b517ec159e2b85005497a13983f095412e34e" @@ -8489,6 +8830,10 @@ when@3.7.2: version "3.7.2" resolved "https://registry.yarnpkg.com/when/-/when-3.7.2.tgz#06bed1296df3a0bfd83f7f31c5e1d779bd97eae8" +whet.extend@~0.9.9: + version "0.9.9" + resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1" + which-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" @@ -8583,6 +8928,10 @@ xdg-basedir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" +"xml-name-validator@>= 2.0.1 < 3.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635" + xml2js@0.2.x: version "0.2.8" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.2.8.tgz#9b81690931631ff09d1957549faf54f4f980b3c2"