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:
discoursebot 2021-04-27 14:49:34 -04:00 committed by GitHub
parent 50f7c25de2
commit f75c9d5e32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 314 additions and 274 deletions

View File

@ -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 .

View File

@ -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: |

3
.gitignore vendored
View File

@ -1,4 +1 @@
.rubocop-https---raw-githubusercontent-com-discourse-discourse-master--rubocop-yml
node_modules
yarn-error.log
.rubocop-https---raw-githubusercontent-com-discourse-*

1
.prettierrc Normal file
View File

@ -0,0 +1 @@
{}

View File

@ -1,2 +0,0 @@
inherit_gem:
rubocop-discourse: default.yml

View File

@ -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

21
LICENSE Normal file
View File

@ -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.

View File

@ -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;
},
},
});

View File

@ -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("");
},
});

View File

@ -1,10 +1,5 @@
import Component from "@ember/component";
export default Component.extend({
tagName: "",
actions: {
selectTag() {
this.selectTag(this.tag);
return false;
},
},
});

View File

@ -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;
},
});

View File

@ -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);

View File

@ -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");
},
});

View File

@ -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;
},
});

View File

@ -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;
});

View File

@ -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) => {

View File

@ -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>

View File

@ -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>

View File

@ -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}}

View File

@ -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"}}

View File

@ -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}}

View File

@ -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")

View File

@ -127,6 +127,10 @@
th {
min-width: 5em;
&[role="button"] {
cursor: pointer;
}
&:hover {
background-color: var(--primary-low, $primary-low);
}

View File

@ -1,4 +1,7 @@
{
"name": "discourse-docs",
"version": "0.1",
"repository": "https://github.com/discourse/discourse-docs",
"author": "Discourse",
"license": "MIT",
"devDependencies": {

View File

@ -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