wuffle 0.72.0 → 0.73.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,7 +8,11 @@ const CHILD_LINK_TYPES = {
8
8
  };
9
9
 
10
10
  /**
11
- * @typedef { { defaultFilter?: string, treatBotsAsReviewers?: boolean } } SearchConfig
11
+ * @typedef { {
12
+ * defaultFilter?: string,
13
+ * treatBotsAsReviewers?: boolean
14
+ * } } SearchConfig
15
+ *
12
16
  * @typedef { import('../../util/search.js').SearchTerm } SearchTerm
13
17
  *
14
18
  * @typedef { import('../../types.js').GitHubUser } GitHubUser
@@ -32,7 +36,8 @@ export default function Search(config, logger, store) {
32
36
  });
33
37
 
34
38
  const {
35
- treatBotsAsReviewers = false
39
+ treatBotsAsReviewers = false,
40
+ defaultFilter
36
41
  } = config;
37
42
 
38
43
  function filterNoop(issue) {
@@ -446,9 +451,11 @@ export default function Search(config, logger, store) {
446
451
  */
447
452
  function getSearchFilter(search, user) {
448
453
 
449
- const filterFn = buildFilterFn(search, user);
454
+ if (!search) {
455
+ search = defaultFilter;
456
+ }
450
457
 
451
- const ignoreFilterFn = buildFilterFn(config.defaultFilter, user);
458
+ const filterFn = buildFilterFn(search, user);
452
459
 
453
460
  return function(issue) {
454
461
  try {
@@ -456,12 +463,7 @@ export default function Search(config, logger, store) {
456
463
  return filterFn(issue);
457
464
  }
458
465
 
459
- if (ignoreFilterFn) {
460
- return ignoreFilterFn(issue);
461
- }
462
-
463
- // no user search, no ignore filter,
464
- // show all issues
466
+ // no search, show all issues
465
467
  return true;
466
468
  } catch (err) {
467
469
  log.warn({ issue: issueIdent(issue), err }, 'filter failed');
@@ -475,4 +477,6 @@ export default function Search(config, logger, store) {
475
477
  // api ///////////////////////
476
478
 
477
479
  this.getSearchFilter = getSearchFilter;
480
+
481
+ this.buildFilterFn = buildFilterFn;
478
482
  }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @typedef { { ignoreFilter?: string } } StoreFilterConfig
3
+ */
4
+
5
+ /**
6
+ * An component that configures the store to filter certain elements,
7
+ * effectively making them invisible to the board and its users.
8
+ *
9
+ * @param { StoreFilterConfig } config
10
+ *
11
+ * @param { import('../store.js').default } store
12
+ * @param { import('./search/Search.js').default } search
13
+ * @param { import('../types.js').Logger } logger
14
+ */
15
+ export default function StoreFilter(config, store, search, logger) {
16
+
17
+ const log = logger.child({
18
+ name: 'wuffle:store-filter'
19
+ });
20
+
21
+ if ('ignoreFilter' in config) {
22
+ const ignoreFilterFn = search.buildFilterFn(config.ignoreFilter);
23
+
24
+ if (ignoreFilterFn) {
25
+ store.setIgnoreFilter(ignoreFilterFn);
26
+ } else {
27
+ log.warn('unparseable <ignoreFilter> - please correct your board configuration');
28
+ }
29
+ }
30
+
31
+ }
package/lib/index.js CHANGED
@@ -27,7 +27,8 @@ const appModules = [
27
27
  import('./apps/auth-routes/index.js'),
28
28
  import('./apps/board-api-routes/index.js'),
29
29
  import('./apps/board-routes.js'),
30
- import('./apps/reindex-store.js')
30
+ import('./apps/reindex-store.js'),
31
+ import('./apps/store-filter.js')
31
32
  ];
32
33
 
33
34
  import loadConfig from './load-config.js';
package/lib/store.js CHANGED
@@ -4,6 +4,9 @@ import { issueIdent } from './util/index.js';
4
4
  import { findLinks } from './util/links.js';
5
5
  import { Links } from './links.js';
6
6
 
7
+ /**
8
+ * @typedef { import('./apps/search/Search.js').FilterFn } FilterFn
9
+ */
7
10
 
8
11
  /**
9
12
  * The store that holds all board data
@@ -39,6 +42,10 @@ export default class Store {
39
42
  this.updateContext = null;
40
43
  this.queuedUpdates = [];
41
44
 
45
+ /**
46
+ * @type { FilterFn }
47
+ */
48
+ this.ignoreFilter = (issue) => false;
42
49
 
43
50
  this.on('updateIssue', async event => {
44
51
 
@@ -303,7 +310,9 @@ export default class Store {
303
310
  /**
304
311
  * Update issue, tagging it as updated.
305
312
  *
306
- * @return {Promise<Object>} promise to updated issue
313
+ * If issue matches the ignore filter it will be removed as part of the update.
314
+ *
315
+ * @return {Promise<Object|undefined>} a promise to the updated issue or undefined in case the update triggered issue deletion
307
316
  */
308
317
  updateIssue(update) {
309
318
 
@@ -374,6 +383,14 @@ export default class Store {
374
383
 
375
384
  const ident = issueIdent(updatedIssue);
376
385
 
386
+ if (this.ignoreFilter(updatedIssue)) {
387
+ this.log.debug({ issue: ident }, 'issue matching ignore filter');
388
+
389
+ await this.removeIssueById(id);
390
+
391
+ return null;
392
+ }
393
+
377
394
  this.log.debug({
378
395
  issue: ident
379
396
  }, 'process update');
@@ -861,6 +878,13 @@ export default class Store {
861
878
  }, 'load JSON complete');
862
879
  }
863
880
 
881
+ /**
882
+ * @param { FilterFn } ignoreFilter
883
+ */
884
+ setIgnoreFilter(ignoreFilter) {
885
+ this.ignoreFilter = ignoreFilter;
886
+ }
887
+
864
888
  }
865
889
 
866
890
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wuffle",
3
- "version": "0.72.0",
3
+ "version": "0.73.0",
4
4
  "description": "A multi-repository task board for GitHub issues",
5
5
  "author": {
6
6
  "name": "Nico Rehwaldt",
@@ -82,5 +82,5 @@
82
82
  "index.js",
83
83
  "wuffle.config.example.js"
84
84
  ],
85
- "gitHead": "f42a56e87fb1f6d3f06ef5e9215c5e0b91544c0b"
85
+ "gitHead": "a58cc7fcd73db7a1dc7babc25b97bb590119b69d"
86
86
  }
@@ -1,47 +1,36 @@
1
1
  /**
2
2
  * This defines board specific configuration.
3
- *
4
- * ### Name
5
- *
6
- * The name of your board, displayed in the board header.
7
- *
8
- *
9
- * ### Description
10
- *
11
- * Optional description of the board, will be served with the board front-end
12
- * for SEO purposes.
13
- *
14
- *
15
- * ### Columns
16
- *
17
- * Valid fields for columns are
18
- *
19
- * * name - unique name
20
- * * label - label, if present on a GitHub issue column will be set
21
- * * closed - if the column issues must be closed
22
- * * sorting - true if column cards should be sorted
23
- * incrementally based on links
24
- * * fifo - true to turn the default column ordering from
25
- * last in first out to first in first out
26
- * * states - a list of board states to map to this column
27
- *
28
- * The default column is the column that holds open issues without
29
- * any label constraints (Inbox in the example below).
30
- *
31
- *
32
- * ### Search Config
33
- *
34
- * You may define a default filter to apply to the board if
35
- * there is no user-defined search query.
36
- *
37
- * You may also configure whether bots are counted as
38
- * legitimate reviewers (for both review and approval).
39
3
  */
40
4
  export default {
41
5
 
6
+ /**
7
+ * The name of your board, displayed in the board header.
8
+ */
42
9
  name: 'My Wuffle Board',
10
+
11
+ /**
12
+ * (Optional) description of the board, will be served with the board
13
+ * front-end for SEO purposes.
14
+ */
43
15
  description: 'This board organizes all my tasks',
44
16
 
17
+ /**
18
+ * Definitions of columns to display on the board, and their state.
19
+ *
20
+ * Valid fields for columns are
21
+ *
22
+ * * name - unique name
23
+ * * label - label, if present on a GitHub issue column will be set
24
+ * * closed - if the column issues must be closed
25
+ * * sorting - true if column cards should be sorted
26
+ * incrementally based on links
27
+ * * fifo - true to turn the default column ordering from
28
+ * last in first out to first in first out
29
+ * * states - a list of board states to map to this column
30
+ *
31
+ * The default column is the column that holds open issues without
32
+ * any label constraints (Inbox in the example below).
33
+ */
45
34
  columns: [
46
35
  { name: 'Inbox', label: null },
47
36
  { name: 'Backlog', label: 'backlog', sorting: true },
@@ -51,7 +40,23 @@ export default {
51
40
  { name: 'Done', label: null, closed: true }
52
41
  ],
53
42
 
43
+ /**
44
+ * (Optional) default filter to apply to the board if there is no
45
+ * user-defined search query.
46
+ */
54
47
  defaultFilter: '!repo:"some/ignored-repository"',
55
48
 
49
+ /**
50
+ * (Optional) Filter matching issues that shall not be saved.
51
+ *
52
+ * Matching issues will not be added. If they were previously on the board
53
+ * they will be removed as part of an update.
54
+ */
55
+ ignoreFilter: 'label:"invalid"',
56
+
57
+ /**
58
+ * Whether or not bots are treated as legitimate reviewers, for review and
59
+ * approval queries. Defaults to `false`.
60
+ */
56
61
  treatBotsAsReviewers: false
57
62
  };