React 16.3.0で追加されたStrictModeコンポーネントについて
2018-04-01のJS: TypeScript 2.8、React 16.3.0、TensorFlow.js - JSer.info を読んで。
React 16.3.0 から StrictMode
コンポーネントというものが追加されたらしい。
公式ドキュメントを読んでみます。
StrictMode
とは
StrictMode
はアプリの潜在的な問題を検出するために追加されたコンポーネント。コンポーネントだが Fragment
などと同じく UI として画面に表示されるものはない。
<StrictMode>...</StrictMode>
で囲まれた子孫コンポーネントに対し、いくつかのチェックを行う。
また development モードでのみ動作し、 production build 時には影響を与えない。
ScrictMode
がチェックしてくれること
今のところ以下。今後のリリースで機能は追加予定とのこと(Additional functionality will be added with future releases of React.)
- 安全でないライフサイクルメソッドの使用(Identifying components with unsafe lifecycles)
- レガシーな string ref の使用(Warning about legacy string ref API usage)
- 予期せぬ副作用の検出(Detecting unexpected side effects)
- (検出するために、特定のライフサイクルメソッドを二度実行する)
1. 安全でないライフサイクルメソッドの使用
背景として、v16.3.0 以降は非同期レンダリングなどのサポートのために一部のライフサイクルメソッド
componentWillMount
componentWillReceiveProps
componentWillUpdate
が今後削除予定となった。
参考:Update on Async Rendering - React Blog
(こっちはまだ読んでない)
<StrictMode>
の子孫コンポーネントでこれらのライフサイクルメソッドを使用しているものがあれば、ブラウザのコンソールで warning が出力される。
(サンプル)
import React, { Component, StrictMode } from 'react'; class UnsafeComponent extends Component { componentWillMount() { console.log('componentWillMount'); } componentWillReceiveProps(props) { console.log('componentWillReceiveProps'); } render() { return <div>Unsafe Component</div>; } } export default function App() { return ( <StrictMode> <UnsafeComponent /> </StrictMode> ); }
(結果)
Warning: Unsafe lifecycle methods were found within a strict-mode tree: in App in AppContainer componentWillMount: Please update the following components to use componentDidMount instead: UnsafeComponent componentWillReceiveProps: Please update the following components to use static getDerivedStateFromProps instead: UnsafeComponent Learn more about this warning here: https://fb.me/react-strict-mode-warnings
該当のコンポーネント名と使っているライフサイクルメソッドが表示されている。
2. レガシーな string ref の使用
ref
を使ってコンポーネントを参照するための方法はこれまで2通りあって
ref="input"
のように文字列で指定するref={(element) => this.input = element}
のように callback 関数で指定する
このうち 1 の文字列で指定する方にはいくつか問題があったらしく、ドキュメントでも 2 の方法を推奨していた。
<StrictMode>
の子孫コンポーネントで 1 の string ref を使っている箇所があると、こちらも同様にブラウザのコンソールでwarning が出る。
(サンプル)
import React, { Component, StrictMode } from 'react'; class LegacyRef extends Component { handleClick = () => { const name = this.refs.name.value; console.log('LegacyRef', name); }; render() { return ( <div> <input ref="name" /> <button onClick={this.handleClick}>click me</button> </div> ); } } class NewRef extends Component { constructor(props) { super(props); this.nameRef = React.createRef(); } handleClick = () => { const name = this.nameRef.current.value; console.log('NewRef', name); }; render() { return ( <div> <input ref={this.nameRef} /> <button onClick={this.handleClick}>click me</button> </div> ); } } export default function App() { return ( <StrictMode> <LegacyRef /> <NewRef /> </StrictMode> ); }
(結果)
Warning: A string ref, "name", has been found within a strict mode tree. String refs are a source of potential bugs and should be avoided. We recommend using createRef() instead. in div (created by LegacyRef) in LegacyRef (created by App) in App in AppContainer Learn more about using refs safely here: https://fb.me/react-strict-mode-string-ref
余談: createRef()
を使った新しい ref の方法
上のサンプルで、 NewRef
コンポーネントがやっているのは v16.3.0 から追加された新しい ref の実装方法で、 createRef()
という関数を使う。
従来の string ref のような書き方で、かつ string ref のときの問題点は解決されている。らしい。
参考:React v16.3.0: New lifecycles and context API - React Blog の createRef API の項
なお createRef()
の導入後も 2 の callback を使った方法はサポートされるので、置き換える必要はない。
3. 予期せぬ副作用の検出
背景として、React の動作時には大きく2つのフェーズがある。
- render フェーズ:DOM に適用する必要のある変更を決定する。
render
メソッドが呼ばれ、結果を直前のrender
の結果と比較する - commit フェーズ:React がすべての変更を DOM に適用する。
componentDidMount
やcomponentDidUpdate
などのライフサイクルメソッドもこのフェーズで呼ばれる
一般に commit フェーズは速いが render は遅い。そのため、非同期レンダリングによってレンダリング処理を複数の小さな処理に分割し、ブラウザをブロックしないように停止と再開をしながらレンダリングを行う。
これにより、commit 前に render フェーズのライフサイクルメソッドが複数回実行される可能性が生じる。
(このあたりはよくわかっていない)
ので、これらのライフサイクルメソッドに副作用がないことが重要となる。
これらのライフサイクルメソッドとは具体的には以下。
- Class コンポーネントの
constructor
メソッド render
setState
の第一引数に関数を渡したときの関数(updater と呼ぶらしい)getDerivedStateFromProps
(v16.3.0 からcomponentWillReceiveProps
の代替として追加)
ただ、これらのメソッドに副作用がないことを自動的に検出することは難しいため、StrictMode
ではこれらのメソッドを2回ずつ実行する。
(サンプル)
class SideEffect extends Component { constructor(props) { super(props); this.state = { count: 0 }; console.log('SideEffect constructor'); } increment = () => { this.setState((prevState, props) => { console.log('SideEffect updater', prevState); return { count: prevState.count + 1, }; }); }; render() { console.log('SideEffect render'); return <div onClick={this.increment}>{this.state.count}</div>; } } export default function App() { return ( <StrictMode> <SideEffect /> </StrictMode> ); }
(結果)
コード
一応上げておく。
Node.js製CLIフレームワークoclifを試す
はじめに
Heroku が oclif という CLI フレームワークをオープンソースとして公開したという記事を読みました。
Heroku CLI や Salesforce DX のベースにもなっているらしい。
どんなもんか触ってみます。
(oclif は (The) Open CLI Framework の略のようです。読み方がわからない。。。)
oclif の特徴
手を動かす前に、どういった特徴があるのか公式ドキュメントに目を通してみます。
Features · oclif: The Open CLI Framework
- Super Speed
- CLI Generator
- コマンド一発で scaffold が生成できる generator がある
- Testing Helpers
- テストが書きやすい。 stdout/stderr を簡単にモックできる
- generator がテストの scaffold も自動生成する
- Auto-documentation
--help
オプションで表示するヘルプテキストが自動生成される- ↑は CLI が publish されるときに README にも自動的に記載される(※最後で軽く触れる)
- (未確認)Plugins
- (未確認)Hooks
- コマンド実行時などのライフサイクルイベントや独自にカスタムイベントを定義し、そこにフックする処理を書ける
- TypeScript
- TypeScript と JavaScript 両方をサポート
- oclif 自体も TypeScript で書かれている
- Coming soon: man pages, Autocomplete
テストしやすく、ドキュメントが自動生成されるのはいいですね。
Single-command と Multi-command
oclif で作成できる CLI には大きく分けて 2 種類あります。
Single-command とは ls
や curl
のように、コマンド自体は1つで引数やオプションを取るものです。
Multi-command とは git
や heroku
のように、後にサブコマンドが続くものです。
試してみる
今回は、自分が過去に Node.js で作った parse-salesforce-object という CLI に oclif を導入してみます。
(Salesforce 開発で使うメタデータファイル(XML)をパースしてよしなに表示してくれるという、ごくごく一部の方にしか需要がないやつです)
この CLI は先ほどの分類で言うと Single-command です。
generator で CLI のひな形(scaffold)作成
Quickstart を参考に、generator を使って必要なファイルを生成します。
$ npx oclif single [コマンド名]
を実行すると途中で色々聞かれるので適宜入力します。
$ npx oclif single parse-salesforce-object npx: 293個のパッケージを17.261秒でインストールしました。 _-----_ ╭──────────────────────────╮ | | │ Time to build a │ |--(o)--| │ single-command CLI with │ `---------´ │ oclif! Version: 1.7.9 │ ( _´U`_ ) ╰──────────────────────────╯ /___A___\ / | ~ | __'.___.'__ ´ ` |° ´ Y ` ? npm package name parse-salesforce-object ? command bin name the CLI will export parse-salesforce-object ? description ? author Shingo Yamazaki @zaki-yama ? version 0.0.5 ? license MIT ? node version supported >=8.0.0 ? github owner of repository (https://github.com/OWNER/repo) zaki-yama ? github name of repository (https://github.com/owner/REPO) parse-salesforce-object ? optional components to include ❯◉ yarn (npm alternative) ◉ mocha (testing framework) ◉ typescript (static typing for javascript) ◉ tslint (static analysis tool for typescript) ◯ semantic-release (automated version management)
最後のオプションで yarn, mocha, TypeScript を使うかどうかは好みです。
インストールが完了すると、 [コマンド名]
でディレクトリが作成され、その下に必要なファイルが揃っています。
npm install
(or yarn
)も実行されているため、必要なパッケージもインストール済みです。
$ tree -I node_modules parse-salesforce-object parse-salesforce-object ├── README.md ├── appveyor.yml ├── bin │ ├── run │ └── run.cmd ├── package.json ├── src │ └── index.ts ├── test │ ├── helpers │ │ └── init.js │ ├── index.test.ts │ ├── mocha.opts │ └── tsconfig.json ├── tsconfig.json ├── tslint.json └── yarn.lock
bin/run
を実行するとコマンドを実行できます。
$ cd parse-salesforce-object
$ ./bin/run
hello world from /Users/yamazaki/workspace/nodejs/parse-salesforce-object/src/index.ts!
コマンドファイルの構成
src/index.ts がコマンド本体です。中身を見てみます。
((1) ~ (3) は便宜的にこちらで番号を振りました)
import {Command, flags} from '@oclif/command' class ParseSalesforceObject extends Command { // (3) static description = 'describe the command here' // (3) static examples = [ `$ parse-salesforce-object hello world from ./src/parse-salesforce-object.ts! `, ] // (2) static flags = { // add --version flag to show CLI version version: flags.version({char: 'v'}), // add --help flag to show CLI version help: flags.help({char: 'h'}), // flag with a value (-n, --name=VALUE) name: flags.string({char: 'n', description: 'name to print'}), force: flags.boolean({char: 'f'}), } // (2) static args = [{name: 'file'}] // (1) async run() { const {args, flags} = this.parse(ParseSalesforceObject) const name = flags.name || 'world' this.log(`hello ${name} from ${__filename}!`) if (args.file && flags.force) { this.log(`you input --force and --file: ${args.file}`) } } } export = ParseSalesforceObject
- (1) コマンドの実処理は
run()
メソッドに記述します - (2) 引数やオプション(flags)はこのように
static
変数として定義します。この後ここをカスタマイズしてみます - (3) description, examples も同様に
static
変数として定義すると、ヘルプテキストに反映されます
最後の (3) について、実際にコマンドを --help
オプションつきで実行すると
$ ./bin/run --help describe the command here USAGE $ parse-salesforce-object [FILE] OPTIONS -f, --force -h, --help show CLI help -n, --name=name name to print -v, --version show CLI version EXAMPLE $ parse-salesforce-object hello world from ./src/parse-salesforce-object.ts!
のように、description および examples に記述した文字列がヘルプの先頭と EXAMPLE セクションに記載されているのがわかります。
引数を処理する
さて、ここからひな形をベースに元の CLI としての機能を実装していきます。
まずは引数の処理から。
参考:Command Arguments · oclif: The Open CLI Framework
元の CLI では
const argv = require('minimist')(process.argv.slice(2)); const filePath = argv._[0]; ... if (!filePath) { console.log(chalk.red('ERROR: You must specify a path to .object file.')); process.exit(1); } fs.readFile(filePath, (err, data) => { ... });
のように、とあるファイルへのパスを必須の引数として受け取るようになっていました。
またその処理のために minimist というライブラリを使っていました。
oclif だと以下のように書けます。
class ParseSalesforceObject extends Command { ... static args = [{ name: 'path', description: 'path to .object file', required: true, }] async run() { const {args, flags} = this.parse(ParseSalesforceObject) fs.readFile(args.path, (err, data) => { ... }) }
引数には { name: 'foo' }
という形で名前を付けておくことができ、run()
メソッド内で(パース後に) args.foo
でアクセスできます。
その他のオプションは https://oclif.io/docs/args.html を参照するといいです。
必須かどうかもオプションで指定できるようになったので判定処理が不要になりました。
# 引数なしで実行するとエラーになる $ ./bin/run › Error: Missing 1 required arg: › path path to .object file › See more help with --help
フラグ(オプション)を処理する
続いて、いくつかのフラグを受け取れるようにします。
フラグとは -f foo
や --file=foo
のようなものを指します。
参考:Command Flags · oclif: The Open CLI Framework
フラグは version と help 以外は
static flags = { force: flags.boolean({char: 'f'}), file: flags.string(), }
のように、
- 引数を受け取るもの:
flags.string()
- 引数を受け取らず、boolean として使うもの:
flags.boolean()
の 2 種類あります。
また両者に共通して、{char: 'f'}
のように char
オプションを指定すると短縮形も扱えるようになります。
その他のオプションは https://oclif.io/docs/flags.html を参照します。
元の CLI には、-f xxx
または --format=xxx
オプションで出力フォーマットを指定でき、その選択肢は markdown, csv, soql
のいずれかとなっていたので
format: flags.string({ char: 'f', description: 'output format', options: ['markdown', 'csv', 'soql'], default: 'markdown', }),
のように options
と default
を利用しました。便利。
# -f で許可されているフォーマット以外を指定するとエラー
$ ./bin/run objects/Expense__c.object -f foo
› Error: Expected --format=foo to be one of: markdown, csv, soql
› See more help with --help
ヘルプを出力してみる
引数やオプションを一通り定義した後で、 --help
によりヘルプを表示してみます。
$ ./bin/run --help USAGE $ parse-salesforce-object PATH ARGUMENTS PATH path to .object file OPTIONS -f, --format=markdown|csv|soql [default: markdown] output format -h, --help show CLI help -n, --namespace=namespace namespace prefix (for SOQL format) -v, --version show CLI version EXAMPLE $ parse-salesforce-object src/objects/Expense__c.object | label | fullName | type | required | | ----------- | ------------- | -------- | -------- | | Amount | Amount__c | Number | false | | Client | Client__c | Text | false | | Date | Date__c | DateTime | false | | Reimbursed? | Reimbursed__c | Checkbox | null |
ARGUMENTS
および OPTIONS
のセクションのところが、定義した引数・フラグの内容から自動生成されました。
GitHub
今回 oclif での置き換えを試した CLI のリポジトリはここにあります。
PR は https://github.com/zaki-yama/parse-salesforce-object/pull/6
まとめと TODO
今回は oclif の導入手順と基本構成についてなんとなくわかったという程度ですが、個人的には
npx oclif single/multi foo
で scaffold から始められるのは楽- 引数やオプションからヘルプ自動生成は便利
といった点が、フレームワークというだけあって良いなと思いました。
また将来的に Autocomplete もサポートしてくれるのは期待したい。
テストを書くところや Plugins、Hooks については試せてないので、今後の TODO ということで。
おまけ:Auto-documentation について
Features#Auto-documentation には
This information is also automatically placed in the README whenever the npm package of the CLI is published. See the multi-command CLI example
と記載がありますが、自動生成したヘルプを README に埋め込む方法はドキュメントに記載がありませんでした。
リンクされてるリポジトリを見ると oclif-dev
という CLI を使ってる っぽいので、これかな...?
あわせて読みたい
Salesforce のエンジニアブログにも記事があった。
Vim+ALEでファイル保存時にPrettierを実行する
メモ。
Prettier という JavaScript のフォーマッターをファイル保存時に自動的に実行する、というのを Vim でやりたい。
特に自分は ESLint や Flow のチェックに ALE というプラグインを使っているため
(参考:VimでESLintとFlowを使うためにNeomakeからALEに乗り換える - Qiita)
Prettier も同じように ALE で設定できないのか調べた。
すると、ちゃんと Prettier の公式ドキュメントに ALE での設定方法が載ってた。
Prettier 単体で使う場合は上記を読むのが一番早いが、自分は ESLint と併用するために prettier-eslint-cli)を使っているのでその前提で手順を記載する。
設定手順
Vim 側
ALE の設定として以下を追加する。
let g:ale_fixers = {} let g:ale_fixers['javascript'] = ['prettier-eslint'] " ファイル保存時に実行 let g:ale_fix_on_save = 1 " ローカルの設定ファイルを考慮する let g:ale_javascript_prettier_use_local_config = 1
※プラグイン管理に dein.vim を使っており、toml で管理している場合は以下のようになる
# rc/dein.toml [[plugins]] repo = 'w0rp/ale' hook_add = ''' let g:ale_statusline_format = ['E%d', 'W%d', 'OK'] nmap <silent> <C-w>j <Plug>(ale_next_wrap) nmap <silent> <C-w>k <Plug>(ale_previous_wrap) let g:ale_fixers = {} let g:ale_fixers['javascript'] = ['prettier-eslint'] " ファイル保存時に実行 let g:ale_fix_on_save = 1 " ローカルの設定ファイルを考慮する let g:ale_javascript_prettier_use_local_config = 1 '''
let g:ale_fixers['javascript'] = ['prettier-eslint']
の部分、prettier 単体では ['prettier']
でいいが ESLint と併用している場合は prettier-eslint-cli を使うため上記の設定になる。
プロジェクト側
prettier-eslint-cli をインストールしておくだけ。
$ yarn add -D prettier-eslint-cli
様子
あんまり早くない。。。
非同期で行われるためそこまで気にならないかもしれないけど。
VSCode とかでもこんなもんなんだろうか。
GitHub
以上を反映した Redux アプリ用テンプレートリポジトリがこちらです。
Prettier 導入の Issue は https://github.com/zaki-yama/redux-express-template/issues/16
リファレンス
冒頭の Prettier のドキュメントのほか、ALE の README でも fixer については記載があった。
https://github.com/w0rp/ale#2ii-fixing
[Salesforce]ApexでPermissionSetの"PermissionsXXX"項目の一覧を取得
ちょいメモ。
参考:PermissionSet | SOAP API 開発者ガイド | Salesforce Developers
Permissions...
から始まる項目がいくつかあるらしいので、Apex で項目一覧を取得してみる。
調べ方
以下を開発者コンソールの Execute Anonymous で実行。ログをダウンロードして USER_DEBUG だけ抽出。
Map<String, Schema.SObjectField> M = Schema.SObjectType.PermissionSet.fields.getMap(); SObjectType t = Schema.getGlobalDescribe().get('PermissionSet'); Map<String,Schema.SObjectField> fields = t.getDescribe().fields.getMap(); for (Schema.SObjectField field : fields.values()) { Schema.DescribeFieldResult dfr = field.getDescribe(); if (dfr.getName().contains('Permissions')) { System.debug(dfr.getName() + ' | ' + dfr.getLabel()); } }
結果
API 参照名 | ラベル |
---|---|
PermissionsEmailSingle | メールの送信 |
PermissionsEmailMass | 一括メール送信 |
PermissionsEditTask | ToDo の編集 |
PermissionsEditEvent | 行動の編集 |
PermissionsExportReport | レポートのエクスポート |
PermissionsImportPersonal | 個人データのインポート |
PermissionsDataExport | ウィークリーデータのエクスポート |
PermissionsManageUsers | ユーザの管理 |
PermissionsEditPublicFilters | 公開リストビューの管理 |
PermissionsEditPublicTemplates | 公開テンプレートの管理 |
PermissionsModifyAllData | すべてのデータの編集 |
PermissionsManageCases | ケースの管理 |
PermissionsMassInlineEdit | リストからの一括編集 |
PermissionsEditKnowledge | 記事の管理 |
PermissionsManageKnowledge | Salesforce ナレッジの管理 |
PermissionsManageSolutions | 公開ソリューションの管理 |
PermissionsCustomizeApplication | アプリケーションのカスタマイズ |
PermissionsEditReadonlyFields | 参照のみ項目の編集 |
PermissionsRunReports | レポート実行 |
PermissionsViewSetup | 設定・定義を参照する |
PermissionsTransferAnyEntity | 所有権の移行 |
PermissionsNewReportBuilder | レポートビルダー |
PermissionsActivateContract | 契約の有効化 |
PermissionsActivateOrder | 注文の有効化 |
PermissionsImportLeads | リードのインポート |
PermissionsManageLeads | リードの管理 |
PermissionsTransferAnyLead | リード所有者の移行 |
PermissionsViewAllData | すべてのデータの参照 |
PermissionsEditPublicDocuments | 公開ドキュメントの管理 |
PermissionsViewEncryptedData | 暗号化されたデータの参照 |
PermissionsEditBrandTemplates | レターヘッドの管理 |
PermissionsEditHtmlTemplates | HTML テンプレートの編集 |
PermissionsChatterInternalUser | Chatter 内部ユーザ |
PermissionsManageTranslation | 翻訳の管理 |
PermissionsDeleteActivatedContract | 有効契約の削除 |
PermissionsChatterInviteExternalUsers | Chatter に顧客を招待する |
PermissionsSendSitRequests | 登録情報照会要求の送信 |
PermissionsManageRemoteAccess | 接続アプリケーションを管理する |
PermissionsCanUseNewDashboardBuilder | ドラッグアンドドロップ ダッシュボードビルダー |
PermissionsManageCategories | カテゴリの管理 |
PermissionsConvertLeads | リードの取引の開始 |
PermissionsPasswordNeverExpires | パスワード無期限 |
PermissionsUseTeamReassignWizards | チーム再割り当てウィザードの使用 |
PermissionsEditActivatedOrders | 有効化された注文の編集 |
PermissionsInstallPackaging | AppExchange パッケージのダウンロード |
PermissionsPublishPackaging | AppExchange パッケージのアップロード |
PermissionsChatterOwnGroups | 新規 Chatter グループの作成および所有 |
PermissionsEditOppLineItemUnitPrice | 商談商品の販売価格の編集 |
PermissionsCreatePackaging | AppExchange パッケージの作成 |
PermissionsBulkApiHardDelete | Bulk API の物理削除 |
PermissionsSolutionImport | ソリューションのインポート |
PermissionsManageCallCenters | コールセンターの管理 |
PermissionsManageSynonyms | シノニムの管理 |
PermissionsViewContent | ポータルのコンテンツの参照 |
PermissionsManageEmailClientConfig | メールクライアント設定の管理 |
PermissionsEnableNotifications | アウトバウンドメッセージの送信 |
PermissionsManageDataIntegrations | データインテグレーションの管理 |
PermissionsDistributeFromPersWksp | コンテンツ配信の作成 |
PermissionsViewDataCategories | データカテゴリの表示 |
PermissionsManageDataCategories | データカテゴリの管理 |
PermissionsAuthorApex | Apex 開発 |
PermissionsManageMobile | モバイル設定を管理する |
PermissionsApiEnabled | API の有効化 |
PermissionsManageCustomReportTypes | カスタムレポートタイプの管理 |
PermissionsEditCaseComments | ケースコメントの編集 |
PermissionsTransferAnyCase | ケース所有者の移行 |
PermissionsContentAdministrator | Salesforce CRM Content の管理 |
PermissionsCreateWorkspaces | ライブラリの作成 |
PermissionsManageContentPermissions | コンテンツ権限の管理 |
PermissionsManageContentProperties | コンテンツプロパティの管理 |
PermissionsManageContentTypes | ファイルのレコードタイプおよびレイアウトの管理 |
PermissionsManageExchangeConfig | Lightning Sync を管理 |
PermissionsManageAnalyticSnapshots | レポート作成スナップショットを管理 |
PermissionsScheduleReports | レポートのスケジュール |
PermissionsManageBusinessHourHolidays | 営業時間の休日の管理 |
PermissionsManageDynamicDashboards | 動的ダッシュボードの管理 |
PermissionsCustomSidebarOnAllPages | すべてのページにカスタムサイドバーを表示 |
PermissionsManageInteraction | フローの管理 |
PermissionsViewMyTeamsDashboards | 私のチームのダッシュボードの参照 |
PermissionsModerateChatter | Chatter のモデレート |
PermissionsResetPasswords | ユーザパスワードのリセットおよびユーザのロック解除 |
PermissionsFlowUFLRequired | フローユーザ機能ライセンスが必要 |
PermissionsCanInsertFeedSystemFields | Chatter フィードにシステム項目値を挿入 |
PermissionsManageKnowledgeImportExport | ナレッジ記事のインポート/エクスポートの管理 |
PermissionsEmailTemplateManagement | メールテンプレートの管理 |
PermissionsEmailAdministration | メール管理 |
PermissionsManageChatterMessages | Chatter メッセージとダイレクトメッセージを管理 |
PermissionsAllowEmailIC | メールベースの ID 検証オプション |
PermissionsChatterFileLink | 公開リンクの作成 |
PermissionsForceTwoFactor | ユーザインターフェースログインの 2 要素認証 |
PermissionsViewEventLogFiles | イベントログファイルを参照 |
PermissionsManageNetworks | コミュニティを作成および設定 |
PermissionsManageAuthProviders | 認証プロバイダの管理 |
PermissionsRunFlow | フローを実行 |
PermissionsCreateCustomizeDashboards | ダッシュボードの作成とカスタマイズ |
PermissionsCreateDashboardFolders | ダッシュボードフォルダを作成 |
PermissionsViewPublicDashboards | 公開フォルダのダッシュボードを参照 |
PermissionsManageDashbdsInPubFolders | 公開フォルダのダッシュボードを管理 |
PermissionsCreateCustomizeReports | レポートの作成とカスタマイズ |
PermissionsCreateReportFolders | レポートフォルダを作成 |
PermissionsViewPublicReports | 公開フォルダのレポートを参照 |
PermissionsManageReportsInPubFolders | 公開フォルダのレポートを管理 |
PermissionsEditMyDashboards | 私のダッシュボードを編集 |
PermissionsEditMyReports | 私のレポートを編集 |
PermissionsViewAllUsers | すべてのユーザの参照 |
PermissionsAllowUniversalSearch | Knowledge One |
PermissionsConnectOrgToEnvironmentHub | 環境ハブに組織を接続 |
PermissionsWorkCalibrationUser | Work.com 調整を有効化 |
PermissionsCreateCustomizeFilters | リストビューを作成およびカスタマイズ |
PermissionsWorkDotComUserPerm | Work.com を有効化 |
PermissionsGovernNetworks | コミュニティを管理する |
PermissionsSalesConsole | セールスコンソール |
PermissionsTwoFactorApi | API ログインの 2 要素認証 |
PermissionsDeleteTopics | トピックを削除 |
PermissionsEditTopics | トピックを編集 |
PermissionsCreateTopics | トピックを作成 |
PermissionsAssignTopics | トピックを割り当てる |
PermissionsIdentityEnabled | Identity 機能を使用 |
PermissionsIdentityConnect | Identity Connect を使用 |
PermissionsAllowViewKnowledge | ナレッジの参照を許可 |
PermissionsContentWorkspaces | ライブラリへのアクセス |
PermissionsManageSearchPromotionRules | 昇格済み検索語の管理 |
PermissionsCustomMobileAppsAccess | カスタムモバイルアプリケーションにアクセス |
PermissionsViewHelpLink | ヘルプリンクを参照 |
PermissionsManageProfilesPermissionsets | プロファイルおよび権限セットを管理 |
PermissionsAssignPermissionSets | 権限セットの割り当て |
PermissionsManageRoles | ロールを管理 |
PermissionsManageIpAddresses | IP アドレスを管理 |
PermissionsManageSharing | 共有を管理 |
PermissionsManageInternalUsers | 内部ユーザを管理 |
PermissionsManagePasswordPolicies | パスワードポリシーを管理 |
PermissionsManageLoginAccessPolicies | ログインアクセスポリシーを管理 |
PermissionsManageCustomPermissions | カスタム権限を管理 |
PermissionsCanVerifyComment | Chatter の質問への回答の確認 |
PermissionsManageUnlistedGroups | 「リストに記載しない」グループを管理 |
PermissionsModifySecureAgents | セキュアエージェントを変更 |
PermissionsManageTwoFactor | API で 2 要素認証を管理 |
PermissionsChatterForSharePoint | Chatter For SharePoint へのアクセス |
PermissionsLightningExperienceUser | Lightning Experience ユーザ |
PermissionsConfigCustomRecs | カスタムおすすめの設定 |
PermissionsSubmitMacrosAllowed | ユーザが元に戻せないマクロを管理 |
PermissionsBulkMacrosAllowed | 複数のレコードに対してマクロを実行 |
PermissionsShareInternalArticles | 内部のナレッジ記事を外部と共有 |
PermissionsManageSessionPermissionSets | セッション権限セットの有効化を管理 |
PermissionsSendAnnouncementEmails | お知らせメールを送信 |
PermissionsChatterEditOwnPost | 自分の投稿を編集 |
PermissionsChatterEditOwnRecordPost | 自分の所有レコードへの投稿を編集 |
PermissionsImportCustomObjects | カスタムオブジェクトのインポート |
PermissionsDelegatedTwoFactor | ユーザインターフェースで 2 要素認証を管理 |
PermissionsChatterComposeUiCodesnippet | UI からのコードスニペットの挿入を許可 |
PermissionsSelectFilesFromSalesforce | Salesforce からファイルを選択 |
PermissionsModerateNetworkUsers | コミュニティユーザモデレート |
PermissionsMergeTopics | トピックのマージ |
PermissionsSubscribeToLightningReports | レポートを登録 |
PermissionsManagePvtRptsAndDashbds | すべての非公開レポートおよびダッシュボードを管理 |
PermissionsAllowLightningLogin | Lightning Login ユーザ |
PermissionsCampaignInfluence2 | キャンペーンインフルエンス |
PermissionsViewDataAssessment | データ評価の参照アクセス権 |
PermissionsRemoveDirectMessageMembers | ダイレクトメッセージから人を削除 |
PermissionsCanApproveFeedPost | フィード投稿とコメントを承認可能 |
PermissionsAddDirectMessageMembers | ダイレクトメッセージに人を追加 |
PermissionsAllowViewEditConvertedLeads | 取引開始済みのリードを表示および編集 |
PermissionsShowCompanyNameAsUserBadge | コミュニティロールとして会社名を表示 |
PermissionsAccessCMC | コミュニティ管理にアクセス |
PermissionsViewHealthCheck | 状態チェックを表示 |
PermissionsManageHealthCheck | 状態チェックを管理 |
PermissionsPackaging2 | 第二世代パッケージの作成と更新 |
PermissionsManageCertificates | 証明書を管理 |
PermissionsCreateReportInLightning | レポートビルダー (Lightning Experience) |
PermissionsPreventClassicExperience | Salesforce Classic に切り替えるオプションを非表示 |
PermissionsHideReadByList | [表示先] リストを非表示 |
PermissionsListEmailSend | リストメールの送信を許可 |
PermissionsFeedPinning | フィードでの投稿の固定 |
PermissionsChangeDashboardColors | ダッシュボードの色を変更 |
PermissionsIotUser | IoT ユーザ |
PermissionsUseWebLink | カスタマイズしたアクションへのアクセスを許可 |
PermissionsViewAllActivities | すべての活動を表示 |
PermissionsSubscribeReportToOtherUsers | レポートを登録: 受信者を追加 |
PermissionsLightningConsoleAllowedForUser | Lightning コンソールユーザ |
PermissionsSubscribeReportsRunAsUser | レポートを登録: 実行ユーザを設定 |
PermissionsSubscribeToLightningDashboards | ダッシュボードへの登録 |
PermissionsApexRestServices | Apex REST サービス |
PermissionsEnableCommunityAppLauncher | コミュニティでアプリケーションランチャーを表示 |
PermissionsManageSurveys | アンケートを管理 |
PermissionsViewRoles | ロールおよびロール階層を表示 |
いっぱいある。
[Salesforce]代理承認者機能の使い方
まとまってるドキュメントが見つからなかったのでメモ。
代理承認者とは
- Salesforce の承認プロセス機能において、承認者の代わりに申請を承認/却下できる人を設定できる機能
- ユーザに対して一人だけ代理承認者を設定しておくことができる
- また承認プロセスの各承認ステップごとに代理承認者による承認を許可するかどうかが設定できる
承認プロセスそのものについては以下の Trailhead モジュールをやるといい。
設定手順
ユーザ設定より代理承認者を設定する
代理承認者を設定したいユーザのユーザ設定画面を開き、下の方の「承認者の設定」セクションに移動する。
「代理承認者」項目に代理承認者にしたいユーザを検索してセットする。
また、代理承認者自身のユーザ設定で、「承認申請メールを受信」項目を「自分が承認者である場合のみ」から「承認者または代理承認者である場合」に変更しておくとよい。理由は後述。
承認プロセス設定より、承認ステップで代理承認を許可する
今度は承認プロセスの設定画面を開き、任意の承認ステップの編集画面を開く。
ステップ 3/3 で、一番下に「代理承認者もこの申請を承認可能にする」という項目があるのでチェックする。
結果
自分が代理承認者になっている承認ステップに申請が回ってきたとき、承認者同様にメールが届く。
メールの件名には「(◯◯の代理承認者)」と書かれているよう。
制限事項
自身が代理承認可能な申請は今のところ「未承認申請一覧」には表示されない。メール以外に確認する手段がないのでつらい。
これについてはずいぶん前から Idea に投稿されてるよう。
また、以下のヘルプ記事ではメール以外のワークアラウンドも紹介されてる(英語)。
Why can't a delegated approver see anything in the Items to approve list?
どうやら「レコードが現在承認プロセスの申請中かどうか」を表すチェックボックス項目をオブジェクトに追加し、それを条件にリストビューを作るという方法らしい。
チェックボックスの ON/OFF は承認プロセスの開始時や最終承認/却下時のアクションとして項目自動更新により自動的に制御できる。
が、これは別に「自身が代理承認になっているものリスト」ではないし、もっと言うと自分が承認者じゃないやつも含まれるのでは。。。
(2018/3/23追記)
と思ったら、標準レポートに「代理承認申請一覧」というのがあった。。。
これで一覧表示できます。
※ただし、標準フォルダは LEX では表示されないため、コピーする必要あり
(参考:レポートおよびダッシュボード: Lightning Experience で使用できない機能とその新機能)
「代理承認者」に設定する以外に、他人の申請を承認/却下する方法
「代理承認者」はユーザにつき一人しか指定できない。もう少し柔軟に代理承認可能なユーザを増やすにはどうするか。
代理承認ではないが、申請を行うオブジェクトに対して「すべての編集」権限があれば任意の申請を承認/却下することができる。
(「すべてのデータの編集」権限もそう)
管理者権限
次の権限のいずれかを持つユーザは承認管理者とみなされます。
- 指定のオブジェクトに対するオブジェクトレベルでの「すべての編集」権限
- 「すべてのデータの編集」ユーザ権限
承認管理者には次の権限があります。
- 承認プロセスの一環としてではなく、未承認申請を承認または却下
- 承認がロックされたレコードの編集
わかっていないこと
- 承認者としてキューやグループを指定したときにどういう挙動になるのか
electron-react-boilerplateでCSSフレームワーク(Lightning Design System)をインストールするとエラー
Chatter Desktop という Electron アプリ を作っていて真っ先にハマったところのメモ。
Lightning Design System という CSS フレームワークを入れようとしたところ、以下のエラーとなった。
$ git clone --depth=1 https://github.com/chentsulin/electron-react-boilerplate.git your-project-name $ cd your-project-name $ yarn $ yarn add @salesforce-ux/design-system ... ERROR in dll renderer Module not found: Error: Can't resolve '@salesforce-ux/design-system' in '/Users/yamazaki/workspace/electron/electron-react-boilerplate' @ dll renderer ERROR in ./node_modules/bootstrap/dist/js/bootstrap.js Module not found: Error: Can't resolve 'jquery' in '/Users/yamazaki/workspace/electron/electron-react-boilerplate/node_modules/bootstrap/dist/js' @ ./node_modules/bootstrap/dist/js/bootstrap.js 7:81-98 @ dll renderer ERROR in ./node_modules/bootstrap/dist/js/bootstrap.js Module not found: Error: Can't resolve 'popper.js' in '/Users/yamazaki/workspace/electron/electron-react-boilerplate/node_modules/bootstrap/dist/js' @ ./node_modules/bootstrap/dist/js/bootstrap.js 7:100-120 @ dll renderer npm ERR! code ELIFECYCLE npm ERR! errno 2 npm ERR! electron-react-boilerplate@0.13.2 build-dll: `cross-env NODE_ENV=development node --trace-warnings -r babel-register ./node_modules/webpack/bin/webpack --config webpack.config.renderer.dev.dll.js --colors` npm ERR! Exit status 2 npm ERR! npm ERR! Failed at the electron-react-boilerplate@0.13.2 build-dll script. npm ERR! This is probably not a problem with npm. There is likely additional logging output above. npm ERR! A complete log of this run can be found in: npm ERR! /Users/yamazaki/.npm/_logs/2018-03-04T21_19_46_858Z-debug.log error Command failed with exit code 2. info Visit https://yarnpkg.com/en/docs/cli/add for documentation about this command.
https://github.com/chentsulin/electron-react-boilerplate/blob/master/package.json#L23
どうやら postinstall スクリプトが走っており、この中で build-dll
という DLL ファイルの生成処理をやろうとして失敗しているよう。
また build-dll
は webpack.config.renderer.dev.dll.js
を見て webpack によるビルドを行っているので、設定ファイルの中身を見る。そうすると
entry: { renderer: ( Object .keys(dependencies || {}) .filter(dependency => dependency !== 'font-awesome') ) },
ここで、元から入っていた font-awesome
については明示的にビルド対象から外しているようだ。
なので手動で
entry: { renderer: ( Object .keys(dependencies || {}) .filter(dependency => { // also ignore installed CSS library return dependency !== 'font-awesome' && dependency !== '@salesforce-ux/design-system'; }) ) },
というふうにインストールする CSS フレームワークをビルド対象から除外してやると、ビルドに成功するようになった。
が、正しい手順なのかがよくわからず、Issue で質問してみることにした。
おまけ: webpack.config.renderer.dev.dll.js
がやっていること
開発時のビルドパフォーマンス向上のために webpack.DLLPlugin というのを使っている。
DLLPlugin についてはきちんと理解したわけではないが、外部ライブラリなど毎回毎回ビルドする必要がないモジュールを DLL バンドルという形で別ファイルに切り出し、require() 時に読み込むらしい。
こちらの記事が非常に参考になった。
LDSとdesign-system-reactをBabel&webpackな環境に導入する
メモ。
ちょっと前から Lightning Design System(LDS)の React 実装が公式から出てます。
Lightning Design System for React
で、ようやく入れてみようとドキュメントを頼りにやってみたところ色々手こずったので、手順をまとめておきます。
はじめに
design-system-react の設定に関するドキュメントは、以下のように点在しています。
1 が一番参考にしたドキュメント。webpack.config.js の設定例なども載っています。基本はここを見ながらやりました。
(ここに書かれてる内容は private repo で管理してるらしい)
2 は 1 と被る部分もあり、ただ Icon の設定に関してはここにしか記載されてません。
また 1, 2 は design-system-react のインストール手順であり、これだけだと LDS はインストールされず、スタイルがあたりません。
LDS を webpack から使えるようにするための情報が 3 に載っています。
以下では、設定手順を大きく「1. design-system-react の設定」と「2. LDS の設定」に分けて記載します。
サンプルコード
Redux & Express でのアプリのひな形リポジトリに導入したときの PR です。
ディレクトリ構成
クライアント側のファイルは public
というディレクトリに配置するような構成になっています。
- public - assets - lds --- LDS はここに展開 - bundle.js --- ビルド後のファイル - components --- React & Redux の - containers - ... - index.js --- エントリーポイント - index.html - package.json - webpack.config.base.babel.js - webpack.config.dev.babel.js - webpack.config.prod.babel.js
1. design-system-react の設定
まずは design-system-react のインストールから設定までの手順。主に先ほどの 1. Getting Started を参考にします。
インストール
npm でインストールできます。
$ npm install @salesforce-ux/design-system @salesforce/design-system-react
webpack の設定
Getting Started のページに webpack.config.js の設定例があるので、それを参考に設定していきます。
// webpack.config.babel.js (抜粋) export default { context: path.resolve(path.join(__dirname, 'public')), entry: [ './index', ], + resolve: { + extensions: ['.js', '.jsx'], + }, output: { filename: 'bundle.js', path: path.resolve(path.join(__dirname, 'public', 'assets')), publicPath: '/assets/', }, module: { rules: [ { - test: /\.js$/, - exclude: /node_modules/, + test: /\.jsx?$/, + include: [ + path.resolve(path.join(__dirname, 'public')), + path.resolve(path.join(__dirname, 'node_modules/@salesforce/design-system-react')), + ], use: 'babel-loader', }, { ...
(ファイル全体は こちら を参照)
ポイントとしては
- design-system-react のファイルは
.jsx
なので、.jsx
もビルドできるようにresolve.extensions
および babel-loader を適用する正規表現を修正 - 元々 node_modules 以下はすべて babe-loader の対象外としていたが、design-system-react は対象に含めるよう修正
です。
また、この記事を書いた時点ではドキュメントの方では
path.join(__dirname, 'node_modules/design-system-react')
というように @salesforce
が入ってなかったんですが、入れるのが正しいです。
Issue で報告したのでそのうち直るはず。
Babel の設定
.babelrc
を修正します。
これには @salesforce/babel-preset-design-system-react という preset を使えとドキュメントにはありますが、中身
https://github.com/salesforce/design-system-react/blob/master/preset/index.js
を見てみると
- babel-preset-env
- babel-preset-react
- babel-plugin-transform-object-rest-spread
- babel-plugin-transform-class-properties
- babel-plugin-transform-export-extensions
を指定しているだけなので、既に設定されている .babelrc
の内容に合わせて必要な preset/plugin を個別に追加するという対応でもいいのかもしれません。
(実際自分のリポジトリでも babel-plugin-transform-export-extensions 以外は使っていた)
今回は素直にこの preset を使うようにします。
$ npm install -D @salesforce/babel-preset-design-system-react
// .babelrc { "presets": ["@salesforce/babel-preset-design-system-react"] }
使う
このような形で import して使います。
// components/App.js import React, { Component } from 'react'; import Button from '@salesforce/design-system-react/components/button'; export default class App extends Component { render() { return ( <Button iconName="download" iconPosition="left" label="Neutral Icon" /> ); } }
2. LDS の設定
さて、今度は LDS を読み込むための設定をします。
これは docs/webpack.md がある程度参考になります。
インストール
$ npm install @salesforce-ux/design-system style-loader css-loader file-loader
必要になる loader も一緒にインストールしときます。
webpack の設定
// webpack.config.babel.js ... export default { ... module: { rules: [ ... + { + test: /\.min\.css$/, + use: ['style-loader', 'css-loader'], + }, + { + test: /\.(eot|svg|ttf|woff|woff2)$/, + loader: 'file-loader', + options: { + name: '[name].[ext]', + outputPath: 'lds/', + }, + }, ...
postinstall 時の処理
次に、npm install 後に LDS を静的リソース配信用のディレクトリ(ここでは public/assets/lds/
)にコピーしておきます。
ドキュメントでは postinstall.js スクリプトを作ってシンボリックリンクを貼る処理をやっているようですが、単にコピーするだけなら package.json 内に記述しても十分だと思います。
// package.json
{
"scripts": {
+ "postinstall": "rm -rf public/assets/lds && cp -r node_modules/@salesforce-ux/design-system/assets public/assets/lds",
...
}
読み込み
アプリのエントリーポイントで
// public/index.js import { render } from 'react-dom'; import { AppContainer } from 'react-hot-loader'; +import '@salesforce-ux/design-system/assets/styles/salesforce-lightning-design-system.min.css'; + import configureStore from './store/configureStore'; import App from './containers/App'; ...
とすれば OK です。
3. Icon パスの設定
最後にもう一点だけ。Icon を使う場合、アプリのルートで <IconSettings>
コンポーネントを使い、パスを正しく設定しておく必要があります。
README#icon-usage や SLDS React | Icon Settings あたりに記載があります。
// public/index.js import { AppContainer } from 'react-hot-loader'; import '@salesforce-ux/design-system/assets/styles/salesforce-lightning-design-system.min.css'; +import IconSettings from '@salesforce/design-system-react/components/icon-settings'; import configureStore from './store/configureStore'; import App from './containers/App'; import './styles/index.scss'; const store = configureStore(); const rootEl = document.getElementById('root'); +const LDS_ROOT = 'assets/lds'; render( <AppContainer> <Provider store={store}> - <App /> + <IconSettings + standardSprite={`${LDS_ROOT}/icons/standard-sprite/svg/symbols.svg`} + utilitySprite={`${LDS_ROOT}/icons/utility-sprite/svg/symbols.svg`} + actionSprite={`${LDS_ROOT}/icons/action-sprite/svg/symbols.svg`} + doctypeSprite={`${LDS_ROOT}/icons/doctype-sprite/svg/symbols.svg`} + customSprite={`${LDS_ROOT}/icons/custom-sprite/svg/symbols.svg`} + > + <App /> + </IconSettings> </Provider> </AppContainer>, rootEl, );
ここに関してはよくわかってないことが 2 点あって、
1) <IconSettings>
には iconPath
を指定する方法と、xxxSprite
というアイコンの種類ごとのパスを指定する方法とあるんですが、webpack を使ってると後者を推奨してるようです。
Individual sprites If you are using webpack it is advised to use the sprite properties {actionSprite, standardSprite...} to specify the individual sprite paths so that webpack can easily re-write the paths.
この PR で追加されたようで、そこでも webpack のためにということが書かれていますが詳しいことはよくわからず。
2) xxxSprite
の指定のしかたとして、Example にあるように
import actionSprite from '@salesforce-ux/design-system/assets/icons/action-sprite/svg/symbols.svg';
のようにすればいいのかなと思ったんですが、なぜかうまくいかず。。。
結局 postinstall でコピーした方のパスを指定してうまくいったのでそうしています。
結果
<Button>
だけですが、無事に LDS のスタイルがあたった状態でコンポーネントが描画できていることが確認できました。アイコンも表示されています。
おわりに
書いてみるとなんてことないんですが、 @salesforce
がちょいちょい抜けてたりとドキュメントの整備が追いついてないみたいで結構ハマりました。。。
とりあえず使えるところまでできてよかった。
トラブルシューティング
遭遇したエラー達。
ERROR in ./node_modules/@salesforce/design-system-react/components/button/index.jsx Module parse failed: Unexpected token (228:3) You may need an appropriate loader to handle this file type.
ERROR in ./public/components/App.js Module not found: Error: Can't resolve '@salesforce/design-system-react/components/button' in '/Users/yamazaki/workspace/react/redux-express-template/public/components'
→ webpack の設定不備。 .jsx
がビルド対象になっていない、 node_modules/@salesforce/design-system-react
が include されていない、などなど。
/Users/yamazaki/workspace/react/redux-express-template/node_modules/webpack/lib/webpack.js:19 throw new WebpackOptionsValidationError(webpackOptionsValidationErrors); ^ WebpackOptionsValidationError: Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema. - configuration.resolve.extensions[0] should not be empty. -> A non-empty string at webpack (/Users/yamazaki/workspace/react/redux-express-template/node_modules/webpack/lib/webpack.js:19:9) at Object.<anonymous> (/Users/yamazaki/workspace/react/redux-express-template/app.js:13:20) at Module._compile (module.js:643:30) at babelWatchLoader (/Users/yamazaki/workspace/react/redux-express-template/node_modules/babel-watch/runner.js:50:13) at Object.require.extensions.(anonymous function) [as .js] (/Users/yamazaki/workspace/react/redux-express-template/node_modules/babel-watch/runner.js:61:7) at Module.load (module.js:556:32) at tryModuleLoad (module.js:499:12) at Function.Module._load (module.js:491:3) at Function.Module.runMain (module.js:684:10) at process.on (/Users/yamazaki/workspace/react/redux-express-template/node_modules/babel-watch/runner.js:108:21)
→ webpack の resolve.exntensions
に空文字 ['', '.js', '.jsx']
は webpack 2 系以降 NG になったぽい。使うなら'*'
。