Commit 9738a977 authored by Boris Vasilenko's avatar Boris Vasilenko
Browse files

Merge branch 'master' into NAS-115340

parents d4e7d28e f53ab6e8
Showing with 191 additions and 198 deletions
+191 -198
......@@ -4,3 +4,6 @@
# These owners will be the default owners for everything in
# the repo. Unless a later match takes precedence,
* @truenas/ui-team
# Tests
/tests/** @truenas/releng
# Contributing
Anyone is free to help us build and maintain this project. If you see an issue that needs working on because it's important to you, you can contribute to the code by
- First fork the repo, and then clone it locally.
- Create a new branch.
- Review the [README](https://github.com/truenas/webui/blob/master/README.md) file to learn how to build and run the project as well as connect it to your TrueNAS
- Make the required changes.
## Branches
Here's the layout of the main branches
- `master` corresponds to most recent scale
- `truenas/12.0-stable` points to TrueNAS Core 12.0
- `truenas/13.0-stbale` corresponds to TrueNAS Core 13.0
Based on the version of TrueNAS that you would like to make changes to, base your branch from that branch in the project. This affects whether or not we're able to merge your changes back to the relevent version since they have significant differences and cannot be interchanged.
## Code Validation
ESLint is setup to ensure that the code is up to the format standards that we would like to keep in our project. If the linter sees issues in your project, it might ask you to fix those issues before you can make a commit. A set of precommit commands will run to extract new text into translation files and check linter for any issues.
### Translating the UI
If you want to contribute to the translation of our UI, you can do so by editing one of the `[language_name].json` files under `src\assets\i18n\`. In each of those files, text strings and their translations in the relevant language are kept as key/value pairs e.g.,
`
{
...,
"Translate this text": "[Translation]",
...
}
`
## Tests
When adding new changes, try to add unit tests when and where possible. Covering is also reported on the PRs by the `codecov` bot.
## Raise a Pull Request
Pull requests require at least one approved review from one of the members of the UI team before they can be merged. When you create a new PR, a member of the UI team will be automatically asked to review it. Alternatively, you can ask for review from @truenas/ui_team.
Once we have reviewed your PR, we will provide any feedback that needs addressing. If you feel a requested change is wrong, don't be afraid to discuss with us in the comments. Once the feedback is addressed, and the PR is reviewed, we'll ensure the branch is up to date with target, and merge it for you. Depending on the status of the project, sometimes only authorized members of the UI team can merge PRs. In which case, it might take a bit more time for it to be merged.
......@@ -108,3 +108,8 @@ You can test your strings in an [online editor](http://format-message.github.io/
Stock images used on the dashboard UI are courtesy of Pixabay.com and are subject to the Simplified Pixabay License.
Full license details can be found at https://pixabay.com/service/license/.
# Contributing
Learn how you can contribute to our project and help us maintain it [on our Contribution guide](https://github.com/truenas/webui/blob/NAS-112459/CONTRIBUTING.md).
\ No newline at end of file
......@@ -71,7 +71,8 @@ export class AppComponent {
router.events.pipe(untilDestroyed(this)).subscribe((event) => {
// save currenturl
if (event instanceof NavigationEnd) {
if (this.ws.loggedIn && event.url !== '/sessions/signin') {
const navigation = this.router.getCurrentNavigation();
if (this.ws.loggedIn && event.url !== '/sessions/signin' && !navigation?.extras?.skipLocationChange) {
sessionStorage.currentUrl = event.url;
}
}
......
......@@ -35,6 +35,7 @@ import { rootEffects, rootReducers } from 'app/store';
import { CustomRouterStateSerializer } from 'app/store/router/custom-router-serializer';
import { AppComponent } from './app.component';
import { rootRouterConfig } from './app.routes';
import { getWindow, WINDOW } from './helpers/window.helper';
import { AppLoaderModule } from './modules/app-loader/app-loader.module';
import { AppLoaderService } from './modules/app-loader/app-loader.service';
import { AppCommonModule } from './modules/common/app-common.module';
......@@ -119,6 +120,10 @@ import { WebSocketService } from './services/ws.service';
showDialog: false,
}),
},
{
provide: WINDOW,
useFactory: getWindow,
},
],
bootstrap: [
AppComponent,
......
......@@ -32,7 +32,8 @@ export class MockWebsocketService extends WebSocketService {
this.call = jest.fn();
this.job = jest.fn();
this.subscribe = jest.fn(() => this.subscribeStream$ as Observable<ApiEvent<unknown>>);
this.logout = jest.fn();
this.subscribe = jest.fn(() => this.subscribeStream$ as Observable<ApiEvent<any>>);
this.sub = jest.fn(() => of());
this.socket = {
send: jest.fn(),
......
export enum DatasetAclType {
Inherit = 'INHERIT',
Off = 'OFF',
NoAcl = 'NOACL',
Nfsv4 = 'NFSV4',
Nfs4Acl = 'NFS4ACL',
Posix = 'POSIX',
PosixAcl = 'POSIXACL',
}
export enum DatasetEncryptionType {
Default = 'DEFAULT', // Key
Passphrase = 'PASSPHRASE',
}
export enum DatasetQuotaType {
Dataset = 'DATASET',
User = 'USER',
Group = 'GROUP',
UserObj = 'USEROBJ',
GroupObj = 'GROUPOBJ',
}
export enum DatasetSource {
Local = 'local',
Remote = 'remote',
}
export enum DatasetType {
Filesystem = 'FILESYSTEM',
Volume = 'VOLUME',
}
export enum DatasetAclType {
Inherit = 'INHERIT',
Off = 'OFF',
NoAcl = 'NOACL',
Nfsv4 = 'NFSV4',
Nfs4Acl = 'NFS4ACL',
Posix = 'POSIX',
PosixAcl = 'POSIXACL',
}
export enum DatasetEncryptionType {
Default = 'DEFAULT', // Key
Passphrase = 'PASSPHRASE',
}
export enum DatasetQuotaType {
Dataset = 'DATASET',
User = 'USER',
Group = 'GROUP',
UserObj = 'USEROBJ',
GroupObj = 'GROUPOBJ',
}
export enum DatasetSource {
Local = 'local',
Remote = 'remote',
}
export enum DatasetType {
Filesystem = 'FILESYSTEM',
Volume = 'VOLUME',
}
// Enum doesn't work too well with numeric keys.
export type DatasetVolumeBlockSize =
| '512'
| '1K'
| '2K'
| '4K'
| '8K'
| '16K'
| '32K'
| '64K'
| '128K';
export type DatasetRecordSize =
| '512'
| '1K'
| '2K'
| '4K'
| '8K'
| '16K'
| '32K'
| '64K'
| '128K'
| '256K'
| '512K'
| '1024K';
export enum DatasetSync {
Standard = 'STANDARD',
Always = 'ALWAYS',
Disabled = 'DISABLED',
Inherit = 'INHERIT',
}
export enum DatasetSnapdir {
Visible = 'VISIBLE',
Hidden = 'HIDDEN',
Inherit = 'INHERIT',
}
export enum DatasetChecksum {
On = 'ON',
Off = 'OFF',
Fletcher2 = 'FLETCHER2',
Fletcher4 = 'FLETCHER4',
Sha256 = 'SHA256',
Sha512 = 'SHA512',
Skein = 'SKEIN',
Edonr = 'EDONR',
}
export enum DatasetCaseSensitivity {
Inherit = 'INHERIT',
Sensitive = 'SENSITIVE',
Insensitive = 'INSENSITIVE',
Mixed = 'MIXED',
}
export enum DatasetShareType {
Generic = 'GENERIC',
Smb = 'SMB',
}
export enum DatasetXattr {
Inherit = 'INHERIT',
On = 'ON',
Sa = 'SA',
}
......@@ -5,7 +5,7 @@ export enum FailoverDisabledReason {
NoPong = 'NO_PONG',
NoFailover = 'NO_FAILOVER',
NoLicense = 'NO_LICENSE',
DisagreeCarp = 'DISAGREE_CARP',
DisagreeVip = 'DISAGREE_VIP',
MismatchDisks = 'MISMATCH_DISKS',
NoCriticalInterfaces = 'NO_CRITICAL_INTERFACES',
}
......@@ -6,6 +6,12 @@ export enum NetworkInterfaceType {
Unknown = 'UNKNOWN',
}
export enum CreateNetworkInterfaceType {
Bridge = 'BRIDGE',
LinkAggregation = 'LINK_AGGREGATION',
Vlan = 'VLAN',
}
export enum NetworkInterfaceAliasType {
Inet = 'INET',
Inet6 = 'INET6',
......
......@@ -5,7 +5,7 @@ export enum ProductType {
Enterprise = 'ENTERPRISE',
}
export const productTypeReadableText = new Map<ProductType, string>([
export const productTypeLabels = new Map<ProductType, string>([
[ProductType.Scale, 'SCALE'],
[ProductType.ScaleEnterprise, 'SCALE ENTERPRISE'],
[ProductType.Core, 'CORE'],
......
export type WithInherit<T> = T | typeof inherit;
export const inherit = 'INHERIT' as const;
/**
* Prefer injecting window token instead of using window directly.
* This will make mocking easier when writing tests.
*
* @example
* ```
* constructor(
* @Inject(WINDOW) private window: Window
* )
* ```
*/
import { InjectionToken } from '@angular/core';
// eslint-disable-next-line @typescript-eslint/naming-convention
export const WINDOW = new InjectionToken<string>('Window');
export function getWindow(): Window {
return window;
}
......@@ -10,4 +10,5 @@ export default {
no_snapshot_sent_yet: T('No snapshots sent yet'),
task_is_running: T('Task is running'),
task_aborted: T('Task Aborted'),
};
import { Validators } from '@angular/forms';
import { marker as T } from '@biesbjerg/ngx-translate-extract-marker';
import { portRangeValidator } from 'app/modules/entity/entity-form/validators/range-validation';
export default {
fieldset_source: T('Source'),
fieldset_remote: T('Remote'),
fieldset_schedule: T('Schedule'),
fieldset_options: T('More Options'),
rsync_path_placeholder: T('Path'),
rsync_path_tooltip: T('Browse to the path to be copied. Linux\
file path limits apply. Other operating systems can have different\
limits which might affect how they can be used as sources or\
destinations.'),
rsync_path_validation: [Validators.required],
rsync_user_placeholder: T('User'),
rsync_user_tooltip: T('Select the user to run the rsync task. The user\
selected must have permissions to write to the\
specified directory on the remote host.'),
rsync_user_validation: [Validators.required],
rsync_remotehost_placeholder: T('Remote Host'),
rsync_remotehost_validation: [Validators.required],
rsync_remotehost_tooltip: T('Enter the IP address or hostname of the remote\
system that will store the copy. Use the format\
<i>username@remote_host</i> if the username differs\
on the remote host.'),
rsync_remoteport_placeholder: T('Remote SSH Port'),
rsync_remoteport_tooltip: T('Enter the SSH Port of the remote system.'),
rsync_remoteport_validation: [portRangeValidator(), Validators.required],
rsync_mode_placeholder: T('Rsync Mode'),
rsync_mode_tooltip: T('Choose to either use a custom-defined remote module \
of the rsync server or to use an SSH configuration for the rsync task.'),
rsync_remotemodule_placeholder: T('Remote Module Name'),
rsync_remotemodule_tooltip: T('At least one module must be defined in <a\
href="https://www.samba.org/ftp/rsync/rsyncd.conf.html"\
target="_blank">rsyncd.conf(5)</a> of the rsync\
server or in the <b>Rsync Modules</b> of another\
system.'),
rsync_remotemodule_validation: [Validators.required],
rsync_remotepath_placeholder: T('Remote Path'),
rsync_remotepath_tooltip: T('Browse to the existing path on the remote host to\
sync with. Maximum path length is 255 characters'),
type: 'checkbox',
name: 'rsync_validate_rpath',
rsync_validate_rpath_placeholder: T('Validate Remote Path'),
rsync_validate_rpath_tooltip: T('Set to automatically create the defined <b>Remote\
Path</b> if it does not exist.'),
value: true,
rsync_direction_placeholder: T('Direction'),
rsync_direction_tooltip: T('Direct the flow of data to the remote host.'),
rsync_direction_validation: [Validators.required],
rsync_description_placeholder: T('Description'),
rsync_description_tooltip: T('Enter a description of the rsync task.'),
rsync_picker_placeholder: T('Schedule'),
rsync_picker_tooltip: T('Select a schedule preset or choose <i>Custom</i>\
to open the advanced scheduler.'),
rsync_recursive_placeholder: T('Recursive'),
rsync_recursive_tooltip: T('Set to include all subdirectories of the specified\
directory. When unset, only the specified directory\
is included.'),
rsync_times_placeholder: T('Times'),
rsync_times_tooltip: T('Set to preserve modification times of files.'),
rsync_compress_placeholder: T('Compress'),
rsync_compress_tooltip: T('Set to reduce the size of data to transmit.\
Recommended for slow connections.'),
rsync_archive_placeholder: T('Archive'),
rsync_archive_tooltip: T('When set, rsync is run recursively, preserving\
symlinks, permissions, modification times, group,\
and special files. When run as root, owner, device\
files, and special files are also preserved.\
Equivalent to passing the flags <i>-rlptgoD</i> to\
rsync.'),
rsync_delete_placeholder: T('Delete'),
rsync_delete_tooltip: T('Delete files in the destination directory\
that do not exist in the source directory.'),
rsync_quiet_placeholder: T('Quiet'),
rsync_quiet_tooltip: T('Set to suppress informational messages from the\
remote server.'),
rsync_preserveperm_placeholder: T('Preserve Permissions'),
rsync_preserveperm_tooltip: T('Set to preserve original file permissions. This is\
useful when the user is set to <i>root</i>.'),
rsync_preserveattr_placeholder: T('Preserve Extended Attributes'),
rsync_preserveattr_tooltip: T('<a\ href="https://en.wikipedia.org/wiki/Extended_file_attributes"\
target="_blank">Extended attributes</a> are\
preserved, but must be supported by both systems.'),
rsync_delayupdates_placeholder: T('Delay Updates'),
rsync_delayupdates_tooltip: T('Set to save the temporary file from each updated\
file to a holding directory until the end of the\
transfer when all transferred files are renamed\
into place.'),
rsync_extra_placeholder: T('Auxiliary Parameters'),
rsync_extra_tooltip: T('Additional \
<a href="https://rsync.samba.org/ftp/rsync/rsync.html" target="_blank">rsync(1)</a> \
options to include. Separate entries by pressing <code>Enter</code>.<br> \
Note: The "*" character must be escaped with a backslash (\\*.txt) or used \
inside single quotes (\'*.txt\').'),
rsync_enabled_placeholder: T('Enabled'),
rsync_enabled_tooltip: T('Enable this rsync task. Unset to disable this\
rsync task without deleting it.'),
rsync_task_add: T('Add Rsync Task'),
rsync_task_edit: T('Edit Rsync Task'),
};
import { Validators } from '@angular/forms';
import { marker as T } from '@biesbjerg/ngx-translate-extract-marker';
export default {
title: T('Active Directory'),
activedirectory_custactions_basic_id: 'basic_mode',
activedirectory_custactions_advanced_id: 'advanced_mode',
activedirectory_custactions_clearcache_id: 'ds_clearcache',
activedirectory_custactions_clearcache_name: T('Rebuild Directory Service Cache'),
activedirectory_custactions_clearcache_dialog_title: T('Active Directory'),
activedirectory_custactions_clearcache_dialog_message: T('The cache is being rebuilt.'),
activedirectory_custactions_leave_domain: T('Leave Domain'),
ad_leave_domain_dialog: {
message: T('Leaving the domain requires sufficient privileges. Enter your credentials below.'),
username: T('Username'),
pw: T('Password'),
error: T('Error'),
success: T('Success'),
success_msg: T('You have left the domain.'),
},
ad_section_headers: {
dc: T('Domain Credentials'),
advanced_row: T('Advanced Settings'),
advanced_col1: T(''),
advanced_col2: T(''),
},
activedirectory_domainname_name: 'domainname',
activedirectory_domainname_placeholder: T('Domain Name'),
activedirectory_domainname_tooltip: T('Enter the Active Directory domain (<i>example.com</i>)\
or child domain (<i>sales.example.com</i>).'),
activedirectory_domainname_validation: [Validators.required],
activedirectory_bindname_name: 'bindname',
activedirectory_bindname_placeholder: T('Domain Account Name'),
activedirectory_bindname_tooltip: T('Enter the Active Directory administrator account name.'),
activedirectory_bindname_validation: [Validators.required],
activedirectory_bindpw_name: 'bindpw',
activedirectory_bindpw_placeholder: T('Domain Account Password'),
activedirectory_bindpw_tooltip: T('Password for the Active Directory administrator account. \
Required the first time a domain is configured. After initial configuration, the password \
is not needed to edit, start, or stop the service.'),
activedirectory_verbose_logging_name: 'verbose_logging',
activedirectory_verbose_logging_placeholder: T('Verbose logging'),
activedirectory_verbose_logging_tooltip: T('Set to log attempts to join the domain to\
/var/log/messages.'),
activedirectory_trusted_doms_name: 'allow_trusted_doms',
activedirectory_trusted_doms_placeholder: T('Allow Trusted Domains'),
activedirectory_trusted_doms_tooltip: T('When set, usernames do not include a domain name.\
Unset to force domain names to be prepended to user names. One possible reason for unsetting this value\
is to prevent username collisions when Allow Trusted Domains is set and there are identical usernames in\
more than one domain.'),
activedirectory_default_dom_name: 'use_default_domain',
activedirectory_default_dom_placeholder: T('Use Default Domain'),
activedirectory_default_dom_tooltip: T('Unset to prepend the domain name to the username.\
Unset to prevent name collisions when Allow Trusted Domains is set and multiple domains use the same\
username.'),
activedirectory_dns_updates_name: 'allow_dns_updates',
activedirectory_dns_updates_placeholder: T('Allow DNS updates'),
activedirectory_dns_updates_tooltip: T('Set to enable Samba to do DNS updates when joining a domain.'),
activedirectory_disable_fn_cache_name: 'disable_freenas_cache',
activedirectory_disable_fn_cache_placeholder: T('Disable AD User / Group Cache'),
activedirectory_disable_fn_cache_tooltip: T('Set to disable caching AD users and groups. This can\
help when unable to bind to a domain with a large number of users or groups.'),
restrict_pam: {
name: 'restrict_pam',
placeholder: T('Restrict PAM'),
tooltip: T('Set to restrict SSH access in certain circumstances to only members of \
BUILTIN\\Administrators'),
},
activedirectory_site_name: 'site',
activedirectory_site_placeholder: T('Site Name'),
activedirectory_site_tooltip: T('Enter the relative distinguished name of the\
site object in the Active Directory.'),
activedirectory_kerberos_realm_name: 'kerberos_realm',
activedirectory_kerberos_realm_placeholder: T('Kerberos Realm'),
activedirectory_kerberos_realm_tooltip: T('Select an existing realm that was added \
in <b>Directory Services > Kerberos Realms</b>.'),
activedirectory_kerberos_principal_name: 'kerberos_principal',
activedirectory_kerberos_principal_placeholder: T('Kerberos Principal'),
activedirectory_kerberos_principal_tooltip: T('Select the location of the principal in the \
keytab created in <b>Directory Services > Kerberos Keytabs</b>.'),
computer_account_OU_name: 'createcomputer',
computer_account_OU_placeholder: T('Computer Account OU'),
computer_account_OU_tooltip: T('The OU in which new computer accounts are created. \
The OU string is read from top to bottom without RDNs. Slashes ("/") are used as \
delimiters, like <samp>Computers/Servers/NAS</samp>. The backslash ("\\") is \
......@@ -102,70 +47,21 @@ export default {
multiple levels and might require doubling or even quadrupling to take effect. \
When this field is blank, new computer accounts are created in the Active Directory \
default OU.'),
activedirectory_timeout_name: 'timeout',
activedirectory_timeout_placeholder: T('AD Timeout'),
activedirectory_timeout_tooltip: T('Number of seconds before timeout. To view the AD \
connection status, open the interface <i>Task Manager</i>.'),
activedirectory_dns_timeout_name: 'dns_timeout',
activedirectory_dns_timeout_placeholder: T('DNS Timeout'),
activedirectory_dns_timeout_tooltip: T('Number of seconds before a timeout. Increase this\
value if AD DNS queries time out.'),
activedirectory_idmap_backend_name: 'idmap_backend',
activedirectory_idmap_backend_placeholder: T('Idmap backend'),
activedirectory_idmap_backend_tooltip: T('Choose the backend to map Windows security\
identifiers (SIDs) to UNIX UIDs and GIDs. Click Edit to configure that backend.'),
activedirectory_nss_info_name: 'nss_info',
activedirectory_nss_info_placeholder: T('Winbind NSS Info'),
activedirectory_nss_info_tooltip: T('Choose the schema to use when querying AD for\
user/group info. <i>rfc2307</i> uses the schema support included in Windows 2003 R2, <i>sfu</i> is for\
Service For Unix 3.0 or 3.5, and <i>sfu20</i> is for Service For Unix 2.0.'),
activedirectory_enable_name: 'enable',
activedirectory_enable_placeholder: T('Enable (requires password or Kerberos principal)'),
activedirectory_enable_tooltip: T('Enable the Active Directory service.\
The first time this option is set, the Domain Account Password must be entered.'),
activedirectory_netbiosname_a_name: 'netbiosname',
activedirectory_netbiosname_a_placeholder: T('Netbios Name'),
activedirectory_netbiosname_a_tooltip: T('Netbios Name of this NAS. This name must differ from\
the <i>Workgroup</i> name and be no greater than 15 characters.'),
activedirectory_netbiosname_a_validation: [Validators.required, Validators.maxLength(15)],
activedirectory_netbiosname_b_name: 'netbiosname_b',
activedirectory_netbiosname_b_placeholder: T('Netbios Name (TrueNAS Controller 2)'),
activedirectory_netbiosname_b_tooltip: T('Netbios Name of this NAS. This name must differ from\
the <i>Workgroup</i> name and be no greater than 15 characters.'),
activedirectory_netbiosname_b_validation: [Validators.required, Validators.maxLength(15)],
activedirectory_netbiosalias_name: 'netbiosalias',
activedirectory_netbiosalias_placeholder: T('NetBIOS alias'),
activedirectory_netbiosalias_tooltip: T('Alternative names that SMB clients can use when\
connecting to this NAS. Can be no greater than 15 characters.'),
activedirectory_advanced_fields: [
'verbose_logging',
'unix_extensions',
'allow_trusted_doms',
'use_default_domain',
'allow_dns_updates',
'disable_freenas_cache',
'restrict_pam',
'site',
'dcname',
'gcname',
'kerberos_realm',
'kerberos_principal',
'createcomputer',
'timeout',
'dns_timeout',
'idmap_backend',
'nss_info',
'netbiosname',
'netbiosname_b',
'netbiosalias',
],
};
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment