]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: carbonize user management form 59703/head
authorpujashahu <pujashahu@li-37e364cc-2d5a-11b2-a85c-fd7027b8f826.ibm.com>
Tue, 10 Sep 2024 11:05:34 +0000 (16:35 +0530)
committerpujaoshahu <pshahu@redhat.com>
Mon, 16 Dec 2024 15:17:48 +0000 (20:47 +0530)
Fixes: https://tracker.ceph.com/issues/67979
Signed-off-by: Puja Shahu <pshahu@redhat.com>
src/pybind/mgr/dashboard/frontend/src/app/core/auth/auth.module.ts
src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form-role.model.ts
src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/components/date-time-picker/date-time-picker.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/components/date-time-picker/date-time-picker.component.scss
src/pybind/mgr/dashboard/frontend/src/app/shared/components/date-time-picker/date-time-picker.component.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/components/helper/helper.component.html
src/pybind/mgr/dashboard/frontend/src/styles/themes/_content.scss

index c0e0517896cd12278327ce153ea1e1c318a80e4e..f1f04f7c2f0d0ceffdc0b5c45b60fe8657482a00 100644 (file)
@@ -17,13 +17,48 @@ import { UserFormComponent } from './user-form/user-form.component';
 import { UserListComponent } from './user-list/user-list.component';
 import { UserPasswordFormComponent } from './user-password-form/user-password-form.component';
 import { UserTabsComponent } from './user-tabs/user-tabs.component';
-import { ButtonModule, GridModule, IconModule, InputModule } from 'carbon-components-angular';
+
+import {
+  ButtonModule,
+  CheckboxModule,
+  DatePickerModule,
+  GridModule,
+  IconModule,
+  IconService,
+  InputModule,
+  ModalModule,
+  NumberModule,
+  RadioModule,
+  SelectModule,
+  UIShellModule,
+  TimePickerModule,
+  ComboBoxModule
+} from 'carbon-components-angular';
+// Icons
+import ChevronDown from '@carbon/icons/es/chevron--down/16';
+import Close from '@carbon/icons/es/close/32';
+import AddFilled from '@carbon/icons/es/add--filled/32';
+import SubtractFilled from '@carbon/icons/es/subtract--filled/32';
+import Reset from '@carbon/icons/es/reset/32';
+import EyeIcon from '@carbon/icons/es/view/16';
 @NgModule({
   imports: [
     CommonModule,
     FormsModule,
     ReactiveFormsModule,
     SharedModule,
+    UIShellModule,
+    InputModule,
+    GridModule,
+    ButtonModule,
+    IconModule,
+    CheckboxModule,
+    RadioModule,
+    SelectModule,
+    NumberModule,
+    ModalModule,
+    DatePickerModule,
+    TimePickerModule,
     NgbNavModule,
     NgbPopoverModule,
     NgxPipeFunctionModule,
@@ -31,8 +66,8 @@ import { ButtonModule, GridModule, IconModule, InputModule } from 'carbon-compon
     NgbModule,
     IconModule,
     GridModule,
-    ButtonModule,
-    InputModule
+    InputModule,
+    ComboBoxModule
   ],
   declarations: [
     LoginComponent,
@@ -46,7 +81,11 @@ import { ButtonModule, GridModule, IconModule, InputModule } from 'carbon-compon
     UserPasswordFormComponent
   ]
 })
-export class AuthModule {}
+export class AuthModule {
+  constructor(private iconService: IconService) {
+    this.iconService.registerAll([ChevronDown, Close, AddFilled, SubtractFilled, Reset, EyeIcon]);
+  }
+}
 
 const routes: Routes = [
   { path: '', redirectTo: 'users', pathMatch: 'full' },
index 2d323b04ea5d8c09ce1ac311a7b87348f622d503..abf529196f62855c4b56316309bbf004929f37fb 100644 (file)
@@ -4,11 +4,12 @@ export class UserFormRoleModel implements SelectOption {
   name: string;
   description: string;
   selected = false;
-  scopes_permissions: object;
-  enabled = true;
-
-  constructor(name: string, description: string) {
+  scopes_permissions?: object;
+  enabled: boolean;
+  content: string;
+  constructor(name: string, description: string, content: string) {
     this.name = name;
     this.description = description;
+    this.content = content;
   }
 }
index 4169d54c39fa46de376fbd879d88a4714620e03e..d2e521584734b44e42011be6cd9f1ea1e7bdb853 100644 (file)
-<div class="cd-col-form"
-     *cdFormLoading="loading">
-  <form name="userForm"
-        #formDir="ngForm"
-        [formGroup]="userForm"
-        novalidate>
-    <div class="card">
+<div cdsCol
+     [columnNumbers]="{md: 4}">
+  <ng-container *cdFormLoading="loading">
+    <form #frm="ngForm"
+          #formDir="ngForm"
+          [formGroup]="userForm"
+          novalidate>
       <div i18n="form title"
-           class="card-header">{{ action | titlecase }} {{ resource | upperFirst }}</div>
-      <div class="card-body">
-
-        <!-- Username -->
-        <div class="form-group row">
-          <label class="cd-col-form-label"
-                 [ngClass]="{'required': mode !== userFormMode.editing}"
-                 for="username"
-                 i18n>Username</label>
-          <div class="cd-col-form-input">
-            <input class="form-control"
-                   type="text"
-                   placeholder="Username..."
-                   id="username"
-                   name="username"
-                   formControlName="username"
-                   autocomplete="off"
-                   autofocus
-                   ngbTooltip="White spaces at the beginning and end will be trimmed"
-                   i18n-ngbTooltip
-                   cdTrim>
-            <span class="invalid-feedback"
-                  *ngIf="userForm.showError('username', formDir, 'required')"
-                  i18n>This field is required.</span>
-            <span class="invalid-feedback"
-                  *ngIf="userForm.showError('username', formDir, 'notUnique')"
-                  i18n>The username already exists.</span>
-          </div>
-        </div>
-
-        <!-- Password -->
-        <div class="form-group row"
-             *ngIf="!authStorageService.isSSO()">
-          <label class="cd-col-form-label"
-                 for="password">
-            <ng-container i18n>Password</ng-container>
-            <cd-helper *ngIf="passwordPolicyHelpText.length > 0"
-                       class="text-pre-wrap"
-                       html="{{ passwordPolicyHelpText }}">
-            </cd-helper>
-          </label>
-          <div class="cd-col-form-input">
-            <div class="input-group">
-              <input class="form-control"
-                     type="password"
-                     placeholder="Password..."
-                     id="password"
-                     name="password"
-                     autocomplete="new-password"
-                     formControlName="password">
-              <button type="button"
-                      class="btn btn-light"
-                      cdPasswordButton="password">
-              </button>
-            </div>
-            <div class="password-strength-level">
-              <div class="{{ passwordStrengthLevelClass }}"
-                   data-toggle="tooltip"
-                   title="{{ passwordValuation }}">
-              </div>
-            </div>
-            <span class="invalid-feedback"
-                  *ngIf="userForm.showError('password', formDir, 'required')"
-                  i18n>This field is required.</span>
-            <span class="invalid-feedback"
-                  *ngIf="userForm.showError('password', formDir, 'passwordPolicy')">
-              {{ passwordValuation }}
-            </span>
-          </div>
-        </div>
-
-        <!-- Confirm password -->
-        <div class="form-group row"
-             *ngIf="!authStorageService.isSSO()">
-          <label i18n
-                 class="cd-col-form-label"
-                 for="confirmpassword">Confirm password</label>
-          <div class="cd-col-form-input">
-            <div class="input-group">
-              <input class="form-control"
-                     type="password"
-                     placeholder="Confirm password..."
-                     id="confirmpassword"
-                     name="confirmpassword"
-                     autocomplete="new-password"
-                     formControlName="confirmpassword">
-              <button type="button"
-                      class="btn btn-light"
-                      cdPasswordButton="confirmpassword">
-              </button>
-              <span class="invalid-feedback"
-                    *ngIf="userForm.showError('confirmpassword', formDir, 'match')"
-                    i18n>Password confirmation doesn't match the password.</span>
-            </div>
-            <span class="invalid-feedback"
-                  *ngIf="userForm.showError('confirmpassword', formDir, 'required')"
-                  i18n>This field is required.</span>
-          </div>
-        </div>
+           class="form-header">{{ action | titlecase }} {{ resource | upperFirst }}
+      </div>
+      <!-- UserName -->
+      <div class="form-item">
+        <cds-text-label labelInputID="username"
+                        cdRequiredField="Username"
+                        [invalid]="!userForm.controls.username.valid && userForm.controls.username.dirty"
+                        [invalidText]="usernameError"
+                        i18n>Username
+          <input cdsText
+                 placeholder="Username..."
+                 i18n-placeholder
+                 id="username"
+                 formControlName="username"
+                 [invalid]="!userForm.controls.username.valid && userForm.controls.username.dirty"
+                 autofocus
+                 ngbTooltip="White spaces at the beginning and end will be trimmed"
+                 i18n-ngbTooltip
+                 cdTrim>
+        </cds-text-label>
+        <ng-template #usernameError>
+          <span *ngIf="userForm.showError('username', formDir, 'required')">
+            <ng-container i18n>
+             This field is required.
+            </ng-container>
+          </span>
+          <span *ngIf="userForm.showError('username', formDir, 'notUnique')">
+            <ng-container i18n>
+              The username already exists.
+            </ng-container>
+          </span>
+        </ng-template>
+      </div>
+      <!-- Password -->
+      <div class="form-item">
+        <cds-password-label labelInputID="password"
+                            label="Password..."
+                            [invalid]="!userForm.controls.password.valid && userForm.controls.password.dirty"
+                            [invalidText]="passwordError"
+                            i18n>Password
+        <cd-helper *ngIf="passwordPolicyHelpText.length > 0"
+                    class="text-pre-wrap"
+                    html="{{ passwordPolicyHelpText }}">
+        </cd-helper>
+        <input cdsPassword
+               type="password"
+               placeholder="Password..."
+               id="password"
+               autocomplete="new-password"
+               formControlName="password"
+               >
+        </cds-password-label>
+        <ng-template #passwordError>
+          <span class="invalid-feedback"
+                *ngIf="userForm.showError('password', formDir, 'match')"
+                i18n>Password confirmation doesn't match the password.
+          </span>
+          <span class="invalid-feedback"
+                *ngIf="userForm.showError('password', formDir, 'required')"
+                i18n>This field is required.</span>
+          <span class="invalid-feedback"
+                *ngIf="userForm.showError('password', formDir, 'passwordPolicy')">
+            {{ passwordValuation }}
+          </span>
+        </ng-template>
+      </div>
 
-        <!-- Password expiration date -->
-        <div class="form-group row"
-             *ngIf="!authStorageService.isSSO()">
-          <label class="cd-col-form-label"
-                 [ngClass]="{'required': pwdExpirationSettings.pwdExpirationSpan > 0}"
-                 for="pwdExpirationDate">
-            <ng-container i18n>Password expiration date</ng-container>
-            <cd-helper class="text-pre-wrap"
-                       *ngIf="pwdExpirationSettings.pwdExpirationSpan == 0">
-              <p>
+      <!-- Confirm password -->
+      <div class="form-item">
+        <cds-password-label labelInputID="confirmpassword"
+                            label="Confirm password..."
+                            [invalid]="!userForm.controls.confirmpassword.valid && userForm.controls.confirmpassword.dirty"
+                            [invalidText]="confirmpasswordError"
+                            i18n> Confirm password
+          <input cdsPassword
+                 type="password"
+                 placeholder="Confirm password..."
+                 id="confirmpassword"
+                 formControlName="confirmpassword">
+        </cds-password-label>
+        <ng-template #confirmpasswordError>
+          <span class="invalid-feedback"
+                *ngIf="userForm.showError('confirmpassword', formDir, 'match')"
+                i18n>Password confirmation doesn't match the password.</span>
+          <span class="invalid-feedback"
+                *ngIf="userForm.showError('confirmpassword', formDir, 'required')"
+                i18n>This field is required.</span>
+        </ng-template>
+      </div>
+      <!-- Password expiration date -->
+      <div class="form-item"
+           *ngIf="!authStorageService.isSSO()">
+        <cds-text-label  [ngClass]="{'required': pwdExpirationSettings.pwdExpirationSpan > 0}">{{'Password Expiration Date'}}
+          <cd-helper class="text-pre-wrap"
+                     *ngIf="pwdExpirationSettings.pwdExpirationSpan == 0">
+            <span>
                 The Dashboard setting defining the expiration interval of
                 passwords is currently set to <strong>0</strong>. This means
                 if a date is set, the user password will only expire once.
-              </p>
-              <p>
-                Consider configuring the Dashboard setting
-                <a routerLink="/mgr-modules/edit/dashboard"
-                   class="alert-link">USER_PWD_EXPIRATION_SPAN</a>
-                in order to let passwords expire periodically.
-              </p>
-            </cd-helper>
-          </label>
-          <div class="cd-col-form-input">
-            <div class="input-group">
-              <input class="form-control"
-                     i18n-placeholder
-                     placeholder="Password expiration date..."
-                     id="pwdExpirationDate"
-                     name="pwdExpirationDate"
-                     formControlName="pwdExpirationDate"
-                     [ngbPopover]="popContent"
-                     triggers="manual"
-                     #p="ngbPopover"
-                     (click)="p.open()"
-                     (keypress)="p.close()">
-              <button type="button"
-                      class="btn btn-light"
-                      (click)="clearExpirationDate()">
-                <i class="icon-prepend {{ icons.destroy }}"></i>
-              </button>
-              <span class="invalid-feedback"
-                    *ngIf="userForm.showError('pwdExpirationDate', formDir, 'required')"
-                    i18n>This field is required.</span>
-            </div>
-          </div>
-        </div>
-
-        <!-- Name -->
-        <div class="form-group row">
-          <label i18n
-                 class="cd-col-form-label"
-                 for="name">Full name</label>
-          <div class="cd-col-form-input">
-            <input class="form-control"
-                   type="text"
-                   placeholder="Full name..."
-                   id="name"
-                   name="name"
-                   formControlName="name">
-          </div>
-        </div>
-
-        <!-- Email -->
-        <div class="form-group row">
-          <label i18n
-                 class="cd-col-form-label"
-                 for="email">Email</label>
-          <div class="cd-col-form-input">
-            <input class="form-control"
-                   type="email"
-                   placeholder="Email..."
-                   id="email"
-                   name="email"
-                   formControlName="email">
-
-            <span class="invalid-feedback"
-                  *ngIf="userForm.showError('email', formDir, 'email')"
-                  i18n>Invalid email.</span>
-          </div>
-        </div>
-
-        <!-- Roles -->
-        <div class="form-group row">
-          <label class="cd-col-form-label"
-                 i18n>Roles</label>
-          <div class="cd-col-form-input">
-            <span class="no-border full-height"
-                  *ngIf="allRoles">
-              <cd-select-badges [data]="userForm.controls.roles.value"
-                                [options]="allRoles"
-                                [messages]="messages"></cd-select-badges>
             </span>
-          </div>
-        </div>
-
-        <!-- Enabled -->
-        <div class="form-group row"
-             *ngIf="!isCurrentUser()">
-          <div class="cd-col-form-offset">
-            <div class="custom-control custom-checkbox">
-              <input type="checkbox"
-                     class="custom-control-input"
-                     id="enabled"
-                     name="enabled"
-                     formControlName="enabled">
-              <label class="custom-control-label"
-                     for="enabled"
-                     i18n>Enabled</label>
-            </div>
-          </div>
-        </div>
-
-        <!-- Force change password -->
-        <div class="form-group row"
-             *ngIf="!isCurrentUser() && !authStorageService.isSSO()">
-          <div class="cd-col-form-offset">
-            <div class="custom-control custom-checkbox">
-              <input type="checkbox"
-                     class="custom-control-input"
-                     id="pwdUpdateRequired"
-                     name="pwdUpdateRequired"
-                     formControlName="pwdUpdateRequired">
-              <label class="custom-control-label"
-                     for="pwdUpdateRequired"
-                     i18n>User must change password at next logon</label>
-            </div>
-          </div>
-        </div>
-
+            <span>Consider configuring the Dashboard setting
+              <a routerLink="/mgr-modules/edit/dashboard"
+                 class="alert-link">USER_PWD_EXPIRATION_SPAN</a>
+                  in order to let passwords expire periodically.
+            </span>
+          </cd-helper>
+        <cd-date-time-picker [control]="userForm.get('pwdExpirationDate')"
+                             placeHolder="Password expiration date"
+                             [hasTime]="false"
+                             [defaultDate]="passwordexp"
+                             i18n-name
+                             >
+        </cd-date-time-picker>
+      </cds-text-label>
+        <span class="invalid-feedback"
+              *ngIf="userForm.showError('pwdExpirationDate', formDir, 'required')"
+              i18n>This field is required.
+        </span>
+      </div>
+      <!--Full Name-->
+      <div class="form-item">
+        <cds-text-label for="name"
+                        i18n> Full Name
+          <input cdsText
+                 type="text"
+                 placeholder="Full Name..."
+                 id="name"
+                 formControlName="name">
+        </cds-text-label>
+      </div>
+      <!-- Email -->
+      <div class="form-item">
+        <cds-text-label for="email"
+                        [invalid]="!userForm.controls.email.valid && userForm.controls.email.dirty"
+                        [invalidText]="emailError"
+                        i18n>
+          Email
+          <input cdsText
+                 type="email"
+                 placeholder="Email..."
+                 id="email"
+                 formControlName="email">
+        </cds-text-label>
+        <ng-template #emailError>
+          <span class="invalid-feedback"
+                *ngIf="userForm.showError('email', formDir, 'email')"
+                i18n>Invalid email.
+          </span>
+        </ng-template>
+      </div>
+      <!-- Roles -->
+      <div class="form-item"
+           *ngIf="allRoles">
+        <cds-combo-box label="Roles"
+                       type="multi"
+                       selectionFeedback="top-after-reopen"
+                       for="roles"
+                       formControlName="roles"
+                       id="roles"
+                       placeholder="Select Roles..."
+                       i18n-placeholder
+                       [appendInline]="true"
+                       [items]="allRoles"
+                       itemValueKey="name"
+                       i18n>
+          <cds-dropdown-list></cds-dropdown-list>
+        </cds-combo-box>
+      </div>
+      <!-- Enabled -->
+      <div class="form-item"
+           *ngIf="!isCurrentUser()">
+        <cds-checkbox id="enabled"
+                      formControlName="enabled"
+                      name="enabled"
+                      i18n>Enabled
+        </cds-checkbox>
       </div>
-      <div class="card-footer">
-        <cd-form-button-panel (submitActionEvent)="submit()"
-                              [form]="userForm"
-                              [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
-                              wrappingClass="text-right"></cd-form-button-panel>
+      <!-- Force change password -->
+      <div class="form-item"
+           *ngIf="!isCurrentUser() && !authStorageService.isSSO()">
+        <cds-checkbox id="pwdUpdateRequired"
+                      formControlName="pwdUpdateRequired"
+                      name="pwdUpdateRequired"
+                      i18n>User must change password at next logon
+        </cds-checkbox>
       </div>
-    </div>
-  </form>
+      <!--Submit Button-->
+      <cd-form-button-panel (submitActionEvent)="submit()"
+                            [form]="userForm"
+                            [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+                            wrappingClass="text-right">
+      </cd-form-button-panel>
+    </form>
+  </ng-container>
 </div>
 
 <ng-template #removeSelfUserReadUpdatePermissionTpl>
index 7c02b86eae0583bf11bd3df0be1d66f72f56a8a4..009d4c193e420a82e9ff05394bd6a2e5dcb467a5 100644 (file)
@@ -55,7 +55,8 @@ export class UserFormComponent extends CdForm implements OnInit {
   icons = Icons;
   pwdExpirationSettings: CdPwdExpirationSettings;
   pwdExpirationFormat = 'YYYY-MM-DD';
-
+  selectedRole: string[];
+  passwordexp: boolean = false;
   constructor(
     private authService: AuthService,
     private authStorageService: AuthStorageService,
@@ -91,6 +92,7 @@ export class UserFormComponent extends CdForm implements OnInit {
         password: [
           '',
           [],
+
           [
             CdValidators.passwordPolicy(
               this.userService,
@@ -105,7 +107,7 @@ export class UserFormComponent extends CdForm implements OnInit {
           ]
         ],
         confirmpassword: [''],
-        pwdExpirationDate: [undefined],
+        pwdExpirationDate: [''],
         email: ['', [CdValidators.email]],
         roles: [[]],
         enabled: [true, [Validators.required]],
@@ -121,8 +123,10 @@ export class UserFormComponent extends CdForm implements OnInit {
     if (this.router.url.startsWith('/user-management/users/edit')) {
       this.mode = this.userFormMode.editing;
       this.action = this.actionLabels.EDIT;
+      this.passwordexp = false;
     } else {
       this.action = this.actionLabels.CREATE;
+      this.passwordexp = true;
     }
 
     const observables = [this.roleService.list(), this.settingsService.getStandardSettings()];
@@ -130,6 +134,7 @@ export class UserFormComponent extends CdForm implements OnInit {
       (result: [UserFormRoleModel[], CdPwdExpirationSettings]) => {
         this.allRoles = _.map(result[0], (role) => {
           role.enabled = true;
+          role.content = `${role.name}, ${role.description}`;
           return role;
         });
         this.pwdExpirationSettings = new CdPwdExpirationSettings(result[1]);
@@ -158,7 +163,6 @@ export class UserFormComponent extends CdForm implements OnInit {
       this.userService.get(username).subscribe((userFormModel: UserFormModel) => {
         this.response = _.cloneDeep(userFormModel);
         this.setResponse(userFormModel);
-
         this.loadingReady();
       });
     });
@@ -173,20 +177,28 @@ export class UserFormComponent extends CdForm implements OnInit {
       this.userForm.get(key).setValue(response[key])
     );
     const expirationDate = response['pwdExpirationDate'];
+
     if (expirationDate) {
+      this.passwordexp = false;
       this.userForm
         .get('pwdExpirationDate')
         .setValue(moment(expirationDate * 1000).format(this.pwdExpirationFormat));
+    } else {
+      this.passwordexp = true;
     }
   }
 
   getRequest(): UserFormModel {
     const userFormModel = new UserFormModel();
+
     ['username', 'password', 'name', 'email', 'roles', 'enabled', 'pwdUpdateRequired'].forEach(
-      (key) => (userFormModel[key] = this.userForm.get(key).value)
+      (key) => {
+        userFormModel[key] = this.userForm.get(key).value;
+      }
     );
     const expirationDate = this.userForm.get('pwdExpirationDate').value;
     if (expirationDate) {
+      this.passwordexp = false;
       const mom = moment(expirationDate, this.pwdExpirationFormat);
       if (
         this.mode !== this.userFormMode.editing ||
index 328e72cc5955bebeb27662721ca17e348df351b7..ccdb70e39e4fe966c463d4ff8a4d55f8e98c9565 100644 (file)
@@ -1,22 +1,23 @@
-<div cdsCol
-     class="form-item">
-  <div cdsRow>
-<cds-date-picker [label]="name"
-                 i18n-label
-                 placeholder="NOT PROTECTED"
-                 formControlname="expiresAt"
-                 dateFormat="Y/m/d"
-                 [value]="date"
-                 (valueChange)="onModelChange($event)"
-                 [helperText]="helperText"
-                 [disabled]="disabled"
-                 cdsTheme="theme"></cds-date-picker>
-<cds-timepicker (valueChange)="onModelChange($event)"
-                [(ngModel)]="time"
-                label="Select a time"
-                [disabled]="disabled"
-                pattern="(1[012]|[0-9]):[0-5][0-9]"
-                *ngIf="hasTime">
+<div cdsCol>
+  <div cdsRow
+       class="form-item-append">
+    <cds-text-label>{{name}}
+      <cds-date-picker  i18n-label
+                        [placeholder]="placeHolder"
+                        formControlname="expiresAt"
+                        dateFormat="Y/m/d"
+                        [value]="date"
+                        (valueChange)="onModelChange($event)"
+                        [helperText]="helperText"
+                        [disabled]="disabled"
+                        cdsTheme="theme"></cds-date-picker>
+    </cds-text-label>
+  <cds-text-label *ngIf="hasTime">Select a time
+  <cds-timepicker (valueChange)="onModelChange($event)"
+                  [(ngModel)]="time"
+                  [disabled]="disabled"
+                  pattern="(1[012]|[0-9]):[0-5][0-9]"
+                  *ngIf="hasTime">
   <cds-timepicker-select [(ngModel)]="ampm"
                          [disabled]="disabled"
                          (valueChange)="onModelChange($event)">
@@ -24,5 +25,7 @@
             value="AM">AM</option>
     <option value="PM">PM</option>
   </cds-timepicker-select>
-</cds-timepicker></div>
+</cds-timepicker>
+</cds-text-label>
+</div>
 </div>
index 4841d2ed92d0178f73ab407b5c2a43e51f48341d..3458d9171a7a56cb46f266db10799f38bc1a9e0d 100644 (file)
@@ -25,7 +25,8 @@ export class DateTimePickerComponent implements OnInit {
 
   @Input()
   helperText = '';
-
+  @Input()
+  placeHolder = '';
   @Input()
   disabled = false;
 
@@ -39,9 +40,8 @@ export class DateTimePickerComponent implements OnInit {
   date: { [key: number]: string }[] = [];
   time: string;
   ampm: string;
-
   sub: Subscription;
-
+  @Input() defaultDate: boolean = false;
   constructor(private calendar: NgbCalendar) {}
 
   ngOnInit() {
@@ -59,8 +59,12 @@ export class DateTimePickerComponent implements OnInit {
     if (!mom.isValid() || mom.isBefore(moment())) {
       mom = moment();
     }
+    if (this.defaultDate) {
+      this.date.push([]);
+    } else {
+      this.date.push(mom.format('YYYY-MM-DD'));
+    }
 
-    this.date.push(mom.format('YYYY-MM-DD'));
     const time = mom.format('HH:mm:ss');
     this.time = mom.format('hh:mm');
     this.ampm = mom.hour() >= 12 ? 'PM' : 'AM';
@@ -76,7 +80,9 @@ export class DateTimePickerComponent implements OnInit {
 
   onModelChange(event?: any) {
     if (event) {
-      if (Array.isArray(event)) {
+      if (event.length === 0) {
+        this.datetime.date = { date: null, time: null, ampm: null };
+      } else if (Array.isArray(event)) {
         this.datetime.date = moment(event[0]).format('YYYY-MM-DD');
       } else if (event && ['AM', 'PM'].includes(event)) {
         const initialMoment = moment(this.datetime.time, 'hh:mm:ss A');
index da1a4800f7f451722888a2c02fcf792905b8607b..81ad90914b6aaf1a42df53d2d3ab20e9d24e2fec 100644 (file)
@@ -5,7 +5,8 @@
   <ng-content></ng-content>
 </ng-template>
 
-<cds-tooltip [description]="popoverTpl">
+<cds-tooltip [description]="popoverTpl"
+             [autoAlign]="true">
   <svg cdsIcon="information"
        size="16"
        title="info"></svg>
index 37f89aba17fc6d96d1b43c6f5d09ba2442a90ec1..0725b63dbfd09338c08e48d8b6a8d9f9b668df24 100644 (file)
@@ -33,6 +33,7 @@ $content-theme: map-merge(
     text-primary: vv.$dark,
     text-secondary: vv.$dark,
     text-disabled: vv.$gray-500,
+    icon-secondary: vv.$gray-800,
     field-01: colors.$gray-10,
     interactive: vv.$primary
   )