src/app/system/system.component.ts

Implements

OnInit

Metadata

Relationships

Used by

Depends on

Index

Properties
Methods

Constructor

constructor(appService: AppService, sasService: SasService, licenceService: LicenceService, appSettingsService: AppSettingsService)
Parameters :
Name Type Optional
appService AppService No
sasService SasService No
licenceService LicenceService No
appSettingsService AppSettingsService No

Methods

downloadConfiguration
downloadConfiguration()
Returns : void
exportDdl
exportDdl()
Returns : void
isValidLibref
isValidLibref(value: string)
Parameters :
Name Type Optional
value string No
Returns : boolean
ngOnInit
ngOnInit()
Returns : void
openDdlExport
openDdlExport()
Returns : void
Private parseResponse
parseResponse(res: any)
Parameters :
Name Type Optional
res any No
Returns : any
refreshDataCatalog
refreshDataCatalog()
Returns : void
refreshDataLineage
refreshDataLineage()
Returns : void
settingChange
settingChange(event: Event)
Parameters :
Name Type Optional
event Event No
Returns : void

Properties

appInfo
Type : AppInfo
Default value : { adapterVersion: VERSION.adapterVersion || 'n/a', appVersion: (VERSION.tag || '').replace('v', ''), buildTimestamp: moment(parseInt(VERSION.timestamp)).format( 'DD-MMM-YYYY HH:MM' ) }
dcLib
Type : string
Default value : globals.dcLib
ddlFlavour
Type : string
Default value : 'SAS'
ddlModal
Type : boolean
Default value : false
ddlSchema
Type : string
Default value : ''
environmentInfo
Type : EnvironmentInfo | null
http
Type : boolean
Default value : location.protocol === 'http:'
Infinity
Type : unknown
Default value : Infinity
licenceInfo
Type : LicenseKeyData | null
licenceState
Type : unknown
Default value : this.licenceService.licenceState
refreshingDataCatalog
Type : boolean
Default value : false
refreshingDataLineage
Type : boolean
Default value : false
response
Type : string
Default value : 'No response'
responseModal
Type : boolean
Default value : false
serverType
Type : string
settings
Type : AppSettings
targetLibref
Type : string
Default value : globals.dcLib
import { Component, OnInit, ViewEncapsulation } from '@angular/core'
import moment from 'moment'
import { VERSION } from 'src/environments/version'
import { LicenseKeyData } from '../models/LicenseKeyData'
import { AppService } from '../services/app.service'
import { LicenceService } from '../services/licence.service'
import { SasService } from '../services/sas.service'
import { AppInfo } from './models/app-info.model'
import { EnvironmentInfo } from './models/environment-info.model'
import { AppSettingsService } from '../services/app-settings.service'
import { AppSettings } from '../models/AppSettings'
import { RequestWrapperResponse } from '../models/request-wrapper/RequestWrapperResponse'
import { globals } from '../_globals'

@Component({
  selector: 'app-system',
  templateUrl: './system.component.html',
  styleUrls: ['./system.component.scss'],
  host: {
    class: 'content-container'
  },
  encapsulation: ViewEncapsulation.None,
  standalone: false
})
export class SystemComponent implements OnInit {
  appInfo: AppInfo = {
    adapterVersion: VERSION.adapterVersion || 'n/a',
    appVersion: (VERSION.tag || '').replace('v', ''),
    buildTimestamp: moment(parseInt(VERSION.timestamp)).format(
      'DD-MMM-YYYY HH:MM'
    )
  }
  serverType: string
  environmentInfo: EnvironmentInfo | null
  licenceInfo: LicenseKeyData | null
  http: boolean = location.protocol === 'http:'
  refreshingDataCatalog: boolean = false
  refreshingDataLineage: boolean = false
  response: string = 'No response'
  responseModal: boolean = false

  Infinity = Infinity
  dcLib: string = globals.dcLib
  targetLibref: string = globals.dcLib
  ddlModal: boolean = false
  ddlFlavour: string = 'SAS'
  ddlSchema: string = ''

  licenceState = this.licenceService.licenceState
  settings: AppSettings

  constructor(
    private appService: AppService,
    private sasService: SasService,
    private licenceService: LicenceService,
    private appSettingsService: AppSettingsService
  ) {
    this.serverType = this.sasService.getServerType()
    this.licenceInfo = this.licenceService.getLicenseKeyData()
    this.environmentInfo = this.appService.getEnvironmentInfo()
    this.settings = this.appSettingsService.settings.value

    if (this.environmentInfo.AUTOEXEC) {
      this.environmentInfo.AUTOEXEC = decodeURIComponent(
        this.environmentInfo.AUTOEXEC
      )
    }

    this.appSettingsService.settings.subscribe((settings: AppSettings) => {
      this.settings = settings
    })
  }

  ngOnInit(): void {}

  settingChange(event: Event) {
    this.appSettingsService.setAppSettings(this.settings)
  }

  isValidLibref(value: string): boolean {
    return /^[A-Za-z_]\w{0,7}$/.test(value.trim())
  }

  downloadConfiguration() {
    let sasjsConfig = this.sasService.getSasjsConfig()
    let storage = sasjsConfig.serverUrl
    let metaData = sasjsConfig.appLoc
    let path = this.sasService.getExecutionPath()
    let lib = this.targetLibref.toUpperCase().trim()
    let downUrl =
      storage + path + '/?_program=' + metaData + '/services/admin/exportconfig'
    if (lib && lib !== this.dcLib && this.isValidLibref(lib)) {
      downUrl += '&dclib=' + encodeURIComponent(lib)
    }
    window.open(downUrl)
  }

  openDdlExport() {
    this.ddlFlavour = 'SAS'
    this.ddlSchema = ''
    this.ddlModal = true
  }

  exportDdl() {
    let sasjsConfig = this.sasService.getSasjsConfig()
    let storage = sasjsConfig.serverUrl
    let metaData = sasjsConfig.appLoc
    let path = this.sasService.getExecutionPath()
    let downUrl =
      storage +
      path +
      '/?_program=' +
      metaData +
      '/services/admin/exportdb&flavour=' +
      encodeURIComponent(this.ddlFlavour)
    let schema = this.ddlSchema.trim()
    if (this.ddlFlavour !== 'SAS' && schema) {
      downUrl += '&schema=' + encodeURIComponent(schema)
    }
    window.open(downUrl)
    this.ddlModal = false
  }

  refreshDataCatalog() {
    this.refreshingDataCatalog = true

    this.sasService
      .request('admin/refreshcatalog', null)
      .then((res: RequestWrapperResponse) => {
        this.response = this.parseResponse(res.adapterResponse)
        this.responseModal = true
      })
      .catch((err: any) => {
        this.response = this.parseResponse(err.adapterResponse)
        this.responseModal = true
      })
      .finally(() => {
        this.refreshingDataCatalog = false
      })
  }

  refreshDataLineage() {
    this.refreshingDataLineage = true

    this.sasService
      .request('admin/refreshtablelineage', null)
      .then((res: RequestWrapperResponse) => {
        this.response = this.parseResponse(res.adapterResponse)
        this.responseModal = true
      })
      .catch((err: any) => {
        this.response = this.parseResponse(err.adapterResponse)
        this.responseModal = true
      })
      .finally(() => {
        this.refreshingDataLineage = false
      })
  }

  private parseResponse(res: any) {
    return typeof res === 'object' ? JSON.stringify(res) : res
  }
}
<div class="content-area">
  <div
    class="card p-10 d-flex clr-flex-column clr-align-items-center clr-justify-content-center"
  >
    <h4 class="text-center m-0">System information</h4>
    <hr class="w-100 light" />
    <div class="content-box d-flex clr-flex-column">
      <div
        class="sys-info d-flex clr-justify-content-center clr-flex-column clr-flex-lg-row"
      >
        <div>
          <h6 cds-text="subsection" class="mb-10">
            Environment Details <span class="dark"></span>
          </h6>
          <p cds-text="label" class="m-0">
            SYSSITE: <span class="dark">{{ environmentInfo?.SYSSITE }}</span>
          </p>
          <p cds-text="label" class="m-0">
            SYSSCPL: <span class="dark">{{ environmentInfo?.SYSSCPL }}</span>
          </p>
          <p cds-text="label" class="m-0">
            SYSTCPIPHOSTNAME:
            <span class="dark">{{ environmentInfo?.SYSTCPIPHOSTNAME }}</span>
          </p>
          <p cds-text="label" class="m-0">
            SYSVLONG: <span class="dark">{{ environmentInfo?.SYSVLONG }}</span>
          </p>
          <p cds-text="label" class="m-0">
            MEMSIZE: <span class="dark">{{ environmentInfo?.MEMSIZE }}</span>
          </p>
          <p cds-text="label" class="m-0">
            SYSPROCESSMODE:
            <span class="dark">{{ environmentInfo?.SYSPROCESSMODE }}</span>
          </p>
          <p cds-text="label" class="m-0">
            SYSHOSTNAME:
            <span class="dark">{{ environmentInfo?.SYSHOSTNAME }}</span>
          </p>
          <p cds-text="label" class="m-0">
            SYSUSERID:
            <span class="dark">{{ environmentInfo?.SYSUSERID }}</span>
          </p>
          <p cds-text="label" class="m-0">
            SYSHOSTINFOLONG:
            <span class="dark">{{ environmentInfo?.SYSHOSTINFOLONG }}</span>
          </p>
          <p cds-text="label" class="m-0">
            SYSENCODING:
            <span class="dark">{{ environmentInfo?.SYSENCODING }}</span>
          </p>
          <p cds-text="label" class="m-0">
            AUTOEXEC: <span class="dark">{{ environmentInfo?.AUTOEXEC }}</span>
          </p>
          <p cds-text="label" class="m-0">
            TIMEZONE:
            <span class="dark">{{
              environmentInfo?.TIMEZONE || '(not set)'
            }}</span>
          </p>
          <p cds-text="label" class="m-0">
            SYSTIMEZONEIDENT:
            <span class="dark">{{
              environmentInfo?.SYSTIMEZONEIDENT || '(not set)'
            }}</span>
          </p>
          <p cds-text="label" class="m-0">
            SYSTIMEZONEOFFSET:
            <span class="dark">{{
              environmentInfo?.SYSTIMEZONEOFFSET || '0'
            }}</span>
          </p>
        </div>

        <div class="d-flex clr-justify-content-lg-center">
          <div>
            <h6 cds-text="subsection" class="mb-10">
              Data Controller Details <span class="dark"></span>
            </h6>
            <p cds-text="label" class="m-0">
              Application version:
              <span class="dark">{{ appInfo.appVersion }}</span>
            </p>
            <p cds-text="label" class="m-0">
              Build timestamp:
              <span class="dark">{{ appInfo.buildTimestamp }}</span>
            </p>
            <p cds-text="label" class="m-0">
              Adapter version:
              <span class="dark">{{ appInfo.adapterVersion }}</span>
            </p>
            <p cds-text="label" class="m-0">
              HTTP: <span class="dark">{{ http ? 'YES' : 'NO' }}</span>
            </p>
            <p cds-text="label" class="m-0">
              DC Admin Group:
              <span class="dark">{{ environmentInfo?.DC_ADMIN_GROUP }}</span>
            </p>
            <p cds-text="label" class="m-0">
              App Location:
              <span class="dark">{{ environmentInfo?.APP_LOC }}</span>
            </p>
          </div>
        </div>

        <div>
          <h6 cds-text="subsection" class="mb-10">
            Licence details <span class="dark"></span>
          </h6>
          <p cds-text="label" class="m-0">
            Valid until:
            <span class="dark">{{ licenceInfo?.valid_until }}</span>
          </p>
          <p cds-text="label" class="m-0">
            Users allowed:
            <span class="dark">{{ licenceInfo?.users_allowed }}</span>
          </p>
          <p cds-text="label" class="m-0">
            Site IDs:
            <span class="dark">{{ licenceInfo?.site_id_multiple }}</span>
          </p>
          <p cds-text="label" class="m-0">
            Free Tier:
            <span class="dark">{{ licenceInfo?.demo ? 'YES' : 'NO' }}</span>
          </p>
          @if (licenceState.value.viewer_rows_allowed !== Infinity) {
            <p class="m-0">
              Viewer rows limit:
              <span class="dark">{{
                licenceState.value.viewer_rows_allowed
              }}</span>
            </p>
          }
          @if (licenceState.value.editor_rows_allowed !== Infinity) {
            <p class="m-0">
              Editor rows limit:
              <span class="dark">{{
                licenceState.value.editor_rows_allowed
              }}</span>
            </p>
          }
          @if (licenceState.value.stage_rows_allowed !== Infinity) {
            <p class="m-0">
              Stage rows limit:
              <span class="dark">{{
                licenceState.value.stage_rows_allowed
              }}</span>
            </p>
          }
          @if (licenceState.value.history_rows_allowed !== Infinity) {
            <p class="m-0">
              History rows limit:
              <span class="dark">{{
                licenceState.value.history_rows_allowed
              }}</span>
            </p>
          }
          @if (licenceState.value.submit_rows_limit !== Infinity) {
            <p class="m-0">
              Submit rows limit:
              <span class="dark">{{
                licenceState.value.submit_rows_limit
              }}</span>
            </p>
          }
          @if (licenceState.value.tables_in_library_limit !== Infinity) {
            <p class="m-0">
              Tables in library limit:
              <span class="dark">{{
                licenceState.value.tables_in_library_limit
              }}</span>
            </p>
          }
          @if (licenceState.value.viewbox_limit !== Infinity) {
            <p class="m-0">
              Viewboxes limit:
              <span class="dark">{{ licenceState.value.viewbox_limit }}</span>
            </p>
          }
          @if (licenceState.value.lineage_daily_limit !== Infinity) {
            <p class="m-0">
              Lineage daily limit:
              <span class="dark">{{
                licenceState.value.lineage_daily_limit
              }}</span>
            </p>
          }
          <p cds-text="label" class="m-0">
            Viewboxes:
            <span class="dark">{{
              licenceState.value.viewbox ? 'YES' : 'NO'
            }}</span>
          </p>
          <p cds-text="label" class="m-0">
            File Upload:
            <span class="dark">{{
              licenceState.value.fileUpload ? 'YES' : 'NO'
            }}</span>
          </p>
          <p cds-text="label" class="m-0">
            Edit record:
            <span class="dark">{{
              licenceState.value.editRecord ? 'YES' : 'NO'
            }}</span>
          </p>
          <p cds-text="label" class="m-0">
            Add record:
            <span class="dark">{{
              licenceState.value.addRecord ? 'YES' : 'NO'
            }}</span>
          </p>
        </div>
      </div>

      <hr class="w-100 light" />

      <!-- Keep the logic in case we in future have more then 2 themes (light, dark) -->
      <!-- -->
      <!-- <div class="user-action">
      Keep selected theme after reload

      <clr-checkbox-wrapper>
        <input [(ngModel)]="settings.persistSelectedTheme" (change)="settingChange($event)" value="persistDarkMode" type="checkbox" clrToggle />
      </clr-checkbox-wrapper>
    </div> -->

      @if (environmentInfo?.ISADMIN === 1) {
        @if (serverType === 'SAS9') {
          <div class="admin-action">
            Refresh Data Lineage
            <button
              (click)="refreshDataLineage()"
              [clrLoading]="refreshingDataLineage"
              class="btn btn-info btn-sm"
            >
              REFRESH
            </button>
          </div>
        }
        <div class="admin-action">
          Refresh Data Catalog
          <button
            (click)="refreshDataCatalog()"
            [clrLoading]="refreshingDataCatalog"
            class="btn btn-info btn-sm"
          >
            REFRESH
          </button>
        </div>
        <div class="admin-action">
          Download Configuration
          <div class="libref-group">
            <clr-tooltip class="libref-tooltip">
              <label clrTooltipTrigger class="libref-label">
                Target DC Library
                <cds-icon shape="info-circle" size="16"></cds-icon>
              </label>
              <clr-tooltip-content
                clrPosition="bottom-left"
                clrSize="md"
                *clrIfOpen
              >
                Enter the target DC library and the downloaded files will
                contain this, instead of the original.
              </clr-tooltip-content>
            </clr-tooltip>
            <input
              type="text"
              class="clr-input libref-input"
              maxlength="8"
              [ngModel]="dcLib"
              (ngModelChange)="targetLibref = $event.toUpperCase()"
              placeholder="e.g. MYLIB"
            />
          </div>
          <button
            (click)="downloadConfiguration()"
            [disabled]="targetLibref !== dcLib && !isValidLibref(targetLibref)"
            class="btn btn-info btn-sm"
          >
            DOWNLOAD
          </button>
        </div>
        <div class="admin-action">
          Update Licence Key
          <button routerLink="/licensing/update" class="btn btn-info btn-sm">
            UPDATE
          </button>
        </div>
        <div class="admin-action">
          Export DC Library DDL
          <button (click)="openDdlExport()" class="btn btn-info btn-sm">
            EXPORT
          </button>
        </div>
      }
    </div>
  </div>
</div>

<clr-modal [(clrModalOpen)]="responseModal">
  <h3 class="modal-title">Response</h3>
  <div class="modal-body">
    {{ response }}
  </div>
  <div class="modal-footer">
    <button
      type="button"
      class="btn btn-sm btn-primary"
      (click)="responseModal = false"
    >
      Ok
    </button>
  </div>
</clr-modal>

<clr-modal [(clrModalOpen)]="ddlModal">
  <h3 class="modal-title">Export DC Library DDL</h3>
  <div class="modal-body">
    <clr-select-container>
      <label>Flavour</label>
      <select [(ngModel)]="ddlFlavour" clrSelect>
        <option value="SAS">SAS</option>
        <option value="PGSQL">PGSQL</option>
        <option value="TSQL">TSQL</option>
      </select>
    </clr-select-container>
    @if (ddlFlavour !== 'SAS') {
      <clr-input-container>
        <label>Schema (optional)</label>
        <input
          clrInput
          type="text"
          [(ngModel)]="ddlSchema"
          placeholder="e.g. DC"
        />
      </clr-input-container>
    }
  </div>
  <div class="modal-footer">
    <button
      type="button"
      class="btn btn-sm btn-outline"
      (click)="ddlModal = false"
    >
      Cancel
    </button>
    <button type="button" class="btn btn-sm btn-primary" (click)="exportDdl()">
      Export
    </button>
  </div>
</clr-modal>

./system.component.scss

.libref-group {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin: 0 8px;
}

.libref-label {
  cursor: pointer;
  font-size: 0.55rem;
  font-weight: 600;
  color: var(--clr-p4-color, #565656);
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.libref-input {
  width: 100px;
  text-transform: uppercase;
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""