mirror of
https://github.com/bitwarden/browser
synced 2025-12-14 15:23:33 +00:00
[EC-424] top level vault (#4267)
* [EC-424] remove cog menu and header hr * [EC-424] change "Add item" to "New item" * [EC-424] include text for "New item" * [EC-424] add new item dropdown to org vault - add parent collection to dialog params * [EC-14] show Add Item if missing permissions
This commit is contained in:
@@ -36,6 +36,7 @@ export interface CollectionDialogParams {
|
|||||||
collectionId?: string;
|
collectionId?: string;
|
||||||
organizationId: string;
|
organizationId: string;
|
||||||
initialTab?: CollectionDialogTabType;
|
initialTab?: CollectionDialogTabType;
|
||||||
|
parentCollectionId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum CollectionDialogResult {
|
export enum CollectionDialogResult {
|
||||||
@@ -133,6 +134,8 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.nestOptions = collections;
|
this.nestOptions = collections;
|
||||||
|
const parent = collections.find((c) => c.id === this.params.parentCollectionId);
|
||||||
|
this.formGroup.patchValue({ parent: parent?.name ?? null });
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-9">
|
<div class="col-9">
|
||||||
<div class="page-header d-flex">
|
<div class="tw-mb-4 tw-flex">
|
||||||
<h1>
|
<h1>
|
||||||
{{ "vaultItems" | i18n }}
|
{{ "vaultItems" | i18n }}
|
||||||
<small #actionSpinner [appApiAction]="vaultItemsComponent.actionPromise">
|
<small #actionSpinner [appApiAction]="vaultItemsComponent.actionPromise">
|
||||||
@@ -30,20 +30,44 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
</small>
|
</small>
|
||||||
</h1>
|
</h1>
|
||||||
<div class="ml-auto d-flex">
|
<div *ngIf="!activeFilter.isDeleted" class="ml-auto d-flex">
|
||||||
<app-vault-bulk-actions
|
<div *ngIf="organization.canCreateNewCollections" class="dropdown mr-2" appListDropdown>
|
||||||
[vaultItemsComponent]="vaultItemsComponent"
|
<button
|
||||||
[deleted]="activeFilter.isDeleted"
|
class="btn"
|
||||||
[organization]="organization"
|
bitButton
|
||||||
>
|
buttonType="primary"
|
||||||
</app-vault-bulk-actions>
|
type="button"
|
||||||
|
data-toggle="dropdown"
|
||||||
|
id="newItemDropdown"
|
||||||
|
aria-haspopup="true"
|
||||||
|
aria-expanded="false"
|
||||||
|
appA11yTitle="{{ 'new' | i18n }}"
|
||||||
|
>
|
||||||
|
{{ "new" | i18n }}<i class="bwi bwi-angle-down tw-ml-2" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
id="dropdown"
|
||||||
|
class="dropdown-menu dropdown-menu-right tw-mt-2"
|
||||||
|
aria-labelledby="newItemDropdown"
|
||||||
|
>
|
||||||
|
<button class="dropdown-item" appStopClick (click)="addCipher()">
|
||||||
|
<i class="bwi bwi-fw bwi-globe" aria-hidden="true"></i>
|
||||||
|
{{ "item" | i18n }}
|
||||||
|
</button>
|
||||||
|
<button class="dropdown-item" appStopClick (click)="addCollection()">
|
||||||
|
<i class="bwi bwi-fw bwi-collection" aria-hidden="true"></i>
|
||||||
|
{{ "collection" | i18n }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<button
|
<button
|
||||||
|
*ngIf="!organization?.canCreateNewCollections"
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-outline-primary btn-sm ml-auto"
|
bitButton
|
||||||
|
buttonType="primary"
|
||||||
(click)="addCipher()"
|
(click)="addCipher()"
|
||||||
*ngIf="!activeFilter.isDeleted"
|
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-plus bwi-fw" aria-hidden="true"></i>{{ "addItem" | i18n }}
|
<i class="bwi bwi-plus bwi-fw" aria-hidden="true"></i>{{ "newItem" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
ViewContainerRef,
|
ViewContainerRef,
|
||||||
} from "@angular/core";
|
} from "@angular/core";
|
||||||
import { ActivatedRoute, Params, Router } from "@angular/router";
|
import { ActivatedRoute, Params, Router } from "@angular/router";
|
||||||
import { combineLatest, firstValueFrom, Subject } from "rxjs";
|
import { combineLatest, firstValueFrom, lastValueFrom, Subject } from "rxjs";
|
||||||
import { first, switchMap, takeUntil } from "rxjs/operators";
|
import { first, switchMap, takeUntil } from "rxjs/operators";
|
||||||
|
|
||||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||||
@@ -22,10 +22,15 @@ import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUti
|
|||||||
import { SyncService } from "@bitwarden/common/abstractions/sync/sync.service.abstraction";
|
import { SyncService } from "@bitwarden/common/abstractions/sync/sync.service.abstraction";
|
||||||
import { Organization } from "@bitwarden/common/models/domain/organization";
|
import { Organization } from "@bitwarden/common/models/domain/organization";
|
||||||
import { CipherView } from "@bitwarden/common/models/view/cipher.view";
|
import { CipherView } from "@bitwarden/common/models/view/cipher.view";
|
||||||
|
import { DialogService } from "@bitwarden/components";
|
||||||
|
|
||||||
import { VaultFilterService } from "../../vault/vault-filter/services/abstractions/vault-filter.service";
|
import { VaultFilterService } from "../../vault/vault-filter/services/abstractions/vault-filter.service";
|
||||||
import { VaultFilter } from "../../vault/vault-filter/shared/models/vault-filter.model";
|
import { VaultFilter } from "../../vault/vault-filter/shared/models/vault-filter.model";
|
||||||
import { EntityEventsComponent } from "../manage/entity-events.component";
|
import { EntityEventsComponent } from "../manage/entity-events.component";
|
||||||
|
import {
|
||||||
|
CollectionDialogResult,
|
||||||
|
openCollectionDialog,
|
||||||
|
} from "../shared/components/collection-dialog";
|
||||||
|
|
||||||
import { AddEditComponent } from "./add-edit.component";
|
import { AddEditComponent } from "./add-edit.component";
|
||||||
import { AttachmentsComponent } from "./attachments.component";
|
import { AttachmentsComponent } from "./attachments.component";
|
||||||
@@ -66,6 +71,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
|||||||
private syncService: SyncService,
|
private syncService: SyncService,
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
private modalService: ModalService,
|
private modalService: ModalService,
|
||||||
|
private dialogService: DialogService,
|
||||||
private messagingService: MessagingService,
|
private messagingService: MessagingService,
|
||||||
private broadcasterService: BroadcasterService,
|
private broadcasterService: BroadcasterService,
|
||||||
private ngZone: NgZone,
|
private ngZone: NgZone,
|
||||||
@@ -160,6 +166,21 @@ export class VaultComponent implements OnInit, OnDestroy {
|
|||||||
this.vaultItemsComponent.search(200);
|
this.vaultItemsComponent.search(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async addCollection() {
|
||||||
|
const dialog = openCollectionDialog(this.dialogService, {
|
||||||
|
data: {
|
||||||
|
organizationId: this.organization?.id,
|
||||||
|
parentCollectionId: this.activeFilter.collectionId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const result = await lastValueFrom(dialog.closed);
|
||||||
|
if (result === CollectionDialogResult.Saved || result === CollectionDialogResult.Deleted) {
|
||||||
|
this.vaultItemsComponent.actionPromise = this.vaultItemsComponent.refresh();
|
||||||
|
await this.vaultItemsComponent.actionPromise;
|
||||||
|
this.vaultItemsComponent.actionPromise = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async editCipherAttachments(cipher: CipherView) {
|
async editCipherAttachments(cipher: CipherView) {
|
||||||
if (this.organization.maxStorageGb == null || this.organization.maxStorageGb === 0) {
|
if (this.organization.maxStorageGb == null || this.organization.maxStorageGb === 0) {
|
||||||
this.messagingService.send("upgradeOrganization", { organizationId: cipher.organizationId });
|
this.messagingService.send("upgradeOrganization", { organizationId: cipher.organizationId });
|
||||||
|
|||||||
@@ -103,7 +103,6 @@ import { ToolsComponent } from "../tools/tools.component";
|
|||||||
import { AddEditCustomFieldsComponent } from "../vault/add-edit-custom-fields.component";
|
import { AddEditCustomFieldsComponent } from "../vault/add-edit-custom-fields.component";
|
||||||
import { AddEditComponent } from "../vault/add-edit.component";
|
import { AddEditComponent } from "../vault/add-edit.component";
|
||||||
import { AttachmentsComponent } from "../vault/attachments.component";
|
import { AttachmentsComponent } from "../vault/attachments.component";
|
||||||
import { BulkActionsComponent } from "../vault/bulk-actions.component";
|
|
||||||
import { CollectionsComponent } from "../vault/collections.component";
|
import { CollectionsComponent } from "../vault/collections.component";
|
||||||
import { FolderAddEditComponent } from "../vault/folder-add-edit.component";
|
import { FolderAddEditComponent } from "../vault/folder-add-edit.component";
|
||||||
import { ShareComponent } from "../vault/share.component";
|
import { ShareComponent } from "../vault/share.component";
|
||||||
@@ -130,7 +129,6 @@ import { SharedModule } from "./shared.module";
|
|||||||
ApiKeyComponent,
|
ApiKeyComponent,
|
||||||
AttachmentsComponent,
|
AttachmentsComponent,
|
||||||
BillingSyncKeyComponent,
|
BillingSyncKeyComponent,
|
||||||
BulkActionsComponent,
|
|
||||||
ChangeEmailComponent,
|
ChangeEmailComponent,
|
||||||
ChangeKdfComponent,
|
ChangeKdfComponent,
|
||||||
ChangePasswordComponent,
|
ChangePasswordComponent,
|
||||||
@@ -237,7 +235,6 @@ import { SharedModule } from "./shared.module";
|
|||||||
AdjustStorageComponent,
|
AdjustStorageComponent,
|
||||||
ApiKeyComponent,
|
ApiKeyComponent,
|
||||||
AttachmentsComponent,
|
AttachmentsComponent,
|
||||||
BulkActionsComponent,
|
|
||||||
ChangeEmailComponent,
|
ChangeEmailComponent,
|
||||||
ChangeKdfComponent,
|
ChangeKdfComponent,
|
||||||
ChangePasswordComponent,
|
ChangePasswordComponent,
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
<div class="dropdown mr-2" appListDropdown>
|
|
||||||
<button
|
|
||||||
class="btn btn-sm btn-outline-secondary dropdown-toggle"
|
|
||||||
type="button"
|
|
||||||
id="bulkActionsButton"
|
|
||||||
data-toggle="dropdown"
|
|
||||||
aria-haspopup="true"
|
|
||||||
aria-expanded="false"
|
|
||||||
appA11yTitle="{{ 'options' | i18n }}"
|
|
||||||
>
|
|
||||||
<i class="bwi bwi-cog" aria-hidden="true"></i>
|
|
||||||
</button>
|
|
||||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="bulkActionsButton">
|
|
||||||
<button
|
|
||||||
class="dropdown-item"
|
|
||||||
appStopClick
|
|
||||||
(click)="bulkMove()"
|
|
||||||
*ngIf="!deleted && !organization"
|
|
||||||
>
|
|
||||||
<i class="bwi bwi-fw bwi-folder" aria-hidden="true"></i>
|
|
||||||
{{ "moveSelected" | i18n }}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="dropdown-item"
|
|
||||||
appStopClick
|
|
||||||
(click)="bulkShare()"
|
|
||||||
*ngIf="!deleted && !organization"
|
|
||||||
>
|
|
||||||
<i class="bwi bwi-fw bwi-arrow-circle-right" aria-hidden="true"></i>
|
|
||||||
{{ "moveSelectedToOrg" | i18n }}
|
|
||||||
</button>
|
|
||||||
<button class="dropdown-item" (click)="bulkRestore()" *ngIf="deleted && !organization">
|
|
||||||
<i class="bwi bwi-fw bwi-undo" aria-hidden="true"></i>
|
|
||||||
{{ "restoreSelected" | i18n }}
|
|
||||||
</button>
|
|
||||||
<button class="dropdown-item text-danger" (click)="bulkDelete()">
|
|
||||||
<i class="bwi bwi-fw bwi-trash" aria-hidden="true"></i>
|
|
||||||
{{ (deleted ? "permanentlyDeleteSelected" : "deleteSelected") | i18n }}
|
|
||||||
</button>
|
|
||||||
<div class="dropdown-divider"></div>
|
|
||||||
<button class="dropdown-item" appStopClick (click)="selectAll(true)">
|
|
||||||
<i class="bwi bwi-fw bwi-check-square" aria-hidden="true"></i>
|
|
||||||
{{ "selectAll" | i18n }}
|
|
||||||
</button>
|
|
||||||
<button class="dropdown-item" appStopClick (click)="selectAll(false)">
|
|
||||||
<i class="bwi bwi-fw bwi-minus-square" aria-hidden="true"></i>
|
|
||||||
{{ "unselectAll" | i18n }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
import { Component, Input } from "@angular/core";
|
|
||||||
import { lastValueFrom } from "rxjs";
|
|
||||||
|
|
||||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
|
||||||
import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service";
|
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
|
||||||
import { CipherRepromptType } from "@bitwarden/common/enums/cipherRepromptType";
|
|
||||||
import { Organization } from "@bitwarden/common/models/domain/organization";
|
|
||||||
import { DialogService } from "@bitwarden/components";
|
|
||||||
|
|
||||||
import {
|
|
||||||
BulkDeleteDialogResult,
|
|
||||||
openBulkDeleteDialog,
|
|
||||||
} from "./bulk-action-dialogs/bulk-delete-dialog/bulk-delete-dialog.component";
|
|
||||||
import {
|
|
||||||
BulkMoveDialogResult,
|
|
||||||
openBulkMoveDialog,
|
|
||||||
} from "./bulk-action-dialogs/bulk-move-dialog/bulk-move-dialog.component";
|
|
||||||
import {
|
|
||||||
BulkRestoreDialogResult,
|
|
||||||
openBulkRestoreDialog,
|
|
||||||
} from "./bulk-action-dialogs/bulk-restore-dialog/bulk-restore-dialog.component";
|
|
||||||
import {
|
|
||||||
BulkShareDialogResult,
|
|
||||||
openBulkShareDialog,
|
|
||||||
} from "./bulk-action-dialogs/bulk-share-dialog/bulk-share-dialog.component";
|
|
||||||
import { VaultItemsComponent } from "./vault-items.component";
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: "app-vault-bulk-actions",
|
|
||||||
templateUrl: "bulk-actions.component.html",
|
|
||||||
})
|
|
||||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
|
|
||||||
export class BulkActionsComponent {
|
|
||||||
@Input() vaultItemsComponent: VaultItemsComponent;
|
|
||||||
@Input() deleted: boolean;
|
|
||||||
@Input() organization: Organization;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private platformUtilsService: PlatformUtilsService,
|
|
||||||
private i18nService: I18nService,
|
|
||||||
private dialogService: DialogService,
|
|
||||||
private passwordRepromptService: PasswordRepromptService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async bulkDelete() {
|
|
||||||
if (!(await this.promptPassword())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectedCipherIds = this.vaultItemsComponent.selectedCipherIds;
|
|
||||||
if (selectedCipherIds.length === 0) {
|
|
||||||
this.platformUtilsService.showToast(
|
|
||||||
"error",
|
|
||||||
this.i18nService.t("errorOccurred"),
|
|
||||||
this.i18nService.t("nothingSelected")
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dialog = openBulkDeleteDialog(this.dialogService, {
|
|
||||||
data: {
|
|
||||||
permanent: this.deleted,
|
|
||||||
cipherIds: selectedCipherIds,
|
|
||||||
organization: this.organization,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await lastValueFrom(dialog.closed);
|
|
||||||
if (result === BulkDeleteDialogResult.Deleted) {
|
|
||||||
await this.vaultItemsComponent.refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async bulkRestore() {
|
|
||||||
if (!(await this.promptPassword())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectedCipherIds = this.vaultItemsComponent.selectedCipherIds;
|
|
||||||
if (selectedCipherIds.length === 0) {
|
|
||||||
this.platformUtilsService.showToast(
|
|
||||||
"error",
|
|
||||||
this.i18nService.t("errorOccurred"),
|
|
||||||
this.i18nService.t("nothingSelected")
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dialog = openBulkRestoreDialog(this.dialogService, {
|
|
||||||
data: {
|
|
||||||
cipherIds: selectedCipherIds,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await lastValueFrom(dialog.closed);
|
|
||||||
if (result === BulkRestoreDialogResult.Restored) {
|
|
||||||
this.vaultItemsComponent.refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async bulkShare() {
|
|
||||||
if (!(await this.promptPassword())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectedCiphers = this.vaultItemsComponent.selectedCiphers;
|
|
||||||
if (selectedCiphers.length === 0) {
|
|
||||||
this.platformUtilsService.showToast(
|
|
||||||
"error",
|
|
||||||
this.i18nService.t("errorOccurred"),
|
|
||||||
this.i18nService.t("nothingSelected")
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dialog = openBulkShareDialog(this.dialogService, { data: { ciphers: selectedCiphers } });
|
|
||||||
|
|
||||||
const result = await lastValueFrom(dialog.closed);
|
|
||||||
if (result === BulkShareDialogResult.Shared) {
|
|
||||||
this.vaultItemsComponent.refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async bulkMove() {
|
|
||||||
if (!(await this.promptPassword())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectedCipherIds = this.vaultItemsComponent.selectedCipherIds;
|
|
||||||
if (selectedCipherIds.length === 0) {
|
|
||||||
this.platformUtilsService.showToast(
|
|
||||||
"error",
|
|
||||||
this.i18nService.t("errorOccurred"),
|
|
||||||
this.i18nService.t("nothingSelected")
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dialog = openBulkMoveDialog(this.dialogService, {
|
|
||||||
data: { cipherIds: selectedCipherIds },
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await lastValueFrom(dialog.closed);
|
|
||||||
if (result === BulkMoveDialogResult.Moved) {
|
|
||||||
this.vaultItemsComponent.refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
selectAll(select: boolean) {
|
|
||||||
this.vaultItemsComponent.checkAll(select);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async promptPassword() {
|
|
||||||
const selectedCiphers = this.vaultItemsComponent.selectedCiphers;
|
|
||||||
const notProtected = !selectedCiphers.find(
|
|
||||||
(cipher) => cipher.reprompt !== CipherRepromptType.None
|
|
||||||
);
|
|
||||||
|
|
||||||
return notProtected || (await this.passwordRepromptService.showPasswordPrompt());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div [ngClass]="{ 'col-6': isShowingCards, 'col-9': !isShowingCards }">
|
<div [ngClass]="{ 'col-6': isShowingCards, 'col-9': !isShowingCards }">
|
||||||
<div class="page-header d-flex">
|
<div class="tw-mb-4 tw-flex">
|
||||||
<h1>
|
<h1>
|
||||||
{{ "vaultItems" | i18n }}
|
{{ "vaultItems" | i18n }}
|
||||||
<small #actionSpinner [appApiAction]="vaultItemsComponent.actionPromise">
|
<small #actionSpinner [appApiAction]="vaultItemsComponent.actionPromise">
|
||||||
@@ -32,18 +32,14 @@
|
|||||||
</small>
|
</small>
|
||||||
</h1>
|
</h1>
|
||||||
<div class="ml-auto d-flex">
|
<div class="ml-auto d-flex">
|
||||||
<app-vault-bulk-actions
|
|
||||||
[vaultItemsComponent]="vaultItemsComponent"
|
|
||||||
[deleted]="activeFilter.isDeleted"
|
|
||||||
>
|
|
||||||
</app-vault-bulk-actions>
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-outline-primary btn-sm"
|
bitButton
|
||||||
|
buttonType="primary"
|
||||||
(click)="addCipher()"
|
(click)="addCipher()"
|
||||||
*ngIf="!activeFilter.isDeleted"
|
*ngIf="!activeFilter.isDeleted"
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-plus bwi-fw" aria-hidden="true"></i>{{ "addItem" | i18n }}
|
<i class="bwi bwi-plus bwi-fw" aria-hidden="true"></i>{{ "newItem" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -386,6 +386,9 @@
|
|||||||
"select": {
|
"select": {
|
||||||
"message": "Select"
|
"message": "Select"
|
||||||
},
|
},
|
||||||
|
"newItem": {
|
||||||
|
"message": "New item"
|
||||||
|
},
|
||||||
"addItem": {
|
"addItem": {
|
||||||
"message": "Add item"
|
"message": "Add item"
|
||||||
},
|
},
|
||||||
@@ -395,6 +398,14 @@
|
|||||||
"viewItem": {
|
"viewItem": {
|
||||||
"message": "View item"
|
"message": "View item"
|
||||||
},
|
},
|
||||||
|
"new":
|
||||||
|
{
|
||||||
|
"message": "New",
|
||||||
|
"description": "for adding new items"
|
||||||
|
},
|
||||||
|
"item": {
|
||||||
|
"message": "Item"
|
||||||
|
},
|
||||||
"ex": {
|
"ex": {
|
||||||
"message": "ex.",
|
"message": "ex.",
|
||||||
"description": "Short abbreviation for 'example'."
|
"description": "Short abbreviation for 'example'."
|
||||||
|
|||||||
Reference in New Issue
Block a user