@things-factory/auth-ui 10.1.254 → 10.1.257

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/dist-client/bootstrap.js +2 -2
  2. package/dist-client/bootstrap.js.map +1 -1
  3. package/dist-client/components/access-decision-popup.d.ts +9 -8
  4. package/dist-client/components/access-decision-popup.js +46 -58
  5. package/dist-client/components/access-decision-popup.js.map +1 -1
  6. package/dist-client/components/access-request-popup.d.ts +13 -8
  7. package/dist-client/components/access-request-popup.js +78 -102
  8. package/dist-client/components/access-request-popup.js.map +1 -1
  9. package/dist-client/components/app-binding-detail.d.ts +7 -5
  10. package/dist-client/components/app-binding-detail.js +62 -82
  11. package/dist-client/components/app-binding-detail.js.map +1 -1
  12. package/dist-client/components/appliance-editor.d.ts +10 -9
  13. package/dist-client/components/appliance-editor.js +87 -138
  14. package/dist-client/components/appliance-editor.js.map +1 -1
  15. package/dist-client/components/application-editor.d.ts +7 -5
  16. package/dist-client/components/application-editor.js +58 -92
  17. package/dist-client/components/application-editor.js.map +1 -1
  18. package/dist-client/components/my-login-history.js +18 -40
  19. package/dist-client/components/my-login-history.js.map +1 -1
  20. package/dist-client/components/my-passkeys.d.ts +4 -3
  21. package/dist-client/components/my-passkeys.js +29 -51
  22. package/dist-client/components/my-passkeys.js.map +1 -1
  23. package/dist-client/components/my-roles.d.ts +3 -4
  24. package/dist-client/components/my-roles.js +36 -55
  25. package/dist-client/components/my-roles.js.map +1 -1
  26. package/dist-client/components/partner-role-editor.js +27 -50
  27. package/dist-client/components/partner-role-editor.js.map +1 -1
  28. package/dist-client/components/profile-component.d.ts +2 -2
  29. package/dist-client/components/profile-component.js +18 -26
  30. package/dist-client/components/profile-component.js.map +1 -1
  31. package/dist-client/components/role-template-picker.d.ts +3 -3
  32. package/dist-client/components/role-template-picker.js +28 -42
  33. package/dist-client/components/role-template-picker.js.map +1 -1
  34. package/dist-client/components/user-detail.d.ts +23 -22
  35. package/dist-client/components/user-detail.js +125 -179
  36. package/dist-client/components/user-detail.js.map +1 -1
  37. package/dist-client/components/user-invite.d.ts +8 -6
  38. package/dist-client/components/user-invite.js +106 -141
  39. package/dist-client/components/user-invite.js.map +1 -1
  40. package/dist-client/components/user-popups-standard.test.js +1 -1
  41. package/dist-client/components/user-popups-standard.test.js.map +1 -1
  42. package/dist-client/components/user-role-editor.js +72 -122
  43. package/dist-client/components/user-role-editor.js.map +1 -1
  44. package/dist-client/entity360/person-360.d.ts +8 -11
  45. package/dist-client/entity360/person-360.js +49 -68
  46. package/dist-client/entity360/person-360.js.map +1 -1
  47. package/dist-client/entries/oauth2/oauth2-decision-page.js +13 -25
  48. package/dist-client/entries/oauth2/oauth2-decision-page.js.map +1 -1
  49. package/dist-client/identity-confirmation/identity-confirmation.d.ts +13 -14
  50. package/dist-client/identity-confirmation/identity-confirmation.js +39 -45
  51. package/dist-client/identity-confirmation/identity-confirmation.js.map +1 -1
  52. package/dist-client/pages/audit/audit-page.d.ts +4 -4
  53. package/dist-client/pages/audit/audit-page.js +28 -39
  54. package/dist-client/pages/audit/audit-page.js.map +1 -1
  55. package/dist-client/pages/domain-link/domain-link-management.js +1 -1
  56. package/dist-client/pages/domain-link/domain-link-management.js.map +1 -1
  57. package/dist-client/pages/partner/partner-management.js +30 -68
  58. package/dist-client/pages/partner/partner-management.js.map +1 -1
  59. package/dist-client/pages/role/role-extra-removal.test.d.mts +1 -0
  60. package/dist-client/pages/role/role-extra-removal.test.mjs +73 -0
  61. package/dist-client/pages/role/role-extra-removal.test.mjs.map +1 -0
  62. package/dist-client/pages/role/role-list-page.js +20 -22
  63. package/dist-client/pages/role/role-list-page.js.map +1 -1
  64. package/dist-client/pages/role/role-privilege-page.d.ts +36 -8
  65. package/dist-client/pages/role/role-privilege-page.js +216 -158
  66. package/dist-client/pages/role/role-privilege-page.js.map +1 -1
  67. package/dist-client/pages/role/role-task-review.test.js +20 -16
  68. package/dist-client/pages/role/role-task-review.test.js.map +1 -1
  69. package/dist-client/pages/role/role-template-gap.test.js +8 -3
  70. package/dist-client/pages/role/role-template-gap.test.js.map +1 -1
  71. package/dist-client/tsconfig.tsbuildinfo +1 -1
  72. package/helps/auth/roles.en.md +13 -49
  73. package/helps/auth/roles.ko.md +13 -32
  74. package/package.json +9 -8
  75. package/tests/page-state.test.ts +2 -1
  76. package/tests/password-rule-shown.test.ts +2 -2
  77. package/tests/person-360-sections.test.ts +9 -5
  78. package/translations/en.json +5 -1
  79. package/translations/es.json +5 -1
  80. package/translations/ja.json +5 -1
  81. package/translations/ko.json +5 -1
  82. package/translations/ms.json +5 -1
  83. package/translations/zh.json +5 -1
@@ -1,59 +1,23 @@
1
- # Roles
1
+ # Role management
2
2
 
3
- ![flowchart_role_management](./images/flowchart-role-management.jpg)
3
+ Roles define the access privileges granted to users. The list shows each role's privilege count and user count. Assign roles to users through user management.
4
4
 
5
- Operato has roles for users’ access rights. Each role confers a different set of privileges for a given user of Operato. For example, users who have **Admin** rights can restrict other users’ access rights so that they cannot view or modify internal information.
5
+ ## Add and edit roles
6
6
 
7
- ### Properties
7
+ Use **Add role** to choose a template or create a role without privileges. Edit names and descriptions in the role list and save. Use **Edit privileges** to review and edit a role's tasks and individual privileges.
8
8
 
9
- - **Roles**: job (title) or role name
10
- - **Privileges**: privileges to access the system
9
+ Inherited roles are read-only. Edit them in the domain that owns them.
11
10
 
12
- ### Role List
11
+ ## Compare with a template
13
12
 
14
- You can search the roles registered by domain.
15
- ![registered_role](./images/registered-role.png)
13
+ The **Vs template** column shows both missing and extra privilege counts against the base template. Comparisons use saved privileges. Extra privileges may be intentional.
16
14
 
17
- ### Type of Roles
15
+ - **Add** shows the missing privileges and asks for confirmation before adding them.
16
+ - **Review extras** opens the role's template comparison to review privileges outside the template.
17
+ - **Remove extra privileges** shows the privileges and impact before confirmation. Confirming removes the displayed extras; cancelling keeps them. Other roles remain unchanged.
18
18
 
19
- 1. Main role
19
+ Save or cancel pending edits before adding or removing privileges through template comparison. Changing the base template does not automatically add or remove privileges.
20
20
 
21
- - It has privilege to access Operato.
21
+ ## Delete roles
22
22
 
23
- | ROLES | PRIVILEGE |
24
- | :---------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- |
25
- | Admin | Can invite users to Operato Hub, have full privilege in WMS |
26
- | Customer | Can create Goods Arrival Notice (GAN) and Release Order (RO), and view reports |
27
- | Office admin | Can receive or approve the request of Goods Arrival Notice (GAN), Release Order (RO), activate worksheets and generate reports in Operato WMS for customers |
28
- | Warehouse manager | Execute unloading, putaway, returning, picking, batch picking and loading |
29
- | Warehouse staff | Execute unloading, putaway, returning, picking, batch picking and loading |
30
-
31
- ---
32
-
33
- 2. Shared role
34
-
35
- - It is used to assign menus in the Operato WMS.
36
-
37
- ## <ins>Create Role</ins>
38
-
39
- **Admins** can add any role they want.
40
- ![create_role](./images/create-role.png)
41
-
42
- 1. Enter the name and description according to the form format.
43
- 2. Click ![create_button](./images/create-button2.png)
44
-
45
- ## <ins>Update Role</ins>
46
-
47
- Click on a role name to edit the role's name, description and privileges.
48
-
49
- ### Role Privilages
50
-
51
- Below the role name, a list of access rights for functions is displayed. After checking the desired authority, click ![save_button](./images/save-button2.png)
52
-
53
- ![role_privilage](./images/role-privilage.png)
54
-
55
- You can grant roles to users in a bizplace through the **User Management** menu which is accessible through the **Users** tab in the sidebar.
56
-
57
- ## <ins>Delete Role</ins>
58
-
59
- You can delete unused roles. Please note that if a partner is using a role, it cannot be deleted.
23
+ Select unused roles and choose **Delete**. Roles assigned to users and inherited roles cannot be deleted here.
@@ -1,42 +1,23 @@
1
- # roles
1
+ # 역할 관리
2
2
 
3
- operato는 사용자들의 접근 권한을 위한 역할들이 존재합니다. 각각의 역할에 따라 operato system을 사용하는 기능들에 대한 접근 권한을 둘 수 있습니다.<br>
4
- 예를 들어, 관리자 권한이 없는 일반 사용자의 경우 내부 정보를 조회하거나 수정할 수 없도록 읽기, 편집 등의 접근 권한을 제한할 수 있습니다.<br>
3
+ 역할은 사용자에게 부여할 접근 권한을 정의합니다. 역할별 권한 수와 해당 역할이 부여된 사용자 수를 목록에서 확인할 수 있습니다. 역할을 사용자에게 부여하려면 사용자 관리에서 설정합니다.
5
4
 
6
- ## porperties
5
+ ## 역할 추가와 수정
7
6
 
8
- - **roles**
9
- : 직업(직책)이나 역할 이름
7
+ **역할 추가**에서 템플릿을 선택하거나 권한 없는 새 역할을 생성합니다. 이름과 설명은 역할 목록에서 수정하고 저장합니다. **권한 편집**을 누르면 역할의 업무와 개별 권한을 확인하고 수정할 수 있습니다.
10
8
 
11
- - **privileges**
12
- : 시스템에 접근할 수 있는 권한
9
+ 부모 도메인에서 상속된 역할은 조회만 가능합니다. 수정하려면 해당 역할을 관리하는 도메인에서 작업해야 합니다.
13
10
 
14
- ## role list
11
+ ## 템플릿과 비교
15
12
 
16
- 도메인별로 등록된 role을 조회할 수 있습니다.<br>
13
+ 목록의 **템플릿 대비** 열은 기준 템플릿보다 부족한 권한 수와 추가된 권한 수를 표시합니다. 이 비교는 저장된 권한을 기준으로 하며, 추가 권한이 있다는 사실만으로 설정 오류를 뜻하지는 않습니다.
17
14
 
18
- ![role_list](./images/role-list.png)
19
- <br>
15
+ - **추가**: 부족한 권한 목록을 확인한 뒤 역할에 추가합니다.
16
+ - **추가 권한 검토**: 해당 역할의 템플릿 비교 화면을 엽니다. 기준 템플릿에 없는 권한 목록을 검토할 수 있습니다.
17
+ - **추가 권한 삭제**: 삭제할 권한과 영향을 확인한 뒤 승인하면 표시된 추가 권한을 삭제합니다. 취소하면 유지합니다. 다른 역할의 권한은 변경하지 않습니다.
20
18
 
21
- ## create role
19
+ 저장하지 않은 편집 내용이 있으면 먼저 저장하거나 취소한 뒤 템플릿 권한을 추가·삭제해야 합니다. 템플릿 변경만으로 현재 권한이 자동 추가되거나 삭제되지는 않습니다.
22
20
 
23
- 관리자는 원하는 role을 추가할 수 있습니다.<br>
24
- ![create_role](./images/create-role.png)
25
- form 형식에 맞게 name, description을 입력 후 'create' 버튼을 클릭하여 생성합니다.<br>
26
- (role의 privileges는 role을 추가한 후 추가된 role을 클릭하여 수정할 수 있습니다.)
21
+ ## 역할 삭제
27
22
 
28
- ## update role
29
-
30
- role 이름을 클릭하면 해당 role의 이름, 설명과 privileges를 수정할 수 있습니다.
31
-
32
- ### role privileges
33
-
34
- role name아래에는 기능들에 대한 접근 권한 리스트가 보여지며, 원하는 권한을 체크한 후 'save'버튼을 클릭하여 저장합니다.
35
- ![role_privileges](./images/role-privileges.png)
36
-
37
- _<u>사용자에게 role을 부여하려면 user 관리 메뉴에서 도메인에 속한 사용자들의 role을 설정할 수 있습니다.</u>_
38
-
39
- ## delete role
40
-
41
- 사용하지 않는 role을 삭제할 수 있습니다.<br>
42
- <u>\* partner에서 role을 사용하고 있을 경우 삭제가 되지 않습니다.</u>
23
+ 사용하지 않는 역할을 선택하고 **삭제**를 누릅니다. 사용자에게 부여된 역할과 상속된 역할은 이 화면에서 삭제할 수 없습니다.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/auth-ui",
3
- "version": "10.1.254",
3
+ "version": "10.1.257",
4
4
  "main": "dist-server/index.js",
5
5
  "browser": "dist-client/index.js",
6
6
  "things-factory": true,
@@ -29,25 +29,26 @@
29
29
  "dependencies": {
30
30
  "@material/web": "^2.0.0",
31
31
  "@operato/attribute": "^10.29.39",
32
- "@operato/data-grist": "^10.29.39",
32
+ "@operato/data-grist": "^10.29.69",
33
+ "@operato/graphql": "^10.29.69",
33
34
  "@operato/i18n": "^10.0.0",
34
35
  "@operato/input": "^10.29.39",
35
- "@operato/layout": "^10.29.39",
36
+ "@operato/layout": "^10.29.69",
36
37
  "@operato/list-state": "^10.29.39",
37
38
  "@operato/lottie-player": "^10.0.0",
38
39
  "@operato/moment-timezone-es": "^10.0.0",
39
40
  "@operato/oops": "^10.29.49",
40
41
  "@operato/p13n": "^10.29.39",
41
42
  "@operato/popup": "^10.29.39",
42
- "@operato/shell": "^10.29.39",
43
+ "@operato/shell": "^10.29.69",
43
44
  "@operato/styles": "^10.0.0",
44
- "@operato/utils": "^10.29.39",
45
+ "@operato/utils": "^10.29.69",
45
46
  "@things-factory/apptool-base": "^10.1.254",
46
- "@things-factory/auth-base": "^10.1.254",
47
- "@things-factory/component-ui": "^10.1.254",
47
+ "@things-factory/auth-base": "^10.1.257",
48
+ "@things-factory/component-ui": "^10.1.257",
48
49
  "@things-factory/more-base": "^10.1.254",
49
50
  "base64url": "^3.0.1",
50
51
  "clipboard": "^2.0.6"
51
52
  },
52
- "gitHead": "793e2fd617db5bb917ec892e64956fb690f7e7b0"
53
+ "gitHead": "885b594299601ca4936f4f39701d6713273bbf1e"
53
54
  }
@@ -23,7 +23,8 @@ describe('role privileges says what happened', () => {
23
23
  })
24
24
 
25
25
  it('★ keeps what the server said, and offers to read it again', () => {
26
- expect(source).toMatch(/this\.loadError = response\.errors/)
26
+ /* What the server said, or what was thrown - the declared read keeps either as its error (ADR-0190). */
27
+ expect(source).toMatch(/this\.loadError = read\.error/)
27
28
  expect(source).toMatch(/\.error=\$\{this\.loadError\}/)
28
29
  expect(source).toMatch(/@retry=\$\{\(\) => this\.fetch\(\)\}/)
29
30
  })
@@ -15,8 +15,8 @@ const read = (file: string) => readFileSync(path.resolve(__dirname, '..', file),
15
15
  describe('the password rule shown is the server rule', () => {
16
16
  it('★ the profile hands over the rule, not the query answer', () => {
17
17
  const source = read('client/components/profile-component.ts')
18
- expect(source).toMatch(/this\.passwordRule = response\.data\?\.passwordRule\b/)
19
- expect(source).not.toMatch(/this\.passwordRule = response\.data\s*$/m)
18
+ expect(source).toMatch(/return this\.rule\.data\?\.passwordRule\b/)
19
+ expect(source).not.toMatch(/return this\.rule\.data\s*$/m)
20
20
  })
21
21
 
22
22
  it('★ the form draws the pattern and the help from the rule in render', () => {
@@ -49,14 +49,17 @@ describe('the person 360 sections', () => {
49
49
  '★ %s shows its door answer through the shared section frame, never its own none',
50
50
  (_, one) => {
51
51
  const code = read(one.file)
52
- expect(code).toMatch(/this\.answer = readEntity360Door\(response,/)
52
+ expect(code).toMatch(/return entity360Answer(<[^>]*>)?\(this\.\w+, /)
53
53
  expect(code).toMatch(/<ox-entity360-section[\s\S]*\.state=\$\{answer\?\.state \?\? 'loading'\}/)
54
54
  expect(code).toMatch(/\.message=\$\{answer\?\.message \?\? ''\}/)
55
55
  }
56
56
  )
57
57
 
58
- it.each(Object.entries(SECTIONS))('%s drops an answer for a subject that is no longer shown', (_, one) => {
59
- expect(read(one.file)).toMatch(/await client\.query[\s\S]*if \(this\.subject\?\.id !== id\) return\s*this\.answer =/)
58
+ it.each(Object.entries(SECTIONS))('%s reads for the subject shown, and nothing without one (ADR-0190)', (_, one) => {
59
+ const code = read(one.file)
60
+ expect(code).toMatch(/new QueryController\(/)
61
+ expect(code).toMatch(/variables: \(\) =>\s*\(?this\.subject\?\.id \?/)
62
+ expect(code).not.toMatch(/client\.query/)
60
63
  })
61
64
 
62
65
  it("★ roles are this site's - read through userRoles, never User.roles which answers every domain", () => {
@@ -74,7 +77,7 @@ describe('the person 360 sections', () => {
74
77
  })
75
78
 
76
79
  it('membership reads this person only', () => {
77
- expect(read(SECTIONS.membership.file)).toMatch(/filters: \[\{ name: 'userId', operator: 'eq', value: id \}\]/)
80
+ expect(read(SECTIONS.membership.file)).toMatch(/filters: \[\{ name: 'userId', operator: 'eq', value: this\.subject\.id \}\]/)
78
81
  })
79
82
 
80
83
  it('the dock reads who they are, then what they hold, then their roles', () => {
@@ -87,6 +90,7 @@ describe('the person 360 sections', () => {
87
90
  describe('signing out', () => {
88
91
  it('★ takes this user\'s unsaved drafts out of the browser before the page leaves (ADR-0098)', () => {
89
92
  const bootstrap = read('auth-ui/client/bootstrap.ts')
90
- expect(bootstrap).toMatch(/auth\.on\('presignout', async \(\) => \{\s*const user = \(auth\.credential as any\)\?\.id\s*if \(user\) await removeDraftsOf\(user\)/)
93
+ /* The drafts' owner is named in one place, @operato/shell draftOwner (ADR-0190). */
94
+ expect(bootstrap).toMatch(/auth\.on\('presignout', async \(\) => \{\s*const user = draftOwner\(\)\s*if \(user\) await removeDraftsOf\(user\)/)
91
95
  })
92
96
  })
@@ -546,5 +546,9 @@
546
546
  "text.my roles none": "You hold no role. Ask for access on the screen you need.",
547
547
  "text.my roles owner": "As the owner of this site you open some screens without a role - not the facts only their own role opens, such as pay and bank accounts.",
548
548
  "text.my roles count": "My roles ({count})",
549
- "text.my roles shared tasks": "Work every role of yours gives"
549
+ "text.my roles shared tasks": "Work every role of yours gives",
550
+ "text.extra against template": "{count} extra",
551
+ "button.review extra privileges": "Review extras",
552
+ "button.remove extra privileges": "Remove extra privileges",
553
+ "text.remove extra privileges": "Remove {count} privileges outside the {template} template from role {role}? This role will no longer grant these privileges. Other roles remain unchanged. Privileges to remove: {list}"
550
554
  }
@@ -546,5 +546,9 @@
546
546
  "text.my roles none": "No tiene ningún rol. Solicite acceso en la pantalla que necesita.",
547
547
  "text.my roles owner": "Como propietario del sitio abre algunas pantallas sin un rol, salvo los datos que solo abre su propio rol, como nóminas y cuentas bancarias.",
548
548
  "text.my roles count": "Mis roles ({count})",
549
- "text.my roles shared tasks": "Trabajo común a todos sus roles"
549
+ "text.my roles shared tasks": "Trabajo común a todos sus roles",
550
+ "text.extra against template": "{count} adicionales",
551
+ "button.review extra privileges": "Revisar adicionales",
552
+ "button.remove extra privileges": "Eliminar permisos adicionales",
553
+ "text.remove extra privileges": "¿Eliminar del rol {role} los {count} permisos que no están en la plantilla {template}? Este rol dejará de conceder esos permisos. Los permisos de otros roles se mantienen. Permisos que se eliminarán: {list}"
550
554
  }
@@ -546,5 +546,9 @@
546
546
  "text.my roles none": "付与されたロールがありません。必要な画面で権限を申請してください。",
547
547
  "text.my roles owner": "サイトの所有者なのでロールがなくても開ける画面があります。給与・口座のように担当ロールだけが開く情報は例外です。",
548
548
  "text.my roles count": "自分のロール {count}件",
549
- "text.my roles shared tasks": "すべてのロールに共通の業務"
549
+ "text.my roles shared tasks": "すべてのロールに共通の業務",
550
+ "text.extra against template": "追加 {count}件",
551
+ "button.review extra privileges": "追加権限を確認",
552
+ "button.remove extra privileges": "追加権限を削除",
553
+ "text.remove extra privileges": "役割「{role}」からテンプレート「{template}」に含まれない権限{count}件を削除しますか?この役割では対象の権限が付与されなくなります。他の役割の権限は維持されます。削除対象: {list}"
550
554
  }
@@ -546,5 +546,9 @@
546
546
  "text.my roles none": "부여받은 역할이 없습니다. 필요한 화면에서 권한을 요청하세요.",
547
547
  "text.my roles owner": "사업장 소유자라 역할 밖에서도 열리는 화면이 있습니다. 급여·계좌처럼 담당 역할만 여는 정보는 예외입니다.",
548
548
  "text.my roles count": "내 역할 {count}개",
549
- "text.my roles shared tasks": "모든 역할에 공통인 업무"
549
+ "text.my roles shared tasks": "모든 역할에 공통인 업무",
550
+ "text.extra against template": "추가 {count}개",
551
+ "button.review extra privileges": "추가 권한 검토",
552
+ "button.remove extra privileges": "추가 권한 삭제",
553
+ "text.remove extra privileges": "{role} 역할에서 {template} 템플릿에 포함되지 않은 권한 {count}개를 삭제하시겠습니까? 삭제하면 이 역할에 해당 권한이 부여되지 않습니다. 다른 역할의 권한은 유지됩니다. 삭제 대상: {list}"
550
554
  }
@@ -546,5 +546,9 @@
546
546
  "text.my roles none": "Anda tiada peranan. Mohon akses di skrin yang anda perlukan.",
547
547
  "text.my roles owner": "Sebagai pemilik tapak, anda boleh membuka sesetengah skrin tanpa peranan, kecuali maklumat yang hanya dibuka oleh peranannya sendiri seperti gaji dan akaun bank.",
548
548
  "text.my roles count": "Peranan saya ({count})",
549
- "text.my roles shared tasks": "Kerja yang sama bagi semua peranan anda"
549
+ "text.my roles shared tasks": "Kerja yang sama bagi semua peranan anda",
550
+ "text.extra against template": "{count} tambahan",
551
+ "button.review extra privileges": "Semak kebenaran tambahan",
552
+ "button.remove extra privileges": "Padam kebenaran tambahan",
553
+ "text.remove extra privileges": "Padam {count} kebenaran di luar templat {template} daripada peranan {role}? Peranan ini tidak lagi memberikan kebenaran tersebut. Kebenaran peranan lain kekal. Kebenaran untuk dipadam: {list}"
550
554
  }
@@ -546,5 +546,9 @@
546
546
  "text.my roles none": "您没有任何角色。请在需要的画面申请权限。",
547
547
  "text.my roles owner": "作为站点所有者,您无需角色也能打开部分画面;工资、账户等只由其负责角色打开的信息除外。",
548
548
  "text.my roles count": "我的角色 {count} 个",
549
- "text.my roles shared tasks": "所有角色共有的业务"
549
+ "text.my roles shared tasks": "所有角色共有的业务",
550
+ "text.extra against template": "额外 {count} 项",
551
+ "button.review extra privileges": "查看额外权限",
552
+ "button.remove extra privileges": "删除额外权限",
553
+ "text.remove extra privileges": "是否从角色 {role} 中删除模板 {template} 未包含的 {count} 项权限?此角色将不再授予这些权限。其他角色的权限保持不变。待删除权限:{list}"
550
554
  }