172 lines
6.4 KiB
HTML
172 lines
6.4 KiB
HTML
<div class="p-3 space-y-3">
|
|
@if (authorizationRequirements().length) {
|
|
<section class="space-y-3">
|
|
<div>
|
|
<div class="text-xs font-semibold uppercase tracking-wide text-slate-600">Provider Authorizations</div>
|
|
<div class="mt-1 text-[11px] text-slate-500">Provide the missing runtime credentials required by this execution.</div>
|
|
</div>
|
|
|
|
@for (requirement of authorizationRequirements(); track requirement.key) {
|
|
<div class="rounded-md border border-amber-200 bg-amber-50 p-3">
|
|
<div class="flex items-start justify-between gap-3">
|
|
<div class="min-w-0">
|
|
<div class="text-xs font-semibold text-slate-800">{{ requirement.provider }}</div>
|
|
<div class="mt-1 text-[11px] text-slate-500 break-all">{{ requirement.key }}</div>
|
|
</div>
|
|
<span class="rounded-full bg-white px-2 py-1 text-[10px] font-semibold uppercase tracking-wide text-amber-700">
|
|
{{ requirement.fieldName || 'authorization' }}
|
|
</span>
|
|
</div>
|
|
|
|
<div class="mt-2 text-xs text-slate-600">{{ requirement.description || 'Runtime authorization required.' }}</div>
|
|
|
|
@if (requirement.requiredBySteps.length) {
|
|
<div class="mt-2 text-[11px] text-slate-500">
|
|
Required by: {{ requirement.requiredBySteps.join(', ') }}
|
|
</div>
|
|
}
|
|
|
|
<div class="mt-3 flex items-start gap-2">
|
|
<mat-form-field appearance="outline" class="flex-1">
|
|
<mat-label>{{ requirement.fieldName || 'Authorization' }}</mat-label>
|
|
<input
|
|
matInput
|
|
[type]="isAuthorizationVisible(requirement.key) ? 'text' : 'password'"
|
|
[readonly]="readOnly()"
|
|
[ngModel]="authorizationValue(requirement.key)"
|
|
(ngModelChange)="onAuthorizationValueChange(requirement, $event)" />
|
|
</mat-form-field>
|
|
|
|
<button
|
|
type="button"
|
|
mat-stroked-button
|
|
class="shrink-0"
|
|
[disabled]="readOnly()"
|
|
(click)="toggleAuthorizationVisibility(requirement.key, $event)">
|
|
{{ isAuthorizationVisible(requirement.key) ? 'Hide' : 'Show' }}
|
|
</button>
|
|
|
|
<button
|
|
type="button"
|
|
mat-flat-button
|
|
class="shrink-0"
|
|
[disabled]="!canSubmitAuthorization(requirement.key)"
|
|
(click)="submitAuthorization(requirement, $event)">
|
|
Save
|
|
</button>
|
|
</div>
|
|
|
|
@if (isAuthorizationSaving(requirement.key)) {
|
|
<div class="mt-2 text-[11px] text-blue-600">Saving authorization...</div>
|
|
}
|
|
@if (authorizationSavingError(requirement.key); as errorMessage) {
|
|
<div class="mt-2 text-[11px] text-red-600">{{ errorMessage }}</div>
|
|
}
|
|
</div>
|
|
}
|
|
</section>
|
|
}
|
|
|
|
@if (!editableInputs().length && !authorizationRequirements().length) {
|
|
<div class="text-xs text-slate-500">No manual inputs required.</div>
|
|
} @else {
|
|
@if (editableInputs().length) {
|
|
<div class="text-xs font-semibold uppercase tracking-wide text-slate-600">Manual Inputs</div>
|
|
}
|
|
@for (executionInput of editableInputs(); track executionInput.key) {
|
|
<div class="rounded-md border border-slate-200 bg-slate-50 p-2">
|
|
<div class="mb-3 flex min-h-[52px] flex-col items-center justify-center rounded-[10px] border border-blue-200 bg-gradient-to-b from-blue-50 to-blue-100 px-3 py-2 text-center text-blue-700">
|
|
<div class="text-[14px] font-extrabold leading-tight">{{ executionInput.title }}</div>
|
|
<div class="mt-1 text-[11px] font-semibold uppercase tracking-[0.04em] text-blue-600">{{ executionInput.subtitle }}</div>
|
|
</div>
|
|
<div class="mb-2 text-[10px] text-slate-500">Type: {{ inputTypeLabel(executionInput) }}</div>
|
|
|
|
@if (isFileInput(executionInput)) {
|
|
<input
|
|
type="file"
|
|
class="block w-full text-sm text-slate-700"
|
|
[attr.multiple]="isMultipleInput(executionInput) ? '' : null"
|
|
[disabled]="readOnly()"
|
|
(change)="onFileInputChange(executionInput, $event)" />
|
|
} @else {
|
|
@if (isMultipleInput(executionInput)) {
|
|
<div class="space-y-3">
|
|
@for (textValue of textValues(executionInput); track $index) {
|
|
<div class="flex items-start gap-2">
|
|
<mat-form-field appearance="outline" class="flex-1">
|
|
<mat-label>{{ executionInput.subtitle }} {{ $index + 1 }}</mat-label>
|
|
<textarea
|
|
matInput
|
|
rows="3"
|
|
[readonly]="readOnly()"
|
|
[ngModel]="textValue"
|
|
(ngModelChange)="updateTextItem(executionInput, $index, $event)">
|
|
</textarea>
|
|
</mat-form-field>
|
|
|
|
<button
|
|
type="button"
|
|
mat-stroked-button
|
|
class="shrink-0"
|
|
[disabled]="readOnly() || textValues(executionInput).length <= 1"
|
|
(click)="removeTextItem(executionInput, $index)">
|
|
Remove
|
|
</button>
|
|
</div>
|
|
}
|
|
|
|
<button
|
|
type="button"
|
|
mat-stroked-button
|
|
[disabled]="readOnly()"
|
|
(click)="addTextItem(executionInput)">
|
|
Add item
|
|
</button>
|
|
|
|
<div class="flex justify-end">
|
|
<button
|
|
type="button"
|
|
mat-flat-button
|
|
[disabled]="!canSubmitTextInput(executionInput)"
|
|
(click)="submitTextInput(executionInput, $event)">
|
|
Save
|
|
</button>
|
|
</div>
|
|
</div>
|
|
} @else {
|
|
<div class="space-y-3">
|
|
<mat-form-field appearance="outline" class="w-full">
|
|
<mat-label>{{ executionInput.subtitle }}</mat-label>
|
|
<textarea
|
|
matInput
|
|
rows="4"
|
|
[readonly]="readOnly()"
|
|
[ngModel]="executionInput.value"
|
|
(ngModelChange)="onTextInputChange(executionInput, $event)">
|
|
</textarea>
|
|
</mat-form-field>
|
|
|
|
<div class="flex justify-end">
|
|
<button
|
|
type="button"
|
|
mat-flat-button
|
|
[disabled]="!canSubmitTextInput(executionInput)"
|
|
(click)="submitTextInput(executionInput, $event)">
|
|
Save
|
|
</button>
|
|
</div>
|
|
</div>
|
|
}
|
|
}
|
|
|
|
@if (isInputSaving(executionInput.key)) {
|
|
<div class="mt-2 text-[11px] text-blue-600">Saving...</div>
|
|
}
|
|
@if (inputSavingError(executionInput.key); as errorMessage) {
|
|
<div class="mt-2 text-[11px] text-red-600">{{ errorMessage }}</div>
|
|
}
|
|
</div>
|
|
}
|
|
}
|
|
</div>
|