Compare commits

...
8 Commits
Author SHA1 Message Date
4gl 2dfeb02faf chore: packages / deploy
Build / Build-and-ng-test (pull_request) Successful in 5m43s
Lighthouse Checks / lighthouse (pull_request) Successful in 22m48s
Build / Build-and-test-development (pull_request) Successful in 26m22s
2026-08-19 10:45:57 +01:00
Yury 9deccd072d Merge pull request 'fix: core major bump plus autofix of viya context on deploy' (#306) from sasfixes into version7-13
Build / Build-and-ng-test (pull_request) Successful in 5m39s
Lighthouse Checks / lighthouse (pull_request) Successful in 22m13s
Build / Build-and-test-development (pull_request) Successful in 26m26s
Reviewed-on: #306
2026-08-19 09:40:20 +00:00
hermes 9023eb2a39 fix: escape regex metacharacters in context name before prxchange
Build / Build-and-ng-test (pull_request) Successful in 5m30s
Lighthouse Checks / lighthouse (pull_request) Successful in 22m5s
Build / Build-and-test-development (pull_request) Successful in 25m28s
symget('_contextname') is concatenated directly into the PRX replacement
string in makedata.sas. A context name containing \ or $ would be
interpreted as a backreference or variable interpolation in the Perl
regex replacement. Escape both characters with a leading backslash in a
data step before embedding the value in the prxchange call.
2026-08-18 14:46:34 +01:00
hermes 72484ae844 fix: clarify debug comment is permanent, extend ComputeContextDetails with Viya response fields
Build / Build-and-ng-test (pull_request) Successful in 5m30s
Lighthouse Checks / lighthouse (pull_request) Successful in 22m2s
Build / Build-and-test-development (pull_request) Successful in 26m15s
- sasjs-configurator: rewrite _debug=131 comment to make explicit that
  debug is ALWAYS enabled for the makedata service (runs once during
  deployment, debug output always wanted for diagnostics). Remove the
  commented-out debug-off line that caused reviewer confusion.
- viya-compute-context-details.model: extend Attributes with
  allowXCMD, sessionInactiveTimeout (number), and make all attribute
  fields optional. Add Environment interface with autoExecLines string
  array. Add environment? to ComputeContextDetails (optional, not all
  contexts expose it).
- automatic.component: rewrite extractRunAs to use
  attributes.runServerAs directly per the actual Viya API response
  shape. Remove all any casts and the non-existent runAsUserId /
  environment.runAsUserId field probes.
2026-08-18 14:45:04 +01:00
hermes 003550b965 chore: reference configurator improvements for Viya deploy
Build / Build-and-ng-test (pull_request) Canceled after 0s
Build / Build-and-test-development (pull_request) Canceled after 0s
Lighthouse Checks / lighthouse (pull_request) Canceled after 0s
fixes #303
2026-08-18 12:44:57 +01:00
hermes 45226e19d6 chore: address PR #306 review feedback
- Add explanatory comments for deliberately enabled debug mode in configurator
- Fix deploy-field-description font-size from 0.55rem to 0.85rem (was unreadably small)
2026-08-18 12:44:54 +01:00
4gl df2027dab6 feat: updated configurator for Viya deploy
Build / Build-and-ng-test (pull_request) Successful in 5m34s
Lighthouse Checks / lighthouse (pull_request) Successful in 22m2s
Build / Build-and-test-development (pull_request) Successful in 24m52s
2026-08-18 12:21:29 +01:00
4gl 6527c10f26 fix: core major bump plus autofix of viya context on deploy
Build / Build-and-ng-test (pull_request) Successful in 5m8s
Lighthouse Checks / lighthouse (pull_request) Successful in 21m36s
Build / Build-and-test-development (pull_request) Successful in 25m4s
2026-08-17 15:46:52 +01:00
47 changed files with 704 additions and 248 deletions
+38 -38
View File
@@ -21,8 +21,8 @@
"@clr/icons": "^13.0.2",
"@clr/ui": "file:libraries/clr-ui-17.9.0.tgz",
"@handsontable/angular-wrapper": "^18.0.0",
"@sasjs/adapter": "^4.17.3",
"@sasjs/utils": "^3.5.9",
"@sasjs/adapter": "^4.18.0",
"@sasjs/utils": "^3.6.0",
"@sheet/crypto": "file:libraries/sheet-crypto.tgz",
"@types/d3-graphviz": "^2.6.7",
"@types/text-encoding": "0.0.35",
@@ -1984,8 +1984,8 @@
"node": "^20.19.0 || ^22.12.0 || >=24.0.0"
},
"peerDependencies": {
"rxjs": "^6.5.3 || ^7.4.0",
"@angular/core": "20.3.27"
"@angular/core": "20.3.27",
"rxjs": "^6.5.3 || ^7.4.0"
}
},
"node_modules/@angular/compiler": {
@@ -2007,25 +2007,25 @@
"dev": true,
"license": "MIT",
"dependencies": {
"tslib": "^2.3.0",
"yargs": "^18.0.0",
"semver": "^7.0.0",
"chokidar": "^4.0.0",
"@babel/core": "7.29.7",
"reflect-metadata": "^0.2.0",
"@jridgewell/sourcemap-codec": "^1.4.14",
"chokidar": "^4.0.0",
"convert-source-map": "^1.5.1",
"@jridgewell/sourcemap-codec": "^1.4.14"
"reflect-metadata": "^0.2.0",
"semver": "^7.0.0",
"tslib": "^2.3.0",
"yargs": "^18.0.0"
},
"bin": {
"ngc": "bundles/src/bin/ngc.js",
"ng-xi18n": "bundles/src/bin/ng_xi18n.js"
"ng-xi18n": "bundles/src/bin/ng_xi18n.js",
"ngc": "bundles/src/bin/ngc.js"
},
"engines": {
"node": "^20.19.0 || ^22.12.0 || >=24.0.0"
},
"peerDependencies": {
"typescript": ">=5.8 <6.0",
"@angular/compiler": "20.3.27"
"@angular/compiler": "20.3.27",
"typescript": ">=5.8 <6.0"
},
"peerDependenciesMeta": {
"typescript": {
@@ -2045,15 +2045,15 @@
"node": "^20.19.0 || ^22.12.0 || >=24.0.0"
},
"peerDependencies": {
"@angular/compiler": "20.3.27",
"rxjs": "^6.5.3 || ^7.4.0",
"zone.js": "~0.15.0",
"@angular/compiler": "20.3.27"
"zone.js": "~0.15.0"
},
"peerDependenciesMeta": {
"zone.js": {
"@angular/compiler": {
"optional": true
},
"@angular/compiler": {
"zone.js": {
"optional": true
}
}
@@ -2070,10 +2070,10 @@
"node": "^20.19.0 || ^22.12.0 || >=24.0.0"
},
"peerDependencies": {
"rxjs": "^6.5.3 || ^7.4.0",
"@angular/core": "20.3.27",
"@angular/common": "20.3.27",
"@angular/platform-browser": "20.3.27"
"@angular/core": "20.3.27",
"@angular/platform-browser": "20.3.27",
"rxjs": "^6.5.3 || ^7.4.0"
}
},
"node_modules/@angular/platform-browser": {
@@ -2088,9 +2088,9 @@
"node": "^20.19.0 || ^22.12.0 || >=24.0.0"
},
"peerDependencies": {
"@angular/core": "20.3.27",
"@angular/animations": "20.3.27",
"@angular/common": "20.3.27",
"@angular/animations": "20.3.27"
"@angular/core": "20.3.27"
},
"peerDependenciesMeta": {
"@angular/animations": {
@@ -2111,9 +2111,9 @@
"node": "^20.19.0 || ^22.12.0 || >=24.0.0"
},
"peerDependencies": {
"@angular/core": "20.3.27",
"@angular/common": "20.3.27",
"@angular/compiler": "20.3.27",
"@angular/core": "20.3.27",
"@angular/platform-browser": "20.3.27"
}
},
@@ -2129,10 +2129,10 @@
"node": "^20.19.0 || ^22.12.0 || >=24.0.0"
},
"peerDependencies": {
"rxjs": "^6.5.3 || ^7.4.0",
"@angular/core": "20.3.27",
"@angular/common": "20.3.27",
"@angular/platform-browser": "20.3.27"
"@angular/core": "20.3.27",
"@angular/platform-browser": "20.3.27",
"rxjs": "^6.5.3 || ^7.4.0"
}
},
"node_modules/@arr/every": {
@@ -8844,12 +8844,12 @@
]
},
"node_modules/@sasjs/adapter": {
"version": "4.17.3",
"resolved": "https://registry.npmjs.org/@sasjs/adapter/-/adapter-4.17.3.tgz",
"integrity": "sha512-UGVDLhT5+EyV5Lr0vtDeUg8/XUhUfox73VyZ9fjJmBhZUnfnwSsvvp2P9E7X7lfkQPXOHJKHFCXPhG33+D1MIQ==",
"version": "4.18.0",
"resolved": "https://registry.npmjs.org/@sasjs/adapter/-/adapter-4.18.0.tgz",
"integrity": "sha512-1gP0Rsl2cRAMSchjCIrDkF+T6WA/fPXGIB+ABAXWCQxr6gM2JXqthebL+GxwDsq0yCoEp4w47KplaEkdBDy/EQ==",
"license": "ISC",
"dependencies": {
"@sasjs/utils": "^3.5.6",
"@sasjs/utils": "^3.6.0",
"axios": "1.18.1",
"axios-cookiejar-support": "5.0.5",
"form-data": "4.0.6",
@@ -8858,9 +8858,9 @@
}
},
"node_modules/@sasjs/utils": {
"version": "3.5.9",
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-3.5.9.tgz",
"integrity": "sha512-Qg4N8LoR51vN8WyYUap2OyvJi+6woJk7ph5ylbFVomO9CM+7KIvkMJLFAtwmKSccWPn+FSy2Lhi39pQ/HA1dug==",
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-3.6.0.tgz",
"integrity": "sha512-5BEH4l7g5K84uq+UsN83g8iPBHqAfuHaQ9FH93UsEruDB3fZybAamAiH1Im8riZAs6ConFczkFucypz5mJRgNQ==",
"license": "ISC",
"dependencies": {
"@fast-csv/format": "4.3.5",
@@ -14946,12 +14946,12 @@
"integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==",
"funding": [
{
"url": "https://github.com/sponsors/fastify",
"type": "github"
"type": "github",
"url": "https://github.com/sponsors/fastify"
},
{
"url": "https://opencollective.com/fastify",
"type": "opencollective"
"type": "opencollective",
"url": "https://opencollective.com/fastify"
}
],
"license": "BSD-3-Clause"
+2 -2
View File
@@ -55,8 +55,8 @@
"@clr/icons": "^13.0.2",
"@clr/ui": "file:libraries/clr-ui-17.9.0.tgz",
"@handsontable/angular-wrapper": "^18.0.0",
"@sasjs/adapter": "^4.17.3",
"@sasjs/utils": "^3.5.9",
"@sasjs/adapter": "^4.18.0",
"@sasjs/utils": "^3.6.0",
"@sheet/crypto": "file:libraries/sheet-crypto.tgz",
"@types/d3-graphviz": "^2.6.7",
"@types/text-encoding": "0.0.35",
+12 -19
View File
@@ -130,25 +130,18 @@
</div>
}
<div class="logo d-flex clr-align-items-center">
@if (!router.url.includes('deploy')) {
<a href="#" [routerLink]="['/']" class="nav-link">
<img
class="without-text d-block d-md-none"
src="images/dc-logo.svg"
alt="datacontroller logo without text"
/>
<img
class="with-text d-none d-md-block"
src="images/datacontroller.svg"
alt="datacontroller logo"
/>
</a>
}
@if (router.url.includes('deploy')) {
<a>
<span class="clr-icon header-logo ml-10"></span>
</a>
}
<a href="#" [routerLink]="['/']" class="nav-link">
<img
class="without-text d-block d-md-none"
src="images/dc-logo.svg"
alt="datacontroller logo without text"
/>
<img
class="with-text d-none d-md-block"
src="images/datacontroller.svg"
alt="datacontroller logo"
/>
</a>
</div>
@if (
!router.url.includes('deploy') && !router.url.includes('licensing')
@@ -77,69 +77,173 @@
}
<h4 class="text-center my-15">Viya Deploy</h4>
<p class="deploy-intro">
Configure and deploy Data Controller to your Viya environment. Deployment
creates the backend SAS services and the control library used by the
application.
</p>
<hr />
<label for="dcloc" class="mt-20 clr-control-label">App Loc</label>
<div class="mb-10 clr-control-container">
<div class="clr-input-wrapper">
<p class="mt-0">{{ appLoc }}</p>
<div class="deploy-field">
<label class="clr-control-label">App Loc</label>
<p class="deploy-field-description">
The SAS drive folder in which the Data Controller frontend and services are
deployed. Derived from your deployment configuration &mdash; it cannot be
changed here.
</p>
<div class="clr-control-container">
<div class="clr-input-wrapper">
<p class="m-0">{{ appLoc }}</p>
</div>
</div>
</div>
<label for="dcloc" class="mt-20 clr-control-label">DC Loc</label>
<div class="mb-10 clr-control-container dc-loc-input-wrapper">
<div class="clr-input-wrapper small-mt">
<input clrInput name="dcloc" [(ngModel)]="dcPath" />
<div class="deploy-field">
<label for="dcloc" class="clr-control-label">DC Loc</label>
<p class="deploy-field-description">
A physical directory on the compute server to which the deployment user can
write. Data Controller stores its control tables, staging area and audit
history here.
</p>
<div class="clr-control-container dc-loc-input-wrapper">
<div class="clr-input-wrapper small-mt">
<input clrInput name="dcloc" [(ngModel)]="dcPath" />
</div>
</div>
</div>
<label for="dcloc" class="mt-20 clr-control-label">SAS Admin group</label>
<div class="mb-10 clr-control-container">
<div class="clr-input-wrapper small-mt">
@if (!adminGroupsLoading) {
<select clrSelect name="options" [(ngModel)]="selectedAdminGroup">
@for (adminGroup of adminGroups; track adminGroup) {
<option [value]="adminGroup.id">
{{ adminGroup.name }}
</option>
<div class="deploy-field">
<label for="adminGroup" class="clr-control-label">SAS Admin group</label>
<p class="deploy-field-description">
The group you select becomes the Data Controller Admin Group &mdash;
everyone in it will have unrestricted access to Data Controller. By default
the list is filtered to the groups your identity
@if (currentUserInfo?.id) {
(<strong>{{ currentUserInfo?.id }}</strong
>)
}
is a member of. Toggle below to list every group on the Viya server.
</p>
<clr-toggle-container class="mt-0">
<clr-toggle-wrapper>
<input
id="show-all-groups-toggle"
type="checkbox"
[(ngModel)]="showAllGroups"
(ngModelChange)="onShowAllGroupsChange()"
clrToggle
/>
<label for="show-all-groups-toggle">Show all groups</label>
</clr-toggle-wrapper>
</clr-toggle-container>
<div class="clr-control-container">
<div class="clr-input-wrapper small-mt">
@if (!adminGroupsLoading) {
<select clrSelect name="adminGroup" [(ngModel)]="selectedAdminGroup">
@for (adminGroup of adminGroups; track adminGroup) {
<option [value]="adminGroup.id">
{{ adminGroup.name }}
</option>
}
</select>
}
@if (adminGroupsLoading) {
<clr-spinner clrInline class="spinner-sm"></clr-spinner>
}
</div>
</div>
</div>
@if (!showAllContexts) {
<div class="deploy-field">
<label for="batchId" class="clr-control-label">Batch ID</label>
<p class="deploy-field-description">
The batch identity (<code>runServerAs</code>) under which Data Controller
jobs will execute. It is used to filter the Compute Context dropdown below
to only the contexts running as this identity.
</p>
<div class="clr-control-container">
<div class="clr-input-wrapper small-mt">
@if (!computeContextsLoading) {
<select
clrSelect
name="batchId"
[(ngModel)]="selectedBatchId"
(ngModelChange)="onBatchIdChange()"
>
@for (batchId of batchIds; track batchId) {
<option [value]="batchId">
{{ batchId }}
</option>
}
</select>
}
</select>
}
@if (adminGroupsLoading) {
<clr-spinner clrInline class="spinner-sm"></clr-spinner>
}
</div>
</div>
<label for="computeContext" class="mt-20 clr-control-label"
>Compute Context</label
>
<div class="mb-10 clr-control-container">
<div class="clr-input-wrapper small-mt">
@if (!computeContextsLoading) {
<select
clrSelect
name="options"
(ngModelChange)="onComputeContextChange($event)"
[(ngModel)]="selectedComputeContext"
>
@for (computeContext of computeContexts; track computeContext) {
<option [value]="computeContext.id">
{{ computeContext.name }}
</option>
@if (computeContextsLoading) {
<clr-spinner clrInline class="spinner-sm"></clr-spinner>
}
</select>
}
@if (computeContextsLoading) {
<clr-spinner clrInline class="spinner-sm"></clr-spinner>
}
</div>
</div>
</div>
}
<div class="deploy-field">
<label for="computeContext" class="clr-control-label">Compute Context</label>
<p class="deploy-field-description">
The compute context used to run the Data Controller services (including the
<code>makedata</code> deployment job). Only reusable contexts matching the
selected Batch ID are shown, unless the toggle below is enabled.
</p>
<clr-toggle-container class="mt-0">
<clr-toggle-wrapper>
<input
id="show-all-contexts-toggle"
type="checkbox"
[(ngModel)]="showAllContexts"
(ngModelChange)="onShowAllContextsChange()"
clrToggle
/>
<label for="show-all-contexts-toggle">Show all compute contexts</label>
</clr-toggle-wrapper>
</clr-toggle-container>
<div class="clr-control-container">
<div class="clr-input-wrapper small-mt">
@if (!computeContextsLoading) {
<select
clrSelect
name="computeContext"
(ngModelChange)="onComputeContextChange($event)"
[(ngModel)]="selectedComputeContext"
>
@for (
computeContext of getFilteredComputeContexts();
track computeContext
) {
<option [value]="computeContext.id">
{{ computeContext.name }}
</option>
}
</select>
}
@if (computeContextsLoading) {
<clr-spinner clrInline class="spinner-sm"></clr-spinner>
}
</div>
</div>
</div>
@if (runningAsUser) {
<label for="dcloc" class="mt-20 clr-control-label">Running as user:</label>
<div class="mb-10 clr-control-container">
<div class="clr-input-wrapper">
<p class="mt-0">{{ runningAsUser }}</p>
<div class="deploy-field">
<label class="clr-control-label">Running as user</label>
<p class="deploy-field-description">
The identity under which Data Controller jobs will run with the selected
compute context. This user must be able to write to the DC Loc above.
</p>
<div class="clr-control-container">
<div class="clr-input-wrapper">
<p class="m-0">
<strong>{{ runningAsUser }}</strong>
</p>
</div>
</div>
</div>
}
@@ -25,6 +25,13 @@ import {
Item as ComputeContextItem
} from 'src/app/viya-api-explorer/models/viya-compute-contexts.model'
export interface ComputeContextInfo {
id: string
name: string
runAs: string | null
reusable: boolean
}
@Component({
selector: 'app-automatic-deploy',
templateUrl: './automatic.component.html',
@@ -60,6 +67,21 @@ export class AutomaticComponent implements OnInit {
public currentUserInfoLoading: boolean = false
public computeContextsLoading: boolean = false
public adminGroups: { id: string; name: string }[] = []
/** Compute contexts enriched with their batch identity and reusability */
public computeContextInfos: ComputeContextInfo[] = []
/** Distinct batch identities (runServerAs) across reusable contexts */
public batchIds: string[] = []
public selectedBatchId: string = ''
/**
* When enabled, any compute context can be chosen (the batch id dropdown
* is hidden and no reusability / batch id filtering is applied)
*/
public showAllContexts: boolean = false
/** All groups on the Viya server */
public allAdminGroups: { id: string; name: string }[] = []
/** Groups the current user is a member of */
public memberAdminGroups: { id: string; name: string }[] = []
public showAllGroups: boolean = false
public runningAsUser: string | undefined
public currentUserInfo: ViyaApiCurrentUser | null = null
public computeContexts: ComputeContextItem[] = []
@@ -104,9 +126,9 @@ export class AutomaticComponent implements OnInit {
}
public async loadData() {
await this.getCurrentUser()
await this.getAdminGroups()
await this.getComputeContexts()
await this.getCurrentUser()
setTimeout(() => {
if (this.selectedComputeContext) {
@@ -120,20 +142,13 @@ export class AutomaticComponent implements OnInit {
this.computeContextsLoading = true
this.sasViyaService.getComputeContexts().subscribe(
(res: ViyaComputeContexts) => {
this.computeContextsLoading = false
const defaultContext = res.items.find(
(item: ComputeContextItem) =>
item.name === 'SAS Job Execution compute context'
)
if (defaultContext) {
this.selectedComputeContext = defaultContext.id
}
async (res: ViyaComputeContexts) => {
this.computeContexts = res.items
await this.getComputeContextDetails()
this.computeContextsLoading = false
resolve()
},
(err) => {
@@ -143,6 +158,137 @@ export class AutomaticComponent implements OnInit {
})
}
/**
* The `/compute/contexts` list view is minimal, so each context is fetched
* in full (in parallel) to pick up its batch identity (runServerAs) and
* whether it reuses server processes. Only reusable contexts with a batch
* identity feed the batch id dropdown.
*/
public async getComputeContextDetails() {
const infos = await Promise.all(
this.computeContexts.map(
(context: ComputeContextItem) =>
new Promise<ComputeContextInfo>((resolveInfo) => {
this.sasViyaService.getComputeContextById(context.id).subscribe(
(details: ComputeContextDetails) => {
resolveInfo({
id: context.id,
name: context.name,
runAs: this.extractRunAs(details),
reusable: details.attributes?.reuseServerProcesses === 'true'
})
},
(err: any) => {
this.loggerService.error(
`Error while getting compute context ${context.name}`,
err
)
resolveInfo({
id: context.id,
name: context.name,
runAs: null,
reusable: false
})
}
)
})
)
)
this.computeContextInfos = infos
this.batchIds = [
...new Set(
infos
.filter((info) => info.reusable && info.runAs)
.map((info) => info.runAs as string)
)
]
if (this.batchIds.length) {
this.selectedBatchId = this.batchIds[0]
}
const filteredContexts = this.getFilteredComputeContexts()
const defaultContext =
filteredContexts.find(
(info: ComputeContextInfo) =>
info.name === 'SAS Job Execution compute context'
) || filteredContexts[0]
if (defaultContext) {
this.selectedComputeContext = defaultContext.id
}
}
/**
* Pulls the runAs (batch) identity out of a compute context. The batch user
* is exposed as `attributes.runServerAs` in the Viya compute context API
* response. Not all contexts expose one.
*/
public extractRunAs(details: ComputeContextDetails): string | null {
return details.attributes?.runServerAs || null
}
/**
* The contexts offered in the dropdown. By default only reusable contexts
* (`reuseServerProcesses`) matching the selected batch id are shown. When
* the `showAllContexts` toggle is on, all contexts are shown.
*/
public getFilteredComputeContexts(): ComputeContextInfo[] {
if (this.showAllContexts) {
return this.computeContextInfos
}
return this.computeContextInfos.filter(
(info: ComputeContextInfo) =>
info.reusable && info.runAs === this.selectedBatchId
)
}
/**
* Changing the batch id re-filters the compute context dropdown and makes
* sure the currently selected context exists in the displayed list.
*/
public onBatchIdChange() {
this.ensureSelectedComputeContext()
}
/**
* Toggles the compute context dropdown between contexts matching the
* selected batch id and all contexts on the Viya server.
*/
public onShowAllContextsChange() {
this.ensureSelectedComputeContext()
}
private ensureSelectedComputeContext() {
const filteredContexts = this.getFilteredComputeContexts()
const selectedContextExists = filteredContexts.some(
(info: ComputeContextInfo) => info.id === this.selectedComputeContext
)
if (!selectedContextExists) {
this.selectedComputeContext = filteredContexts.length
? filteredContexts[0].id
: ''
}
this.updateRunningAsUser()
}
private updateRunningAsUser() {
const selectedContext = this.computeContextInfos.find(
(info: ComputeContextInfo) => info.id === this.selectedComputeContext
)
this.runningAsUser =
selectedContext?.runAs || this.currentUserInfo?.id || 'unknown'
}
public async getCurrentUser() {
return new Promise<void>((resolve, reject) => {
this.currentUserInfoLoading = true
@@ -170,16 +316,21 @@ export class AutomaticComponent implements OnInit {
this.adminGroupsLoading = true
;(this.sasViyaService
.getAdminGroups()
.subscribe((res: ViyaApiIdentities) => {
this.adminGroupsLoading = false
.subscribe(async (res: ViyaApiIdentities) => {
// Map admin groups with only needed fields
this.adminGroups = res.items.map((item: Item) => {
this.allAdminGroups = res.items.map((item: Item) => {
return {
id: item.id,
name: item.name
}
})
await this.getMemberAdminGroups()
this.applyAdminGroupFilter()
this.adminGroupsLoading = false
resolve()
}),
(err: any) => {
@@ -192,16 +343,72 @@ export class AutomaticComponent implements OnInit {
})
}
public async onComputeContextChange(computeContextId: string) {
this.sasViyaService
.getComputeContextById(computeContextId)
.subscribe((res: ComputeContextDetails) => {
if (res.attributes && res.attributes.runServerAs) {
this.runningAsUser = res.attributes.runServerAs
} else {
this.runningAsUser = this.currentUserInfo?.id || 'unknown'
/**
* Fetches the groups the current user is a member of, from the Viya
* identities API. If the memberships cannot be fetched, the member list
* falls back to all groups.
*/
public async getMemberAdminGroups() {
return new Promise<void>((resolve) => {
this.sasViyaService.getCurrentUserGroupMemberships().subscribe(
(res: ViyaApiIdentities) => {
const memberIds = res.items.map((item: Item) => item.id)
this.memberAdminGroups = this.allAdminGroups.filter(
(group: { id: string; name: string }) =>
memberIds.includes(group.id)
)
resolve()
},
(err: any) => {
this.loggerService.error(
'Error while getting user group memberships',
err
)
this.memberAdminGroups = this.allAdminGroups
resolve()
}
})
)
})
}
/**
* Toggles the SAS Admin group dropdown between the groups the current user
* is a member of and all groups on the Viya server.
*/
public onShowAllGroupsChange() {
this.applyAdminGroupFilter()
}
/**
* Applies the member/all groups filter to the dropdown and makes sure the
* currently selected group exists in the displayed list.
*/
private applyAdminGroupFilter() {
this.adminGroups =
this.showAllGroups || !this.memberAdminGroups.length
? this.allAdminGroups
: this.memberAdminGroups
const selectedGroupExists = this.adminGroups.some(
(group: { id: string; name: string }) =>
group.id === this.selectedAdminGroup
)
if (!selectedGroupExists && this.adminGroups.length) {
this.selectedAdminGroup = this.adminGroups[0].id
}
}
public async onComputeContextChange(computeContextId: string) {
// The explicit (ngModelChange) handler runs before the [(ngModel)]
// assignment updates the field, so synchronise the selected context id
// here before deriving the running user. Otherwise the displayed user
// lags behind the dropdown by one change.
this.selectedComputeContext = computeContextId
this.updateRunningAsUser()
}
public getComputeContextName(id: string): string | undefined {
@@ -428,9 +635,12 @@ export class AutomaticComponent implements OnInit {
return
}
/* Use a function replacement so $ in computeContextName is treated as a
literal character. In a string replacement, $ has special meaning
($&, $1, $` etc.); a function return value is used verbatim. */
const updatedContent = indexHtmlContent.replace(
/contextname="[^"]*"/g,
`contextname="${computeContextName}"`
() => `contextname="${computeContextName}"`
)
await this.sasService
@@ -120,8 +120,10 @@ export class SasjsConfiguratorComponent implements OnInit {
* Creating database
*/
makeData() {
// const _debug = "&_debug=131"; //debug on
const _debug = ' ' //debug off
// Debug is ALWAYS enabled for this service. The makedata service runs only once
// during deployment configuration, so full debug output (131) is always wanted
// to help diagnose any issues. This is NOT temporary — do not remove or gate it.
const _debug = '&_debug=131'
let executor = this.sasService.getExecutionPath()
const root = this.sasJsConfig.appLoc
@@ -168,6 +168,20 @@ export class SasViyaService {
)
}
/**
* @returns The groups the current user is a member of
*/
getCurrentUserGroupMemberships(
limit: number = 10000
): Observable<ViyaApiIdentities> {
return this.get<ViyaApiIdentities>(
`${this.serverUrl}/identities/users/@currentUser/memberships?limit=${limit}`,
{
withCredentials: true
}
)
}
getCurrentUser(): Observable<ViyaApiCurrentUser> {
return this.get<ViyaApiCurrentUser>(
`${this.serverUrl}/identities/users/@currentUser`,
@@ -1,5 +1,6 @@
export interface ComputeContextDetails {
attributes?: Attributes
environment?: Environment
createdBy: string
creationTimeStamp: string
description: string
@@ -27,8 +28,14 @@ export interface LaunchContext {
contextId: string
}
export interface Attributes {
reuseServerProcesses: string
runServerAs: string
serverMinAvailable: string
export interface Environment {
autoExecLines: string[]
}
export interface Attributes {
allowXCMD?: string
reuseServerProcesses?: string
runServerAs?: string
serverMinAvailable?: string
sessionInactiveTimeout?: number
}
+18
View File
@@ -2931,6 +2931,24 @@ body[cds-theme='light'] {
// AUTOMATIC-DEPLOY.COMPONENT
app-automatic-deploy {
.deploy-intro {
margin: 0 0 5px 0;
}
.deploy-field {
margin-top: 25px;
.clr-control-label {
font-weight: 600;
}
.deploy-field-description {
margin: 0;
font-size: 0.85rem;
opacity: 0.75;
}
}
.dc-loc-input-wrapper {
input {
width: 500px;
+18 -17
View File
@@ -6,8 +6,8 @@
"": {
"name": "dc-sas",
"dependencies": {
"@sasjs/cli": "4.18.5",
"@sasjs/core": "5.0.0"
"@sasjs/cli": "4.19.0",
"@sasjs/core": "5.1.0"
}
},
"node_modules/@asamuzakjp/css-color": {
@@ -200,12 +200,12 @@
}
},
"node_modules/@sasjs/adapter": {
"version": "4.17.2",
"resolved": "https://registry.npmjs.org/@sasjs/adapter/-/adapter-4.17.2.tgz",
"integrity": "sha512-VfQgTPgHxfnuGyXyPW1VaVwqY3KaUnllte212F2cxceXcUGfCVT6CpDn1GlYQgOyF7W1fsrmnrzc7j+xLxjlyA==",
"version": "4.18.0",
"resolved": "https://registry.npmjs.org/@sasjs/adapter/-/adapter-4.18.0.tgz",
"integrity": "sha512-1gP0Rsl2cRAMSchjCIrDkF+T6WA/fPXGIB+ABAXWCQxr6gM2JXqthebL+GxwDsq0yCoEp4w47KplaEkdBDy/EQ==",
"license": "ISC",
"dependencies": {
"@sasjs/utils": "^3.5.6",
"@sasjs/utils": "^3.6.0",
"axios": "1.18.1",
"axios-cookiejar-support": "5.0.5",
"form-data": "4.0.6",
@@ -214,15 +214,15 @@
}
},
"node_modules/@sasjs/cli": {
"version": "4.18.5",
"resolved": "https://registry.npmjs.org/@sasjs/cli/-/cli-4.18.5.tgz",
"integrity": "sha512-ev58r3DRPmYTH955fTLiwqwjRHC/A0sjhrc+vdwQszT0MnrwyUrYMtYLpJ6IwA0GMHTMIofOKgNt/zdNItICSw==",
"version": "4.19.0",
"resolved": "https://registry.npmjs.org/@sasjs/cli/-/cli-4.19.0.tgz",
"integrity": "sha512-AVerY31E0+BdprT42ZyG2FKb/aYQLwXvAiPP0hqT4mW9B8N3vSJKkR+8yNBfNtyZb7EyRj7GRf2mc2eZkQL/NA==",
"license": "ISC",
"dependencies": {
"@sasjs/adapter": "4.17.2",
"@sasjs/adapter": "^4.18.0",
"@sasjs/core": "4.68.1",
"@sasjs/lint": "2.4.3",
"@sasjs/utils": "3.5.9",
"@sasjs/utils": "^3.6.0",
"adm-zip": "0.6.0",
"chalk": "4.1.2",
"dotenv": "16.0.3",
@@ -235,6 +235,7 @@
"node-graphviz": "0.1.1",
"node-powershell": "5.0.1",
"ora": "5.4.1",
"prompts": "2.4.1",
"shelljs": "0.10.0",
"ssl-root-cas": "1.3.1",
"xml": "1.0.1",
@@ -251,9 +252,9 @@
"license": "MIT"
},
"node_modules/@sasjs/core": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/@sasjs/core/-/core-5.0.0.tgz",
"integrity": "sha512-TUOJhA80dh3Bo6hTWogAbOi8EdzPoEWrOG6keIpbcEd3cbY569Fpa4W67zotLPqiHtJy2lEHkkJkc3u7MfSvTg==",
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/@sasjs/core/-/core-5.1.0.tgz",
"integrity": "sha512-E+7capXQJyKXNnZpDVsUjFpq0qnKeQJIjyxVzz90pJiQVntzeva0+WPuzt6gX74Xi3MHfyOlACOmERbN62Fksg==",
"license": "MIT"
},
"node_modules/@sasjs/lint": {
@@ -304,9 +305,9 @@
}
},
"node_modules/@sasjs/utils": {
"version": "3.5.9",
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-3.5.9.tgz",
"integrity": "sha512-Qg4N8LoR51vN8WyYUap2OyvJi+6woJk7ph5ylbFVomO9CM+7KIvkMJLFAtwmKSccWPn+FSy2Lhi39pQ/HA1dug==",
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-3.6.1.tgz",
"integrity": "sha512-Oyi3nkmhi9IjV7hiZhiqRplJspjQqIA7XT6SSBp+nsXLFeHfQacKJ8tqqCUkzcz7MtG2/ifact64zj4voAsBdg==",
"license": "ISC",
"dependencies": {
"@fast-csv/format": "4.3.5",
+3 -2
View File
@@ -20,6 +20,7 @@
"server-mihajlo": "npm run cpfavicon && sasjs cbd -t server-mihajlo && npm run serverdata-mihajlo",
"serverdata-mihajlo": "sasjs request services/admin/makedata -d deploy/makeDataServer.json -l sasjsresults/makedata_server.log -o sasjsresults/makedata_server.json -t server-mihajlo",
"serverdata": "sasjs request services/admin/makedata -d deploy/makeDataServer.json -l sasjsresults/makedata_server.log -o sasjsresults/makedata_server.json -t server",
"nextviya": "sasjs cb -t nextviya && sasjs run sasjsbuild/viya.sas -t nextviya",
"viya": "npm run viyacbd && sasjs test",
"viyacbd": "sasjs folder delete /Public/app/viya && sasjs cbd -t viya && npm run viyadata",
"viyadata": "sasjs request services/admin/makedata -d deploy/makeDataViya.json -l sasjsresults/makedata.log -o sasjsresults/output.json -t viya",
@@ -28,8 +29,8 @@
},
"private": true,
"dependencies": {
"@sasjs/cli": "4.18.5",
"@sasjs/core": "5.0.0"
"@sasjs/cli": "4.19.0",
"@sasjs/core": "5.1.0"
},
"overrides": {
"nanoid": "3.3.18"
+2 -2
View File
@@ -8,7 +8,7 @@
@li mpe_checkrestore.sas
@li mp_assert.sas
@li mp_assertscope.sas
@li mp_execute.sas
@li mx_execute.sas
@author 4GL Apps Ltd
@@ -19,7 +19,7 @@
**/
/* first, run a data update */
%mp_execute(&appLoc/tests/services/auditors/postdata.test.1,
%mx_execute(&appLoc/tests/services/auditors/postdata.test.1,
viyacontext=&defaultcontext
)
+3 -3
View File
@@ -10,7 +10,7 @@
@li mp_assertscope.sas
@li mpe_getversions.sas
@li mpe_targetloader.sas
@li mx_testservice.sas
@li mx_execute.sas
**/
@@ -37,7 +37,7 @@ data work.jsdata;
output;
stop;
run;
%mx_testservice(&appLoc/services/editors/stagedata,
%mx_execute(&appLoc/services/editors/stagedata,
viyacontext=&defaultcontext,
inputfiles=&f1:sascontroltable,
inputdatasets=jsdata,
@@ -66,7 +66,7 @@ data work.sascontroltable;
output;
stop;
run;
%mx_testservice(&appLoc/services/auditors/postdata,
%mx_execute(&appLoc/services/auditors/postdata,
viyacontext=&defaultcontext,
inputdatasets=work.sascontroltable,
outlib=web2,
+46
View File
@@ -141,6 +141,52 @@
},
"contextName": "SAS Job Execution compute context"
},
{
"name": "nextviya",
"serverUrl": "https://nextviya.emea.sas.com",
"serverType": "SASVIYA",
"httpsAgentOptions": {
"allowInsecureRequests": false
},
"appLoc": "/Users/viyademo18/dc",
"deployConfig": {
"deployServicePack": false
},
"macroFolders": [
"sasjs/targets/viya/macros_viya"
],
"programFolders": [
"sasjs/db/datactrl"
],
"buildConfig": {
"initProgram": "sasjs/utils/buildinitviya.sas",
"buildResultsFolder": "sasjsresults",
"buildOutputFolder": "sasjsbuild",
"buildOutputFileName": "viya.sas",
"termProgram": "",
"macroVars": {}
},
"serviceConfig": {
"serviceFolders": [
"sasjs/targets/viya/services_viya/viya_users",
"sasjs/targets/viya/services_viya/admin",
"sasjs/targets/viya/services_viya/public",
"sasjs/targets/viya/services_viya/validations"
],
"initProgram": "sasjs/utils/serviceinitviya.sas",
"termProgram": "",
"macroVars": {}
},
"streamConfig": {
"streamWeb": true,
"streamWebFolder": "web",
"webSourcePath": "../client/dist",
"streamServiceName": "DC",
"streamLogo": "favicon.ico",
"assetPaths": []
},
"contextName": "SAS Studio compute context"
},
{
"name": "vtest",
"appLoc": "/Users/&sysuserid/dctest",
+3 -3
View File
@@ -4,7 +4,7 @@
<h4> SAS Macros </h4>
@li mp_assertdsobs.sas
@li mx_testservice.sas
@li mx_execute.sas
**/
@@ -17,7 +17,7 @@ data work.params;
name='flavour';value='PGSQL';output;
name='schema';value='public';output;
run;
%mx_testservice(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputparams=work.params,
outref=webout,
@@ -48,7 +48,7 @@ data work.params;
name='flavour';value='';output;
name='schema';value='';output;
run;
%mx_testservice(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputparams=work.params,
outref=web2,
@@ -5,7 +5,7 @@
<h4> SAS Macros </h4>
@li mp_assert.sas
@li mp_assertdsobs.sas
@li mx_testservice.sas
@li mx_execute.sas
**/
@@ -17,7 +17,7 @@ data work.params;
length name $32 value $1000;
name='libref';value='DCTEST';output;
run;
%mx_testservice(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputparams=work.params,
outref=webout,
@@ -3,14 +3,14 @@
@brief testing gethistory service
<h4> SAS Macros </h4>
@li mp_execute.sas
@li mx_execute.sas
@li mp_assertdsobs.sas
**/
%let _program=&appLoc/services/approvers/getapprovals;
%mp_execute(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
outlib=webout
)
@@ -3,7 +3,7 @@
@brief testing gethistory service
<h4> SAS Macros </h4>
@li mp_execute.sas
@li mx_execute.sas
@li mp_assertdsobs.sas
**/
@@ -18,7 +18,7 @@ data _null_;
put '50';
run;
%mp_execute(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputfiles=fref1:BrowserParams ,
outlib=webout,
@@ -3,7 +3,7 @@
@brief testing postdata with mpe_x_test
<h4> SAS Macros </h4>
@li mx_testservice.sas
@li mx_execute.sas
@li mp_assert.sas
@@ -49,7 +49,7 @@ data work.jsdata;
else stop;
run;
%mx_testservice(&appLoc/services/editors/stagedata,
%mx_execute(&appLoc/services/editors/stagedata,
viyacontext=&defaultcontext,
inputdatasets=work.jsdata work.sascontroltable,
outlib=web1,
@@ -79,7 +79,7 @@ data work.sascontroltable;
output;
stop;
run;
%mx_testservice(&appLoc/services/auditors/postdata,
%mx_execute(&appLoc/services/auditors/postdata,
viyacontext=&defaultcontext,
inputdatasets=work.sascontroltable,
outlib=web2,
@@ -118,7 +118,7 @@ data work.sascontroltable;
output;
stop;
run;
%mx_testservice(&appLoc/services/auditors/postdata,
%mx_execute(&appLoc/services/auditors/postdata,
viyacontext=&defaultcontext,
inputdatasets=work.sascontroltable,
outlib=web3,
@@ -3,7 +3,7 @@
@brief testing postdata with format table
<h4> SAS Macros </h4>
@li mp_execute.sas
@li mx_execute.sas
@li mp_assert.sas
@@ -31,7 +31,7 @@ data work.jsdata;
if _n_>20 then stop;
run;
%mp_execute(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputdatasets=work.sascontroltable work.jsdata,
outlib=web1,
@@ -61,7 +61,7 @@ data work.sascontroltable;
output;
stop;
run;
%mp_execute(&appLoc/services/auditors/postdata,
%mx_execute(&appLoc/services/auditors/postdata,
viyacontext=&defaultcontext,
inputdatasets=work.sascontroltable,
outlib=web2,
+4 -4
View File
@@ -9,7 +9,7 @@
@li mf_getuniquefileref.sas
@li mf_getuniquename.sas
@li mp_filterstore.sas
@li mx_testservice.sas
@li mx_execute.sas
**/
@@ -25,7 +25,7 @@ data _null_;
put 'LIBDS:$43.';
put "&dclib..MPE_TABLES";
run;
%mx_testservice(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputfiles=&f1:sascontroltable,
outlib=web1,
@@ -106,7 +106,7 @@ data _null_;
put "&dclib..MPE_TABLES,&filter_rk";
run;
%mx_testservice(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputfiles=&f2:sascontroltable,
outlib=web2
@@ -186,7 +186,7 @@ data _null_;
put "DCTEST.DCFMTS-FC,&filter_rk3";
run;
%mx_testservice(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputfiles=&f3:sascontroltable,
outlib=web3,
@@ -7,7 +7,7 @@
@li mp_assertcolvals.sas
@li mp_assertdsobs.sas
@li mf_getuniquefileref.sas
@li mx_testservice.sas
@li mx_execute.sas
**/
@@ -29,7 +29,7 @@ data _null_;
put '_____DELETE__THIS__RECORD_____:$2. LIBREF:$8. DSN:$10. ACCESS_LEVEL:$7.';
put 'No,DC265453,MPE_X_TEST,APPROVE';
run;
%mx_testservice(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputfiles=&f1:sascontroltable &f2:source_row,
outlib=web1,
@@ -75,7 +75,7 @@ data _null_;
put 'DC266708,MPE_VALIDATIONSF,14,TXTEMPORAL,BASE_LIB BASE_DS BASE_COL RULE_TYPE,TX_FROM'@;
put ',TX_TO, , , , , , , , ,,,Configuration of data quality rules in Editor component, , ,No';
run;
%mx_testservice(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputfiles=&f1:sascontroltable &f2:source_row,
outlib=web2,
@@ -5,7 +5,7 @@
<h4> SAS Macros </h4>
@li mp_assertcolvals.sas
@li mf_getuniquefileref.sas
@li mx_testservice.sas
@li mx_execute.sas
**/
@@ -33,7 +33,7 @@ data _null_;
put "&dclib,MPE_VALIDATIONS,14,TXTEMPORAL,BASE_LIB BASE_DS BASE_COL RULE_TYPE,TX_FROM"@;
put ',TX_TO, , , , , , , , ,,,Configuration of data quality rules in Editor component, , ,No';
run;
%mx_testservice(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputfiles=&f1:sascontroltable &f2:source_row,
outlib=web2,
@@ -4,7 +4,7 @@
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mx_testservice.sas
@li mx_execute.sas
@li mp_assert.sas
@li mp_assertdsobs.sas
@@ -24,7 +24,7 @@ data _null_;
put "BASEL-KM1";
run;
%mx_testservice(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputfiles=&f1:getxlmaps_in,
outlib=web1,
+5 -5
View File
@@ -4,7 +4,7 @@
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mx_testservice.sas
@li mx_execute.sas
@li mp_assert.sas
@@ -18,7 +18,7 @@ by primary_key_field;
run;
/* run an update */
%mx_testservice(&appLoc/tests/services/auditors/postdata.test.1,
%mx_execute(&appLoc/tests/services/auditors/postdata.test.1,
viyacontext=&defaultcontext
)
@@ -30,7 +30,7 @@ data APPROVE1;
run;
/* run another update for good measure */
%mx_testservice(&appLoc/tests/services/auditors/postdata.test.1,
%mx_execute(&appLoc/tests/services/auditors/postdata.test.1,
viyacontext=&defaultcontext
)
@@ -40,7 +40,7 @@ data work.restore_in;
output;
stop;
run;
%mx_testservice(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputdatasets=work.restore_in,
outlib=web1,
@@ -69,7 +69,7 @@ data work.sascontroltable;
output;
stop;
run;
%mx_testservice(&appLoc/services/auditors/postdata,
%mx_execute(&appLoc/services/auditors/postdata,
viyacontext=&defaultcontext,
inputdatasets=work.sascontroltable,
outlib=web3,
@@ -4,7 +4,7 @@
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mx_testservice.sas
@li mx_execute.sas
@li mp_assert.sas
@@ -38,7 +38,7 @@ data _null_;
put "ALL,SASAdministrators,&dclib,MPE_ROW_LEVEL_SECURITY,AND,OR,0,RLS_SCOPE,NE,"@;
put z ",0,No";
run;
%mx_testservice(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputfiles=&f1:sascontroltable &f2:jsdata,
outlib=web1,
@@ -3,7 +3,7 @@
@brief testing stagedata with format table
<h4> SAS Macros </h4>
@li mx_testservice.sas
@li mx_execute.sas
@li mp_assert.sas
@@ -30,7 +30,7 @@ data work.jsdata;
if _n_>20 then stop;
run;
%mx_testservice(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputdatasets=work.sascontroltable work.jsdata,
outlib=web1,
@@ -6,7 +6,7 @@
2. applying LOADTYPE=REPLACE to a table with row level EDIT security
<h4> SAS Macros </h4>
@li mx_testservice.sas
@li mx_execute.sas
@li mp_assert.sas
@@ -64,7 +64,7 @@ data work.jsdata;
output;
run;
%mx_testservice(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputdatasets=work.sascontroltable work.jsdata,
outlib=web1,
@@ -132,7 +132,7 @@ data work.jsdata;
_____DELETE__THIS__RECORD_____='No';
run;
%mx_testservice(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputdatasets=work.sascontroltable work.jsdata,
outlib=web2,
@@ -173,7 +173,7 @@ delete from &dc_libref..mpe_row_level_security
where rls_libref="DCTEST" and rls_table='WIDEBOY';
quit;
%mx_testservice(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputdatasets=work.sascontroltable work.jsdata,
outlib=web3,
@@ -3,7 +3,7 @@
@brief testing getchangeinfo service
<h4> SAS Macros </h4>
@li mp_execute.sas
@li mx_execute.sas
@li mp_assert.sas
@li mp_assertcolvals.sas
@li mf_getuniquefileref.sas
@@ -46,7 +46,7 @@ data work.jsdata;
else stop;
run;
%mx_testservice(&appLoc/services/editors/stagedata,
%mx_execute(&appLoc/services/editors/stagedata,
viyacontext=&defaultcontext,
inputdatasets=work.jsdata work.sascontroltable,
outlib=web1,
@@ -73,7 +73,7 @@ data _null_;
put 'TABLE:$43.';
put "&dsid";
run;
%mp_execute(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputfiles=&f3:sascontroltable,
outlib=web3,
@@ -4,7 +4,7 @@
<h4> SAS Macros </h4>
@li mp_assertcolvals.sas
@li mp_execute.sas
@li mx_execute.sas
@li mf_getuniquefileref.sas
**/
@@ -17,7 +17,7 @@ data _null_;
put 'LIBDS:$43. COL:$32.';
put "&dclib..MPE_X_TEST,SOME_TIME";
run;
%mp_execute(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputfiles=&f3:iwant,
outlib=web3
@@ -4,7 +4,7 @@
<h4> SAS Macros </h4>
@li mp_assertcolvals.sas
@li mp_execute.sas
@li mx_execute.sas
@li mf_getuniquefileref.sas
**/
@@ -35,7 +35,7 @@ AND,OR,2,DSN,=,"'MPE_LOCK_ANYTABLE'"
AND,OR,2,DSN,=,"'MPE_X_TEST'"
;;;;
run;
%mp_execute(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputfiles=&f1:iwant &f2:filterquery,
outlib=web2
@@ -4,7 +4,7 @@
<h4> SAS Macros </h4>
@li mp_assertcolvals.sas
@li mp_execute.sas
@li mx_execute.sas
@li mf_getuniquefileref.sas
**/
@@ -31,7 +31,7 @@ datalines4;
AND,OR,1,FMTNAME,CONTAINS,"'MOR'"
;;;;
run;
%mp_execute(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputfiles=&f2:filterquery,
inputdatasets=work.iwant,
@@ -4,7 +4,7 @@
<h4> SAS Macros </h4>
@li mp_assertcolvals.sas
@li mp_execute.sas
@li mx_execute.sas
@li mf_getuniquefileref.sas
**/
@@ -17,7 +17,7 @@ data _null_;
put 'LIBDS:$43. COL:$32.';
put "&dclib..MPE_TABLES,LIBREF";
run;
%mp_execute(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputfiles=&f1:iwant,
outlib=web1
+3 -3
View File
@@ -4,7 +4,7 @@
<h4> SAS Macros </h4>
@li mp_assertdsobs.sas
@li mx_testservice.sas
@li mx_execute.sas
**/
@@ -18,7 +18,7 @@ data work.params;
name='ds';value='';output;
name='flavour';value='TSQL';output;
run;
%mx_testservice(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputparams=work.params,
outref=webout,
@@ -53,7 +53,7 @@ data work.params;
name='libref';value="DCTEST";output;
name='ds';value='DCFMTS-FC';output;
run;
%mx_testservice(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputparams=work.params,
outref=web2,
+2 -2
View File
@@ -5,7 +5,7 @@
<h4> SAS Macros </h4>
@li mf_getuser.sas
@li mp_assertcols.sas
@li mp_execute.sas
@li mx_execute.sas
**/
@@ -13,7 +13,7 @@
/* add user */
%put &=sasjs_mdebug;
%mp_execute(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
outlib=webout,
mdebug=1,
@@ -4,7 +4,7 @@
<h4> SAS Macros </h4>
@li mp_assertdsobs.sas
@li mx_testservice.sas
@li mx_execute.sas
**/
@@ -19,7 +19,7 @@ data work.params;
name='filter';value='0';output;
run;
%mx_testservice(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputparams=work.params,
outref=webout,
@@ -52,7 +52,7 @@ data work.params2;
name='filter';value='0';output;
run;
%mx_testservice(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputparams=work.params2,
outref=web2,
@@ -86,7 +86,7 @@ data work.params3;
name='filter';value='0';output;
run;
%mx_testservice(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputparams=work.params3,
outref=web3,
@@ -4,7 +4,7 @@
<h4> SAS Macros </h4>
@li mp_assert.sas
@li mx_testservice.sas
@li mx_execute.sas
<h4> Related Programs </h4>
@li refreshlibinfo.sas
@@ -17,7 +17,7 @@ data work.lib2refresh;
libref="&dclib";
run;
%mx_testservice(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputdatasets=work.lib2refresh,
outlib=web1,
@@ -5,7 +5,7 @@
<h4> SAS Macros </h4>
@li mf_getuser.sas
@li mp_assertcolvals.sas
@li mx_testservice.sas
@li mx_execute.sas
**/
@@ -18,7 +18,7 @@ delete from &dc_libref..mpe_users
where user_id="&userid";
/* add user */
%mx_testservice(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
outlib=webout,
mdebug=&sasjs_mdebug
@@ -7,13 +7,13 @@
@li mp_assertdsobs.sas
@li mpe_getpath2settings.sas
@li mx_append2pgm.sas
@li mx_testservice.sas
@li mx_execute.sas
**/
%let _program=&appLoc/services/public/startupservice;
%mx_testservice(&_program,
%mx_execute(&_program,
mdebug=&sasjs_mdebug,
outlib=webout,
viyacontext=&defaultcontext
@@ -80,7 +80,7 @@ proc sort data=work.append2 nodupkey; by libref dsn;run;
proc append base=&dc_libref..mpe_tables data=work.append2;run;
%mx_testservice(&_program,
%mx_execute(&_program,
mdebug=&sasjs_mdebug,
outlib=webout2,
viyacontext=&defaultcontext
@@ -104,7 +104,7 @@ data work.append3;
run;
proc append base=&dc_libref..mpe_security data=work.append3;
run;
%mx_testservice(&_program,
%mx_execute(&_program,
mdebug=&sasjs_mdebug,
outlib=webout3,
viyacontext=&defaultcontext
@@ -3,7 +3,7 @@
@brief testing public/validatefilter service
<h4> SAS Macros </h4>
@li mp_execute.sas
@li mx_execute.sas
@li mp_assertdsobs.sas
@li mp_assertcolvals.sas
@li mf_getuniquefileref.sas
@@ -31,7 +31,7 @@ AND,AND,1,LIBREF,CONTAINS,"'DC'"
AND,OR,2,DSN,=,"'MPE_LOCK_ANYTABLE'"
;;;;
run;
%mp_execute(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputfiles=&f1:iwant &f2:filterquery,
outlib=web1
@@ -58,7 +58,7 @@ OPERATOR_NM='CONTAINS';
RAW_VALUE="'MORD'";
;;;;
run;
%mp_execute(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputdatasets=work.iwant work.filterquery,
outlib=web2,
@@ -9,7 +9,7 @@
<h4> SAS Macros </h4>
@li mp_assert.sas
@li mp_execute.sas
@li mx_execute.sas
@li mf_getuniquefileref.sas
**/
@@ -48,7 +48,7 @@ GROUP_LOGIC:$3. SUBGROUP_LOGIC:$3. SUBGROUP_ID:8. VARIABLE_NM:$32. OPERATOR_NM:$
AND,AND,1,PRIMARY_KEY_FIELD,IN,"(1,2,3)"
;;;;
run;
%mp_execute(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputfiles=&f1:iwant &f2:filterquery,
outlib=web1
@@ -72,7 +72,7 @@ data _null_;
put "&dclib..MPE_X_TEST,&filter_rk";
run;
%mp_execute(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputfiles=&f3:SASControlTable ,
outlib=web2,
@@ -5,7 +5,7 @@
<h4> SAS Macros </h4>
@li mp_assert.sas
@li mp_execute.sas
@li mx_execute.sas
**/
@@ -16,7 +16,7 @@ data work.sascontroltable;
FILTER_RK=0;
run;
%mp_execute(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputdatasets=work.SASControlTable ,
outlib=web2,
+2 -2
View File
@@ -4,7 +4,7 @@
<h4> SAS Macros </h4>
@li mp_assertdsobs.sas
@li mp_execute.sas
@li mx_execute.sas
<h4> Related Programs </h4>
@li viewlibs.sas
@@ -17,7 +17,7 @@ data work.sascontroltable;
mplib="&dclib";
run;
%mp_execute(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
outlib=web1
)
@@ -7,7 +7,7 @@
@li mf_getengine.sas
@li mp_assert.sas
@li mp_assertdsobs.sas
@li mx_testservice.sas
@li mx_execute.sas
<h4> Related Programs </h4>
@li viewtables.sas
@@ -23,7 +23,7 @@ data work.sascontroltable;
mplib="DCTEST";
run;
%mx_testservice(&_program,
%mx_execute(&_program,
viyacontext=&defaultcontext,
inputdatasets=work.sascontroltable,
outlib=web1,
@@ -5,6 +5,7 @@
<h4> SAS Macros </h4>
@li mf_getapploc.sas
@li mf_getuniquefileref.sas
@li mf_mkdir.sas
@li mf_trimstr.sas
@li mp_abort.sas
@@ -12,6 +13,7 @@
@li mpe_makedata.sas
@li mpe_makedatamodel.sas
@li mpe_makesampledata.sas
@li mv_createfile.sas
@li mv_deletejes.sas
@version 3.5
@@ -210,6 +212,64 @@ run;
,msg=%str(Err during settings job creation)
)
/* Update the compute context in the streamed frontend (DC.html) so that
Data Controller runs under the same context that was selected when this
service was invoked. The file must be re-created using %mv_createfile
(the same macro used to stream the frontend at deploy time) rather than
updated in place with a filesrvc fileref - only the Files service POST
assigns the correct mime type (text/html / file_html), without which the
frontend will not stream. */
%global _contextname;
%if %symexist(_contextname) and %length(%superq(_contextname))>0 %then %do;
%local dchtml_in dchtml_out;
%let dchtml_in=%mf_getuniquefileref();
%let dchtml_out=%mf_getuniquefileref();
/* Escape regex metacharacters (\ and $) in the context name so they are
treated as literals when embedded in the prxchange replacement string.
In a Perl regex replacement, \ introduces a backreference and $ introduces
variable interpolation; prefixing each with \ quotes them as literals. */
%local _contextname_escaped;
data _null_;
length _ctxname $256 _ctxesc $512;
_ctxname=symget('_contextname');
_ctxesc=tranwrd(tranwrd(_ctxname,'\','\\'),'$','\$');
call symputx('_contextname_escaped',_ctxesc);
run;
/* read the existing frontend */
filename &dchtml_in filesrvc folderpath="&root" filename="DC.html"
lrecl=32767;
%mp_abort(iftrue= (&syscc ne 0)
,mac=&sysmacroname
,msg=%str(Unable to open DC.html in &root)
)
/* write the updated html to a temporary file */
data _null_;
file &dchtml_out lrecl=32767;
infile &dchtml_in lrecl=32767 truncover;
input;
length line $32767;
line=prxchange(cats('s|contextname="[^"]*"|contextname="'
,symget('_contextname_escaped')
,'"|'
),-1,_infile_);
put line;
run;
filename &dchtml_in clear;
%mp_abort(iftrue= (&syscc ne 0)
,mac=&sysmacroname
,msg=%str(Unable to update compute context in DC.html)
)
/* re-create DC.html via the Files service to retain the html mime type */
%mv_createfile(path=&root, name=DC.html, inref=&dchtml_out)
filename &dchtml_out clear;
%end;
%else %put NOTE: &_program: _contextname not provided, DC.html not updated;
%webout(OPEN)
data result;
+1 -1
View File
@@ -17,7 +17,7 @@
@li mddl_dc_difftable.sas
@li mddl_dc_locktable.sas
@li mp_init.sas
@li mp_execute.sas
@li mx_execute.sas
@li ms_createfile.sas
@li ms_deletefile.sas
@li mx_getcode.sas
+2 -2
View File
@@ -4,7 +4,7 @@
@details services have been built, now to build the DB.
<h4> SAS Macros </h4>
@li mx_testservice.sas
@li mx_execute.sas
@version 3.5
@author 4GL Apps Ltd
@@ -26,7 +26,7 @@ data work.params;
output;
run;
%mx_testservice(&appLoc/services/admin/makedata,
%mx_execute(&appLoc/services/admin/makedata,
inputparams=work.params,
outlib=webout,
debug=log