#cofacts
2020-05-01
Nacs
10:36:15
@nacs13 has joined the channel
lucien
14:55:49
好猛
github
15:22:31
From comments in <https://github.com/cofacts/rumors-line-bot/pull/169|#169>: • `Query.context` is a little bit confusing with apollo context • `UserContext.state` & `UserContext.data` should be non-nullable
github
15:34:11
*<https://github.com/cofacts/rumors-line-bot/compare/a28f1b6b5ba2...8a390abf8dac|8 new commits> pushed to <https://github.com/cofacts/rumors-line-bot/tree/dev|`dev`>* <https://github.com/cofacts/rumors-line-bot/commit/080040ad2857b3c1d410465f4ccb5a755f48caf7|`080040ad`> - GraphQL authentication & context population <https://github.com/cofacts/rumors-line-bot/commit/30c8a3e52d0715a56eb6eace1484d834eb29cfe4|`30c8a3e5`> - Implement authentication, @auth directive and context field <https://github.com/cofacts/rumors-line-bot/commit/da8ccf6e33848f919e4459fbe91d3b7391052851|`da8ccf6e`> - Redundent jest.mock() as manual mocks for node modules will always load. <https://github.com/cofacts/rumors-line-bot/commit/f24191c880cf28a4fb879d64a1f440ea76071f14|`f24191c8`> - Add "manual" (auto) mock for redisClient so that all redisClient deps are mocked (such as in graphql/__tests__/insights) <https://github.com/cofacts/rumors-line-bot/commit/8dfa0c12afe6b0f6c8b49b798e4474c955450a89|`8dfa0c12`> - Prettier fix <https://github.com/cofacts/rumors-line-bot/commit/5295edb20990e761d51773539fab7903d37fc657|`5295edb2`> - Avoid calling the real redisClient in unit tests <https://github.com/cofacts/rumors-line-bot/commit/97b491de65d9a67c9c92bbdb4ac4118ff8f8359f|`97b491de`> - Add userId in GraphQL context after authentication <https://github.com/cofacts/rumors-line-bot/commit/8a390abf8dac39ad4701a9870628cbb1f06dad0c|`8a390abf`> - Merge pull request #169 from cofacts/auth-api
github
15:37:06
*<https://github.com/cofacts/rumors-line-bot/compare/8a390abf8dac...c5b684609691|9 new commits> pushed to <https://github.com/cofacts/rumors-line-bot/tree/dev|`dev`>* <https://github.com/cofacts/rumors-line-bot/commit/d36d76e47d90f391580d4ca5866aab14aa1efcf5|`d36d76e4`> - Implements mutation GraphQL endpoints for LIFF <https://github.com/cofacts/rumors-line-bot/commit/deb8bdd8075e5107db100ca2062caff5d5dccaba|`deb8bdd8`> - Remove submitReplyRequest because it is no longer needed <https://github.com/cofacts/rumors-line-bot/commit/ea856c552b8e8612936609b8fec6773c7a53d31d|`ea856c55`> - Remove submitArticle mutation because it's not needed <https://github.com/cofacts/rumors-line-bot/commit/b853bed252645822f9a81eccd79a9b72160efb64|`b853bed2`> - Prettier fix <https://github.com/cofacts/rumors-line-bot/commit/7860ec7dcc8c773ee25755d1563e26a3a4d16ac1|`7860ec7d`> - Add unit test for gql <https://github.com/cofacts/rumors-line-bot/commit/8ec314510a5e31c4de95248b3e6b09caa690a9b6|`8ec31451`> - Lint fix <https://github.com/cofacts/rumors-line-bot/commit/cc864507472181a1d2d713d18e5ecb675ac41824|`cc864507`> - gql error handling test. For test coverage... <https://github.com/cofacts/rumors-line-bot/commit/f86275a983ddd303333466dea15de103e17159ca|`f86275a9`> - Prettier fix <https://github.com/cofacts/rumors-line-bot/commit/c5b684609691bad8ec9ed6bd83df397dae310f40|`c5b68460`> - Merge pull request #170 from cofacts/mutation-api
github
15:38:01
*<https://github.com/cofacts/rumors-line-bot/compare/c5b684609691...8cc7ede5ddaf|8 new commits> pushed to <https://github.com/cofacts/rumors-line-bot/tree/dev|`dev`>* <https://github.com/cofacts/rumors-line-bot/commit/9d7f9b991f55c65a5f282ef0e11f1e0307099b1a|`9d7f9b99`> - Setup svelte liff and server build <https://github.com/cofacts/rumors-line-bot/commit/0bb6c769cdefba3d5d1589579d3fc3096c2779b7|`0bb6c769`> - audit fix <https://github.com/cofacts/rumors-line-bot/commit/51673df03e493ef42ddc49abbd3cfee1789d1396|`51673df0`> - Add liff proxy in dev mode <https://github.com/cofacts/rumors-line-bot/commit/eb8d1a7859035ff2b936544b29521d590465fbc6|`eb8d1a78`> - Add basic svelte setup <https://github.com/cofacts/rumors-line-bot/commit/0c2d09f027979d223b13077a61796da77fdc49ef|`0c2d09f0`> - Svelte i18n and corejs polyfill <https://github.com/cofacts/rumors-line-bot/commit/711fe7f2fb924332b0d94991777211c2fe3a1bfb|`711fe7f2`> - Imports polyfills that supports Safari10 and Android 52 <https://github.com/cofacts/rumors-line-bot/commit/10bb13afcf58cda3e5a09a68f61b13df3aeecd28|`10bb13af`> - Eslint ignore built liff/* <https://github.com/cofacts/rumors-line-bot/commit/8cc7ede5ddaf463e80977208ae97a93c81fa68f5|`8cc7ede5`> - Merge pull request #171 from cofacts/svelte-liff
mrorz
19:34:45
/github unsubscribe cofacts commits,statuses,deployments,releases
mrorz
19:35:18
/github subscribe cofacts reviews,comments
mrorz
19:37:50
@ggm PR review 囉,請過目
https://github.com/cofacts/rumors-line-bot/pull/182
mongoClient 的實作我覺得有些太複雜了,abstraction 也有點怪 QQ
https://github.com/cofacts/rumors-line-bot/pull/182
mongoClient 的實作我覺得有些太複雜了,abstraction 也有點怪 QQ
噢其實我覺得好像繼承 mongoClient 比較好
然後為什麼不要用 es6 class 呀
其他我晚點繼續看噢
mrorz
2020-05-01 22:38:24
React 寫久就會不喜歡 class (欸
其實主要是看到底想做的是 generalized client 還是 specialized singleton
我不反對做成 generalized client,就是包成 class、new 時進行連線,constructor 裡面設定 URL 等等
我也不反對另外做個 factory function 來吐一個前述的 class 的 singleton instance
但現在這個 class 實在太詭異,輸出的 constructor 可以改 URL 卻不能改 dbName,又有 singleton 的 static method、也會自動 connect 等等
其實主要是看到底想做的是 generalized client 還是 specialized singleton
我不反對做成 generalized client,就是包成 class、new 時進行連線,constructor 裡面設定 URL 等等
我也不反對另外做個 factory function 來吐一個前述的 class 的 singleton instance
但現在這個 class 實在太詭異,輸出的 constructor 可以改 URL 卻不能改 dbName,又有 singleton 的 static method、也會自動 connect 等等
mrorz
2020-05-01 22:45:42
我們對 `mongoClient` 還有下面的需求,會讓我覺得要滿足這些需求時,做成 class 反而是比較多餘的封裝
1. 我們會希望整個 app 共用一個 MongoDB 連線,而不是每個 request 來就重新連 MongoDB
2. 我們會連的資料庫就是 env vars 裡面指定的那些,不會有別的資料庫
這應該也是為什麼你會設計 `getInstance` 這個 static method 來回傳 singleton,因為 singleton 才是能滿足我們需求的 pattern
但如果我們想要的是 singleton 的話,那在 Javascript 的世界裡,我們大可以直接使用 object literal 就能辦到,不需要大費周章地包成 class 然後 instantiate 自己之類的
1. 我們會希望整個 app 共用一個 MongoDB 連線,而不是每個 request 來就重新連 MongoDB
2. 我們會連的資料庫就是 env vars 裡面指定的那些,不會有別的資料庫
這應該也是為什麼你會設計 `getInstance` 這個 static method 來回傳 singleton,因為 singleton 才是能滿足我們需求的 pattern
但如果我們想要的是 singleton 的話,那在 Javascript 的世界裡,我們大可以直接使用 object literal 就能辦到,不需要大費周章地包成 class 然後 instantiate 自己之類的
我是覺得自動連線的地方比較怪異沒錯,但其實你改成的 `getClient()` 的方式也是做了一樣的事情?「可以改 URI 卻不能改 dbName」為什麼不合理呀?我們不會用到別的 db 所以 `dbName` 不能改,但是會根據 `production` 和 `staging` 來有不同的 URI,所以 MONGODB_URI 會透過環境變數修改
mrorz
2020-05-01 23:21:54
主要的差別在 expose 出整個 class,跟只吐一個 factory method 的差別唷
mrorz
2020-05-01 23:24:49
應該是說我在裡面寫的那份 code 就是
「可以達成一樣的事情,但不會 leak 其他邏輯(規定要某種 call 法)的 abstraction」
「可以達成一樣的事情,但不會 leak 其他邏輯(規定要某種 call 法)的 abstraction」
嗯懂
但還是有隱含已連線的問題,要真的解決這個怪異,可能改成 getConnectedClient 之類的吧
然後我不覺得這是大費周章的包成 class 耶,不過就是定義一個 class 寫個 singleton ,用 object literal 的寫法不就也是模擬成 class 的樣子嗎?(吐出一個 object,然後他有一些 function 可以呼叫)那為什麼不直接用 class 來定義勒?
mrorz
2020-05-01 23:30:46
`getConnectedClient` 比較像是吐 object 的 factory (function) 的感覺
還是你是想說的是,既然我們都可以用 object literal 來做了,何須用 class
mrorz
2020-05-01 23:31:08
恩也可以這麼說
試想我們今天如果要加一上另外一個 function,你要做的事情是在 setupClient 的回傳值裡面加入一個 function
而 class 方法要做的事情,是在 class 裡面加入一個 function
我覺得 class 的做法不是比較直覺比較合理嗎?
我去找到這個 class 定義在哪裡,替他加上一個 function
mrorz
2020-05-01 23:33:07
我的直覺會是
我找到那個物件在哪裡,然後加上一個 method
我找到那個物件在哪裡,然後加上一個 method
而且 object literal 的做法,就會讓回傳值包得長長的
mrorz
2020-05-01 23:33:34
因為我要一包物件
他出生就是個 instance
他出生就是個 instance
mrorz
2020-05-01 23:34:32
factory 只是因為我想把連線之類的事情,從 import file 的時機點,延後到呼叫 `getClient`時做
不然其實我覺得 import 時就 connect 其實也挺好的
不然其實我覺得 import 時就 connect 其實也挺好的
mrorz
2020-05-01 23:35:04
這樣就真的只要 `export default obj` 然後那個 `obj` 就是整個 module 的內容惹
mrorz
2020-05-01 23:36:58
啊其實不太行,最後至少還是要回傳個 promise
要等 connect (async) 之後才能讓使用者操作
要等 connect (async) 之後才能讓使用者操作
嗯一定要回 promise
不然就是在某個地方先 await 過之類的(感覺很奇怪)
mrorz
2020-05-01 23:38:37
那就是 promise of 那個可以 db 呀 collection 呀 close 呀的 API (一個物件)
mrorz
2020-05-01 23:42:44
畢竟 JS 的 module.exports 本身就是個大 singleton
那我好奇噢,如果之後轉 typescript 的話,class 的做法可以明確的知道定義長怎樣,不管是每個 function 的或是自己,那這樣的話 object literal 的做法會長怎樣?
我需要另外定義一個 Type/Interface 來描述他是嗎?
mrorz
2020-05-01 23:45:32
轉 Typescript 的話
我會訂個 type 描述 `CofactsMongoClient`
然後定 getClient 會回傳 `Promise<CofactsMongoClient>`
我會訂個 type 描述 `CofactsMongoClient`
然後定 getClient 會回傳 `Promise<CofactsMongoClient>`
mrorz
2020-05-01 23:46:17
那些 function 的 type 都指定好之後,讓 typescript 的 structural typing 確認我的 implementation 是不是確實會生出這個形狀的東西
嗯但 class 的做法不用另外再描述
mrorz
2020-05-01 23:46:43
對外面來說他就是吐 `Promise<CofactsMongoClient>` 的 function~
mrorz
2020-05-01 23:50:50
如果要 class 的話,那我覺得我們就在 constructor 裡面回傳那個 singleton instance 吧
像是這份答案的 ES7 version (Update 2019) https://stackoverflow.com/a/6733919/1582110
把 class expose 出去的時候,外面的人只能做一件事情,就是 new 它
然後 new 它,就只會回傳那個 singleton,然後連線啥的都會自動做好這樣
這樣一來外面的使用者只有一種使用方法,會是比較合適的封裝
像是這份答案的 ES7 version (Update 2019) https://stackoverflow.com/a/6733919/1582110
把 class expose 出去的時候,外面的人只能做一件事情,就是 new 它
然後 new 它,就只會回傳那個 singleton,然後連線啥的都會自動做好這樣
這樣一來外面的使用者只有一種使用方法,會是比較合適的封裝
mrorz
2020-05-01 23:51:14
就是 constructor 裡面會處理 getInstance or getClient 的概念
mrorz
2020-05-01 23:54:24
(我發現另一篇類似發問文的 best answer 就是 instance XD 但那是在 class 出現之前寫的)
https://stackoverflow.com/questions/1479319/simplest-cleanest-way-to-implement-singleton-in-javascript
https://stackoverflow.com/questions/1479319/simplest-cleanest-way-to-implement-singleton-in-javascript
好我來看看,然後把 connected 寫在註解好了,我覺得拿到一個已連線的 client 真的怪怪的 XDD 但每次呼叫 .connect() 也不是辦法
對啊沒有 class 一定是會這樣寫呀 還是 var 耶
mrorz
2020-05-01 23:56:21
我覺得比較棘手的部分是,我們的東西是 async 的,所以 class constructor 要怎麼處理那個 async 的部分其實滿討厭
`Downvote for the accepted answer not being a singleton at all. It's just a global variable. – mlibby Feb 25 '13 at 12:53`
XDD
mrorz
2020-05-01 23:57:21
對沒有原生 class 的 JS 來說
真的就是 global variable 呀 XD
真的就是 global variable 呀 XD
對啊他好嚴格
mrorz
2020-05-01 23:58:15
大概是四人幫的粉絲、喜歡 Java 不喜歡 Javascript 的人 (?
mrorz
2020-05-02 00:01:31
> class constructor 要怎麼處理那個 async 的部分其實滿討厭
我現在想到的東西超怪的耶,就是 constructor 會回傳一個 promise,然後 promise 會 resolve to singleton instance when connected to database
所以會有一個超詭異的狀況:
我 new 一個 class ,但拿到的不是該 class 的 instance 而是 promise of that instance
超反直覺的
我現在想到的東西超怪的耶,就是 constructor 會回傳一個 promise,然後 promise 會 resolve to singleton instance when connected to database
所以會有一個超詭異的狀況:
我 new 一個 class ,但拿到的不是該 class 的 instance 而是 promise of that instance
超反直覺的
mrorz
2020-05-02 00:02:11
除非我們 extend Promise (更鬧了)
mrorz
2020-05-02 00:11:59
要不然就是保留現在的 getInstance
未來 Typescript 的時候直接用 private constructor 把 new 那條路堵起來,這樣只能呼叫 `getInstance` 抓 instance
https://khalilstemmler.com/blogs/typescript/when-to-use-a-private-constructor/
未來 Typescript 的時候直接用 private constructor 把 new 那條路堵起來,這樣只能呼叫 `getInstance` 抓 instance
https://khalilstemmler.com/blogs/typescript/when-to-use-a-private-constructor/
extend Promise 很帥耶⋯
mrorz
2020-05-02 00:14:40
我不太能接受 extend Promise
我覺得 private constructor 是最接近你原本想做的東西了
我覺得 private constructor 是最接近你原本想做的東西了
mrorz
2020-05-02 00:14:45
現在沒有 typescript
mrorz
2020-05-02 00:14:56
就放個註解說「不要 new!」吧
嗯 typescript 的話就可以 private constructor
好
啊然後其實 dbName 也可以拿掉,用預設的,也就是 MONGODB_URI 的
mrorz
2020-05-02 00:25:53
喔喔那個 mongodb connection uri `/` 後面帶的 db name 是 auth 用 db,不一定等於資料存放的 db 的說
`/` 後面是 dbname 沒錯, `authsource` 可以指定另外的 auth
mrorz
2020-05-02 00:27:17
https://docs.mongodb.com/manual/reference/connection-string/ 是 `defaultauthdb` 唷
欸不是
mrorz
2020-05-02 00:27:38
所以就算有帶 `/dbName` 我們還是要 `db(dbName)` 一次
我要說的是可以這樣 `/cofacts?authsource=admin`
mrorz
2020-05-02 00:28:09
嗯但這樣連線完,你似乎還是得要 `.db('cofacts')` ?
mrorz
2020-05-02 00:28:44
可以試試看
我的印象是還是要 `db` 指定 db name
我的印象是還是要 `db` 指定 db name
不用噢
The name of the database we want to use. If not provided, use database name from connection string.
mrorz
2020-05-02 00:31:07
真的耶
mrorz
2020-05-02 00:31:08
學到了
mrorz
2020-05-02 00:31:09
酷
ggm
19:51:11
好啊我看看
ggm
20:30:03
噢其實我覺得好像繼承 mongoClient 比較好
ggm
20:31:12
然後為什麼不要用 es6 class 呀
ggm
20:32:10
其他我晚點繼續看噢
mrorz
22:38:24
React 寫久就會不喜歡 class (欸
其實主要是看到底想做的是 generalized client 還是 specialized singleton
我不反對做成 generalized client,就是包成 class、new 時進行連線,constructor 裡面設定 URL 等等
我也不反對另外做個 factory function 來吐一個前述的 class 的 singleton instance
但現在這個 class 實在太詭異,輸出的 constructor 可以改 URL 卻不能改 dbName,又有 singleton 的 static method、也會自動 connect 等等
其實主要是看到底想做的是 generalized client 還是 specialized singleton
我不反對做成 generalized client,就是包成 class、new 時進行連線,constructor 裡面設定 URL 等等
我也不反對另外做個 factory function 來吐一個前述的 class 的 singleton instance
但現在這個 class 實在太詭異,輸出的 constructor 可以改 URL 卻不能改 dbName,又有 singleton 的 static method、也會自動 connect 等等
mrorz
22:45:42
我們對 `mongoClient` 還有下面的需求,會讓我覺得要滿足這些需求時,做成 class 反而是比較多餘的封裝
1. 我們會希望整個 app 共用一個 MongoDB 連線,而不是每個 request 來就重新連 MongoDB
2. 我們會連的資料庫就是 env vars 裡面指定的那些,不會有別的資料庫
這應該也是為什麼你會設計 `getInstance` 這個 static method 來回傳 singleton,因為 singleton 才是能滿足我們需求的 pattern
但如果我們想要的是 singleton 的話,那在 Javascript 的世界裡,我們大可以直接使用 object literal 就能辦到,不需要大費周章地包成 class 然後 instantiate 自己之類的
1. 我們會希望整個 app 共用一個 MongoDB 連線,而不是每個 request 來就重新連 MongoDB
2. 我們會連的資料庫就是 env vars 裡面指定的那些,不會有別的資料庫
這應該也是為什麼你會設計 `getInstance` 這個 static method 來回傳 singleton,因為 singleton 才是能滿足我們需求的 pattern
但如果我們想要的是 singleton 的話,那在 Javascript 的世界裡,我們大可以直接使用 object literal 就能辦到,不需要大費周章地包成 class 然後 instantiate 自己之類的
ggm
23:07:12
我是覺得自動連線的地方比較怪異沒錯,但其實你改成的 `getClient()` 的方式也是做了一樣的事情?「可以改 URI 卻不能改 dbName」為什麼不合理呀?我們不會用到別的 db 所以 `dbName` 不能改,但是會根據 `production` 和 `staging` 來有不同的 URI,所以 MONGODB_URI 會透過環境變數修改
- 👍1
mrorz
23:21:54
主要的差別在 expose 出整個 class,跟只吐一個 factory method 的差別唷
mrorz
23:24:49
應該是說我在裡面寫的那份 code 就是
「可以達成一樣的事情,但不會 leak 其他邏輯(規定要某種 call 法)的 abstraction」
「可以達成一樣的事情,但不會 leak 其他邏輯(規定要某種 call 法)的 abstraction」
ggm
23:25:32
嗯懂
ggm
23:28:34
但還是有隱含已連線的問題,要真的解決這個怪異,可能改成 getConnectedClient 之類的吧
ggm
23:30:00
然後我不覺得這是大費周章的包成 class 耶,不過就是定義一個 class 寫個 singleton ,用 object literal 的寫法不就也是模擬成 class 的樣子嗎?(吐出一個 object,然後他有一些 function 可以呼叫)那為什麼不直接用 class 來定義勒?
mrorz
23:30:46
`getConnectedClient` 比較像是吐 object 的 factory (function) 的感覺
ggm
23:30:50
還是你是想說的是,既然我們都可以用 object literal 來做了,何須用 class
mrorz
23:31:08
恩也可以這麼說
ggm
23:31:23
試想我們今天如果要加一上另外一個 function,你要做的事情是在 setupClient 的回傳值裡面加入一個 function
ggm
23:31:42
而 class 方法要做的事情,是在 class 裡面加入一個 function
ggm
23:32:00
我覺得 class 的做法不是比較直覺比較合理嗎?
ggm
23:32:23
我去找到這個 class 定義在哪裡,替他加上一個 function
mrorz
23:33:07
我的直覺會是
我找到那個物件在哪裡,然後加上一個 method
我找到那個物件在哪裡,然後加上一個 method
ggm
23:33:12
而且 object literal 的做法,就會讓回傳值包得長長的
mrorz
23:33:34
因為我要一包物件
他出生就是個 instance
他出生就是個 instance
mrorz
23:34:32
factory 只是因為我想把連線之類的事情,從 import file 的時機點,延後到呼叫 `getClient`時做
不然其實我覺得 import 時就 connect 其實也挺好的
不然其實我覺得 import 時就 connect 其實也挺好的
mrorz
23:35:04
這樣就真的只要 `export default obj` 然後那個 `obj` 就是整個 module 的內容惹
mrorz
23:36:58
啊其實不太行,最後至少還是要回傳個 promise
要等 connect (async) 之後才能讓使用者操作
要等 connect (async) 之後才能讓使用者操作
ggm
23:37:57
嗯一定要回 promise
ggm
23:38:15
不然就是在某個地方先 await 過之類的(感覺很奇怪)
mrorz
23:38:37
那就是 promise of 那個可以 db 呀 collection 呀 close 呀的 API (一個物件)
mrorz
23:42:44
畢竟 JS 的 module.exports 本身就是個大 singleton
ggm
23:43:11
那我好奇噢,如果之後轉 typescript 的話,class 的做法可以明確的知道定義長怎樣,不管是每個 function 的或是自己,那這樣的話 object literal 的做法會長怎樣?
ggm
23:44:30
我需要另外定義一個 Type/Interface 來描述他是嗎?
mrorz
23:45:32
轉 Typescript 的話
我會訂個 type 描述 `CofactsMongoClient`
然後定 getClient 會回傳 `Promise<CofactsMongoClient>`
我會訂個 type 描述 `CofactsMongoClient`
然後定 getClient 會回傳 `Promise<CofactsMongoClient>`
mrorz
23:46:17
那些 function 的 type 都指定好之後,讓 typescript 的 structural typing 確認我的 implementation 是不是確實會生出這個形狀的東西
mrorz
23:46:43
對外面來說他就是吐 `Promise<CofactsMongoClient>` 的 function~
mrorz
23:50:50
如果要 class 的話,那我覺得我們就在 constructor 裡面回傳那個 singleton instance 吧
像是這份答案的 ES7 version (Update 2019) https://stackoverflow.com/a/6733919/1582110
把 class expose 出去的時候,外面的人只能做一件事情,就是 new 它
然後 new 它,就只會回傳那個 singleton,然後連線啥的都會自動做好這樣
這樣一來外面的使用者只有一種使用方法,會是比較合適的封裝
像是這份答案的 ES7 version (Update 2019) https://stackoverflow.com/a/6733919/1582110
把 class expose 出去的時候,外面的人只能做一件事情,就是 new 它
然後 new 它,就只會回傳那個 singleton,然後連線啥的都會自動做好這樣
這樣一來外面的使用者只有一種使用方法,會是比較合適的封裝
Stack Overflow
Possible Duplicate: Simplest/Cleanest way to implement singleton in JavaScript? I'm using this pattern for singletons, in the example the singleton is PlanetEarth: var NAMESPACE = function ()...
mrorz
23:51:14
就是 constructor 裡面會處理 getInstance or getClient 的概念
mrorz
23:54:24
(我發現另一篇類似發問文的 best answer 就是 instance XD 但那是在 class 出現之前寫的)
https://stackoverflow.com/questions/1479319/simplest-cleanest-way-to-implement-singleton-in-javascript
https://stackoverflow.com/questions/1479319/simplest-cleanest-way-to-implement-singleton-in-javascript
Stack Overflow
What is the simplest/cleanest way to implement singleton pattern in JavaScript?
ggm
23:54:36
好我來看看,然後把 connected 寫在註解好了,我覺得拿到一個已連線的 client 真的怪怪的 XDD 但每次呼叫 .connect() 也不是辦法
ggm
23:55:41
對啊沒有 class 一定是會這樣寫呀 還是 var 耶
ggm
23:56:30
`Downvote for the accepted answer not being a singleton at all. It's just a global variable. – mlibby Feb 25 '13 at 12:53`
ggm
23:56:31
XDD
mrorz
23:57:21
對沒有原生 class 的 JS 來說
真的就是 global variable 呀 XD
真的就是 global variable 呀 XD
ggm
23:57:39
對啊他好嚴格
mrorz
23:58:15
大概是四人幫的粉絲、喜歡 Java 不喜歡 Javascript 的人 (?
2020-05-02
mrorz
00:01:31
> class constructor 要怎麼處理那個 async 的部分其實滿討厭
我現在想到的東西超怪的耶,就是 constructor 會回傳一個 promise,然後 promise 會 resolve to singleton instance when connected to database
所以會有一個超詭異的狀況:
我 new 一個 class ,但拿到的不是該 class 的 instance 而是 promise of that instance
超反直覺的
我現在想到的東西超怪的耶,就是 constructor 會回傳一個 promise,然後 promise 會 resolve to singleton instance when connected to database
所以會有一個超詭異的狀況:
我 new 一個 class ,但拿到的不是該 class 的 instance 而是 promise of that instance
超反直覺的
mrorz
00:02:11
除非我們 extend Promise (更鬧了)
mrorz
00:11:59
要不然就是保留現在的 getInstance
未來 Typescript 的時候直接用 private constructor 把 new 那條路堵起來,這樣只能呼叫 `getInstance` 抓 instance
https://khalilstemmler.com/blogs/typescript/when-to-use-a-private-constructor/
未來 Typescript 的時候直接用 private constructor 把 new 那條路堵起來,這樣只能呼叫 `getInstance` 抓 instance
https://khalilstemmler.com/blogs/typescript/when-to-use-a-private-constructor/
khalilstemmler.com
In this blog post, I explain how using a private constructor helps to force a single way to create an object, and why it's most commonly used with the Factory Pattern.
ggm
00:14:15
extend Promise 很帥耶⋯
mrorz
00:14:40
我不太能接受 extend Promise
我覺得 private constructor 是最接近你原本想做的東西了
我覺得 private constructor 是最接近你原本想做的東西了
mrorz
00:14:45
現在沒有 typescript
ggm
00:15:41
嗯 typescript 的話就可以 private constructor
ggm
00:15:45
好
ggm
00:22:50
啊然後其實 dbName 也可以拿掉,用預設的,也就是 MONGODB_URI 的
github
00:25:15
Update: as <https://g0v-slack-archive.g0v.ronny.tw/index/channel/C2PPMRQGP/2020-05|discussed in Slack> we decided to add a comment to constructor to indicate that the users of `CofactsMongoClient` should never call `new` by themselves. When we adopt Typescript in the future, we will make the constructor private to make sure that users of `CofactsMongoClient` can only retrieve its singleton instance via `getInstance()` static method. `CofactsMongoClient` is dedicated to connecting to Cofacts LINE bot mongodb, not something that is generalized. ES6 class is used so that it's easier to define method and update the client type in the same time, also ensures a smoother updater when we rewrite in Typescript.
mrorz
00:25:53
喔喔那個 mongodb connection uri `/` 後面帶的 db name 是 auth 用 db,不一定等於資料存放的 db 的說
ggm
00:26:48
`/` 後面是 dbname 沒錯, `authsource` 可以指定另外的 auth
ggm
00:27:36
欸不是
mrorz
00:27:38
所以就算有帶 `/dbName` 我們還是要 `db(dbName)` 一次
ggm
00:27:41
我要說的是可以這樣 `/cofacts?authsource=admin`
mrorz
00:28:09
嗯但這樣連線完,你似乎還是得要 `.db('cofacts')` ?
mrorz
00:28:44
可以試試看
我的印象是還是要 `db` 指定 db name
我的印象是還是要 `db` 指定 db name
ggm
00:29:15
不用噢
ggm
00:29:25
The name of the database we want to use. If not provided, use database name from connection string.
mrorz
00:31:07
真的耶
mrorz
00:31:08
學到了
mrorz
01:11:54
Replied to a thread: 2020-04-22 22:43:20
cofacts.hacktabl.org
Cofacts is a collaborative system connecting instant messages and fact-check reports or different opinions together. It’s a grass-root effort fighting mis/disinformation in Taiwan.![]()
mrorz
01:14:21
但那應該是因為有 user 的 app id 是 `DEVELOPMENT_BACKEND` 的關係。因此,其實 reply 或任何東西的 user 都有可能是 null,程式邏輯上不能有任何地方沒有先檢查 user 不是 null 就直接存取 user 唷。
cc/ @yanglin5689446
cc/ @yanglin5689446
mrorz
02:30:34
這其實是當時為了讓 localhost 開發方便,
訂有讓 localhost 可以看到 app_id = `DEVEOPMENT_BACKEND` 的使用者的緣故
https://github.com/cofacts/rumors-api/blob/master/src/graphql/models/User.js#L113-L115
其實只要是 localhost:3000 接上 API server 之後,就能打 mutation,這其實不太安全,所以才做了這種 `DEVELOPMENT_BACKEND` 機制,特別允許這種 localhost:3000 的 request,只是安上不同 appId https://github.com/cofacts/rumors-api/blob/master/src/checkHeaders.js#L37-L42
訂有讓 localhost 可以看到 app_id = `DEVEOPMENT_BACKEND` 的使用者的緣故
https://github.com/cofacts/rumors-api/blob/master/src/graphql/models/User.js#L113-L115
其實只要是 localhost:3000 接上 API server 之後,就能打 mutation,這其實不太安全,所以才做了這種 `DEVELOPMENT_BACKEND` 機制,特別允許這種 localhost:3000 的 request,只是安上不同 appId https://github.com/cofacts/rumors-api/blob/master/src/checkHeaders.js#L37-L42
mrorz
02:33:53
而 staging 上那個造成 exception 的 reply,app_id 確實是 `DEVELOPMENT_BACKEND` @@
```{
"_index" : "replies_v1_0_2",
"_type" : "doc",
"_id" : "jD2sy3EBrIRcahlYXQri",
"_version" : 2,
"found" : true,
"_source" : {
"userId" : "hD1qunEBrIRcahlYYQoi",
"appId" : "DEVELOPMENT_FRONTEND",
"type" : "NOT_ARTICLE",
"text" : "fasdfasdfadsfasdfadsfasdfadsfadsfadsfadsfadsfadsfadsfasdffasdfasdfadsfasdfadsfasdfadsfadsfadsfadsfadsfadsfadsfasdffasdfasdfadsfasdfadsfasdfadsfadsfadsfadsfadsfadsfadsfasdf",
"reference" : "fasdfasdfadsfasdfadsfasdfadsfadsfadsfadsfadsfadsfadsfasdf",
"createdAt" : "2020-04-30T15:20:03.289Z",
"hyperlinks" : [ ]
}
}```
```{
"_index" : "replies_v1_0_2",
"_type" : "doc",
"_id" : "jD2sy3EBrIRcahlYXQri",
"_version" : 2,
"found" : true,
"_source" : {
"userId" : "hD1qunEBrIRcahlYYQoi",
"appId" : "DEVELOPMENT_FRONTEND",
"type" : "NOT_ARTICLE",
"text" : "fasdfasdfadsfasdfadsfasdfadsfadsfadsfadsfadsfadsfadsfasdffasdfasdfadsfasdfadsfasdfadsfadsfadsfadsfadsfadsfadsfasdffasdfasdfadsfasdfadsfasdfadsfadsfadsfadsfadsfadsfadsfasdf",
"reference" : "fasdfasdfadsfasdfadsfasdfadsfadsfadsfadsfadsfadsfadsfasdf",
"createdAt" : "2020-04-30T15:20:03.289Z",
"hyperlinks" : [ ]
}
}```
mrorz
02:38:52
還是其實我應該做的是在 staging 開放 localhost 但 production 不開放
把 `DEVELOPMENT_BACKEND` 機制整個淘汰掉
以及把資料庫內所有 appId = `DEVELOPMENT_BACKEND` 的東西都砍掉?
把 `DEVELOPMENT_BACKEND` 機制整個淘汰掉
以及把資料庫內所有 appId = `DEVELOPMENT_BACKEND` 的東西都砍掉?
mrorz
02:39:24
但這樣就無法模擬有不同 appId 的狀況就是了 QQ
github
12:29:52
Merge base temporarily changed to new page UI for correct diff. Will change back to dev benefits merge.
2020-05-03
github
04:26:48
Seems that in staging site, `user` being `null` would break `Avatar` and throw exception. I think the implementation of `<Avatar>` should guard against `null`.
github
04:26:48
Mobile menu has the same z-index with result dropdown but comes later in DOM, thus it is coming through: <https://user-images.githubusercontent.com/108608/80872659-d78d9100-8ce5-11ea-87e3-61657e99221d.gif|z-index> May need to increase z-index here, or form a stacking context with `z-index: 0` for mobile menu to contain the badge?![]()
github
04:26:48
As discussed <https://g0v-tw.slack.com/archives/C2PPMRQGP/p1587274861203800|in Slack>, please don't use `withData` in non-page components. Just use them on components under `pages/` directory.
github
04:26:48
Seems that the padding is too large in mobile version, names and avatar do not align in center. <https://user-images.githubusercontent.com/108608/80833043-5ddf9f80-8c20-11ea-83e7-e8e3722f4d24.png|image> You can use object / array notation on `py` for setting this responsively <https://material-ui.com/system/basics/#object|https://material-ui.com/system/basics/#object>![]()
github
04:26:48
Inconsistent size of thumb-up/down button and the reason button in mobile view. <https://user-images.githubusercontent.com/108608/80891170-f5aebd80-8cf4-11ea-8163-818ee6de925a.png|image> Corresponding mockup: <https://user-images.githubusercontent.com/108608/80891197-1f67e480-8cf5-11ea-851f-39bc14f9c875.png|image>![]()
github
04:26:48
I think we can open another ticket for implementing the real "for you" count listed in spec: <https://g0v.hackmd.io/iJm9_nZaTA2GyInn7ycxoA|https://g0v.hackmd.io/iJm9_nZaTA2GyInn7ycxoA> The "自己沒有送過任何 normal articleReply" part has no API yet, while "article.replyRequestCount >= N (default N = 2)" and "沒有任何 normal articleReply 符合「正feedback>負feedback && status == "NORMAL"」" are currently available in `ListArticle` filter.
github
04:26:49
Search result for replies is different from mockup. It should be listing replies that has the query text, rather than articles that has the query text. Mockup: <https://user-images.githubusercontent.com/108608/80891388-3a872400-8cf6-11ea-9ecc-dfd781fd27fc.png|image> Current: <https://user-images.githubusercontent.com/108608/80891392-4377f580-8cf6-11ea-99c0-fae928ed5f47.png|image> This may be huge so can include in future PRs.![]()
github
04:26:49
You also need `vote` under each feedbacks, because the you are using `vote` to move feedbacks in the right tab. Currently both tabs are empty because no feedback has `vote` field...... <https://user-images.githubusercontent.com/108608/80891094-61445b00-8cf4-11ea-82a2-eda5e2b83054.png|image>![]()
mrorz
14:10:48
https://github.com/cofacts/rumors-site/pull/248/files
@yanglin5689446 是說這個是不是還沒 ready 呀
我看用到 `ExpandableText` 的地方傳了 `lineClamp` 進去,但 `ExpandableText` 內部並沒有處理它
@yanglin5689446 是說這個是不是還沒 ready 呀
我看用到 `ExpandableText` 的地方傳了 `lineClamp` 進去,但 `ExpandableText` 內部並沒有處理它
mrorz
16:24:58
我在想要不要比照 `hasPositiveFeedbackArticleReply` ,在 `ListArticle` filter做一個 `hasMyArticleReply`
`true` 就是有,`false`就是沒有
不過之後 profile page 如果要列出某使用者的 `articleReply`,不知道是要改 `ListArticle` filter 還是要在 User 底下加 field 就是了⋯⋯
cc/ @lucien @yanglin5689446
`true` 就是有,`false`就是沒有
不過之後 profile page 如果要列出某使用者的 `articleReply`,不知道是要改 `ListArticle` filter 還是要在 User 底下加 field 就是了⋯⋯
cc/ @lucien @yanglin5689446
yanglin
16:28:01
如果有座在 `ListArticle` 在 profile 就繼續用就可以了吧?
反正 query 會被 group 在一起發送?
反正 query 會被 group 在一起發送?
mrorz
16:28:03
如果「某使用者的 `articleReply`」只會在 profile 之類的頁面使用,那確實是做在 User 底下比較合理,這樣 `ListArticle` filter 只要實作「有/沒有我的 articleReply」filter 即可
github
16:39:13
<https://github.com/orgs/cofacts/projects/5#card-37456782|https://github.com/orgs/cofacts/projects/5#card-37456782> added here
github
16:40:31
card added here: <https://github.com/orgs/cofacts/projects/5#card-34990256|https://github.com/orgs/cofacts/projects/5#card-34990256>
2020-05-04
github
00:49:29
*PR has been edited* :construction_worker: This PR has received other commits, so Renovate will stop updating it to avoid conflicts or other problems. If you wish to abandon your changes and have Renovate start over you may click the "rebase" checkbox in the PR body/description.
github
00:59:54
<https://coveralls.io/builds/30522585|Coverage Status> Coverage decreased (-5.1%) to 85.901% when pulling *<https://github.com/cofacts/rumors-api/commit/a64cc97a8f82f0c4bcd3b9f5946f4b55feb91ea9|a64cc97> on renovate/all* into *<https://github.com/cofacts/rumors-api/commit/4e8354b1aed320fc76cdeb09a4c1468822e09956|4e8354b> on master*.
github
01:13:01
The Elasticsearch js library we are <https://www.npmjs.com/package/elasticsearch|currently using> is deprecated, thus we are migrating to the <https://www.elastic.co/blog/new-elasticsearch-javascript-client-released|new client>. 95% of the changes in this PR is to mitigate this <https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/6.x/breaking-changes.html|breaking change>: > The returned value of an API call will no longer be the body, statusCode, and headers for callbacks and just the body for promises. The new returned value will be a unique object containing the body, statusCode, headers, warnings, and meta, for both callback and promises. Therefore a majority of the code change is destructuring `body` from the all the values the elasticsearch client returns. We remove elasticsearch log related setup, since the new client does not have an integrated logger anymore. We add unit test to `auth.js`, in which some of its logic binding to passport cannot be tested, thus the coverage goes down a bit. Lastly, the version of submodule rumors-db is also updated. In latest changes, `.env` file is removed from rumors-db codebase, thus we need to provide ELASTICSEARCH_URL manually in package.json of rumors-api, otherwise it will break environments like Travis CI.
mrorz
2020-05-04 01:18:23
因為原本的 elasticsearch js client deprecate 了,我更新了一下 elasticsearch js client。
他有個大 breaking change,更正了 client 回傳的所有結構,所以導致 rumors-api 裡面每一個有呼叫到 elasticsearch client 的地方幾乎都要跟著改。總之這個 PR 之所以巨大就是大在這囧
他有個大 breaking change,更正了 client 回傳的所有結構,所以導致 rumors-api 裡面每一個有呼叫到 elasticsearch client 的地方幾乎都要跟著改。總之這個 PR 之所以巨大就是大在這囧
mrorz
2020-05-06 12:59:25
這個變更太多了,為了找出有沒有問題
我先把它放到 staging 上跑跑看囉
如果大家最近打 staging API 出問題請提出,說不定是這個 PR 的問題
我先把它放到 staging 上跑跑看囉
如果大家最近打 staging API 出問題請提出,說不定是這個 PR 的問題
@darkbtf 留意個
mrorz
01:18:23
因為原本的 elasticsearch js client deprecate 了,我更新了一下 elasticsearch js client。
他有個大 breaking change,更正了 client 回傳的所有結構,所以導致 rumors-api 裡面每一個有呼叫到 elasticsearch client 的地方幾乎都要跟著改。總之這個 PR 之所以巨大就是大在這囧
他有個大 breaking change,更正了 client 回傳的所有結構,所以導致 rumors-api 裡面每一個有呼叫到 elasticsearch client 的地方幾乎都要跟著改。總之這個 PR 之所以巨大就是大在這囧
- 😱1
mrorz
01:20:19
@yanglin5689446
其實主要是考量 `ListArticle` 這裡如果計算 `articleReply` 還要考慮是「哪個使用者發的 `articleReply`」那 API 就不能只是 boolean
而必須是個 boolean + user ID string,所以會從
```hasMyArticleReply: Boolean```
變成
```articleReplyFrom: { userId: String, appId: String, exists: Boolean }```
(想不到更好的取名 囧)
其實主要是考量 `ListArticle` 這裡如果計算 `articleReply` 還要考慮是「哪個使用者發的 `articleReply`」那 API 就不能只是 boolean
而必須是個 boolean + user ID string,所以會從
```hasMyArticleReply: Boolean```
變成
```articleReplyFrom: { userId: String, appId: String, exists: Boolean }```
(想不到更好的取名 囧)
- 👍1
github
01:32:56
其實我是指左邊兩顆 vote 按鈕,與右邊灰底的顯示部分不一樣高 <https://user-images.githubusercontent.com/108608/80921136-0ddf1500-8da7-11ea-9607-e723cb5b942d.png|image> Mockup 裡,雖然 mobile / desktop 下的 button 高度不同,但左右兩塊都是等高的。![]()
github
02:03:01
mobile 下, avatar 應該要跟右側文字置中。目前這樣好像有點太低了 <https://user-images.githubusercontent.com/108608/80921817-3ff27600-8dab-11ea-959e-14a0224b806d.png|image>![]()
github
03:41:26
Actually, replies page has different filter from article page. Mockup: <https://user-images.githubusercontent.com/108608/80923827-88646080-8db8-11ea-8dea-faf365456f67.png|image> Spec: <https://g0v.hackmd.io/ZZWHWi2BTuyhkSWzAvKLAw#%E9%81%8E%E6%BF%BE%E9%81%B8%E9%A0%85%EF%BC%9A|https://g0v.hackmd.io/ZZWHWi2BTuyhkSWzAvKLAw#%E9%81%8E%E6%BF%BE%E9%81%B8%E9%A0%85%EF%BC%9A> The API for "我查核過" and reply type filtering is still on the way, but "還未有有效查核", "熱門回報" and "熱門討論" are legit `ListArticle` filters already (`hasPositiveFeedbackArticleReply`, `replyRequestCount` and `replyCount` respectively). Considering the size of this change, I think we can handle this in future PRs, may need a ticket for this.![]()
github
10:22:18
card added here: <https://github.com/orgs/cofacts/projects/5#card-37494391|https://github.com/orgs/cofacts/projects/5#card-37494391>
github
14:03:41
LGTM! Let's ship it to staging <https://github.githubassets.com/images/icons/emoji/shipit.png|:shipit:>![]()
1- ❤️1
mrorz
2020-05-04 16:25:49
Deployed to staging 🚀
yanglin
19:09:54
是說現在的 category 是透過一個環境變數決定要不要顯示
不過現在 category 功能應該已經測試過了?
可以打開了嗎?
不過現在 category 功能應該已經測試過了?
可以打開了嗎?
mrorz
19:54:45
被藏起來的是 add category 的功能
我覺得應該要藏到有訊息被 category 分好類為止(也就是資料庫裡會有一些訊息是分好類的),這樣使用者就能用這些當成例子,判斷手頭上還沒有被分類的某訊息是屬於哪一類。
分類的進度要問 @ggm
我覺得新寫介面的話就不用考慮那個 env var 了
我覺得應該要藏到有訊息被 category 分好類為止(也就是資料庫裡會有一些訊息是分好類的),這樣使用者就能用這些當成例子,判斷手頭上還沒有被分類的某訊息是屬於哪一類。
分類的進度要問 @ggm
我覺得新寫介面的話就不用考慮那個 env var 了
2020-05-05
github
02:12:43
Current implementation (puppeteer) eats up too much resource and the its throughput cannot keep up with the usage of rumors-api. We should consider other solutions as well. *Resources* Previous research: <https://github.com/cofacts/rumors-api/issues/41|cofacts/rumors-api#41> Web archiving tools by IIPC (behind wayback machine) <https://github.com/iipc/awesome-web-archiving|https://github.com/iipc/awesome-web-archiving> *Archiver* • Python + headless chrome <https://github.com/internetarchive/brozzler|https://github.com/internetarchive/brozzler> • Headless chrome <https://github.com/N0taN3rd/Squidwarc|https://github.com/N0taN3rd/Squidwarc> • Headless chrome with queue <https://github.com/yujiosaka/headless-chrome-crawler|https://github.com/yujiosaka/headless-chrome-crawler> • Save all in one html file <https://github.com/Y2Z/monolith|https://github.com/Y2Z/monolith> *Text summarization (w/ Chinese upport)* • request + newspaper3k (Python3) <https://newspaper.readthedocs.io/en/latest/|https://newspaper.readthedocs.io/en/latest/> *Misc* • Readability + readability-readarable <https://github.com/mozilla/readability#whats-readability-readerable|https://github.com/mozilla/readability#whats-readability-readerable>
yanglin
10:54:11
再麻煩你幫我 review 了🙏
chihao
14:54:53
有個關於 cofacts collected messages 的問題,如果想知道含有特定關鍵字的 collected message,推薦在這裡搜尋嗎? https://cofacts.g0v.tw/articles?filter=all 在這裡搜尋可以按照時間排序嗎?
mrorz
2020-05-05 15:21:02
1. 可以在搜尋框搜尋無誤唷!不過如果文字長一點,會有不一樣的效果。
2. 現在 UI 沒有,但之後搜尋介面下可以按照其他方式排序,也可以指定要哪個時間送進來的資料。
2. 現在 UI 沒有,但之後搜尋介面下可以按照其他方式排序,也可以指定要哪個時間送進來的資料。
chihao
2020-05-05 15:21:36
mrorz++
mrorz
2020-05-05 15:22:04
這個部分是 @yanglin5689446 實作的 ~~
mrorz
2020-05-05 15:22:33
之後的 UI 在這個 staging 上測試中
https://cofacts.hacktabl.org/search?type=messages&q=%E8%B2%BC%E5%9C%96
https://cofacts.hacktabl.org/search?type=messages&q=%E8%B2%BC%E5%9C%96
chihao
2020-05-05 15:22:36
感謝 🙌 有其他搜尋的管道嗎?我記得好像有 API 但還沒用過 😅
mrorz
2020-05-05 15:23:24
Chatbot 就是搜尋管道之一
只是 Chatbot 比對比較嚴格,差太多就會說找不到
只是 Chatbot 比對比較嚴格,差太多就會說找不到
mrorz
2020-05-05 15:23:45
網站上的搜尋功能,設定寬鬆很多,擦邊都算相似
mrorz
2020-05-05 15:24:18
GraphQL API 是 ListArticles ,filter.moreLikeThis
ggm
15:05:25
30k 篇的分類都分好了,隨時可以打回去 production
ggm
15:13:01
我其實忘記現在 category mutation API 是不是上 production 了,上了的話 @darkbtf 就可以把我們現在標的好的資料含若水標記的資料全部打回去哩
mrorz
2020-05-05 15:27:30
應該是有在 production 上
我覺得可以先把資料放進 Staging 測測
我覺得可以先把資料放進 Staging 測測
恩恩我們是預計這禮拜會打到 staging
但是 staging 和 production 的文章好像長得不一樣
就能打就打(?
mrorz
2020-05-05 16:45:30
嗯嗯
就是 staging 不存在的文章就跳過~
就是 staging 不存在的文章就跳過~
mrorz
15:21:02
1. 可以在搜尋框搜尋無誤唷!不過如果文字長一點,會有不一樣的效果。
2. 現在 UI 沒有,但之後搜尋介面下可以按照其他方式排序,也可以指定要哪個時間送進來的資料。
2. 現在 UI 沒有,但之後搜尋介面下可以按照其他方式排序,也可以指定要哪個時間送進來的資料。
chihao
15:21:36
mrorz++
mrorz
15:22:04
這個部分是 @yanglin5689446 實作的 ~~
mrorz
15:22:33
之後的 UI 在這個 staging 上測試中
https://cofacts.hacktabl.org/search?type=messages&q=%E8%B2%BC%E5%9C%96
https://cofacts.hacktabl.org/search?type=messages&q=%E8%B2%BC%E5%9C%96
chihao
15:22:36
感謝 🙌 有其他搜尋的管道嗎?我記得好像有 API 但還沒用過 😅
mrorz
15:23:24
Chatbot 就是搜尋管道之一
只是 Chatbot 比對比較嚴格,差太多就會說找不到
只是 Chatbot 比對比較嚴格,差太多就會說找不到
mrorz
15:23:45
網站上的搜尋功能,設定寬鬆很多,擦邊都算相似
mrorz
15:24:18
GraphQL API 是 ListArticles ,filter.moreLikeThis
mrorz
15:27:30
應該是有在 production 上
我覺得可以先把資料放進 Staging 測測
我覺得可以先把資料放進 Staging 測測
ggm
15:28:09
恩恩我們是預計這禮拜會打到 staging
ggm
15:28:26
但是 staging 和 production 的文章好像長得不一樣
ggm
15:28:43
就能打就打(?
yanglin
15:59:41
不知道為什麼 `GetArticle` 只要 query `requestedForReply` 就會變得很慢欸 0.0
mrorz
2020-05-05 16:46:42
會不會是因為你 get 的那篇 article 的 reply request 太多呀
mrorz
2020-05-05 16:47:56
咦不對呀
他用 userId + articleId 下去搜的話,應該只會找到 0 個或 1 個 @@
他用 userId + articleId 下去搜的話,應該只會找到 0 個或 1 個 @@
yanglin
2020-05-05 16:49:29
requestedForReply 應該只是一個布林?
mrorz
2020-05-05 16:49:52
他是即時去搜 replyrequest
yanglin
2020-05-05 16:50:23
了解
yanglin
2020-05-05 16:50:39
我只要加這個 field 就會一直轉圈圈 XD
mrorz
2020-05-05 16:50:41
他是「這個使用者有沒有按過我也想知道」
所以每個人不一樣~
所以每個人不一樣~
mrorz
2020-05-05 16:50:54
但不應該要轉很久才對
mrorz
2020-05-05 16:51:17
啊除非
你是在文章列表裡面下 `requestedForReply`
你是在文章列表裡面下 `requestedForReply`
yanglin
2020-05-05 16:51:42
我是在 `GetArticle` 下
mrorz
2020-05-05 16:52:07
怪
應該不會慢很多才對,就是多一個到 elasticsearch 撈資料的動作而已 @@
應該不會慢很多才對,就是多一個到 elasticsearch 撈資料的動作而已 @@
yanglin
2020-05-08 18:03:25
今天稍微調查了一下發現
只要加了 `requestedForReply`
Hyperlink 的 polling 就會沒有 response
導致 app 一直轉圈圈
只要加了 `requestedForReply`
Hyperlink 的 polling 就會沒有 response
導致 app 一直轉圈圈
mrorz
2020-05-08 18:38:49
怪了,為什麼會跟 hyperlink 有關 QQ
yanglin
2020-05-08 18:40:36
我也不太確定 我之後再試試看
我現在是在 Article details 的頁面的 GetArticle query 新增 就會
我現在是在 Article details 的頁面的 GetArticle query 新增 就會
mrorz
2020-05-14 12:13:55
我發現 5/4 更新 staging API 成 https://github.com/cofacts/rumors-api/pull/153 的版本之後,5/5 @yanglin5689446 就回報問題
朝 API 裡面 elasticsearch result 沒接好的方向調查 ing
朝 API 裡面 elasticsearch result 沒接好的方向調查 ing
mrorz
2020-05-14 14:19:44
結果不是 elasticsearch result 沒接好
而是
1. 一般來說,跟使用者相關的 object field 如 `ownVote` 等等,在沒有指定 userId (如:SSR) 時,會直接回傳 null。然而, `requestedForReply` 錯誤地使用了只有 mutation API 該用的 `assertUser({...})` ,所以只要有 requestedForReply 就會產生 error。
而是
1. 一般來說,跟使用者相關的 object field 如 `ownVote` 等等,在沒有指定 userId (如:SSR) 時,會直接回傳 null。然而, `requestedForReply` 錯誤地使用了只有 mutation API 該用的 `assertUser({...})` ,所以只要有 requestedForReply 就會產生 error。
mrorz
2020-05-14 14:21:02
mrorz
2020-05-14 14:22:16
2. 我們用的 apollo-link-error 如果有 exception 的話,他就會無聲無息地悶不吭聲,讓後面的 apollo-client resolve 一整個卡住。我是在 `BatchHttpLink` 與 `onError` 中間插了一個印 console 的 link 才能抓到那個 error。
目前我們的 `onError` 裡頭用了 `alert()`,在 NodeJS 環境下並無此 function,所以他其實應該在 runtime 時遇到了 Reference error,但卻無聲無息。
目前我們的 `onError` 裡頭用了 `alert()`,在 NodeJS 環境下並無此 function,所以他其實應該在 runtime 時遇到了 Reference error,但卻無聲無息。
mrorz
2020-05-14 15:48:31
至於 apollo-link-error 把 runtime error 吃掉這件事情,我在 codesandbox 上卻無法重現
https://codesandbox.io/s/awesome-shamir-vpf2d?file=/index.js
https://codesandbox.io/s/awesome-shamir-vpf2d?file=/index.js
mrorz
2020-05-14 15:50:01
看起來 error 有好好地被抓出來 @@
mrorz
16:45:30
嗯嗯
就是 staging 不存在的文章就跳過~
就是 staging 不存在的文章就跳過~
mrorz
16:46:42
會不會是因為你 get 的那篇 article 的 reply request 太多呀
mrorz
16:47:56
咦不對呀
他用 userId + articleId 下去搜的話,應該只會找到 0 個或 1 個 @@
他用 userId + articleId 下去搜的話,應該只會找到 0 個或 1 個 @@
yanglin
16:49:29
requestedForReply 應該只是一個布林?
mrorz
16:49:52
他是即時去搜 replyrequest
mrorz
16:50:13
``` requestedForReply: { type: GraphQLBoolean, description: 'If the current user has requested for reply for this article', resolve: async ({ id }, args, { userId, appId, loaders }) => { assertUser({ userId, appId }); const userReplyRequests = await loaders.searchResultLoader.load({ index: 'replyrequests', body: { query: { bool: { must: [{ term: { userId } }, { term: { articleId: id } }], }, }, }, }); return userReplyRequests && userReplyRequests.length > 0; }, }, ```
yanglin
16:50:23
了解
yanglin
16:50:39
我只要加這個 field 就會一直轉圈圈 XD
mrorz
16:50:41
他是「這個使用者有沒有按過我也想知道」
所以每個人不一樣~
所以每個人不一樣~
mrorz
16:50:54
但不應該要轉很久才對
mrorz
16:51:17
啊除非
你是在文章列表裡面下 `requestedForReply`
你是在文章列表裡面下 `requestedForReply`
yanglin
16:51:42
我是在 `GetArticle` 下
mrorz
16:52:07
怪
應該不會慢很多才對,就是多一個到 elasticsearch 撈資料的動作而已 @@
應該不會慢很多才對,就是多一個到 elasticsearch 撈資料的動作而已 @@
stbb1025
17:11:03
@lucien @mrorz發佈查核闢謠的時候,資料來源是一定要附上的嗎?還是可以空白?或是不硬性規定但平台這邊會希望使用者附上資料來源?
mrorz
2020-05-05 17:12:15
只有「不在查證範圍」可以不用附來源,否則原則上是一定要附。
但過去也有些人亂打哎哎
但過去也有些人亂打哎哎
lucien
2020-05-05 17:24:29
我覺得我們可以實驗看看改成一定要附上
lucien
2020-05-05 17:25:51
就算是他自己打電話去確認,他也要附註他自己去電話查核的時間跟紀錄,所以應該會有文字記錄
stbb1025
2020-05-05 17:28:54
水
stbb1025
2020-05-05 17:29:14
這樣我mobile比較好設計
lucien
2020-05-05 17:29:35
不在查證範圍 是一定沒有來源欄位的
lucien
2020-05-05 17:29:56
比較有爭議是個人意見,到底要不要給來源
lucien
2020-05-05 17:30:14
個人意見找反例有時候會非常困難
mrorz
2020-05-05 17:32:07
我覺得個人意見還是要有欄位讓他填「不同意見」
就算只是佐證自己在回應裡講的材料也好
只是這就不是嚴格的「不同意見出處」
就算只是佐證自己在回應裡講的材料也好
只是這就不是嚴格的「不同意見出處」
mrorz
17:12:15
只有「不在查證範圍」可以不用附來源,否則原則上是一定要附。
但過去也有些人亂打哎哎
但過去也有些人亂打哎哎
mrorz
17:15:46
lucien
17:24:29
我覺得我們可以實驗看看改成一定要附上
stbb1025
17:28:54
水
stbb1025
17:29:14
這樣我mobile比較好設計
lucien
17:29:35
不在查證範圍 是一定沒有來源欄位的
lucien
17:29:56
比較有爭議是個人意見,到底要不要給來源
lucien
17:30:14
個人意見找反例有時候會非常困難
mrorz
17:32:07
我覺得個人意見還是要有欄位讓他填「不同意見」
就算只是佐證自己在回應裡講的材料也好
只是這就不是嚴格的「不同意見出處」
就算只是佐證自己在回應裡講的材料也好
只是這就不是嚴格的「不同意見出處」
github
22:11:51
We can use this so that the translators don't need to handle the triangles: ``` ({expanded ? t`Show Less` + ' ▲' : t`Show More` + ' ▼'}) ``` or ``` ({expanded ? `${t`Show Less`} ▲` : `${t`Show More`} ▼`}) ```
github
22:38:00
Not sure why, but there are some weird cases that need to trace code to figure out why <https://user-images.githubusercontent.com/108608/81078431-cf6d6580-8f20-11ea-9f84-6179c4ba4342.png|image> The article content is `555`. Can be found by searching `555` in page. Other similar scenario are: <https://user-images.githubusercontent.com/108608/81078509-ec099d80-8f20-11ea-8040-4ee1f7cccce0.png|image> <https://user-images.githubusercontent.com/108608/81078549-fd52aa00-8f20-11ea-94b4-6f2fef72861e.png|image>![]()
github
23:02:05
Blocked by <https://github.com/storybookjs/storybook/issues/10631|storybookjs/storybook#10631>
github
23:12:40
I suggest adding the component to storybook so that we can get visual documentation & snapshot testing
2020-05-06
mrorz
00:16:01
mrorz
2020-05-06 12:22:22
請問 @yanglin5689446 今天晚上有空線上會議嗎~
今天晚上 @stbb1025 會與 @lucien 討論 UI (detail page mobile 版),也想問問你有沒有什麼想當面問的
時間大概會是 @lucien 到場的時間(8pm~11pm 之間的不知道什麼時間)
今天晚上 @stbb1025 會與 @lucien 討論 UI (detail page mobile 版),也想問問你有沒有什麼想當面問的
時間大概會是 @lucien 到場的時間(8pm~11pm 之間的不知道什麼時間)
yanglin
2020-05-06 12:35:28
可以喔
lucien
2020-05-06 19:00:55
今天我可以線上會議嗎?
mrorz
2020-05-06 19:33:57
可
lucien
2020-05-06 19:55:52
我大概九點
stbb1025
2020-05-06 21:13:41
開始叫我唷
lucien
2020-05-06 21:13:57
我正在使用 tico
lucien
2020-05-06 21:14:03
毫無反應
stbb1025
2020-05-06 21:19:37
@lucien 你不見了
github
01:16:18
Update: 1. abort LIFF on desktop <https://camo.githubusercontent.com/425d8a29fc7b947ffbbc9ca790a714c00c0ee8eb/68747470733a2f2f73332d61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f6730762d6861636b6d642d696d616765732f75706c6f6164732f75706c6f61645f32353230343736353734383931643233303762643131343533326165323237372e676966|https://camo.githubusercontent.com/425d8a29fc7b947ffbbc9ca790a714c00c0ee8eb/68747470733a2f2f73332d61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f6730762d6861636b6d642d696d616765732f75706c6f6164732f75706c6f61645f32353230343736353734383931643233303762643131343533326165323237372e676966> 2. explicitly tell user that we have recorded their feedback (regardless of them inputting the reason or not) in LIFF <https://camo.githubusercontent.com/59a3074d175f7d205d2e1eafaacb6c92f2a04171/68747470733a2f2f73332d61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f6730762d6861636b6d642d696d616765732f75706c6f6164732f75706c6f61645f62313061303365653566333061623433323163323437386161316634663735342e706e67|https://camo.githubusercontent.com/59a3074d175f7d205d2e1eafaacb6c92f2a04171/68747470733a2f2f73332d61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f6730762d6861636b6d642d696d616765732f75706c6f6164732f75706c6f61645f62313061303365653566333061623433323163323437386161316634663735342e706e67>![]()
github
01:57:25
As discussed in <https://g0v.hackmd.io/@mrorz/BksBf58KI#%E9%80%81%E5%87%BA-source-%E8%88%87-reason-%E5%BE%8C%E7%9A%84%E8%A8%8A%E6%81%AF%E9%87%8D%E8%A4%87%E5%95%8F%E9%A1%8C|https://g0v.hackmd.io/@mrorz/BksBf58KI#%E9%80%81%E5%87%BA-source-%E8%88%87-reason-%E5%BE%8C%E7%9A%84%E8%A8%8A%E6%81%AF%E9%87%8D%E8%A4%87%E5%95%8F%E9%A1%8C> This PR turns the 2 bubbles after LIFF response into carousel to make it more compact, hopefully the message will not overwhelm the user. <https://user-images.githubusercontent.com/108608/81098815-790e2000-8f3c-11ea-8c1d-d2917421ab65.png|image> Note that • In response to source (first carousel), both bubble are all call-to-actions (we want user to both provide more info and share) • In response to reason (2nd carousel), not many people updates their own reason, thus use gray color instead; also, the update bubble is moved to the right (2nd bubble).![]()
github
01:59:45
*Pull Request Test Coverage Report for <https://coveralls.io/builds/30576473|Build 771>* • *2* of *2* *(100.0%)* changed or added relevant lines in *2* files are covered. • No unchanged relevant lines lost coverage. • Overall coverage increased (+*0.02%*) to *98.652%* * * * * * * *:yellow_heart: - <https://coveralls.io|Coveralls>*
github
09:23:09
nonumpa
2020-05-06 09:33:34
Draft 也會抓出來啊 😦
mrorz
2020-05-06 11:16:54
ready to review 會再一次 XDD
nonumpa
09:33:34
Draft 也會抓出來啊 😦
github
11:11:40
this seems like the old behavior of original commit, but I rebase the commit, it should look like these now: <https://user-images.githubusercontent.com/12843409/81135340-5276d600-8f8a-11ea-806c-b92fbfde2c68.png|截圖 2020-05-06 上午11 10 29> <https://user-images.githubusercontent.com/12843409/81135343-560a5d00-8f8a-11ea-873a-99dba391476d.png|截圖 2020-05-06 上午11 10 14>![]()
mrorz
11:16:54
ready to review 會再一次 XDD
github
11:20:18
It seems that it only happens on specific articles that has only 1 line, and the line is super short, on desktop. You can search for `555` on <https://cofacts.hacktabl.org/replies|staging> to see the following sample <https://user-images.githubusercontent.com/108608/81135607-72f36000-8f8b-11ea-975b-7a81433e250a.png|image>![]()
yanglin
2020-05-06 11:52:28
@mrorz 因為我有 rebase 然後改掉原本的 commit
所以可能跟之前 deploy 到 staging 得不太一樣
可能要再 deploy 一次試試
目前我這看起來是好的(如 comment 的附圖)
所以可能跟之前 deploy 到 staging 得不太一樣
可能要再 deploy 一次試試
目前我這看起來是好的(如 comment 的附圖)
mrorz
2020-05-06 12:36:40
感謝,確認正常
yanglin
11:52:28
@mrorz 因為我有 rebase 然後改掉原本的 commit
所以可能跟之前 deploy 到 staging 得不太一樣
可能要再 deploy 一次試試
目前我這看起來是好的(如 comment 的附圖)
所以可能跟之前 deploy 到 staging 得不太一樣
可能要再 deploy 一次試試
目前我這看起來是好的(如 comment 的附圖)
mrorz
12:22:22
Replied to a thread: 2020-05-06 00:16:01
請問 @yanglin5689446 今天晚上有空線上會議嗎~
今天晚上 @stbb1025 會與 @lucien 討論 UI (detail page mobile 版),也想問問你有沒有什麼想當面問的
時間大概會是 @lucien 到場的時間(8pm~11pm 之間的不知道什麼時間)
今天晚上 @stbb1025 會與 @lucien 討論 UI (detail page mobile 版),也想問問你有沒有什麼想當面問的
時間大概會是 @lucien 到場的時間(8pm~11pm 之間的不知道什麼時間)
mrorz
12:36:40
感謝,確認正常
mrorz
12:59:25
Replied to a thread: 2020-05-04 01:13:01
這個變更太多了,為了找出有沒有問題
我先把它放到 staging 上跑跑看囉
如果大家最近打 staging API 出問題請提出,說不定是這個 PR 的問題
我先把它放到 staging 上跑跑看囉
如果大家最近打 staging API 出問題請提出,說不定是這個 PR 的問題
- 👍2
github
14:14:23
New article details page UI <https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO/Cofacts-website?node-id=681%3A0|mockup>
ggm
17:33:34
@darkbtf 留意個
lucien
19:00:55
今天我可以線上會議嗎?
github
19:21:33
But `null` and `undefined` are different in mongodb. For example ``` db.collection('inventory').find({ item: null }); ``` ``` db.collection('inventory').find({ item: { $exists: false } }); ``` I'm not sure there is any effect in the future, so I choose the precise defines.
mrorz
19:33:57
可
lucien
19:55:52
我大概九點
stbb1025
21:13:41
開始叫我唷
lucien
21:13:57
我正在使用 tico
lucien
21:14:03
毫無反應
mrorz
21:15:16
@lucien @stbb1025 我們是不是換個 Jitsi 才有聲音呀
這裡都白白看不到你們
這裡都白白看不到你們
stbb1025
21:15:35
我跟@lucien 可以通話
lucien
21:16:24
我跟 nick 一國
stbb1025
21:16:33
yeah
mrorz
21:18:51
@yanglin5689446 我們在這裡開會
https://tico.chat/powercall?room=cofactshack&type=timeFirst
https://tico.chat/powercall?room=cofactshack&type=timeFirst
tico.chat
The considerate messenger. Chat with whom you care about always at the best moments and times![]()
stbb1025
21:19:37
@lucien 你不見了
lucien
21:19:53
我聽得到各位
lucien
21:20:03
你們聽不到我
lucien
21:42:08
mrorz
21:50:20
mrorz
21:53:36
from yang: https://stackoverflow.com/questions/43833049/how-to-make-fixed-content-go-above-ios-keyboard
Stack Overflow
I can only find questions where people have the opposite problem. I want my fixed content to go above the iOS keyboard. Image of the problem: I want iOS to behave like Android. Is there a simpl...
mrorz
21:54:45
Pixel 2: Top 與 Bottom 在鍵盤出現時都會出現
iPhone X: 整個螢幕往上推,top 會被推不見,bottom 仍然黏著
iPhone X: 整個螢幕往上推,top 會被推不見,bottom 仍然黏著
mrorz
22:02:08
@yanglin5689446 FYI: 從我們的 analytics 做的手機上的 browser version 統計
https://g0v.hackmd.io/@mrorz/rksKX45D8#LIFF-compatibility
https://g0v.hackmd.io/@mrorz/rksKX45D8#LIFF-compatibility
HackMD
20200408 會議紀錄 ===== > Workis: MrOrz, bil, lucien > 線上:志超 > 線上開會:<https://tico.chat/powercall?room=>
github
22:11:06
Hi all, I really enjoy your works with cofacts chatbot. I can easily distinguish the truth of messages from my parents, that is reeeally good. However, there is a feature that I need is not in the current version. The feature I need is `sharing the results to other chat rooms`, such as my parent's private message or family channel etc. Thanks for your effort. You are the best.
mrorz
22:17:43
material-ui.com
Tabs make it easy to explore and switch between different views.
mrorz
23:13:01
Material design menu
https://material-ui.com/components/menus/
https://material-ui.com/components/menus/
material-ui.com
Menus display a list of choices on temporary surfaces.
2020-05-07
mrorz
00:06:59
LINE bot 的新流程在 staging 囉
大家可以打開手機到 staging 玩玩看
staging 這邊請:https://lin.ee/1QUzEX4nI
跟上週不太一樣的地方有:
1. 阻擋桌面版點出 LIFF
2. 修改理由與分享 flex message 的排列
3. 按下「有用」/「沒用」後的 LIFF 告知使用者已經紀錄 voting
PR 堆得很高 :books: 我想如果 PR 放一個月都沒人看的話,就要包裹通過囉 .__.
https://github.com/cofacts/rumors-line-bot/pulls
大家可以打開手機到 staging 玩玩看
staging 這邊請:https://lin.ee/1QUzEX4nI
跟上週不太一樣的地方有:
1. 阻擋桌面版點出 LIFF
2. 修改理由與分享 flex message 的排列
3. 按下「有用」/「沒用」後的 LIFF 告知使用者已經紀錄 voting
PR 堆得很高 :books: 我想如果 PR 放一個月都沒人看的話,就要包裹通過囉 .__.
https://github.com/cofacts/rumors-line-bot/pulls
github
00:10:31
Yeah I know about the `$exists`. But if you declare a field to be any type that is not null, say, a string, can you still assign `null` to that field?
github
00:54:16
Hi <https://github.com/shrimp509|@shrimp509> it's glad to see the chatbot helps :) If you feel like sharing the results from Cofacts to other chatrooms, you may either 1. long-press the reply and choose "share". After that you can select multiple messages to share (usually the reason and the references provided by the editor) and then choose the target chatrooms. 2. When the chatbot asks if the reply is useful, reply "yes". The chatbot will then encourage you to share this reply with friends. Option 2 works like this: <https://user-images.githubusercontent.com/108608/81205116-d23d8880-8ffc-11ea-9a15-fb2cd86e87b8.png|Screenshot_20200507-004353_2> <https://user-images.githubusercontent.com/108608/81205127-d5387900-8ffc-11ea-819c-a0b28bb97ef4.png|Screenshot_20200507-004411> We designed this flow because we really needs the user's feedback on usefulness of a reply, and we don't want to ask user to share a reply if they think it's not useful in the first place.![]()
github
09:06:57
Got it!! I didn't notice the share button after choosing one of the results. Thanks for your detail explanation of why you design like this. I understand your consideration. Thank you again.
github
11:54:33
If `process.env.IMAGE_MESSAGE_ENABLED` is not true, image messages will not be tracked. Maybe we can extract this along with <https://github.com/cofacts/rumors-line-bot/blob/7a93a085e75e9d3ac1bcd8018b4a1625e4353bdf/src/webhook/index.js#L168|index.js L168>, <https://github.com/cofacts/rumors-line-bot/blob/7a93a085e75e9d3ac1bcd8018b4a1625e4353bdf/src/webhook/index.js#L179|index.js L179> to the beginning of <https://github.com/cofacts/rumors-line-bot/blob/7a93a085e75e9d3ac1bcd8018b4a1625e4353bdf/src/webhook/index.js#L83|process message>.
mrorz
12:22:22
@ggm 關於這個呀 https://github.com/cofacts/rumors-line-bot/pull/182/files/d03bb7533c63264eb241b4cee08548df6fa050df#discussion_r418464972
我有看到你後來把 _id 拿掉,_不過我當時想討論的其實是為什麼要放 `_id`, `userId`, `articleId` 等等欄位進 model,但沒看到有 code 在存取這些欄位。
我有看到你後來把 _id 拿掉,_不過我當時想討論的其實是為什麼要放 `_id`, `userId`, `articleId` 等等欄位進 model,但沒看到有 code 在存取這些欄位。
mrorz
2020-05-07 12:23:42
我已經滿久沒有在用類似這樣的 ORM / Active record pattern 的介面了,通常就是 get 一個物件,呼叫 update 或 insert 也都是直接呼叫 client 傳一個物件進去,沒有在 `obj.save()` 這樣。
lucien
2020-05-07 12:30:46
_id 是 mongodb 預設會有的欄位,在top level schema我記得是拿不掉的
mrorz
2020-05-07 12:36:08
我在說的是像這個檔案
src/database/models/userArticleLink.js
我可以理解用 static method 來把此種 model 相關的 DB operation 收納在一個 class 裡面,但我不知道為什麼會有 L70 開始的下面那些 field,因為目前好像沒有人會去存取這些 field。
他看起來像是預留給 ORM 機制,
也就是之後會有人從資料庫讀出來之後灌進 `UserArticleLink` instance 用的,或有人未來會 `new UserArticleLink` 然後填資料進去。
src/database/models/userArticleLink.js
我可以理解用 static method 來把此種 model 相關的 DB operation 收納在一個 class 裡面,但我不知道為什麼會有 L70 開始的下面那些 field,因為目前好像沒有人會去存取這些 field。
他看起來像是預留給 ORM 機制,
也就是之後會有人從資料庫讀出來之後灌進 `UserArticleLink` instance 用的,或有人未來會 `new UserArticleLink` 然後填資料進去。
mrorz
2020-05-07 12:46:59
還是 GGM 寫下面那些 field,其實是為了 typing? 像這樣:
噢我原本要解釋打到一半睡著 XD
拿掉 `_id` 是因為整個過程中我們都不會需要 `_id` ,所以不需要對 `_id` 做 verify
然後另外那些變數是 class public field declarations,現階段了作用是為了給開發者看說這個 class 會有這個欄位,以及要給 jsdoc 看有這個定義
跟 ORM 其實比較無關,是為了 typing,當我呼叫 `findOrInsertByUserId` 取得實體之後我會有這個 `newReplyNotifyToken` property
mrorz
2020-05-07 12:52:53
了解,所以是 for type definition
不透過 class 做的話,另外寫 jsdoc 要另外
```@typedef {Object} UserSettings```
```@typedef {Object} UserSettings```
然後再寫一些
```@property```
這樣
```@property```
這樣
mrorz
2020-05-07 12:53:38
對對
lucien
2020-05-07 12:56:09
但這邊只是給 jsdoc 對吧
mrorz
2020-05-07 12:59:45
我自己之前接觸過的 repo 其實也大多是以另外寫 type 為主,API function 呼叫時,再去使用那些 type。
利用 class field type definition 來把 typing 與 API 結構放在一起是第一次看到
利用 class field type definition 來把 typing 與 API 結構放在一起是第一次看到
然後存取的部分應該會發生在後面,譬如拿 `newReplyNotifyToken` 出來用,或判斷時間要送推播的時候
用 typescript 當然就可以把 type 抽出來呀
mrorz
2020-05-07 13:04:05
但「把 type 抽出來」這種 pattern,在 JSDoc 裡相對應的語法,就是你不想用的 `@typedef`
mrorz
2020-05-07 13:06:51
我以為你用 class 是想說之後如果轉 typescript 也直接用 typescript class 無痛(?)轉
對啊這也是
mrorz
2020-05-07 13:08:02
雖然 typescript 其實會抱怨說這些 field 沒有 initializer,不過那也是之後轉 typescript 再來研究就好的事 (茶
lucien
2020-05-07 13:10:06
我覺得這樣寫法蠻奇怪的
lucien
2020-05-07 13:10:37
看起來應該要有 factory 去產你要的結構
我覺得 class field type definition 會比寫 jsdoc 還具體還好用,在 typescript 也用得到,到時候就把 `@type {boolean}` 這個換掉就好
lucien
2020-05-07 13:10:57
現在兩個放在一起,就會有這樣的問題
為什麼會像是要用 factory 生成呀?
mrorz
2020-05-07 13:12:09
GGM 484 覺得這些寫 JS 的人都很喜歡 factory pattern
像這個討論串:https://g0v-tw.slack.com/archives/C2PPMRQGP/p1588333070310900
像這個討論串:https://g0v-tw.slack.com/archives/C2PPMRQGP/p1588333070310900
我覺得沒那麼複雜啦 XD
像這個簡單的例子,就是一個 Rectangle 裡面有 height 和 width 這樣而已
mrorz
2020-05-07 13:15:05
我覺得有點像是習慣差異耶
從 C++ / Java 來的人很直覺會想說 type definition 放在 class 很清楚
但大家 Javascript 導入 Typescript 的過程與 mind model,開發者心裡想的其實是,typing 是一種幫我檢查資料形狀的「外掛」
從 C++ / Java 來的人很直覺會想說 type definition 放在 class 很清楚
但大家 Javascript 導入 Typescript 的過程與 mind model,開發者心裡想的其實是,typing 是一種幫我檢查資料形狀的「外掛」
mrorz
2020-05-07 13:16:38
所以 JS developer 會直覺的使用 JS 常用的手段,例如 export object literal 出去當 API、用 thunk 解決呼叫時間問題等等,然後再用 type 去 “annotate” 這些 expose 出去的 API
最主要的目的就是想要透過 class 來描述我從 database (mongo) 拿出來有哪些欄位
mrorz
2020-05-07 13:18:27
另外一個比較意識形態的問題是,Javascript 社群有拒C文化 (這裏的 C 是 class),比較擁抱 fp⋯⋯ XD
es6 出了 class,越來越 js 專案轉 ts,typescript 也有完整的 class,我覺得抗拒 C 文化倒是很難說⋯
其實不用 class 也是寫一堆
```Object.defineProperty```
```A.prototype.oooxxx```
之類的東西呀其實
```Object.defineProperty```
```A.prototype.oooxxx```
之類的東西呀其實
lucien
2020-05-07 13:23:36
Typescript 我覺得很 class
真怪怎麼沒有變色 XD
lucien
2020-05-07 13:23:58
尤其開始用reflect metadata之後
mrorz
2020-05-07 13:32:13
嗯嗯
我只是想解釋為什麼我跟 Lucien 會針對 code 裡用到 class 的不同的地方,都下意識地提出說可以用 factory 解的原因
因為學校裡有教的確實是比較偏 OOP 的習慣,所以我也很好奇我什麼時候 pickup 了這種 JS 的思維
我只是想解釋為什麼我跟 Lucien 會針對 code 裡用到 class 的不同的地方,都下意識地提出說可以用 factory 解的原因
因為學校裡有教的確實是比較偏 OOP 的習慣,所以我也很好奇我什麼時候 pickup 了這種 JS 的思維
lucien
2020-05-07 13:56:08
把工廠跟產出物放在同一個class會導致你沒辦法在 constructor init 產出物的property
lucien
2020-05-07 13:56:35
你進typescript之後會很難處理
lucien
2020-05-07 13:57:10
Mongo orm 會用 model 跟 document 分別描述這兩個東西
工廠其實是 static function (method) 為什麼會影響 constructor init ?
怎麼描述的做法我覺得都有,像是 `loopback 3` 是用分開描述有點像我現在寫的這樣,有一個 .json 另一個 .js,`loopback 4` 則是寫在一個檔案描述,不過他就導入 typescript 了
然後 `sailsjs` 就是把工廠和產出物寫在一起,譬如 `People.create()` 和 `people.save()` 之類的,透過 static function 切開
mrorz
2020-05-07 14:23:43
其實我覺得 `UserArticleLink` 這個 class 好像並不是設計給人 `new` 的,之後有 private constructor 的時候可能一樣要擋起來,跟 `CofactsMongoClient` 一樣
mrorz
12:23:42
我已經滿久沒有在用類似這樣的 ORM / Active record pattern 的介面了,通常就是 get 一個物件,呼叫 update 或 insert 也都是直接呼叫 client 傳一個物件進去,沒有在 `obj.save()` 這樣。
lucien
12:30:46
_id 是 mongodb 預設會有的欄位,在top level schema我記得是拿不掉的
mrorz
12:36:08
我在說的是像這個檔案
src/database/models/userArticleLink.js
我可以理解用 static method 來把此種 model 相關的 DB operation 收納在一個 class 裡面,但我不知道為什麼會有 L70 開始的下面那些 field,因為目前好像沒有人會去存取這些 field。
他看起來像是預留給 ORM 機制,
也就是之後會有人從資料庫讀出來之後灌進 `UserArticleLink` instance 用的,或有人未來會 `new UserArticleLink` 然後填資料進去。
src/database/models/userArticleLink.js
我可以理解用 static method 來把此種 model 相關的 DB operation 收納在一個 class 裡面,但我不知道為什麼會有 L70 開始的下面那些 field,因為目前好像沒有人會去存取這些 field。
他看起來像是預留給 ORM 機制,
也就是之後會有人從資料庫讀出來之後灌進 `UserArticleLink` instance 用的,或有人未來會 `new UserArticleLink` 然後填資料進去。
ggm
12:47:00
噢我原本要解釋打到一半睡著 XD
ggm
12:49:55
然後另外那些變數是 class public field declarations,現階段了作用是為了給開發者看說這個 class 會有這個欄位,以及要給 jsdoc 看有這個定義
- 👌1
ggm
12:51:55
跟 ORM 其實比較無關,是為了 typing,當我呼叫 `findOrInsertByUserId` 取得實體之後我會有這個 `newReplyNotifyToken` property
mrorz
12:52:53
了解,所以是 for type definition
ggm
12:52:58
不透過 class 做的話,另外寫 jsdoc 要另外
```@typedef {Object} UserSettings```
```@typedef {Object} UserSettings```
ggm
12:53:32
然後再寫一些
```@property```
這樣
```@property```
這樣
mrorz
12:53:38
對對
lucien
12:56:09
但這邊只是給 jsdoc 對吧
mrorz
12:59:45
我自己之前接觸過的 repo 其實也大多是以另外寫 type 為主,API function 呼叫時,再去使用那些 type。
利用 class field type definition 來把 typing 與 API 結構放在一起是第一次看到
利用 class field type definition 來把 typing 與 API 結構放在一起是第一次看到
ggm
13:00:52
然後存取的部分應該會發生在後面,譬如拿 `newReplyNotifyToken` 出來用,或判斷時間要送推播的時候
ggm
13:02:06
用 typescript 當然就可以把 type 抽出來呀
mrorz
13:04:05
但「把 type 抽出來」這種 pattern,在 JSDoc 裡相對應的語法,就是你不想用的 `@typedef`
mrorz
13:06:51
我以為你用 class 是想說之後如果轉 typescript 也直接用 typescript class 無痛(?)轉
ggm
13:06:58
對啊這也是
mrorz
13:08:02
雖然 typescript 其實會抱怨說這些 field 沒有 initializer,不過那也是之後轉 typescript 再來研究就好的事 (茶
lucien
13:10:06
我覺得這樣寫法蠻奇怪的
lucien
13:10:37
看起來應該要有 factory 去產你要的結構
ggm
13:10:53
我覺得 class field type definition 會比寫 jsdoc 還具體還好用,在 typescript 也用得到,到時候就把 `@type {boolean}` 這個換掉就好
lucien
13:10:57
現在兩個放在一起,就會有這樣的問題
ggm
13:11:39
為什麼會像是要用 factory 生成呀?
mrorz
13:12:09
GGM 484 覺得這些寫 JS 的人都很喜歡 factory pattern
像這個討論串:https://g0v-tw.slack.com/archives/C2PPMRQGP/p1588333070310900
像這個討論串:https://g0v-tw.slack.com/archives/C2PPMRQGP/p1588333070310900
Johnson Liang
@ggm PR review 囉,請過目
https://github.com/cofacts/rumors-line-bot/pull/182
mongoClient 的實作我覺得有些太複雜了,abstraction 也有點怪 QQ
- Forwarded from #cofacts
- 2020-05-01 19:37:50
ggm
13:12:43
我覺得沒那麼複雜啦 XD
ggm
13:13:08
MDN Web Docs
JavaScript classes, introduced in ECMAScript 2015, are primarily syntactical sugar over JavaScript's existing prototype-based inheritance. The class syntax does not introduce a new object-oriented inheritance model to JavaScript.
ggm
13:14:04
像這個簡單的例子,就是一個 Rectangle 裡面有 height 和 width 這樣而已
mrorz
13:15:05
我覺得有點像是習慣差異耶
從 C++ / Java 來的人很直覺會想說 type definition 放在 class 很清楚
但大家 Javascript 導入 Typescript 的過程與 mind model,開發者心裡想的其實是,typing 是一種幫我檢查資料形狀的「外掛」
從 C++ / Java 來的人很直覺會想說 type definition 放在 class 很清楚
但大家 Javascript 導入 Typescript 的過程與 mind model,開發者心裡想的其實是,typing 是一種幫我檢查資料形狀的「外掛」
mrorz
13:16:38
所以 JS developer 會直覺的使用 JS 常用的手段,例如 export object literal 出去當 API、用 thunk 解決呼叫時間問題等等,然後再用 type 去 “annotate” 這些 expose 出去的 API
ggm
13:17:15
最主要的目的就是想要透過 class 來描述我從 database (mongo) 拿出來有哪些欄位
mrorz
13:18:27
另外一個比較意識形態的問題是,Javascript 社群有拒C文化 (這裏的 C 是 class),比較擁抱 fp⋯⋯ XD
ggm
13:21:21
es6 出了 class,越來越 js 專案轉 ts,typescript 也有完整的 class,我覺得抗拒 C 文化倒是很難說⋯
ggm
13:23:35
其實不用 class 也是寫一堆
```Object.defineProperty```
```A.prototype.oooxxx```
之類的東西呀其實
```Object.defineProperty```
```A.prototype.oooxxx```
之類的東西呀其實
lucien
13:23:36
Typescript 我覺得很 class
ggm
13:23:53
真怪怎麼沒有變色 XD
lucien
13:23:58
尤其開始用reflect metadata之後
mrorz
13:32:13
嗯嗯
我只是想解釋為什麼我跟 Lucien 會針對 code 裡用到 class 的不同的地方,都下意識地提出說可以用 factory 解的原因
因為學校裡有教的確實是比較偏 OOP 的習慣,所以我也很好奇我什麼時候 pickup 了這種 JS 的思維
我只是想解釋為什麼我跟 Lucien 會針對 code 裡用到 class 的不同的地方,都下意識地提出說可以用 factory 解的原因
因為學校裡有教的確實是比較偏 OOP 的習慣,所以我也很好奇我什麼時候 pickup 了這種 JS 的思維
- 👍1
lucien
13:56:08
把工廠跟產出物放在同一個class會導致你沒辦法在 constructor init 產出物的property
lucien
13:56:35
你進typescript之後會很難處理
lucien
13:57:10
Mongo orm 會用 model 跟 document 分別描述這兩個東西
ggm
14:16:17
工廠其實是 static function (method) 為什麼會影響 constructor init ?
ggm
14:21:31
怎麼描述的做法我覺得都有,像是 `loopback 3` 是用分開描述有點像我現在寫的這樣,有一個 .json 另一個 .js,`loopback 4` 則是寫在一個檔案描述,不過他就導入 typescript 了
ggm
14:22:58
然後 `sailsjs` 就是把工廠和產出物寫在一起,譬如 `People.create()` 和 `people.save()` 之類的,透過 static function 切開
mrorz
14:23:43
其實我覺得 `UserArticleLink` 這個 class 好像並不是設計給人 `new` 的,之後有 private constructor 的時候可能一樣要擋起來,跟 `CofactsMongoClient` 一樣
- 👍1
github
14:57:47
Yes, if using mongodb ``` $> db.ppl.insert({phoneNumber: null}) WriteResult({ "nInserted" : 1 }) $> db.ppl.insert({phoneNumber: '0912'}) WriteResult({ "nInserted" : 1 }) $> db.ppl.find() { "_id" : ObjectId("5eb3ad6a9a5e1f8e59885998"), "phoneNumber" : null } { "_id" : ObjectId("5eb3ad739a5e1f8e59885999"), "phoneNumber" : "0912" } ``` There are 2 options: 1. [require=true] Should be exist, then string or null 2. [require=false] It would be string or undefined (not exists) But I think yours is better to be less verbose first, and then update if need.
github
15:02:23
btw, If we follow option 1, then we can query easily ``` db.collection('inventory').find({ itemA: null, itemB: 'book' }); ``` Not sure if it's important for now
github
15:10:55
Hmm if I want to find a document that has one field that does not exist, the first idea that comes to my mind would be `{itemA: {$exists: false}}`, did not think of testing `null` in the first place. The syntax also mixes well with other conditions in place (i.e. `{itemA: {$exists: false}, itemB: 'book'}`). Slightly longer than the `null` version, but I think its occurrence in codebase should be less than field definitions.
github
15:15:29
Seems that json schema we are currently using _does_ block non-required fields from being set to `null`. <https://user-images.githubusercontent.com/108608/81265339-824ed800-9075-11ea-8365-a52860f545f6.png|image>![]()
github
15:21:44
On the other hand, one draw back (?) of using non-required fields would be that it's a bit counterintuitive when we want to set a field conditionally, for instance, ``` const person = { name: 'foo', ...(revealGender ? {gender: input} : {}) } ``` Setting everything to required + allow null for some fields forces us to specify all fields, but is easier (?) to set conditional content: ``` const person = { name: 'foo', gender: revealGender ? input : null, bloodType: null, weight: null, height: null, birthday: null } ```
github
15:31:17
> Seems that json schema we are currently using _does_ block non-required fields from being set to `null`. You are not using the current one ? Should be use `oneOf` in your demo case ?
github
15:44:37
> Hmm if I want to find a document that has one field that does not exist, the first idea that comes to my mind would be `{itemA: {$exists: false}}`, did not think of testing `null` in the first place. I'm not sure that is the first idea. There are different usages in different situations. Let's talk about `newReplyNotifyToken` if it's expired or not working or something. I want to set to be `null`, not `undefined`, and find those documents by using `null` not `{$exists: false}`
github
15:45:55
In the demo case I am testing if jsonschema can block `null` when it's assigned to non-required fields. Personally I think we should either stick to (a) field not-required + can't be null, or (b) all-field-required + can be null, not a mixture of (a) and (b). While the current code is in (b), in the demonstration I was trying to show that (a) also works as exptected.
github
19:11:55
Interesting aspect of `newReplyNotifyToken`, didn't think of that. When `newReplyNotifyToken` is expired, I would ask the user if they want to delete the token. If they say yes, we invoke `db.collection('userArticleLinks').update({$unset: {newReplyNotifyToken: ''}})`. That's indeed longer than setting `newReplyNotifyToken` to `null`.
2020-05-08
mrorz
00:59:19
因為最近會跟其他有興趣實作 Cofacts 的組織接觸,所以更新了一下 developer homepage:
https://hackmd.io/@mrorz/r1nfwTrgM
裡面有
• 更新的系統架構圖
• 更新的 DB index 圖 https://g0v.hackmd.io/@mrorz/S1caurZq8
• 新畫的 ER Model 圖https://g0v.hackmd.io/@mrorz/S1caurZq8
希望這樣對新開發者有助益~
https://hackmd.io/@mrorz/r1nfwTrgM
裡面有
• 更新的系統架構圖
• 更新的 DB index 圖 https://g0v.hackmd.io/@mrorz/S1caurZq8
• 新畫的 ER Model 圖https://g0v.hackmd.io/@mrorz/S1caurZq8
希望這樣對新開發者有助益~
HackMD
【Cofacts 真的假的】Homepage for Developers ====== ## Source codes Cofacts is comprised of several com
- 👍1
mrorz
01:29:22
另外,因為今天 @darkbtf 問到關於 userId / appId 的問題,我覺得應該要把 Cofacts 系統的 userId / appId 機制給寫下來:
https://g0v.hackmd.io/ZcoUOX_-RQSkJyl5xz4_Zg
文件還沒寫完,之後會需要討論說,未來要擴充的話要怎麼處理的細節。
https://g0v.hackmd.io/ZcoUOX_-RQSkJyl5xz4_Zg
文件還沒寫完,之後會需要討論說,未來要擴充的話要怎麼處理的細節。
- 👍1
yanglin
12:29:21
@mrorz 視覺化搜尋趨勢那邊可能需要資料 api
mrorz
2020-05-08 12:29:39
對對那個要補
mrorz
2020-05-11 14:15:40
Will track in https://github.com/cofacts/rumors-api/issues/166
szeming
13:35:45
@szeming has joined the channel
yanglin
18:03:25
今天稍微調查了一下發現
只要加了 `requestedForReply`
Hyperlink 的 polling 就會沒有 response
導致 app 一直轉圈圈
只要加了 `requestedForReply`
Hyperlink 的 polling 就會沒有 response
導致 app 一直轉圈圈
yu_tainan
18:20:20
@ytyubox has joined the channel
mrorz
18:38:49
怪了,為什麼會跟 hyperlink 有關 QQ
yanglin
18:40:36
我也不太確定 我之後再試試看
我現在是在 Article details 的頁面的 GetArticle query 新增 就會
我現在是在 Article details 的頁面的 GetArticle query 新增 就會
2020-05-09
nonumpa
00:15:01
https://g0v.hackmd.io/eIeU2g86Tfu5VnLazNfUvQ#資料表:UserSettings
問個問題,我們會讓使用者同時使用 Line Notify 和 Push Api 嗎
還是會直接從 server 端就決定要用哪種?
兩個都開好像沒什麼意義,功能一樣(雖然 Line notify 可以選擇傳到別的聊天室,但通知訊息主要是針對使用者查過的訊息,預期使用者不會這樣用。)
問個問題,我們會讓使用者同時使用 Line Notify 和 Push Api 嗎
還是會直接從 server 端就決定要用哪種?
兩個都開好像沒什麼意義,功能一樣(雖然 Line notify 可以選擇傳到別的聊天室,但通知訊息主要是針對使用者查過的訊息,預期使用者不會這樣用。)
mrorz
2020-05-09 03:43:01
Hmm 做成 server 端(用 env vars)決定好像比較簡單齁
mrorz
2020-05-09 03:43:47
我們可能英文版與 staging 用 LINE notify (畢竟也沒付費帳號)
localhost 與 production 用 Push API
localhost 與 production 用 Push API
nonumpa
00:35:24
第二個問題,Line notify 我想要做成打開通知就 link,關掉通知就 revoke token,這樣做比較簡單
不然我們除了開關通知可能還要另外做一個 link/revoke 的功能
但其實點了 revoke 就等於關閉通知,點了開啟通知就等於要 link
(關閉通知可以不用 revoke,link 可以不用開啟通知)
不然我們除了開關通知可能還要另外做一個 link/revoke 的功能
但其實點了 revoke 就等於關閉通知,點了開啟通知就等於要 link
(關閉通知可以不用 revoke,link 可以不用開啟通知)
mrorz
2020-05-09 03:53:00
好呀就這樣辦~
mrorz
03:43:01
Hmm 做成 server 端(用 env vars)決定好像比較簡單齁
mrorz
03:53:00
好呀就這樣辦~
hoyang
08:42:01
@hoyangtsai has joined the channel
github
14:03:11
*Pull Request Test Coverage Report for <https://coveralls.io/builds/30669027|Build 787>* • *59* of *62* *(95.16%)* changed or added relevant lines in *5* files are covered. • No unchanged relevant lines lost coverage. • Overall coverage decreased (*-0.5%*) to *96.177%* * * * * * * *:yellow_heart: - <https://coveralls.io|Coveralls>*
ggm
15:04:16
我 rebase dev 之後,跑 test 會噴這個
``` PASS src/lib/__tests__/gql.js
● Console
console.error src/lib/gql.js:53
GraphQL operation contains error: [ { message: 'Runtime error' } ]```
``` PASS src/lib/__tests__/gql.js
● Console
console.error src/lib/gql.js:53
GraphQL operation contains error: [ { message: 'Runtime error' } ]```
mrorz
2020-05-11 14:14:00
Pass 的話不用理~
那個是在測 error handling 嗎?
那個是在測 error handling 嗎?
ggm
15:04:22
要理他嗎?
github
16:14:09
The vertical spacing is imbalanced <https://user-images.githubusercontent.com/108608/81465180-95d77b80-91fa-11ea-8dd5-63061579f71f.png|image> I suggest adding negative bottom margin to `ul.articleList` to undo the bottom margin of `ArticleItem`. Of course other solutions also apply (such as removing the bottom margin for last `ArticleItem` using `:last-child`), but we should still manage the margin of `ul.articleList`; it is still having the default margin defined by the browser. <https://user-images.githubusercontent.com/108608/81465177-87895f80-91fa-11ea-8af7-664d4a0d4b08.png|image>![]()
github
16:14:09
Instead of using `refetch` that cleans up `listArticlesData`, please consider leveraging `fetchMore` which allows us to describe how new data is appended to `listArticlesData` using `updateQuery()`. In this way we don't need to maintain a separate state `articleEdges`. Reference: <https://www.apollographql.com/docs/react/data/pagination/|https://www.apollographql.com/docs/react/data/pagination/> Introductory post: <https://www.apollographql.com/blog/pagination-and-infinite-scrolling-in-apollo-client-59ff064aac61|https://www.apollographql.com/blog/pagination-and-infinite-scrolling-in-apollo-client-59ff064aac61> Also, we don't need to store `nextCursor` in separate state; we can just get the cursor from the last edge in the data. Lastly, the current implementation does not preserve the page if the user enters a detail page from the list and hit back to return. We hope that using `fetchMore` could solve the current issue, since apollo-cache should reserve the items loaded so far and next-router should manage the scroll position.
github
16:14:09
If we leverage `loadMore` and get cursor from last edge directly in `ArticlePageLayout`, we can leave the pagination logic entirely in where pagination happens, reduce the props passed to `LoadMore`. Personally I think `onClick` and `loading` should be enough; we can even detect if we reached the last page outside of `<LoadMore>`.
github
16:14:09
It's a good try of changing the pagination into infinite load. I think we can • leverage `loadMore` instead of `refetch` and see if it helps with preserving pages when user navigates from detail page back to list page. • reduce the props passed to `LoadMore` as we encapsulate pagination logic in the component that uses `LoadMore`.
github
23:29:50
LGTM! Thanks for your patience and the explanation, very inspiring. It seems that it is possible to further simplify the logic of `MongoClient.getInstance()`, see the comment below.
mrorz
2020-05-12 10:49:05
@ggm 有 conflict 唷
也可以參考一下我的 Comment ~
也可以參考一下我的 Comment ~
真怪我之前有 rebase 了說,我又 rebase 然後 push 囉
github
23:29:50
Seems that this is equivalent to: ``` // It returns promise anyway, no need for async in this function. // If we want to hint that this returns a promise, just use JSDoc `@returns {Promise<CofactsMongoClient>}` static getInstance() { // combines set-by-default and default setting return this._instance = this._instance || (async () => { const client = new CofactsMongoClient(MONGODB_URI); await client.mongoClient.connect(); return client; })(); } ``` Giving the async arrow function a good name can further improve its readability: ``` // Somewhere outside the class: // async function instantiateClientAndConnect() { const client = new CofactsMongoClient(MONGODB_URI); await client.mongoClient.connect(); return client; } // Then, back to inside the class, the code is super easy to understand now: // static getInstance() { return this._instance = this._instance || instantiateClientAndConnect(); } ```
mrorz
2020-05-12 10:49:05
@ggm 有 conflict 唷
也可以參考一下我的 Comment ~
也可以參考一下我的 Comment ~
真怪我之前有 rebase 了說,我又 rebase 然後 push 囉
2020-05-10
github
01:32:17
Fix this error: old version of articleCategories is null, instead of being initialized to empty list. ``` { "errors": [ { "message": "illegal_argument_exception", "locations": [ { "line": 2, "column": 3 } ], "path": [ "CreateArticleCategory" ], "extensions": { "code": "INTERNAL_SERVER_ERROR", "exception": { "name": "ResponseError", "meta": { "body": { "error": { "root_cause": [ { "type": "remote_transport_exception", "reason": "[VxKgRte][127.0.0.1:9300][indices:data/write/update[s]]" } ], "type": "illegal_argument_exception", "reason": "failed to execute script", "caused_by": { "type": "script_exception", "reason": "runtime error", "script_stack": [ "found = ctx._source.articleCategories.stream()\n .filter(", " ^---- HERE" ], "script": "\n def found = ctx._source.articleCategories.stream()\n .filter(ar -> ar.get('categoryId').equals(params.articleCategory.get('categoryId')))\n .findFirst();\n\n if (found.isPresent()) {\n HashMap ar = found.get();\n if (ar.get('status').equals('DELETED')) {\n ar.put('status', 'NORMAL');\n ar.put('userId', 'model_test');\n ar.put('appId', 'DEVELOPMENT_BACKEND');\n ar.put('updatedAt', '2020-05-07T11:56:48.759Z');\n } else {\n ctx.op = 'none';\n }\n } else {\n ctx._source.articleCategories.add(params.articleCategory);\n ctx._source.normalArticleCategoryCount = ctx._source.articleCategories.stream().filter(\n ar -> ar.get('status').equals('NORMAL')\n ).count();\n }\n ", "lang": "painless", "caused_by": { "type": "null_pointer_exception", "reason": null } } }, "status": 400 }, "statusCode": 400, "headers": { "content-type": "application/json; charset=UTF-8", "content-length": "1401" }, "warnings": null, "meta": { "context": null, "request": { "params": { "method": "POST", "path": "/articles/doc/zzyt710qo56u/_update", "body": "{\"script\":{\"source\":\"\\n def found = ctx._source.articleCategories.stream()\\n .filter(ar -> ar.get('categoryId').equals(params.articleCategory.get('categoryId')))\\n .findFirst();\\n\\n if (found.isPresent()) {\\n HashMap ar = found.get();\\n if (ar.get('status').equals('DELETED')) {\\n ar.put('status', 'NORMAL');\\n ar.put('userId', 'model_test');\\n ar.put('appId', 'DEVELOPMENT_BACKEND');\\n ar.put('updatedAt', '2020-05-07T11:56:48.759Z');\\n } else {\\n ctx.op = 'none';\\n }\\n } else {\\n ctx._source.articleCategories.add(params.articleCategory);\\n ctx._source.normalArticleCategoryCount = ctx._source.articleCategories.stream().filter(\\n ar -> ar.get('status').equals('NORMAL')\\n ).count();\\n }\\n \",\"lang\":\"painless\",\"params\":{\"articleCategory\":{\"userId\":\"model_test\",\"appId\":\"DEVELOPMENT_BACKEND\",\"aiModel\":\"bert\",\"aiConfidence\":1,\"positiveFeedbackCount\":0,\"negativeFeedbackCount\":0,\"categoryId\":\"mD2n7nEBrIRcahlYLAr7\",\"status\":\"NORMAL\",\"createdAt\":\"2020-05-07T11:56:48.759Z\",\"updatedAt\":\"2020-05-07T11:56:48.759Z\"}}},\"_source\":[\"articleCategories.*\"]}", "querystring": "", "headers": { "User-Agent": "elasticsearch-js/6.8.6 (linux 4.4.0-137-generic-x64; Node.js v12.14.1)", "Content-Type": "application/json", "Content-Length": "1269" }, "timeout": 30000 }, "options": { "warnings": null }, "id": 89085 }, "name": "elasticsearch-js", "connection": { "url": "<http://cofacts-db-staging:9200/>", "id": "<http://cofacts-db-staging:9200/>", "headers": {}, "deadCount": 0, "resurrectTimeout": 0, "_openRequests": 0, "status": "alive", "roles": { "master": true, "data": true, "ingest": true, "ml": false } }, "attempts": 0, "aborted": false } } } }, "authError": false } ], "data": { "CreateArticleCategory": null } } which can be reproduced by this mutation: ``` mutation { CreateArticleCategory( articleId: "zzyt710qo56u" categoryId: "mD2n7nEBrIRcahlYLAr7" aiModel: "bert" aiConfidence: 1.0 ) { articleId categoryId } }
liao.jason2
11:11:36
@liao.jason2 has joined the channel
liao.jason2
11:11:36
@liao.jason2 has joined the channel
github
15:47:07
LGTM! It works on staging, I think we can <https://github.githubassets.com/images/icons/emoji/shipit.png|:shipit:>![]()
github
16:37:11
Please `npm run lint:fix` first. <https://travis-ci.org/github/cofacts/rumors-site/builds/684561774|https://travis-ci.org/github/cofacts/rumors-site/builds/684561774>
github
16:38:13
Suggest adding `copyBtnRef.current`, `content` and `onClick` to dependency array • Adding `copyBtnRef.current` is for the case when DOM of the the button is reconstructed, the `ClipboardJS` instance should be bound to the new DOM element instead. • Adding `content` and `onClick` is to prevent the case when these props are updated, ClipboardJS is still connecting to old callbacks that access an old JS closure.
github
16:55:57
Deploying to production • Backup: `gcs/2020-05-10-before-migration` • Migrated at: TBD *1st round* ``` 16:59 ≎ ~/workspace/rumors-db ➠ npx babel-node db/migrations/202005-add-article-categories.js ResponseError: Response Error at IncomingMessage.<anonymous> (/Users/mrorz/workspace/rumors-db/node_modules/@elastic/elasticsearch/lib/Transport.js:296:25) at IncomingMessage.emit (events.js:205:15) at IncomingMessage.EventEmitter.emit (domain.js:471:20) at endReadableNT (_stream_readable.js:1137:12) at processTicksAndRejections (internal/process/task_queues.js:84:9) { name: 'ResponseError', meta: { body: { took: 4641, timed_out: false, total: 36068, updated: 3577, deleted: 0, batches: 4, version_conflicts: 423, noops: 0, retries: [Object], throttled_millis: 0, requests_per_second: -1, throttled_until_millis: 0, failures: [Array] }, statusCode: 409, headers: { 'content-type': 'application/json; charset=UTF-8', 'content-length': '133674' }, warnings: null, meta: { context: null, request: [Object], name: 'elasticsearch-js', connection: [Object], attempts: 1, aborted: false } } } ```
github
17:35:55
This PR: • tells elasticsearch to do nothing when `articleCategories` exists • log everything when error occurs • log response when success
mrorz
2020-05-10 17:37:27
@darkbtf 麻煩看一下
我小改了一下 migration
改完之後想說在 production 再重跑一次
我小改了一下 migration
改完之後想說在 production 再重跑一次
mrorz
2020-05-10 18:22:51
mrorz
2020-05-10 18:23:52
沒有指定 op = ‘noop’ 的話是不是會無差別寫入呀
mrorz
2020-05-10 18:24:44
第一次完全沒 `noop` ,但最新的 Articles 應該都要有 articleCategories
mrorz
17:37:27
@darkbtf 麻煩看一下
我小改了一下 migration
改完之後想說在 production 再重跑一次
我小改了一下 migration
改完之後想說在 production 再重跑一次
mrorz
18:22:51
Deploying to production • Backup: `gcs/2020-05-10-before-migration` • Migrated at: TBD *1st round* ``` 16:59 ≎ ~/workspace/rumors-db ➠ npx babel-node db/migrations/202005-add-article-categories.js ResponseError: Response Error at IncomingMessage.<anonymous> (/Users/mrorz/workspace/rumors-db/node_modules/@elastic/elasticsearch/lib/Transport.js:296:25) at IncomingMessage.emit (events.js:205:15) at IncomingMessage.EventEmitter.emit (domain.js:471:20) at endReadableNT (_stream_readable.js:1137:12) at processTicksAndRejections (internal/process/task_queues.js:84:9) { name: 'ResponseError', meta: { body: { took: 4641, timed_out: false, total: 36068, updated: 3577, deleted: 0, batches: 4, version_conflicts: 423, noops: 0, retries: [Object], throttled_millis: 0, requests_per_second: -1, throttled_until_millis: 0, failures: [Array] }, statusCode: 409, headers: { 'content-type': 'application/json; charset=UTF-8', 'content-length': '133674' }, warnings: null, meta: { context: null, request: [Object], name: 'elasticsearch-js', connection: [Object], attempts: 1, aborted: false } } } ``` *2nd round* ``` 18:20 ≎ ~/workspace/rumors-db ➠ npx babel-node db/migrations/202005-add-article-categories.js { body: { took: 3650, timed_out: false, total: 36068, updated: 0, deleted: 0, batches: 37, version_conflicts: 0, noops: 36068, retries: { bulk: 0, search: 0 }, throttled_millis: 0, requests_per_second: -1, throttled_until_millis: 0, failures: [] }, statusCode: 200, headers: { 'content-type': 'application/json; charset=UTF-8', 'content-length': '239' }, warnings: null, meta: { context: null, request: { params: [Object], options: [Object], id: 1 }, name: 'elasticsearch-js', connection: { url: '<http://localhost:62222/>', id: '<http://localhost:62222/>', headers: {}, deadCount: 0, resurrectTimeout: 0, _openRequests: 0, status: 'alive', roles: [Object] }, attempts: 0, aborted: false } } ```
mrorz
18:23:52
沒有指定 op = ‘noop’ 的話是不是會無差別寫入呀
mrorz
18:24:44
第一次完全沒 `noop` ,但最新的 Articles 應該都要有 articleCategories
mrorz
18:28:53
關於「過去查過的訊息列表」的細節實作,規劃寫在這裡,請大家過目 @acerxp511 @lucien :
https://g0v.hackmd.io/eIeU2g86Tfu5VnLazNfUvQ?both#Implementation-detail-2020510
主要要討論的東西有:
• 會新增一種 LIFF <> Chatbot GraphQL 的認證方式
• 如何用 google analytics utm_source 追蹤後續動作是來自「過去查過的訊息列表」的操作、並且記錄「過去查過的訊息列表」是「從 rich menu 點開」的還是「從 push message 點開」的
https://g0v.hackmd.io/eIeU2g86Tfu5VnLazNfUvQ?both#Implementation-detail-2020510
主要要討論的東西有:
• 會新增一種 LIFF <> Chatbot GraphQL 的認證方式
• 如何用 google analytics utm_source 追蹤後續動作是來自「過去查過的訊息列表」的操作、並且記錄「過去查過的訊息列表」是「從 rich menu 點開」的還是「從 push message 點開」的
- 👌1
2020-05-11
Sam Ho
09:54:55
@rongson has joined the channel
mrorz
13:13:41
Google search console 說下面這兩個頁面的點擊次數與上個月相比增加最多(+7.37K)
https://cofacts.g0v.tw/article/ui2q0uicd96a
https://cofacts.g0v.tw/article/u4qohr84huax
看來網友對把草莓插在樹上的影片很有興趣
https://cofacts.g0v.tw/article/ui2q0uicd96a
https://cofacts.g0v.tw/article/u4qohr84huax
看來網友對把草莓插在樹上的影片很有興趣
mrorz
13:33:38
不過說到 Google,上週 Cofacts 配合 Youtube API Services Team 的 audit 調查,對方表示 Cofacts 在下面兩點不合格:
1. 沒有在 Privacy 與 ToS 中提及 Youtube ToS - Policy #: III.A.1,2
2. 沒有每 30 天就重新更新爬到的 non-authorized 資料 - Policy #: III.E.4.a-g
1. 沒有在 Privacy 與 ToS 中提及 Youtube ToS - Policy #: III.A.1,2
2. 沒有每 30 天就重新更新爬到的 non-authorized 資料 - Policy #: III.E.4.a-g
mrorz
2020-05-11 13:35:11
mrorz
2020-05-11 13:42:06
2 的部分就就滿討厭的,不只技術上很煩,也會影響 Cofacts 的使用——一但原始謠言影片被下架,30 天內資料庫被強制更新,那個影片的 title 與 description 就會被洗掉。
我在 audit 時給的例子就很明顯,謠言本體剛好是個被下架的影片,拿另一個被重新上架的影片去查,還能查到對應的訊息:https://docs.google.com/document/d/1hlFszsLV9uUJl17L40o6AGZVtyAEoTcLA76wSz969QI/edit
(註: 步驟裡的那個 query 影片之前還活著,大概最近幾天也下架了⋯⋯)
Cofacts 之所以製作 URL preview,其中一個目的就是為了保存訊息被回報的當下,連結裡面的內容,以供未來查詢比對。如果要求我們每 30 天要更新,效果會大打折扣,以上面這個 COVID-19 陰謀論的例子來說,甚至會影響到 COVID-19 的防疫。
不知道大家有沒有什麼想法呢?
我在 audit 時給的例子就很明顯,謠言本體剛好是個被下架的影片,拿另一個被重新上架的影片去查,還能查到對應的訊息:https://docs.google.com/document/d/1hlFszsLV9uUJl17L40o6AGZVtyAEoTcLA76wSz969QI/edit
(註: 步驟裡的那個 query 影片之前還活著,大概最近幾天也下架了⋯⋯)
Cofacts 之所以製作 URL preview,其中一個目的就是為了保存訊息被回報的當下,連結裡面的內容,以供未來查詢比對。如果要求我們每 30 天要更新,效果會大打折扣,以上面這個 COVID-19 陰謀論的例子來說,甚至會影響到 COVID-19 的防疫。
不知道大家有沒有什麼想法呢?
mrorz
13:42:06
Replied to a thread: 2020-05-11 13:33:38
2 的部分就就滿討厭的,不只技術上很煩,也會影響 Cofacts 的使用——一但原始謠言影片被下架,30 天內資料庫被強制更新,那個影片的 title 與 description 就會被洗掉。
我在 audit 時給的例子就很明顯,謠言本體剛好是個被下架的影片,拿另一個被重新上架的影片去查,還能查到對應的訊息:https://docs.google.com/document/d/1hlFszsLV9uUJl17L40o6AGZVtyAEoTcLA76wSz969QI/edit
(註: 步驟裡的那個 query 影片之前還活著,大概最近幾天也下架了⋯⋯)
Cofacts 之所以製作 URL preview,其中一個目的就是為了保存訊息被回報的當下,連結裡面的內容,以供未來查詢比對。如果要求我們每 30 天要更新,效果會大打折扣,以上面這個 COVID-19 陰謀論的例子來說,甚至會影響到 COVID-19 的防疫。
不知道大家有沒有什麼想法呢?
我在 audit 時給的例子就很明顯,謠言本體剛好是個被下架的影片,拿另一個被重新上架的影片去查,還能查到對應的訊息:https://docs.google.com/document/d/1hlFszsLV9uUJl17L40o6AGZVtyAEoTcLA76wSz969QI/edit
(註: 步驟裡的那個 query 影片之前還活著,大概最近幾天也下架了⋯⋯)
Cofacts 之所以製作 URL preview,其中一個目的就是為了保存訊息被回報的當下,連結裡面的內容,以供未來查詢比對。如果要求我們每 30 天要更新,效果會大打折扣,以上面這個 COVID-19 陰謀論的例子來說,甚至會影響到 COVID-19 的防疫。
不知道大家有沒有什麼想法呢?
github
14:10:34
As discussed in <https://g0v-slack-archive.g0v.ronny.tw/index/channel/C2PPMRQGP/2020-05#ts-1588494165.332500|Slack>, we are adding this to `ListArticleFilter`: ``` articleReplyFrom: { userId: String, appId: String, exists: Boolean } ``` In order to filter out articles that • contains my reply (for "我查核過" filter in reply (actually replied _article_) list) • does not contain my reply (for <https://g0v.hackmd.io/iJm9_nZaTA2GyInn7ycxoA|navbar "for you" numbering>) • contains a certain user's reply • contains no certain user's reply Relates to • <https://github.com/cofacts/rumors-api/issues/60|#60> • <https://github.com/cofacts/rumors-api/issues/35|#35> • <https://github.com/cofacts/rumors-site/pull/247#discussion_r419149777|cofacts/rumors-site#247 (comment)>
mrorz
14:14:00
Pass 的話不用理~
那個是在測 error handling 嗎?
那個是在測 error handling 嗎?
github
14:15:34
Article should provide a field that returns analytics data for trend charts using <https://developers.google.com/analytics/devguides/reporting/core/v4|Google Analytics Reporting API> • Chatbot visit per day • Chatbot user count per day • Chatbot total visit in 30 days • Chatbot total user in 30 days • All above stats, but using Cofacts production site as target Related: • <https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO?node-id=889:306#25950845|https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO?node-id=889:306#25950845>
mrorz
14:15:40
Will track in https://github.com/cofacts/rumors-api/issues/166
Article should provide a field that returns analytics data for trend charts using <https://developers.google.com/analytics/devguides/reporting/core/v4|Google Analytics Reporting API> Related: • <https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO?node-id=889:306#25950845|https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO?node-id=889:306#25950845>
github
18:03:12
I eventually remove the LoadMore component and leverage the whole component to `AarticlePageLayout`, because with only `onClick` & `loading` the LoadMore component seems similar to regular button, the actual logics are mostly move to `ArticlePageLayout`, it's a bit strange to have a Component call `LoadMore` while the actual load-more logics are written in upper component.
2020-05-12
github
02:21:21
Sorry, I forgot to consider the case when there is no "next" button: <https://user-images.githubusercontent.com/108608/81596572-e4ea0000-93f6-11ea-9841-4d63cce39514.png|image> (It's fine in mobile, though; it's just that floating action buttons are covering the last item)![]()
github
02:21:21
Thanks for the modification! When clicking into detail pages & back out, the scroll position and previously loaded pages all worked like a charm. Spotted some minor styling issue, not a blocker though.
mrorz
10:49:05
@ggm 有 conflict 唷
也可以參考一下我的 Comment ~
也可以參考一下我的 Comment ~
mrorz
10:59:05
Now on staging:
• API: https://github.com/cofacts/rumors-api/pull/153
• Website: dev branch (infinte scroll pending,稍晚 deploy)
• Chatbot: https://github.com/cofacts/rumors-line-bot/pull/184 (連環 7 PR 的最後一個,還有 4 個沒人 review)
我週三想要把這些都推上 production 來收 user feedback,比較能知道目前為止的這些大變動,有哪些需要改進的地方。推上去之後可能會有一兩週的 error 爆炸期。
網站、chatbot 的 error quota 還有滿多的,我覺得可以接得住 error。
• Staging site: https://cofacts.hacktabl.org/articles
• Staging line bot: https://lin.ee/1QUzEX4nI
大家覺得如何呢?有什麼 release blocker 嗎?
• API: https://github.com/cofacts/rumors-api/pull/153
• Website: dev branch (infinte scroll pending,稍晚 deploy)
• Chatbot: https://github.com/cofacts/rumors-line-bot/pull/184 (連環 7 PR 的最後一個,還有 4 個沒人 review)
我週三想要把這些都推上 production 來收 user feedback,比較能知道目前為止的這些大變動,有哪些需要改進的地方。推上去之後可能會有一兩週的 error 爆炸期。
網站、chatbot 的 error quota 還有滿多的,我覺得可以接得住 error。
• Staging site: https://cofacts.hacktabl.org/articles
• Staging line bot: https://lin.ee/1QUzEX4nI
大家覺得如何呢?有什麼 release blocker 嗎?
mrorz
2020-05-12 11:13:06
我是覺得 staging 的東西放一陣子了,都沒有人有啥意見,就算去 Facebook 社團請人到 staging 點一點,也應該不會有什麼人試。
早晚都要上 production,不如就直接放上去,才能收到真實的 feedback 或抱怨~
早晚都要上 production,不如就直接放上去,才能收到真實的 feedback 或抱怨~
mrorz
2020-05-12 11:19:23
我想有一種做法是
production 放上 staging 的版本、保留原本 production 的 image,如果有很嚴重的問題的話就隨時 revert back 到原本的 production
production 放上 staging 的版本、保留原本 production 的 image,如果有很嚴重的問題的話就隨時 revert back 到原本的 production
mrorz
2020-05-12 11:20:36
如果沒問題的話就 merge 這些 PR、build 正式的 docker image label (其實 staging 跟 production 的 docker image 根本是同一份 code,只是 label 不同,並沒有 build-time config⋯⋯)
lucien
2020-05-12 14:05:07
全民公測可能也不錯
mrorz
2020-05-13 13:16:38
我今天會把 chatbot 與網站英文翻中文
不過還是注意到一些網站的 release blocker:
• ~Article detail 裡的 upvote / downvote 已經被更新為新樣式,但是他是壞的(component prop breaking change?)~ PR249 中已修正
• 文章列表至少應該要有「熱門回報」filter,亦即現在 production 上的「僅顯示兩個回報以上」的功能
• 「等你來答」目前 filter 跟 spec 不符,功能跟 article list 預設目前一致
我覺得至少以上三點要修正,release 比較有意義 @@
Spec 與 mockup 放在:
https://g0v.hackmd.io/0xqZVqKiSYaIeSYFtT5NRg?view#Versions--release-scope
不過還是注意到一些網站的 release blocker:
• ~Article detail 裡的 upvote / downvote 已經被更新為新樣式,但是他是壞的(component prop breaking change?)~ PR249 中已修正
• 文章列表至少應該要有「熱門回報」filter,亦即現在 production 上的「僅顯示兩個回報以上」的功能
• 「等你來答」目前 filter 跟 spec 不符,功能跟 article list 預設目前一致
我覺得至少以上三點要修正,release 比較有意義 @@
Spec 與 mockup 放在:
https://g0v.hackmd.io/0xqZVqKiSYaIeSYFtT5NRg?view#Versions--release-scope
mrorz
2020-05-13 15:49:37
@lucien 針對 chatbot 的連環 PR,現況是
• 我的 PR 會與 GGM database 的部分有 conflict,先 merge 一個進去會比較好處理
• 尚未 review 的 PR 就算有東西要改,在過長的連環 PR 底下要改也很麻煩
我建議我的 chatbot PR 先全部 merge,有問題之後另外開 PR,這樣比較能 unblock 之後的開發與 deploy?
cc/ @ggm @acerxp511
• 我的 PR 會與 GGM database 的部分有 conflict,先 merge 一個進去會比較好處理
• 尚未 review 的 PR 就算有東西要改,在過長的連環 PR 底下要改也很麻煩
我建議我的 chatbot PR 先全部 merge,有問題之後另外開 PR,這樣比較能 unblock 之後的開發與 deploy?
cc/ @ggm @acerxp511
nonumpa
2020-05-13 16:12:40
我投先 merge 一票
conflict 我修掉哩
先 merge ok
全民公測也 ok
mrorz
2020-05-13 20:07:49
@acerxp511 @ggm dev merge 完囉,請把你們的 branch rebase 到最新的 dev
感謝感謝
感謝感謝
mrorz
11:13:06
我是覺得 staging 的東西放一陣子了,都沒有人有啥意見,就算去 Facebook 社團請人到 staging 點一點,也應該不會有什麼人試。
早晚都要上 production,不如就直接放上去,才能收到真實的 feedback 或抱怨~
早晚都要上 production,不如就直接放上去,才能收到真實的 feedback 或抱怨~
mrorz
11:19:23
我想有一種做法是
production 放上 staging 的版本、保留原本 production 的 image,如果有很嚴重的問題的話就隨時 revert back 到原本的 production
production 放上 staging 的版本、保留原本 production 的 image,如果有很嚴重的問題的話就隨時 revert back 到原本的 production
mrorz
11:20:36
如果沒問題的話就 merge 這些 PR、build 正式的 docker image label (其實 staging 跟 production 的 docker image 根本是同一份 code,只是 label 不同,並沒有 build-time config⋯⋯)
lucien
14:05:07
全民公測可能也不錯
2020-05-13
mrorz
11:16:24
lucien
2020-05-13 14:32:10
Coscup我們能報哪一個議程呀
mrorz
2020-05-13 15:18:41
@lucien 已經截止囉。有個 open source chatbot track,但我變不出跟去年不同的內容,所以沒投。
mrorz
13:16:38
Replied to a thread: 2020-05-12 10:59:05
我今天會把 chatbot 與網站英文翻中文
不過還是注意到一些網站的 release blocker:
• ~Article detail 裡的 upvote / downvote 已經被更新為新樣式,但是他是壞的(component prop breaking change?)~ PR249 中已修正
• 文章列表至少應該要有「熱門回報」filter,亦即現在 production 上的「僅顯示兩個回報以上」的功能
• 「等你來答」目前 filter 跟 spec 不符,功能跟 article list 預設目前一致
我覺得至少以上三點要修正,release 比較有意義 @@
Spec 與 mockup 放在:
https://g0v.hackmd.io/0xqZVqKiSYaIeSYFtT5NRg?view#Versions--release-scope
不過還是注意到一些網站的 release blocker:
• ~Article detail 裡的 upvote / downvote 已經被更新為新樣式,但是他是壞的(component prop breaking change?)~ PR249 中已修正
• 文章列表至少應該要有「熱門回報」filter,亦即現在 production 上的「僅顯示兩個回報以上」的功能
• 「等你來答」目前 filter 跟 spec 不符,功能跟 article list 預設目前一致
我覺得至少以上三點要修正,release 比較有意義 @@
Spec 與 mockup 放在:
https://g0v.hackmd.io/0xqZVqKiSYaIeSYFtT5NRg?view#Versions--release-scope
lucien
14:32:10
Coscup我們能報哪一個議程呀
mrorz
15:18:41
@lucien 已經截止囉。有個 open source chatbot track,但我變不出跟去年不同的內容,所以沒投。
mrorz
15:30:54
現在 staging site 上的是 @yanglin5689446 在 PR-249 的內容唷
有新的 article detail:https://cofacts.hacktabl.org/article/1fiten3qki74s
有新的 article detail:https://cofacts.hacktabl.org/article/1fiten3qki74s
mrorz
2020-05-13 15:34:39
直連 article detail 會 time-out,看起來是遇到了之前 yanglin 回報的 `requestedForReply` 欄位很慢的問題
https://g0v-tw.slack.com/archives/C2PPMRQGP/p1588665581350300
https://g0v-tw.slack.com/archives/C2PPMRQGP/p1588665581350300
mrorz
2020-05-13 16:03:50
@lucien @stbb1025 實際用起來才發現,現在「寫新回應」區塊放在「現有回應」上面,可能會讓使用者以為沒有新回應,就自己寫了一個 XD
那個區塊是可以收合的嗎? wireframe 與 mockup 好像沒有標記。而且如果可以收合,也不知道如何把該區塊「合起來」。
cc/ @yanglin5689446
那個區塊是可以收合的嗎? wireframe 與 mockup 好像沒有標記。而且如果可以收合,也不知道如何把該區塊「合起來」。
cc/ @yanglin5689446
stbb1025
2020-05-13 16:05:53
咦?不是點查核闢謠才會展開嗎
mrorz
2020-05-13 16:07:20
stbb1025
2020-05-13 16:09:03
好XD我再補一下
點了之後不用關起來吧?如果照你說的情境,目前的設計他們一定是有看到下面回應才點開的
點了之後不用關起來吧?如果照你說的情境,目前的設計他們一定是有看到下面回應才點開的
lucien
2020-05-13 16:10:42
是點擊才出現
mrorz
2020-05-13 16:11:00
Hmm 那先讓他預設收合後再看看好了
mrorz
2020-05-13 16:11:39
我也是實際在網站上看了之後才發現,使用者有可能看完訊息就想回這件事情
希望預設收合之後,「現有回應」的可見度就會變高。
希望預設收合之後,「現有回應」的可見度就會變高。
yanglin
2020-05-14 08:24:38
所以寫新回應的區塊
手機版跟 PC 版一致都是點了 `查核闢謠` 按鈕之後才打開嗎?
手機版跟 PC 版一致都是點了 `查核闢謠` 按鈕之後才打開嗎?
stbb1025
2020-05-14 09:17:52
手機版會切換到新頁面唷
mrorz
2020-05-14 11:17:13
PC 與手機都是點了按鈕之後才會有查核闢謠的區塊或全版 modal
手機要不要換 URL 可以討論
換網址的話就能按手機的 back
不換網址的話可能還是要處理一下手機的 back 避免誤按(或保留現在的自動儲存功能)
手機要不要換 URL 可以討論
換網址的話就能按手機的 back
不換網址的話可能還是要處理一下手機的 back 避免誤按(或保留現在的自動儲存功能)
yanglin
2020-05-14 15:13:49
我私心覺得兩個都可以換網址一下
這樣我在做的時候可以固定網址 hot relaod 不用一直點開 XD
這樣我在做的時候可以固定網址 hot relaod 不用一直點開 XD
yanglin
2020-05-14 15:38:12
啊 不過 next router 我不熟 QQ
mrorz
2020-05-14 16:55:08
我非常懷疑 next-router 是否能做到這種 full-screen modal 換 URL 但原頁面後面的資料全數保留的事情
可以 google 一下有沒有人做過
可以 google 一下有沒有人做過
mrorz
2020-05-14 16:56:47
說不定其實可以這樣
```// pages/article/[id].js
export default DefaultArticlePage() {
// ...
return <ArticlePage showCreate={false} />
}
// pages/article/[id]/create.js
export default ArticlePageWithCreate() {
// ...
return <ArticlePage showCreate={true} />
}```
然後直接用 next-router `Link` 換頁之類的
因為是兩個相同的 component 所以或許 react reconcile 時會發現是同一個 component 所以不會重新 mount
但可能要測一下
```// pages/article/[id].js
export default DefaultArticlePage() {
// ...
return <ArticlePage showCreate={false} />
}
// pages/article/[id]/create.js
export default ArticlePageWithCreate() {
// ...
return <ArticlePage showCreate={true} />
}```
然後直接用 next-router `Link` 換頁之類的
因為是兩個相同的 component 所以或許 react reconcile 時會發現是同一個 component 所以不會重新 mount
但可能要測一下
mrorz
2020-05-14 16:59:44
雖然這樣做要小心頁面裡的所有 URL 絕對不能用相對路徑,不然 `/article/xxx` 到 `/article/xxx/create` 會導致相對路徑對歪 XD
mrorz
15:34:39
直連 article detail 會 time-out,看起來是遇到了之前 yanglin 回報的 `requestedForReply` 欄位很慢的問題
https://g0v-tw.slack.com/archives/C2PPMRQGP/p1588665581350300
https://g0v-tw.slack.com/archives/C2PPMRQGP/p1588665581350300
yanglin
不知道為什麼 `GetArticle` 只要 query `requestedForReply` 就會變得很慢欸 0.0
- Forwarded from #cofacts
- 2020-05-05 15:59:41
github
15:40:52
Deployed to <https://cofacts.hacktabl.org/articles|https://cofacts.hacktabl.org/articles> so that everyone can inspect. <https://hub.docker.com/r/cofacts/rumors-site/tags|Docker image tags>: `pr249-en` and `pr249-tw`
mrorz
15:49:37
@lucien 針對 chatbot 的連環 PR,現況是
• 我的 PR 會與 GGM database 的部分有 conflict,先 merge 一個進去會比較好處理
• 尚未 review 的 PR 就算有東西要改,在過長的連環 PR 底下要改也很麻煩
我建議我的 chatbot PR 先全部 merge,有問題之後另外開 PR,這樣比較能 unblock 之後的開發與 deploy?
cc/ @ggm @acerxp511
• 我的 PR 會與 GGM database 的部分有 conflict,先 merge 一個進去會比較好處理
• 尚未 review 的 PR 就算有東西要改,在過長的連環 PR 底下要改也很麻煩
我建議我的 chatbot PR 先全部 merge,有問題之後另外開 PR,這樣比較能 unblock 之後的開發與 deploy?
cc/ @ggm @acerxp511
mrorz
16:03:50
@lucien @stbb1025 實際用起來才發現,現在「寫新回應」區塊放在「現有回應」上面,可能會讓使用者以為沒有新回應,就自己寫了一個 XD
那個區塊是可以收合的嗎? wireframe 與 mockup 好像沒有標記。而且如果可以收合,也不知道如何把該區塊「合起來」。
cc/ @yanglin5689446
那個區塊是可以收合的嗎? wireframe 與 mockup 好像沒有標記。而且如果可以收合,也不知道如何把該區塊「合起來」。
cc/ @yanglin5689446
mrorz
16:07:20
stbb1025
16:09:03
好XD我再補一下
點了之後不用關起來吧?如果照你說的情境,目前的設計他們一定是有看到下面回應才點開的
點了之後不用關起來吧?如果照你說的情境,目前的設計他們一定是有看到下面回應才點開的
lucien
16:10:42
是點擊才出現
mrorz
16:11:00
Hmm 那先讓他預設收合後再看看好了
mrorz
16:11:39
我也是實際在網站上看了之後才發現,使用者有可能看完訊息就想回這件事情
希望預設收合之後,「現有回應」的可見度就會變高。
希望預設收合之後,「現有回應」的可見度就會變高。
stbb1025
17:55:04
今天想討論一下這樣的landing page走向o不ok?
ok的話我就繼續把後面內容做完
(這版的寬是1024)
ok的話我就繼續把後面內容做完
(這版的寬是1024)
- ❤️4
- 🐳1
- 🦒1
stbb1025
2020-05-13 17:59:25
@bil @mrorz @lucien
mrorz
2020-05-13 17:59:42
(努力想像首圖英文版怎麼處理)
mrorz
2020-05-13 17:59:57
我覺得很有趣~~
mrorz
2020-05-13 18:00:06
「大家都想知道」是最近新謠言嗎
stbb1025
2020-05-13 18:00:07
可以幫我翻譯一下嗎我就直接排XD
stbb1025
2020-05-13 18:01:46
是熱門謠言,但我想跟大家討論一下要揭露哪些訊息
mrorz
2020-05-13 18:02:57
Got a hoax in messaging app?
Was it a FAKE NEWS?
mrorz
2020-05-13 18:04:31
Got something suspicious in messaging apps?
You may:
Copy & paste the suspicious content here
[Look it UP]
Copy & paste the suspicious content here
[Look it UP]
stbb1025
2020-05-13 18:09:16
Was it a FAKE NEWS? ->我喜歡這個 ❤️
mrorz
2020-05-13 23:54:17
f-word XD
媒體是好朋友,用 f-word 感覺會讓媒體有戒心
媒體是好朋友,用 f-word 感覺會讓媒體有戒心
stbb1025
2020-05-14 12:03:57
原來有這層考量 XD
stbb1025
17:59:25
@bil @mrorz @lucien
mrorz
17:59:42
(努力想像首圖英文版怎麼處理)
mrorz
17:59:57
我覺得很有趣~~
mrorz
18:00:06
「大家都想知道」是最近新謠言嗎
stbb1025
18:00:07
可以幫我翻譯一下嗎我就直接排XD
stbb1025
18:01:46
是熱門謠言,但我想跟大家討論一下要揭露哪些訊息
ggm
18:06:05
真怪我之前有 rebase 了說,我又 rebase 然後 push 囉
ggm
18:06:40
conflict 我修掉哩
ggm
18:08:01
全民公測也 ok
stbb1025
18:09:16
Was it a FAKE NEWS? ->我喜歡這個 ❤️
mrorz
18:25:04
我剛才在整理現在 staging 與 spec 不一樣的地方,然後發現 spec 有個地方我也不太清楚。
想問 @lucien spec 的 article list(可疑訊息) 與 reply list(最新查核)的 default filter 分別是什麼呢?會有「什麼 filter 都沒有」的狀況嗎?如果「什麼 filter 都沒有」,那 article list 與 reply list 的差別會是什麼呢?
想問 @lucien spec 的 article list(可疑訊息) 與 reply list(最新查核)的 default filter 分別是什麼呢?會有「什麼 filter 都沒有」的狀況嗎?如果「什麼 filter 都沒有」,那 article list 與 reply list 的差別會是什麼呢?
mrorz
2020-05-16 13:00:00
@lucien 可以說明一下 article list(可疑訊息) 與 reply list(最新查核)的 default filter 分別是什麼呢?
lucien
2020-05-16 13:48:45
Default 沒有filter 但有 sort
mrorz
2020-05-16 15:09:00
@lucien 所以「最新查核」會顯示「尚未被回應」的文章嗎~?
https://g0v.hackmd.io/@NFi0czulSemxCM8RNSlz8Q/HJ8xT3QVU/%2FZZWHWi2BTuyhkSWzAvKLAw spec 沒說不行唷。
https://g0v.hackmd.io/@NFi0czulSemxCM8RNSlz8Q/HJ8xT3QVU/%2FZZWHWi2BTuyhkSWzAvKLAw spec 沒說不行唷。
mrorz
2020-05-16 15:21:52
所以目前也實作成了這樣,尚無回應的文章也可能會列在「最新查核」
lucien
2020-05-17 16:32:43
最新查核只會出現有查核過的文章
lucien
2020-05-17 16:33:33
一定是至少有一篇回應的
lucien
2020-05-17 16:36:27
現在最新查核也是從 article 下去 filter 而不是 reply 對嗎
lucien
2020-05-17 16:49:54
已更新
lucien
2020-05-17 16:50:29
不過這是不會出現在選項上的 filter
mrorz
2020-05-17 21:00:38
感謝更新,這可能要開一張新票來處理
目前 @yanglin5689446 實作的 `defaultFilter` 機制可能要稍微改一下,才能支援這種「不會出現在選項上、關不掉的 filter」
目前 @yanglin5689446 實作的 `defaultFilter` 機制可能要稍微改一下,才能支援這種「不會出現在選項上、關不掉的 filter」
mrorz
2020-05-17 21:04:41
(現在的 `defaultFilter` 可以被新設的 filter 覆蓋)
delightfullychaotic
21:42:15
請問開會是開完了嗎?我一直找不到連結QQ
delightfullychaotic
2020-05-13 22:00:22
結果有剛剛按個mute 就默默又沒有了== Howie真的不用負責嗎
mrorz
2020-05-13 23:52:26
但我也不知道怎麼重現 XD 他只能通靈
mrorz
2020-05-13 23:53:31
或許我們的 powercall room 很有靈氣
比較容易重現 bug
你可以跟他約在那個 room
說不定就能重現
比較容易重現 bug
你可以跟他約在那個 room
說不定就能重現
nonumpa
21:46:03
會議記錄:https://g0v.hackmd.io/0xqZVqKiSYaIeSYFtT5NRg
線上開會:https://tico.chat/powercall?room=cofactshack&type=timeFirst
線上開會:https://tico.chat/powercall?room=cofactshack&type=timeFirst
tico.chat
The considerate messenger. Chat with whom you care about always at the best moments and times![]()
delightfullychaotic
22:00:22
結果有剛剛按個mute 就默默又沒有了== Howie真的不用負責嗎
Further
23:27:27
@i.further.54 has joined the channel
mrorz
23:52:26
但我也不知道怎麼重現 XD 他只能通靈
mrorz
23:53:31
或許我們的 powercall room 很有靈氣
比較容易重現 bug
你可以跟他約在那個 room
說不定就能重現
比較容易重現 bug
你可以跟他約在那個 room
說不定就能重現
mrorz
23:54:17
f-word XD
媒體是好朋友,用 f-word 感覺會讓媒體有戒心
媒體是好朋友,用 f-word 感覺會讓媒體有戒心
2020-05-14
mrorz
02:38:48
CC
mrorz
2020-05-14 11:34:13
https://cofacts.kktix.cc/events/cofacteditor20 請看看有沒有 misinformation (?)
lucien
2020-05-14 14:49:42
頭到砲管的很迷因耶,不用嗎
mrorz
2020-05-14 17:00:47
那張是直的 超難排
mrorz
2020-05-14 17:13:35
這樣嗎
mrorz
2020-05-14 17:15:15
是說怎麼看得出來那是砲管 w
lucien
2020-05-14 17:30:46
哈哈哈哈
mrorz
2020-05-14 21:48:13
所以要放哪張 wwwww
lucien
2020-05-14 22:15:22
Model 決定@bil
mrorz
2020-05-16 15:33:05
@delightfullychaotic 麻煩你在在地社團散佈惹 m(_ _)m https://cofacts.kktix.cc/events/cofacteditor20
delightfullychaotic
2020-05-16 15:40:47
我覺得有model正面更好!
yanglin
08:24:38
所以寫新回應的區塊
手機版跟 PC 版一致都是點了 `查核闢謠` 按鈕之後才打開嗎?
手機版跟 PC 版一致都是點了 `查核闢謠` 按鈕之後才打開嗎?
stbb1025
09:17:52
手機版會切換到新頁面唷
mrorz
11:17:13
PC 與手機都是點了按鈕之後才會有查核闢謠的區塊或全版 modal
手機要不要換 URL 可以討論
換網址的話就能按手機的 back
不換網址的話可能還是要處理一下手機的 back 避免誤按(或保留現在的自動儲存功能)
手機要不要換 URL 可以討論
換網址的話就能按手機的 back
不換網址的話可能還是要處理一下手機的 back 避免誤按(或保留現在的自動儲存功能)
mrorz
11:34:13
https://cofacts.kktix.cc/events/cofacteditor20 請看看有沒有 misinformation (?)
cofacts.kktix.cc
2 個月一次,用一個下午與 Cofacts 一起工作闢謠解惑,讓不同意見突破同溫層。 來編輯小聚就送限量 Cofacts 貼紙。回應超過200篇,送委外設計LINE貼圖!感謝好想工作室 提供場地。![]()
github
11:55:52
Staging DB provisioned on Heroku, let's give it a shot <https://user-images.githubusercontent.com/108608/81890969-d740a000-95d9-11ea-91ac-8a389767eb25.png|螢幕快照 2020-05-14 上午11 52 59>![]()
stbb1025
12:03:57
原來有這層考量 XD
mrorz
12:13:55
Replied to a thread: 2020-05-05 15:59:41
我發現 5/4 更新 staging API 成 https://github.com/cofacts/rumors-api/pull/153 的版本之後,5/5 @yanglin5689446 就回報問題
朝 API 裡面 elasticsearch result 沒接好的方向調查 ing
朝 API 裡面 elasticsearch result 沒接好的方向調查 ing
- 👌1
mrorz
14:19:44
結果不是 elasticsearch result 沒接好
而是
1. 一般來說,跟使用者相關的 object field 如 `ownVote` 等等,在沒有指定 userId (如:SSR) 時,會直接回傳 null。然而, `requestedForReply` 錯誤地使用了只有 mutation API 該用的 `assertUser({...})` ,所以只要有 requestedForReply 就會產生 error。
而是
1. 一般來說,跟使用者相關的 object field 如 `ownVote` 等等,在沒有指定 userId (如:SSR) 時,會直接回傳 null。然而, `requestedForReply` 錯誤地使用了只有 mutation API 該用的 `assertUser({...})` ,所以只要有 requestedForReply 就會產生 error。
mrorz
14:22:16
2. 我們用的 apollo-link-error 如果有 exception 的話,他就會無聲無息地悶不吭聲,讓後面的 apollo-client resolve 一整個卡住。我是在 `BatchHttpLink` 與 `onError` 中間插了一個印 console 的 link 才能抓到那個 error。
目前我們的 `onError` 裡頭用了 `alert()`,在 NodeJS 環境下並無此 function,所以他其實應該在 runtime 時遇到了 Reference error,但卻無聲無息。
目前我們的 `onError` 裡頭用了 `alert()`,在 NodeJS 環境下並無此 function,所以他其實應該在 runtime 時遇到了 Reference error,但卻無聲無息。
lucien
14:49:42
頭到砲管的很迷因耶,不用嗎
github
14:57:26
During SSR, an GraphQL Error can halt the processing of Apollo-link middlewares, causing the server-side render to return nothing. This PR 1. Always print the error to console 2. Fix SSR by detecting if `alert` exists in the global namespace (it's `undefined` during NodeJS SSR) From discussion: <https://g0v-tw.slack.com/archives/C2PPMRQGP/p1589437262448200?thread_ts=1588665581.350300&cid=C2PPMRQGP|https://g0v-tw.slack.com/archives/C2PPMRQGP/p1589437262448200?thread_ts=1588665581.350300&cid=C2PPMRQGP> > 2. 我們用的 apollo-link-error 如果有 exception 的話,他就會無聲無息地悶不吭聲,讓後面的 apollo-client resolve 一整個卡住。我是在 BatchHttpLink 與 onError 中間插了一個印 console 的 link 才能抓到那個 error。 > 目前我們的 onError 裡頭用了 alert(),在 NodeJS 環境下並無此 function,所以他其實應該在 runtime 時遇到了 Reference error,但卻無聲無息。
yanglin
15:13:49
我私心覺得兩個都可以換網址一下
這樣我在做的時候可以固定網址 hot relaod 不用一直點開 XD
這樣我在做的時候可以固定網址 hot relaod 不用一直點開 XD
yanglin
15:38:12
啊 不過 next router 我不熟 QQ
mrorz
15:48:31
至於 apollo-link-error 把 runtime error 吃掉這件事情,我在 codesandbox 上卻無法重現
https://codesandbox.io/s/awesome-shamir-vpf2d?file=/index.js
https://codesandbox.io/s/awesome-shamir-vpf2d?file=/index.js
github
16:52:46
Currently, `requestedForReply` of `Article` object type would throw error if the user is not logged-in. However, other fields that requires authentication (such as <https://github.com/cofacts/rumors-api/blob/master/src/graphql/models/ArticleReply.js#L68-L89|`ownVote`>, <https://github.com/cofacts/rumors-api/blob/master/src/graphql/models/ArticleReply.js#L42-L51|`canUpdateStatus`>) just returns `null` if the user is not logged in. `assertUser()` is meant for mutation resolvers and ordinary object type resolvers should avoid using `assertUser()`. Related discussion: • <https://g0v-tw.slack.com/archives/C2PPMRQGP/p1588665581350300|https://g0v-tw.slack.com/archives/C2PPMRQGP/p1588665581350300> • <https://g0v-slack-archive.g0v.ronny.tw/index/channel/C2PPMRQGP#ts-1588665581.350300|https://g0v-slack-archive.g0v.ronny.tw/index/channel/C2PPMRQGP#ts-1588665581.350300>
mrorz
16:55:08
我非常懷疑 next-router 是否能做到這種 full-screen modal 換 URL 但原頁面後面的資料全數保留的事情
可以 google 一下有沒有人做過
可以 google 一下有沒有人做過
- 😢1
mrorz
16:56:47
說不定其實可以這樣
```// pages/article/[id].js
export default DefaultArticlePage() {
// ...
return <ArticlePage showCreate={false} />
}
// pages/article/[id]/create.js
export default ArticlePageWithCreate() {
// ...
return <ArticlePage showCreate={true} />
}```
然後直接用 next-router `Link` 換頁之類的
因為是兩個相同的 component 所以或許 react reconcile 時會發現是同一個 component 所以不會重新 mount
但可能要測一下
```// pages/article/[id].js
export default DefaultArticlePage() {
// ...
return <ArticlePage showCreate={false} />
}
// pages/article/[id]/create.js
export default ArticlePageWithCreate() {
// ...
return <ArticlePage showCreate={true} />
}```
然後直接用 next-router `Link` 換頁之類的
因為是兩個相同的 component 所以或許 react reconcile 時會發現是同一個 component 所以不會重新 mount
但可能要測一下
mrorz
16:59:44
雖然這樣做要小心頁面裡的所有 URL 絕對不能用相對路徑,不然 `/article/xxx` 到 `/article/xxx/create` 會導致相對路徑對歪 XD
mrorz
17:00:47
那張是直的 超難排
mrorz
17:15:15
是說怎麼看得出來那是砲管 w
lucien
17:30:46
哈哈哈哈
github
18:25:51
No idea why pr keeps failing no matter how many times I rebuild. `CreateReply` test cleanup always fails. On my local machine, I can reproduce the error for the first time I merge the code, but cannot reproduce at all after the first run. Soooo weird.
mrorz
21:48:13
所以要放哪張 wwwww
lucien
22:15:22
Model 決定@bil
mrorz
22:59:31
cofacts.kktix.cc
2 個月一次,用一個下午與 Cofacts 一起工作闢謠解惑,讓不同意見突破同溫層。 來編輯小聚就送限量 Cofacts 貼紙。回應超過200篇,送委外設計LINE貼圖!感謝好想工作室 提供場地。![]()
2020-05-15
github
14:23:28
Currently if we click "Share" on desktop with a narrow browser screen, the share button does nothing. Let's combine `openMenu` and `handleShare`: • If `navigator.share` exists, use then invoke `navigator.share` • Otherwise, perform logic in `openMenu` We would only need one button this way
github
14:23:28
Looks like something worth joining <http://cofacts.hacktabl.org/storybook/index.html|http://cofacts.hacktabl.org/storybook/index.html> Otherwise we may forget about this component :P
github
14:23:28
`px` incorrect; you may also need to adjust `py` taking its content into consideration *as-is* <https://user-images.githubusercontent.com/108608/81927501-50f67f00-9616-11ea-9497-a4f8c51f00c1.png|image> *to-be* Spec: <https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO/Cofacts-website?node-id=889%3A306|https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO/Cofacts-website?node-id=889%3A306> <https://user-images.githubusercontent.com/108608/81927523-5eac0480-9616-11ea-9321-bd2d0385e6eb.png|image>![]()
github