DEV: Update CI workflows, fix linting issues (#32)
Included: * DEV: Update CI workflows * DEV: Update the plugin URL * DEV: Update Gemfile.lock * DEV: Remove an old rubocop artifact * DEV: Add .prettierrc * DEV: Clean up .gitignore * DEV: Add license * DEV: Update package.json * DEV: Fix template issues * DEV: Re-format code * DEV: Use `@action` * DEV: `inject as controller` * DEV: Use `@computed` * DEV: Avoid naming collision and extra indirection * DEV: Use `discourse-common/utils/decorators` * DEV: Use `role="button"` Co-authored-by: Jarek Radosz <jradosz@gmail.com> Co-authored-by: jjaffeux <j.jaffeux@gmail.com>
This commit is contained in:
parent
50f7c25de2
commit
f75c9d5e32
|
@ -20,18 +20,13 @@ jobs:
|
|||
node-version: 12
|
||||
|
||||
- name: Set up ruby
|
||||
uses: actions/setup-ruby@v1
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 2.7
|
||||
|
||||
- name: Setup bundler
|
||||
run: gem install bundler -v 2.1.4 --no-doc
|
||||
|
||||
- name: Setup gems
|
||||
run: bundle install --jobs 4
|
||||
bundler-cache: true
|
||||
|
||||
- name: Yarn install
|
||||
run: yarn install --dev
|
||||
run: yarn install
|
||||
|
||||
- name: ESLint
|
||||
run: yarn eslint --ext .js,.js.es6 --no-error-on-unmatched-pattern {test,assets}/javascripts
|
||||
|
@ -46,5 +41,8 @@ jobs:
|
|||
yarn prettier --list-different "test/**/*.{js,es6}" ; \
|
||||
fi
|
||||
|
||||
- name: Ember template lint
|
||||
run: yarn ember-template-lint assets/javascripts
|
||||
|
||||
- name: Rubocop
|
||||
run: bundle exec rubocop .
|
||||
|
|
|
@ -10,14 +10,15 @@ on:
|
|||
jobs:
|
||||
build:
|
||||
name: ${{ matrix.build_type }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
runs-on: ubuntu-latest
|
||||
container: discourse/discourse_test:release
|
||||
timeout-minutes: 60
|
||||
|
||||
env:
|
||||
DISCOURSE_HOSTNAME: www.example.com
|
||||
RUBY_GLOBAL_METHOD_CACHE_SIZE: 131072
|
||||
RAILS_ENV: test
|
||||
PGHOST: localhost
|
||||
PGHOST: postgres
|
||||
PGUSER: discourse
|
||||
PGPASSWORD: discourse
|
||||
|
||||
|
@ -26,8 +27,7 @@ jobs:
|
|||
|
||||
matrix:
|
||||
build_type: ["backend", "frontend"]
|
||||
os: [ubuntu-latest]
|
||||
ruby: ["2.6"]
|
||||
ruby: ["2.7"]
|
||||
postgres: ["12"]
|
||||
redis: ["4.x"]
|
||||
|
||||
|
@ -47,13 +47,13 @@ jobs:
|
|||
--health-retries 5
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
repository: discourse/discourse
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Install plugin
|
||||
uses: actions/checkout@master
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: plugins/${{ github.event.repository.name }}
|
||||
fetch-depth: 1
|
||||
|
@ -75,46 +75,30 @@ jobs:
|
|||
git config --global user.email "ci@ci.invalid"
|
||||
git config --global user.name "Discourse CI"
|
||||
|
||||
- name: Setup packages
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -yqq install postgresql-client libpq-dev gifsicle jpegoptim optipng jhead
|
||||
wget -qO- https://raw.githubusercontent.com/discourse/discourse_docker/master/image/base/install-pngquant | sudo sh
|
||||
|
||||
- name: Update imagemagick
|
||||
if: matrix.build_type == 'backend'
|
||||
run: |
|
||||
wget https://raw.githubusercontent.com/discourse/discourse_docker/master/image/base/install-imagemagick
|
||||
chmod +x install-imagemagick
|
||||
sudo ./install-imagemagick
|
||||
|
||||
- name: Setup redis
|
||||
uses: shogo82148/actions-setup-redis@v1
|
||||
with:
|
||||
redis-version: ${{ matrix.redis }}
|
||||
|
||||
- name: Setup ruby
|
||||
uses: actions/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby }}
|
||||
|
||||
- name: Setup bundler
|
||||
run: |
|
||||
gem install bundler -v 2.1.4 --no-doc
|
||||
bundle config deployment 'true'
|
||||
bundle config without 'development'
|
||||
|
||||
- name: Bundler cache
|
||||
uses: actions/cache@v2
|
||||
id: bundler-cache
|
||||
with:
|
||||
path: vendor/bundle
|
||||
key: ${{ runner.os }}-gem-${{ hashFiles('**/Gemfile.lock') }}
|
||||
key: ${{ runner.os }}-${{ matrix.ruby }}-gem-${{ hashFiles('**/Gemfile.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gem-
|
||||
${{ runner.os }}-${{ matrix.ruby }}-gem-
|
||||
|
||||
- name: Setup gems
|
||||
run: bundle install --jobs 4
|
||||
run: |
|
||||
bundle config --local path vendor/bundle
|
||||
bundle config --local deployment true
|
||||
bundle config --local without development
|
||||
bundle install --jobs 4
|
||||
bundle clean
|
||||
|
||||
- name: Lint English locale
|
||||
if: matrix.build_type == 'backend'
|
||||
run: bundle exec ruby script/i18n_lint.rb "plugins/${{ github.event.repository.name }}/locales/{client,server}.en.yml"
|
||||
|
||||
- name: Get yarn cache directory
|
||||
id: yarn-cache-dir
|
||||
|
@ -130,7 +114,7 @@ jobs:
|
|||
${{ runner.os }}-${{ matrix.os }}-yarn-
|
||||
|
||||
- name: Yarn install
|
||||
run: yarn install --dev
|
||||
run: yarn install
|
||||
|
||||
- name: Migrate database
|
||||
run: |
|
||||
|
|
|
@ -1,4 +1 @@
|
|||
.rubocop-https---raw-githubusercontent-com-discourse-discourse-master--rubocop-yml
|
||||
node_modules
|
||||
yarn-error.log
|
||||
.rubocop-https---raw-githubusercontent-com-discourse-*
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{}
|
|
@ -1,2 +0,0 @@
|
|||
inherit_gem:
|
||||
rubocop-discourse: default.yml
|
39
Gemfile.lock
39
Gemfile.lock
|
@ -1,31 +1,32 @@
|
|||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
ast (2.4.1)
|
||||
parallel (1.19.2)
|
||||
parser (2.7.1.5)
|
||||
ast (2.4.2)
|
||||
parallel (1.20.1)
|
||||
parser (3.0.1.0)
|
||||
ast (~> 2.4.1)
|
||||
rainbow (3.0.0)
|
||||
regexp_parser (1.8.1)
|
||||
rexml (3.2.4)
|
||||
rubocop (0.92.0)
|
||||
regexp_parser (2.1.1)
|
||||
rexml (3.2.5)
|
||||
rubocop (1.13.0)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 2.7.1.5)
|
||||
parser (>= 3.0.0.0)
|
||||
rainbow (>= 2.2.2, < 4.0)
|
||||
regexp_parser (>= 1.7)
|
||||
regexp_parser (>= 1.8, < 3.0)
|
||||
rexml
|
||||
rubocop-ast (>= 0.5.0)
|
||||
rubocop-ast (>= 1.2.0, < 2.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 1.4.0, < 2.0)
|
||||
rubocop-ast (0.7.1)
|
||||
unicode-display_width (>= 1.4.0, < 3.0)
|
||||
rubocop-ast (1.4.1)
|
||||
parser (>= 2.7.1.5)
|
||||
rubocop-discourse (2.3.2)
|
||||
rubocop (>= 0.69.0)
|
||||
rubocop-rspec (>= 1.39.0)
|
||||
rubocop-rspec (1.43.2)
|
||||
rubocop (~> 0.87)
|
||||
ruby-progressbar (1.10.1)
|
||||
unicode-display_width (1.7.0)
|
||||
rubocop-discourse (2.4.1)
|
||||
rubocop (>= 1.1.0)
|
||||
rubocop-rspec (>= 2.0.0)
|
||||
rubocop-rspec (2.2.0)
|
||||
rubocop (~> 1.0)
|
||||
rubocop-ast (>= 1.1.0)
|
||||
ruby-progressbar (1.11.0)
|
||||
unicode-display_width (2.0.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
@ -34,4 +35,4 @@ DEPENDENCIES
|
|||
rubocop-discourse
|
||||
|
||||
BUNDLED WITH
|
||||
2.1.4
|
||||
2.2.16
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2021 Civilized Discourse Construction Kit
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -3,14 +3,9 @@ import discourseComputed from "discourse-common/utils/decorators";
|
|||
|
||||
export default Component.extend({
|
||||
tagName: "",
|
||||
|
||||
@discourseComputed("category")
|
||||
categoryName(category) {
|
||||
return this.site.categories.findBy("id", category.id).name;
|
||||
},
|
||||
actions: {
|
||||
selectCategory() {
|
||||
this.selectCategory(this.category);
|
||||
return false;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import Component from "@ember/component";
|
||||
import { debounce } from "@ember/runloop";
|
||||
import { action } from "@ember/object";
|
||||
import discourseDebounce from "discourse-common/lib/debounce";
|
||||
|
||||
export default Component.extend({
|
||||
|
@ -12,14 +13,14 @@ export default Component.extend({
|
|||
debounceFunc(this, "onSearch", term, 500);
|
||||
},
|
||||
|
||||
actions: {
|
||||
onSearchTermChange(term) {
|
||||
this.debouncedSearch(term);
|
||||
},
|
||||
@action
|
||||
onSearchTermChange(term) {
|
||||
this.debouncedSearch(term);
|
||||
},
|
||||
|
||||
clearSearch() {
|
||||
this.set("searchTerm", "");
|
||||
this.onSearch("");
|
||||
},
|
||||
@action
|
||||
clearSearch() {
|
||||
this.set("searchTerm", "");
|
||||
this.onSearch("");
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
import Component from "@ember/component";
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "",
|
||||
actions: {
|
||||
selectTag() {
|
||||
this.selectTag(this.tag);
|
||||
return false;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: "docs-topic-list",
|
||||
|
||||
@discourseComputed("order")
|
||||
sortTitle(order) {
|
||||
return order === "title";
|
||||
|
@ -22,14 +24,15 @@ export default Component.extend({
|
|||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
sortListActivity() {
|
||||
this.sortBy("activity");
|
||||
return false;
|
||||
},
|
||||
sortListTitle() {
|
||||
this.sortBy("title");
|
||||
return false;
|
||||
},
|
||||
@action
|
||||
sortListActivity() {
|
||||
this.sortBy("activity");
|
||||
return false;
|
||||
},
|
||||
|
||||
@action
|
||||
sortListTitle() {
|
||||
this.sortBy("title");
|
||||
return false;
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,20 +1,22 @@
|
|||
import Component from "@ember/component";
|
||||
import { reads } from "@ember/object/computed";
|
||||
import { computed } from "@ember/object";
|
||||
import computed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: "docs-topic",
|
||||
|
||||
originalPostContent: reads("post.cooked"),
|
||||
|
||||
post: computed("topic", function () {
|
||||
@computed("topic")
|
||||
post() {
|
||||
return this.store.createRecord(
|
||||
"post",
|
||||
this.topic.post_stream.posts.firstObject
|
||||
);
|
||||
}),
|
||||
},
|
||||
|
||||
model: computed("post", "topic", function () {
|
||||
@computed("post", "topic")
|
||||
model() {
|
||||
const post = this.post;
|
||||
|
||||
if (!post.topic) {
|
||||
|
@ -22,7 +24,7 @@ export default Component.extend({
|
|||
}
|
||||
|
||||
return post;
|
||||
}),
|
||||
},
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import Controller, { inject } from "@ember/controller";
|
||||
import Controller, { inject as controller } from "@ember/controller";
|
||||
import discourseComputed, { on } from "discourse-common/utils/decorators";
|
||||
import { action } from "@ember/object";
|
||||
import { alias, equal, readOnly } from "@ember/object/computed";
|
||||
import Docs from "discourse/plugins/discourse-docs/discourse/models/docs";
|
||||
import { getOwner } from "@ember/application";
|
||||
|
@ -14,14 +15,12 @@ export default Controller.extend({
|
|||
searchTerm: "search",
|
||||
selectedTopic: "topic",
|
||||
},
|
||||
application: inject(),
|
||||
|
||||
application: controller(),
|
||||
|
||||
isLoading: false,
|
||||
isLoadingMore: false,
|
||||
loadMoreUrl: alias("model.topics.load_more_url"),
|
||||
isTopicLoading: false,
|
||||
categories: readOnly("model.categories"),
|
||||
topics: alias("model.topics.topic_list.topics"),
|
||||
tags: readOnly("model.tags"),
|
||||
filterTags: null,
|
||||
filterCategories: null,
|
||||
filterSolved: false,
|
||||
|
@ -31,7 +30,13 @@ export default Controller.extend({
|
|||
expandedFilters: false,
|
||||
ascending: null,
|
||||
orderColumn: null,
|
||||
|
||||
loadMoreUrl: alias("model.topics.load_more_url"),
|
||||
categories: readOnly("model.categories"),
|
||||
topics: alias("model.topics.topic_list.topics"),
|
||||
tags: readOnly("model.tags"),
|
||||
topicCount: alias("model.topic_count"),
|
||||
emptyResults: equal("topicCount", 0),
|
||||
|
||||
@on("init")
|
||||
_setupFilters() {
|
||||
|
@ -61,8 +66,6 @@ export default Controller.extend({
|
|||
return isSearching || filterSolved;
|
||||
},
|
||||
|
||||
emptyResults: equal("topicCount", 0),
|
||||
|
||||
@discourseComputed
|
||||
canFilterSolved() {
|
||||
return (
|
||||
|
@ -76,108 +79,117 @@ export default Controller.extend({
|
|||
return !!filterTags;
|
||||
},
|
||||
|
||||
actions: {
|
||||
setSelectedTopic(topicId) {
|
||||
this.set("selectedTopic", topicId);
|
||||
@action
|
||||
setSelectedTopic(topicId) {
|
||||
this.set("selectedTopic", topicId);
|
||||
|
||||
window.scrollTo(0, 0);
|
||||
},
|
||||
window.scrollTo(0, 0);
|
||||
},
|
||||
|
||||
onChangeFilterSolved(solvedFilter) {
|
||||
this.set("filterSolved", solvedFilter);
|
||||
},
|
||||
@action
|
||||
onChangeFilterSolved(solvedFilter) {
|
||||
this.set("filterSolved", solvedFilter);
|
||||
},
|
||||
|
||||
updateSelectedTags(tag) {
|
||||
let filter = this.filterTags;
|
||||
if (filter && filter.includes(tag.id)) {
|
||||
filter = filter.replace(tag.id, "").replace(/^\|+|\|+$/g, "");
|
||||
} else if (filter) {
|
||||
filter = `${filter}|${tag.id}`;
|
||||
} else {
|
||||
filter = tag.id;
|
||||
}
|
||||
@action
|
||||
updateSelectedTags(tag) {
|
||||
let filter = this.filterTags;
|
||||
if (filter && filter.includes(tag.id)) {
|
||||
filter = filter.replace(tag.id, "").replace(/^\|+|\|+$/g, "");
|
||||
} else if (filter) {
|
||||
filter = `${filter}|${tag.id}`;
|
||||
} else {
|
||||
filter = tag.id;
|
||||
}
|
||||
|
||||
this.setProperties({
|
||||
filterTags: filter,
|
||||
selectedTopic: null,
|
||||
});
|
||||
},
|
||||
this.setProperties({
|
||||
filterTags: filter,
|
||||
selectedTopic: null,
|
||||
});
|
||||
},
|
||||
|
||||
updateSelectedCategories(category) {
|
||||
let filter = this.filterCategories;
|
||||
if (filter && filter.includes(category.id)) {
|
||||
filter = filter.replace(category.id, "").replace(/^\|+|\|+$/g, "");
|
||||
} else if (filter) {
|
||||
filter = `${filter}|${category.id}`;
|
||||
} else {
|
||||
filter = category.id;
|
||||
}
|
||||
@action
|
||||
updateSelectedCategories(category) {
|
||||
let filter = this.filterCategories;
|
||||
if (filter && filter.includes(category.id)) {
|
||||
filter = filter.replace(category.id, "").replace(/^\|+|\|+$/g, "");
|
||||
} else if (filter) {
|
||||
filter = `${filter}|${category.id}`;
|
||||
} else {
|
||||
filter = category.id;
|
||||
}
|
||||
|
||||
this.setProperties({
|
||||
filterCategories: filter,
|
||||
selectedTopic: null,
|
||||
});
|
||||
},
|
||||
this.setProperties({
|
||||
filterCategories: filter,
|
||||
selectedTopic: null,
|
||||
});
|
||||
|
||||
performSearch(term) {
|
||||
if (term === "") {
|
||||
this.set("searchTerm", null);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
if (term.length < this.siteSettings.min_search_term_length) {
|
||||
return false;
|
||||
}
|
||||
@action
|
||||
performSearch(term) {
|
||||
if (term === "") {
|
||||
this.set("searchTerm", null);
|
||||
return false;
|
||||
}
|
||||
|
||||
this.setProperties({
|
||||
searchTerm: term,
|
||||
selectedTopic: null,
|
||||
});
|
||||
},
|
||||
if (term.length < this.siteSettings.min_search_term_length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sortBy(column) {
|
||||
const order = this.orderColumn;
|
||||
const ascending = this.ascending;
|
||||
if (column === "title") {
|
||||
this.set("orderColumn", "title");
|
||||
} else if (column === "activity") {
|
||||
this.set("orderColumn", "activity");
|
||||
}
|
||||
this.setProperties({
|
||||
searchTerm: term,
|
||||
selectedTopic: null,
|
||||
});
|
||||
},
|
||||
|
||||
if (!ascending && order) {
|
||||
this.set("ascending", true);
|
||||
} else {
|
||||
this.set("ascending", "");
|
||||
}
|
||||
},
|
||||
@action
|
||||
sortBy(column) {
|
||||
const order = this.orderColumn;
|
||||
const ascending = this.ascending;
|
||||
if (column === "title") {
|
||||
this.set("orderColumn", "title");
|
||||
} else if (column === "activity") {
|
||||
this.set("orderColumn", "activity");
|
||||
}
|
||||
|
||||
loadMore() {
|
||||
if (this.canLoadMore && !this.isLoadingMore) {
|
||||
this.set("isLoadingMore", true);
|
||||
if (!ascending && order) {
|
||||
this.set("ascending", true);
|
||||
} else {
|
||||
this.set("ascending", "");
|
||||
}
|
||||
},
|
||||
|
||||
Docs.loadMore(this.loadMoreUrl).then((result) => {
|
||||
const topics = this.topics.concat(result.topics.topic_list.topics);
|
||||
@action
|
||||
loadMore() {
|
||||
if (this.canLoadMore && !this.isLoadingMore) {
|
||||
this.set("isLoadingMore", true);
|
||||
|
||||
this.setProperties({
|
||||
topics,
|
||||
loadMoreUrl: result.topics.load_more_url || null,
|
||||
isLoadingMore: false,
|
||||
});
|
||||
Docs.loadMore(this.loadMoreUrl).then((result) => {
|
||||
const topics = this.topics.concat(result.topics.topic_list.topics);
|
||||
|
||||
this.setProperties({
|
||||
topics,
|
||||
loadMoreUrl: result.topics.load_more_url || null,
|
||||
isLoadingMore: false,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
toggleFilters() {
|
||||
if (!this.expandedFilters) {
|
||||
this.set("expandedFilters", true);
|
||||
} else {
|
||||
this.set("expandedFilters", false);
|
||||
}
|
||||
},
|
||||
@action
|
||||
toggleFilters() {
|
||||
if (!this.expandedFilters) {
|
||||
this.set("expandedFilters", true);
|
||||
} else {
|
||||
this.set("expandedFilters", false);
|
||||
}
|
||||
},
|
||||
|
||||
returnToList() {
|
||||
this.set("selectedTopic", null);
|
||||
getOwner(this).lookup("router:main").transitionTo("docs");
|
||||
},
|
||||
@action
|
||||
returnToList() {
|
||||
this.set("selectedTopic", null);
|
||||
getOwner(this).lookup("router:main").transitionTo("docs");
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,19 +1,24 @@
|
|||
import Controller, { inject } from "@ember/controller";
|
||||
import Controller, { inject as controller } from "@ember/controller";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
export default Controller.extend({
|
||||
indexController: inject("docs.index"),
|
||||
actions: {
|
||||
updateSelectedCategories(category) {
|
||||
this.indexController.send("updateSelectedCategories", category);
|
||||
return false;
|
||||
},
|
||||
updateSelectedTags(tag) {
|
||||
this.indexController.send("updateSelectedTags", tag);
|
||||
return false;
|
||||
},
|
||||
performSearch(term) {
|
||||
this.indexController.send("performSearch", term);
|
||||
return false;
|
||||
},
|
||||
indexController: controller("docs.index"),
|
||||
|
||||
@action
|
||||
updateSelectedCategories(category) {
|
||||
this.indexController.send("updateSelectedCategories", category);
|
||||
return false;
|
||||
},
|
||||
|
||||
@action
|
||||
updateSelectedTags(tag) {
|
||||
this.indexController.send("updateSelectedTags", tag);
|
||||
return false;
|
||||
},
|
||||
|
||||
@action
|
||||
performSearch(term) {
|
||||
this.indexController.send("performSearch", term);
|
||||
return false;
|
||||
},
|
||||
});
|
||||
|
|
|
@ -7,6 +7,7 @@ const Docs = EmberObject.extend({});
|
|||
Docs.reopenClass({
|
||||
list(params) {
|
||||
let filters = [];
|
||||
|
||||
if (params.filterCategories) {
|
||||
filters.push(`category=${params.filterCategories}`);
|
||||
}
|
||||
|
@ -53,10 +54,7 @@ Docs.reopenClass({
|
|||
|
||||
promise = promise.then((data) => {
|
||||
data.topics.topic_list.topics = data.topics.topic_list.topics.map(
|
||||
(topic) => {
|
||||
topic = Topic.create(topic);
|
||||
return topic;
|
||||
}
|
||||
(topic) => Topic.create(topic)
|
||||
);
|
||||
return data;
|
||||
});
|
||||
|
|
|
@ -15,6 +15,7 @@ export default DiscourseRoute.extend({
|
|||
refreshModel: true,
|
||||
},
|
||||
},
|
||||
|
||||
model(params) {
|
||||
this.controllerFor("docs.index").set("isLoading", true);
|
||||
return Docs.list(params).then((result) => {
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
<a {{action "selectCategory"}} class="docs-item docs-category {{if category.active 'selected'}}">
|
||||
<a href {{action "selectCategory"}} class="docs-item docs-category {{if category.active "selected"}}">
|
||||
{{#unless category.active}}
|
||||
{{d-icon "plus"}}
|
||||
{{/unless}}
|
||||
|
||||
{{#if category.active}}
|
||||
{{d-icon "times-circle"}}
|
||||
{{/if}}
|
||||
|
||||
<span class="docs-item-id category-id">{{categoryName}}</span>
|
||||
<span class="docs-item-count category-count">{{category.count}}</span>
|
||||
</a>
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
<a {{action "selectTag"}} class="docs-item docs-tag {{if tag.active 'selected'}} {{if subtag 'subtag'}}">
|
||||
<a href {{action "selectTag"}} class="docs-item docs-tag {{if tag.active "selected"}} {{if subtag "subtag"}}">
|
||||
{{#unless tag.active}}
|
||||
{{d-icon "plus"}}
|
||||
{{/unless}}
|
||||
|
||||
{{#if tag.active}}
|
||||
{{d-icon "times-circle"}}
|
||||
{{/if}}
|
||||
|
||||
<span class="docs-item-id tag-id">{{tag.id}}</span>
|
||||
<span class="docs-item-count tag-count">{{tag.count}}</span>
|
||||
</a>
|
||||
|
|
|
@ -1,27 +1,31 @@
|
|||
{{#load-more selector=".topic-list tr" action=loadMore}}
|
||||
<table class="topic-list">
|
||||
<thead>
|
||||
<th {{action "sortListTitle"}}>
|
||||
{{i18n 'docs.column_titles.topic'}}
|
||||
<th role="button" {{action "sortListTitle"}}>
|
||||
{{i18n "docs.column_titles.topic"}}
|
||||
|
||||
{{#if sortTitle}}
|
||||
{{#if ascending}}
|
||||
{{d-icon 'angle-up'}}
|
||||
{{d-icon "angle-up"}}
|
||||
{{else}}
|
||||
{{d-icon 'angle-down'}}
|
||||
{{d-icon "angle-down"}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</th>
|
||||
<th {{action "sortListActivity"}}>
|
||||
{{i18n 'docs.column_titles.activity'}}
|
||||
|
||||
<th role="button" {{action "sortListActivity"}}>
|
||||
{{i18n "docs.column_titles.activity"}}
|
||||
|
||||
{{#if sortActivity}}
|
||||
{{#if ascending}}
|
||||
{{d-icon 'angle-up'}}
|
||||
{{d-icon "angle-up"}}
|
||||
{{else}}
|
||||
{{d-icon 'angle-down'}}
|
||||
{{d-icon "angle-down"}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</th>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{{#each topics as |topic|}}
|
||||
{{raw "docs-topic-list-item" topic=topic}}
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
}}
|
||||
|
||||
<div class="topic-content">
|
||||
<h1>{{{topic.fancyTitle}}}</h1>
|
||||
<h1>{{html-safe topic.fancyTitle}}</h1>
|
||||
|
||||
{{mount-widget
|
||||
widget="post"
|
||||
model=model
|
||||
|
@ -16,7 +17,7 @@
|
|||
</div>
|
||||
|
||||
<a class="docs-nav-link more" href="/t/{{topic.id}}">
|
||||
{{d-icon "far-comment"}} {{i18n 'docs.topic.navigate_to_topic'}}
|
||||
{{d-icon "far-comment"}} {{i18n "docs.topic.navigate_to_topic"}}
|
||||
</a>
|
||||
|
||||
{{plugin-outlet name="after-docs-topic"}}
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
{{#conditional-loading-spinner condition=isLoading}}
|
||||
{{#if emptyTopics}}
|
||||
<span class="no-topics-found">{{html-safe (i18n 'docs.no_topics')}}</span>
|
||||
<span class="no-topics-found">{{html-safe (i18n "docs.no_topics")}}</span>
|
||||
{{else}}
|
||||
<div class="docs-browse">
|
||||
{{#if site.mobileView}}
|
||||
{{#unless selectedTopic}}
|
||||
{{d-button class="docs-expander" icon=(if expandedFilters "angle-up" "angle-down") action=(action "toggleFilters") label="docs.filter_button"}}
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
<div class="docs-filters">
|
||||
{{#if expandedFilters}}
|
||||
<div class="docs-browse">
|
||||
{{#if site.mobileView}}
|
||||
{{#unless selectedTopic}}
|
||||
{{d-button class="docs-expander" icon=(if expandedFilters "angle-up" "angle-down") action=(action "toggleFilters") label="docs.filter_button"}}
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
|
||||
<div class="docs-filters">
|
||||
{{#if expandedFilters}}
|
||||
{{#if canFilterSolved}}
|
||||
<div class="docs-items docs-solved">
|
||||
<label class="checkbox-label docs-item">
|
||||
|
@ -21,11 +22,11 @@
|
|||
{{i18n "docs.filter_solved"}}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{{/if}}
|
||||
|
||||
{{#if categories}}
|
||||
<div class="docs-items docs-categories">
|
||||
<h3>{{i18n 'docs.categories'}}</h3>
|
||||
<h3>{{i18n "docs.categories"}}</h3>
|
||||
{{#each categories as |category|}}
|
||||
{{docs-category
|
||||
category=category
|
||||
|
@ -35,9 +36,10 @@
|
|||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if tags}}
|
||||
<div class="docs-items docs-tags">
|
||||
<h3>{{i18n 'docs.tags'}}</h3>
|
||||
<h3>{{i18n "docs.tags"}}</h3>
|
||||
{{#each tags as |tag|}}
|
||||
{{docs-tag
|
||||
tag=tag
|
||||
|
@ -46,41 +48,41 @@
|
|||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if selectedTopic}}
|
||||
{{#conditional-loading-spinner condition=isTopicLoading}}
|
||||
{{docs-topic topic=topic return=(action "returnToList")}}
|
||||
{{/conditional-loading-spinner}}
|
||||
{{else}}
|
||||
<div class="docs-results">
|
||||
{{#if isSearchingOrFiltered}}
|
||||
{{#if emptyResults}}
|
||||
<div class="result-count no-result">
|
||||
{{i18n "search.no_results"}}
|
||||
</div>
|
||||
{{plugin-outlet name="after-docs-empty-results"}}
|
||||
{{else}}
|
||||
<div class="result-count">
|
||||
{{i18n "docs.search.results" count=topicCount}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{#unless emptyResults}}
|
||||
{{docs-topic-list
|
||||
topics=topics
|
||||
ascending=ascending
|
||||
order=orderColumn
|
||||
sortBy=(action "sortBy")
|
||||
selectTopic=(action "setSelectedTopic")
|
||||
loadMore=(action "loadMore")
|
||||
loading=isLoadingMore
|
||||
}}
|
||||
{{/unless}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#if selectedTopic}}
|
||||
{{#conditional-loading-spinner condition=isTopicLoading}}
|
||||
{{docs-topic topic=topic return=(action "returnToList")}}
|
||||
{{/conditional-loading-spinner}}
|
||||
{{else}}
|
||||
<div class="docs-results">
|
||||
{{#if isSearchingOrFiltered}}
|
||||
{{#if emptyResults}}
|
||||
<div class="result-count no-result">
|
||||
{{i18n 'search.no_results'}}
|
||||
</div>
|
||||
{{plugin-outlet name="after-docs-empty-results"}}
|
||||
{{else}}
|
||||
<div class="result-count">
|
||||
{{i18n 'docs.search.results'
|
||||
count=topicCount
|
||||
}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{#unless emptyResults}}
|
||||
{{docs-topic-list
|
||||
topics=topics
|
||||
ascending=ascending
|
||||
order=orderColumn
|
||||
sortBy=(action "sortBy")
|
||||
selectTopic=(action "setSelectedTopic")
|
||||
loadMore=(action "loadMore")
|
||||
loading=isLoadingMore
|
||||
}}
|
||||
{{/unless}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/conditional-loading-spinner}}
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
<div class="docs">
|
||||
{{plugin-outlet name="before-docs-search" args=(hash selectCategory=(action "updateSelectedCategories") selectTag=(action "updateSelectedTags") tags=indexController.tags categories=indexController.categories )}}
|
||||
{{plugin-outlet
|
||||
name="before-docs-search"
|
||||
args=(hash
|
||||
selectCategory=(action "updateSelectedCategories")
|
||||
selectTag=(action "updateSelectedTags")
|
||||
tags=indexController.tags
|
||||
categories=indexController.categories
|
||||
)
|
||||
}}
|
||||
|
||||
{{docs-search
|
||||
searchTerm=(readonly indexController.searchTerm)
|
||||
onSearch=(action "performSearch")
|
||||
|
|
|
@ -127,6 +127,10 @@
|
|||
th {
|
||||
min-width: 5em;
|
||||
|
||||
&[role="button"] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--primary-low, $primary-low);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
{
|
||||
"name": "discourse-docs",
|
||||
"version": "0.1",
|
||||
"repository": "https://github.com/discourse/discourse-docs",
|
||||
"author": "Discourse",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# about: A plugin to make it easy to explore and find knowledge base documents in Discourse
|
||||
# version: 0.1
|
||||
# author: Justin DiRose
|
||||
# url: https://github.com/discourse/discourse-knowledge-explorer
|
||||
# url: https://github.com/discourse/discourse-docs
|
||||
|
||||
enabled_site_setting :docs_enabled
|
||||
|
||||
|
@ -34,6 +34,7 @@ after_initialize do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
add_to_class(:topic_query, :list_docs_topics) do
|
||||
default_results(@options)
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue