File

src/app/modules/groups/components/activity/activity-details/activity-details.component.ts

Implements

OnInit OnDestroy

Metadata

Index

Properties
Methods

Constructor

constructor(resourceService: ResourceService, activatedRoute: ActivatedRoute, groupService: GroupsService, toasterService: ToasterService, userService: UserService, router: Router, layoutService: LayoutService, playerService: PublicPlayerService, searchService: SearchService, utilService: UtilService, configService: ConfigService)
Parameters :
Name Type Optional
resourceService ResourceService No
activatedRoute ActivatedRoute No
groupService GroupsService No
toasterService ToasterService No
userService UserService No
router Router No
layoutService LayoutService No
playerService PublicPlayerService No
searchService SearchService No
utilService UtilService No
configService ConfigService No

Methods

addTelemetry
addTelemetry(id, cdata, extra?, obj?)
Parameters :
Name Optional
id No
cdata No
extra Yes
obj Yes
Returns : void
checkForNestedCourses
checkForNestedCourses(groupData, activityData)
Parameters :
Name Optional
groupData No
activityData No
Returns : void
downloadCSVFile
downloadCSVFile()
Returns : void
fetchActivity
fetchActivity(type: string)
Parameters :
Name Type Optional
type string No
Returns : void
Private fetchActivityOnParamChange
fetchActivityOnParamChange()
Returns : void
flattenDeep
flattenDeep(contents)
Parameters :
Name Optional
contents No
Returns : any
getActivityInfo
getActivityInfo()
Returns : void
getContent
getContent(groupData, activityData)
Parameters :
Name Optional
groupData No
activityData No
Returns : void
getSortedMembers
getSortedMembers()
Returns : any
getUpdatedActivityData
getUpdatedActivityData(groupData, activityData)
Parameters :
Name Optional
groupData No
activityData No
Returns : void
handleSelectedCourse
handleSelectedCourse(course)
Parameters :
Name Optional
course No
Returns : void
initLayout
initLayout()
Returns : void
isContentTrackable
isContentTrackable(content, type)
Parameters :
Name Optional
content No
type No
Returns : any
navigateBack
navigateBack()
Returns : void
navigateToActivityDashboard
navigateToActivityDashboard()
Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void
ngOnInit
ngOnInit()
Returns : void
processData
processData(aggResponse: any)
Parameters :
Name Type Optional
aggResponse any No
Returns : void
search
search(searchKey: string)
Parameters :
Name Type Optional
searchKey string No
Returns : void
showActivityType
showActivityType()
Returns : any
toggleDropdown
toggleDropdown()
Returns : void
updateArray
updateArray(course)
Parameters :
Name Optional
course No
Returns : void
validateUser
validateUser(group)
Parameters :
Name Optional
group No
Returns : void

Properties

activity
Type : IActivity
activityDetails
Type : any
activityId
Type : string
activityType
Type : string
courseHierarchy
Type : any
Public csvExporter
Type : any
dropdownContent
Default value : true
enrolmentCount
Type : number
groupData
groupId
Type : string
layoutConfiguration
Type : any
leafNodesCount
Type : number
loaderMessage
Default value : _.get(this.resourceService.messages.fmsg, 'm0087')
memberCardConfig
Type : object
Default value : { size: 'small', isBold: false, isSelectable: false, view: 'horizontal' }
memberListToShow
Type : []
Default value : []
memberListUpdatedOn
Type : string
members
membersCount
Type : number
nestedCourses
Type : []
Default value : []
parentId
Type : string
queryParams
Public resourceService
Type : ResourceService
searchInputBox
Decorators :
@ViewChild('searchInputBox')
selectedCourse
showLoader
Default value : true
showSearchResults
Default value : false
telemetryImpression
Type : IImpressionEventInput
unsubscribe$
Default value : new Subject<void>()
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { UserService, SearchService } from '@sunbird/core';
import { ResourceService, ToasterService, LayoutService, UtilService, ConfigService } from '@sunbird/shared';
import { IImpressionEventInput } from '@sunbird/telemetry';
import * as _ from 'lodash-es';
import { combineLatest, Subject } from 'rxjs';
import { debounceTime, delay, map, takeUntil, tap } from 'rxjs/operators';
import { GroupsService } from './../../../services';
import { IActivity } from '../activity-list/activity-list.component';
import { PublicPlayerService } from '@sunbird/public';
import { ACTIVITY_DASHBOARD, MY_GROUPS, GROUP_DETAILS } from '../../../interfaces/routerLinks';
@Component({
  selector: 'app-activity-details',
  templateUrl: './activity-details.component.html',
  styleUrls: ['./activity-details.component.scss']
})
export class ActivityDetailsComponent implements OnInit, OnDestroy {

  @ViewChild('searchInputBox') searchInputBox;
  unsubscribe$ = new Subject<void>();
  showLoader = true;
  queryParams;
  activityId: string;
  groupId: string;
  groupData;
  activity: IActivity;
  memberListToShow = [];
  showSearchResults = false;
  memberCardConfig = { size: 'small', isBold: false, isSelectable: false, view: 'horizontal' };
  enrolmentCount: number;
  leafNodesCount: number;
  membersCount: number;
  members;
  telemetryImpression: IImpressionEventInput;
  loaderMessage = _.get(this.resourceService.messages.fmsg, 'm0087');
  layoutConfiguration: any;
  memberListUpdatedOn: string;
  nestedCourses = [];
  selectedCourse;
  dropdownContent = true;
  parentId: string;
  public csvExporter: any;
  activityType: string;
  courseHierarchy: any;
  activityDetails: any;

  constructor(
    public resourceService: ResourceService,
    private activatedRoute: ActivatedRoute,
    private groupService: GroupsService,
    private toasterService: ToasterService,
    private userService: UserService,
    private router: Router,
    private layoutService: LayoutService,
    private playerService: PublicPlayerService,
    private searchService: SearchService,
    private utilService: UtilService,
    private configService: ConfigService,
  ) { }

  ngOnInit() {
    this.initLayout();
    this.fetchActivityOnParamChange();
    this.telemetryImpression = this.groupService.getImpressionObject(this.activatedRoute.snapshot, this.router.url);
  }
  initLayout() {
    this.layoutConfiguration = this.layoutService.initlayoutConfig();
    this.layoutService.switchableLayout().
      pipe(takeUntil(this.unsubscribe$)).subscribe(layoutConfig => {
        if (layoutConfig != null) {
          this.layoutConfiguration = layoutConfig.layout;
        }
      });
  }

  private fetchActivityOnParamChange() {
    combineLatest([this.activatedRoute.params, this.activatedRoute.queryParams])
      .pipe(debounceTime(5), // to sync params and queryParams events
        delay(10), // to trigger page exit telemetry event
        tap(data => {
          this.showLoader = true;
        }),
        map((result) => ({ params: { groupId: result[0].groupId, activityId: result[0].activityId }, queryParams: result[1] })),
        takeUntil(this.unsubscribe$))
      .subscribe(({ params, queryParams }) => {
        this.queryParams = { ...queryParams };
        this.groupId = params.groupId;
        this.activityId = params.activityId;
        this.activityType = _.get(this.queryParams, 'primaryCategory') || 'Course';
        this.fetchActivity(this.activityType);
      });
  }

  validateUser(group) {
    const user = _.find(_.get(group, 'members'), (m) => _.get(m, 'userId') === this.userService.userid);
    /* istanbul ignore else */
    if (!user || _.get(user, 'role') === 'member' || _.get(user, 'status') === 'inactive' || _.get(group, 'status') === 'inactive') {
      this.toasterService.warning(this.resourceService.messages.emsg.noAdminRoleActivity);
      this.groupService.goBack();
    }
  }

  fetchActivity(type: string) {
    this.showLoader = true;
    const activityData = { id: this.activityId, type };
    this.groupService.getGroupById(this.groupId, true, true).subscribe(res => {
      this.validateUser(res);
      this.groupData = res;
      this.getActivityInfo();
      if (_.get(this.queryParams, 'mimeType') === this.configService.appConfig.PLAYER_CONFIG.MIME_TYPE.collection) {
        this.checkForNestedCourses(res, activityData);
      } else {
        this.getContent(res, activityData);
      }
    }, err => {
      this.navigateBack();
    });
  }

  navigateBack() {
    this.showLoader = false;
    this.toasterService.error(this.resourceService.messages.emsg.m0005);
    this.groupService.goBack();
  }
  search(searchKey: string) {
    searchKey = _.toLower(searchKey);
    if (searchKey.trim().length) {
      this.showSearchResults = true;
      this.memberListToShow = this.members.filter(item => _.toLower(item.title).includes(searchKey));
      this.addTelemetry('activity-dashboard-member-search', [], { query: searchKey });
    } else {
      this.showSearchResults = false;
      this.memberListToShow = _.cloneDeep(this.members);
    }
  }

  processData(aggResponse: any) {
    const enrolmentInfo = _.find(aggResponse.activity.agg, { metric: 'enrolmentCount' });
    this.leafNodesCount = _.get(this.selectedCourse, 'leafNodesCount') || 0;
    this.enrolmentCount = _.get(enrolmentInfo, 'value');
    this.membersCount = _.get(aggResponse, 'members.length');
    this.memberListUpdatedOn = _.max(_.get(aggResponse, 'activity.agg').map(agg => agg.lastUpdatedOn));
    this.members = aggResponse.members.map((item, index) => {
      /* istanbul ignore else */
      if (_.get(item, 'status') === 'active') {
        const completedCount = _.get(_.find(item.agg, { metric: 'completedCount' }), 'value');
        const userProgress = {
          title: _.get(item, 'userId') === this.userService.userid ?
            `${_.get(item, 'name')}(${this.resourceService.frmelmnts.lbl.you})` : _.get(item, 'name'),
          identifier: _.get(item, 'userId'),
          initial: _.get(item, 'name[0]'),
          indexOfMember: index
        };

        if (this.isContentTrackable(this.activity, _.get(this.activity, 'contentType'))) {
          const progress = completedCount ? _.toString(Math.round((completedCount / this.leafNodesCount) * 100)) || '0' : '0';
          userProgress['progress'] = progress >= 100 ? '100' : progress;
        }
        this.showLoader = false;
        return userProgress;
      }
    });

    this.memberListToShow = this.getSortedMembers();
  }

  getSortedMembers() {
    // sorting by name - alpha order
    const sortedMembers = this.members.sort((a, b) =>
      ((a.title).toLowerCase() > (b.title).toLowerCase()) ? 1 : (((b.title).toLowerCase() > (a.title).toLowerCase()) ? -1 : 0));
    // const sortMembersByProgress = [];
    // const sortMembersByName = [];
    // _.map(_.cloneDeep(this.members), member => {
    //   if (_.get(member, 'identifier') !== this.userService.userid) {
    //     _.get(member, 'progress') > 0 ? sortMembersByProgress.push(member) :  sortMembersByName.push(member);
    //   }
    // });
    // const currentUser = _.find(this.members, {identifier: this.userService.userid});
    // const sortedMembers = _.sortBy(sortMembersByProgress, 'progress', 'dsc').concat(_.sortBy(sortMembersByName, 'title', 'asc'));
    // sortedMembers.unshift(currentUser);
    return sortedMembers || [];
  }

  getActivityInfo() {
    const activityData = _.find(this.groupData.activities, ['id', this.activityId]);
    this.activity = _.get(activityData, 'activityInfo');
  }

  addTelemetry(id, cdata, extra?, obj?) {
    this.groupService.addTelemetry({ id, extra }, this.activatedRoute.snapshot, cdata, this.groupId, obj);
  }
  /**
   * @description - To get the course hierarchy Data
   * @param  {} groupData
   * @param  {} activityData
   */
  checkForNestedCourses(groupData, activityData) {
    this.playerService.getCollectionHierarchy(this.activityId, {})
      .pipe(takeUntil(this.unsubscribe$))
      .subscribe((data) => {
        this.courseHierarchy = data.result.content;
        this.parentId = _.get(this.courseHierarchy, 'identifier');
        this.leafNodesCount = this.courseHierarchy.leafNodesCount;
        this.updateArray(this.courseHierarchy);
        this.getUpdatedActivityData(groupData, activityData);
        const childCourses = this.flattenDeep(this.courseHierarchy.children).filter(c => c.contentType === 'Course');
        if (childCourses.length > 0) {
          childCourses.map((course) => {
            this.updateArray(course);
          });
        }
        this.showLoader = false;
      }, err => {
        this.toasterService.error(this.resourceService.messages.fmsg.m0051);
        this.navigateBack();
      });
  }

  /**
   * @description - get updated activity progress data
   * @param  {} groupData
   * @param  {} activityData
   */
  getUpdatedActivityData(groupData, activityData) {
    this.showLoader = true;
    this.groupService.getActivity(this.groupId, activityData, groupData, this.leafNodesCount).subscribe(data => {
      this.processData(data);
      this.showLoader = false;
      this.activityDetails = data;
    });
  }
  getContent(groupData, activityData) {
    this.playerService.getContent(this.activityId, {})
      .pipe(takeUntil(this.unsubscribe$))
      .subscribe((data) => {
        const courseHierarchy = data.result.content;
        this.leafNodesCount = _.get(courseHierarchy, 'leafNodesCount') || 0;
        this.updateArray(courseHierarchy);
        this.getUpdatedActivityData(groupData, activityData);
        this.showLoader = false;
      }, err => {
        this.toasterService.error(this.resourceService.messages.fmsg.m0051);
        this.navigateBack();
      });
  }

  updateArray(course) {
    this.nestedCourses.push({
      identifier: _.get(course, 'identifier'),
      name: _.get(course, 'name'),
      leafNodesCount: _.get(course, 'leafNodesCount') || 0,
      pkgVersion: _.get(course, 'pkgVersion') ? `${_.get(course, 'pkgVersion')}` : '1.0',
      primaryCategory: _.get(course, 'primaryCategory')
    });
    this.selectedCourse = this.nestedCourses[0];
  }

  flattenDeep(contents) {
    if (contents) {
      return contents.reduce((acc, val) => {
        if (val.children) {
          acc.push(val);
          return acc.concat(this.flattenDeep(val.children));
        } else {
          return acc.concat(val);
        }
      }, []);
    }
    return [];
  }

  handleSelectedCourse(course) {
    this.searchInputBox.nativeElement.value = '';
    this.selectedCourse = course;
    this.toggleDropdown();
    const activityData = { id: this.selectedCourse.identifier, type: 'Course' };
    this.groupService.getActivity(this.groupId, activityData, this.groupData)
      .subscribe((data) => {
        this.showLoader = false;
        this.processData(data);
      }, error => {
        this.showLoader = false;
        this.toasterService.error(this.resourceService.messages.emsg.m0005);
        this.groupService.goBack();
      });
  }
  toggleDropdown() {
    this.dropdownContent = !this.dropdownContent;
  }

  isContentTrackable(content, type) {
    return this.searchService.isContentTrackable(content, type);
  }

  showActivityType() {
    return _.lowerCase(_.get(this.queryParams, 'title'));
  }

  downloadCSVFile() {
    this.addTelemetry('download-csv', [], {},
      { id: _.get(this.selectedCourse, 'identifier'), type: _.get(this.selectedCourse, 'primaryCategory'), ver: _.get(this.selectedCourse, 'pkgVersion') });

    const data = _.map(this.memberListToShow, member => {
      const name = _.get(member, 'title');
      return {
        courseName: _.get(this.selectedCourse, 'name'),
        memberName: name.replace('(You)', ''),
        progress: _.get(member, 'progress') + '%'
      };
    });
    this.utilService.downloadCSV(this.selectedCourse, data);
  }

  /**
   * @description - navigate to activity dashboard page
   */
  navigateToActivityDashboard() {
    this.addTelemetry('activity-detail', [{ id: _.get(this.activity, 'identifier'), type: _.get(this.activity, 'resourceType') }]);
    this.router.navigate([`${MY_GROUPS}/${GROUP_DETAILS}`, _.get(this.groupData, 'id'), `${ACTIVITY_DASHBOARD}`, _.get(this.activity, 'identifier')],
      {
        state: {
          hierarchyData: this.courseHierarchy,
          activity: this.activityDetails,
          memberListUpdatedOn: this.memberListUpdatedOn
        }
      });
  }

  ngOnDestroy() {
    this.unsubscribe$.next();
    this.unsubscribe$.complete();
  }
}
<app-landing-section [textToDisplay]="" [layoutConfiguration]="layoutConfiguration" [noTitle]="true">
</app-landing-section>
<div [ngClass]="layoutConfiguration ? 'sbt-center-container sbt-back-header sbt-mygroups-details relative9' : ''">
  <app-back-button></app-back-button>
  <div class="ui container py-16" *ngIf="showLoader">
    <app-loader [data]='loaderMessage'></app-loader>
  </div>
  <div *ngIf="!showLoader" [appTelemetryImpression]="telemetryImpression">
    <div class="content-header">
      <div class="ui container py-16">
        <div class="content-header__content">
          <div class="d-flex flex-basis-1 mr-32 min-w-0 content-header__content__title">
            <div class="content-header__img mr-8">
              <img [src]="activity?.appIcon || './assets/images/book.png'" alt="" />
            </div>
            <div class="d-flex flex-dc">
              <div class="content-header__title font-weight-bold ellipsis text-left" role="heading" aria-level="2">{{activity?.name}}</div>
              <div class="d-flex flex-ai-center content-header__info mt-4">
                <span>{{activity?.subject?.join(', ')}}</span>
                <span class="dot-divider" *ngIf="activity?.subject?.length"></span>
                <span>{{enrolmentCount}}/{{membersCount}}&nbsp;{{resourceService?.frmelmnts?.lbl?.started}}</span>
              </div>
            </div>
          </div>
          <div class="d-flex flex-ai-end flex-w-wrap content-header__buttons">
            <!--Activity Dashboard-->
            <button tabindex="0" (click)="navigateToActivityDashboard()"
              [disabled]="!isContentTrackable(activity, activity?.contentType)"
              [ngClass]="{'dt-disabled-btn': !isContentTrackable(activity, activity?.contentType)}"
              class="sb-btn sb-btn-normal sb-btn-link  sb-left-icon-btn ml-8 sb-btn-icon-fix disabled sb-btn-link-primary sb-activity-dashboard-btn"
              title="Activity Dashboard">
              <img src="assets/images/Activity_icon.svg" width="20px" class="mr-8" alt="Activity Dashboard">
              Activity Dashboard
            </button>
            <div class="hide">
              <button class="sb-btn sb-btn-outline-secondary sb-btn-normal mr-8"></button>
              <div class="kabab-menu"></div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <div class="ui container mt-24">
      <div class="sb-g mt-24 sbt-sb-g">
        <div class="sb-g-col-xs-12 sb-g-col-md-5 sb-g-col-lg-5 sb-g-col-xxxl-4">
          <div class="nested-group-container flex-dc d-flex">
            <div class="nested-group-content">
              <div class="sb-bg-color-primary nested-course-area" *ngIf="nestedCourses.length > 1">
                <div class="d-flex flex-ai-center flex-jc-space-between py-16 px-24" tabindex="0"
                  (click)="toggleDropdown();addTelemetry('course-dropdown', [])">
                  <div class="fsmall">{{selectedCourse?.name}}</div>
                  <div class="ml-8" [ngClass]="{'open': dropdownContent}">
                    <!-- <img src="assets/images/arrow-dropdown.svg"> -->
                    <button type="button"
                      class="sb-btn sb-btn-normal sb-btn-outline-primary br-24 btn-border">{{resourceService?.frmelmnts?.lbl?.change}}</button>
                  </div>
                </div>
              </div>
              <div class="dropdown-content p-24" [hidden]="dropdownContent">
                <div class="members-group-list d-flex">
                  <div class="members-group-list-item d-flex flex-dc w-100">
                    <div class="member-name" tabindex="0"
                      (click)="handleSelectedCourse(course);addTelemetry('select-course', [{id: course?.identifier, type: 'SelectedDropdown'}], {selectedCourse: {id: course?.identifier }})"
                      *ngFor="let course of nestedCourses">
                      <span class='fnormal'
                        [ngClass]="{'font-weight-bold': course?.identifier === selectedCourse?.identifier }">{{course?.name}}</span>
                    </div>
                  </div>
                </div>
              </div>
            </div>
            <div class="px-16 pt-16">
              <div *ngIf="!isContentTrackable(activity, activity?.contentType)" class="pb-16"><span
                  class="note-color">{{resourceService?.frmelmnts?.lbl?.note}}</span>
                {{resourceService?.frmelmnts.lbl.noProgress | interpolate:'{type}': (showActivityType())}}</div>
              <div class="sb-search-box no-btn">
                <div class="input-div relative">
                  <i class="search icon" aria-hidden="true"></i>
                  <input class="sb-search-input" type="text" #searchInputBox (input)="search(searchInputBox.value)"
                    [placeholder]="resourceService?.frmelmnts?.lbl?.searchWithinGroup" aria-label="search box" />
                </div>
                <button class="sb-btn sb-btn-normal"
                  type="button">{{ resourceService?.frmelmnts?.lbl?.search }}</button>
              </div>
            </div>
            <div class="d-flex flex-ai-center px-16 py-8 flex-jc-space-between"
              *ngIf="isContentTrackable(activity, activity?.contentType)">
              <div *ngIf="parentId !== selectedCourse?.identifier"></div>
              <span class="fxsmall"> {{ resourceService?.frmelmnts?.lbl?.LastUpdated }}:
                {{memberListUpdatedOn | date:'MMM d, y, h:mm a'}} </span>
              <div class="cursor-pointer" *ngIf="parentId === selectedCourse?.identifier" tabindex="0"
                (click)="downloadCSVFile()">
                <i class="download icon sb-color-primary"></i>
                <span class="download-text">{{resourceService?.frmelmnts?.lbl?.downloadAsCSV}}</span>
              </div>
            </div>
            <div class="px-24">
            </div>
            <div class="d-flex flex-dc p-16">
              <div *ngFor="let member of memberListToShow" class="relative">
                <sb-member-card [title]="member?.title" [identifier]="member?.identifier" [config]="memberCardConfig"
                  [progressDisplay]="member?.progress" [indexOfMember]="member?.indexOfMember"
                  [initial]="member?.initial">
                </sb-member-card>
              </div>
            </div>
            <div class="member-no-result p-24" *ngIf="showSearchResults && !memberListToShow?.length">
              <div class="d-flex flex-dc flex-jc-center flex-ai-center text-center">
                <img width="197" src="./assets/images/add-member@2x.svg" alt="">
                <div class="mt-16 no-result-text">
                  {{ resourceService?.frmelmnts?.lbl?.NoSerchGroupMemberResults }}
                </div>
                <div class="my-8 no-result-desc hide">
                  <div>{{ resourceService?.frmelmnts?.lbl?.checkYourSpelling }}</div>
                  <div>{{ resourceService?.frmelmnts?.lbl?.similarButDiffName }}</div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

./activity-details.component.scss

@use "@project-sunbird/sb-styles/assets/mixins/mixins" as *;
@use 'pages/content-header' as *;

.member-no-result {
  .no-result-text {
    font-size: calculateRem(14px);
  }
  .no-result-desc {
    font-size: calculateRem(12px);
    color: var(--gray-200);
  }
}

//nested group css
.nested-group-content {
  border-radius: calculateRem(8px);
  position: relative;
  .nested-course-area {
    border-bottom: calculateRem(1px) solid var(--gray-100);
    color: var(--white);
    border-top-right-radius: 0.5rem;
    border-top-left-radius: 0.5rem;
  }
  .dropdown-content {
    position: absolute;
    z-index: 999;
    background: var(--white);
    width: 100%;
    box-shadow: 0 0.1875rem 0.3125rem 0.25rem rgba(0, 0, 0, 0.05);
    .members-group-list {
      cursor: pointer;
      width: 100%;
      span {
        font-size: calculateRem(16px);
        padding-left: calculateRem(8px);
      }
      .members-group-list-item {
        position: relative;
        .member-name {
          color: var(--gray-800);
          font-size: calculateRem(16px);
          letter-spacing: 0;
          line-height:normal; //20px
          flex: 1;
          text-align: left;
          margin-bottom: calculateRem(24px);
          &:last-child {
            margin-bottom:0px;
          }
        }
      }
    }
  } 
}
.open {
 img {
   transform: rotate(180deg);
 }
}

.btn-border{
  border-radius:calculateRem(24px);
}

.note-color {
  color:var(--red-100);
}

.download-text{
  font-size:calculateRem(12px);
  color:var(--primary-400);
  font-weight: bold;
}

.dt-disabled-btn:disabled, .disabled[disabled]{
  background-color: var(--gray-100)!important;
  border: .0625rem solid!important;
  color: var(--gray-300);
  pointer-events: none !important;
  opacity: 0.95 !important;
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""