Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
feudal
feudalWebpage
Commits
b53457d3
Commit
b53457d3
authored
Jun 21, 2018
by
Lukas Burgey
Browse files
Fix interaction with the backend
parent
c7091df6
Changes
15
Hide whitespace changes
Inline
Side-by-side
src/app/dialogues/credentials/credentials.component.css
0 → 100644
View file @
b53457d3
src/app/dialogues/credentials/credentials.component.html
0 → 100644
View file @
b53457d3
<div
class=
"mat-typography"
>
<h2>
Credentials
</h2>
<p>
You can access the service {{ stateItem.service.name }} at {{ stateItem.site.name }} using the SSH Key {{ stateItem.key.name }}.
</p>
<div
*ngIf=
"credentialCount > 0"
>
<p>
Additional information about accessing the service is displayed below.
</p>
<mat-table
[dataSource]=
"table"
>
<ng-container
matColumnDef=
"name"
>
<mat-header-cell
*matHeaderCellDef
>
Name
</mat-header-cell>
<mat-cell
*matCellDef=
"let element"
>
{{ element.name}}
</mat-cell>
</ng-container>
<ng-container
matColumnDef=
"value"
>
<mat-header-cell
*matHeaderCellDef
>
Value
</mat-header-cell>
<mat-cell
*matCellDef=
"let element"
>
{{ element.value }}
</mat-cell>
</ng-container>
<mat-header-row
*matHeaderRowDef=
"columns"
></mat-header-row>
<mat-row
*matRowDef=
"let row; columns: columns;"
></mat-row>
</mat-table>
</div>
</div>
src/app/dialogues/credentials/credentials.component.ts
0 → 100644
View file @
b53457d3
import
{
Component
,
OnInit
,
Inject
}
from
'
@angular/core
'
;
import
{
MAT_DIALOG_DATA
}
from
'
@angular/material
'
;
import
{
MatTableDataSource
}
from
'
@angular/material
'
;
import
{
UserService
}
from
'
../../user.service
'
;
import
*
as
t
from
'
../../types/types.module
'
;
@
Component
({
selector
:
'
app-credentials
'
,
templateUrl
:
'
./credentials.component.html
'
,
styleUrls
:
[
'
./credentials.component.css
'
]
})
export
class
CredentialsComponent
implements
OnInit
{
public
columns
=
[
"
name
"
,
"
value
"
];
public
stateItem
:
t
.
DeploymentStateItem
;
public
credentialCount
:
number
=
0
;
public
table
:
MatTableDataSource
<
any
>
;
constructor
(
public
userService
:
UserService
,
@
Inject
(
MAT_DIALOG_DATA
)
public
data
:
any
,
)
{
this
.
stateItem
=
data
.
stateItem
;
}
ngOnInit
()
{
const
credentialList
=
[];
for
(
const
key
in
this
.
stateItem
.
credentials
)
{
if
(
this
.
stateItem
.
credentials
.
hasOwnProperty
(
key
))
{
credentialList
.
push
(
{
name
:
key
,
value
:
this
.
stateItem
.
credentials
[
key
],
}
);
}
}
this
.
credentialCount
=
credentialList
.
length
;
this
.
table
=
new
MatTableDataSource
(
credentialList
);
}
}
src/app/dialogues/dialog.service.ts
View file @
b53457d3
...
...
@@ -5,6 +5,9 @@ import { ProfileComponent } from './profile/profile.component';
import
{
SshKeysComponent
}
from
'
./ssh-keys/ssh-keys.component
'
;
import
{
AccountComponent
}
from
'
./account/account.component
'
;
import
{
QuestionnaireComponent
}
from
'
./questionnaire/questionnaire.component
'
;
import
{
CredentialsComponent
}
from
'
./credentials/credentials.component
'
;
import
*
as
t
from
'
../types/types.module
'
;
@
Injectable
()
export
class
DialogService
{
...
...
@@ -12,6 +15,7 @@ export class DialogService {
sshKeysDialog
:
MatDialogRef
<
any
>
;
accountDialog
:
MatDialogRef
<
any
>
;
questionnaireDialog
:
MatDialogRef
<
any
>
;
credentialsDialog
:
MatDialogRef
<
any
>
;
settings
=
{
width
:
'
80%
'
,
...
...
@@ -42,12 +46,23 @@ export class DialogService {
);
}
public
openQuestionnaire
(
ta
sk
Item
:
any
)
{
public
openQuestionnaire
(
s
ta
te
Item
:
t
.
DeploymentStateItem
)
{
this
.
questionnaireDialog
=
this
.
dialog
.
open
(
QuestionnaireComponent
,
{
data
:
{
taskItem
:
taskItem
,
stateItem
:
stateItem
,
}
}
);
}
public
openCredentials
(
stateItem
:
t
.
DeploymentStateItem
)
{
this
.
credentialsDialog
=
this
.
dialog
.
open
(
CredentialsComponent
,
{
data
:
{
stateItem
:
stateItem
,
}
}
);
...
...
src/app/dialogues/dialogues.module.ts
View file @
b53457d3
...
...
@@ -11,6 +11,7 @@ import {QuestionnaireComponent} from './questionnaire/questionnaire.component';
import
{
ProfileComponent
}
from
'
./profile/profile.component
'
;
import
{
SshKeysComponent
}
from
'
./ssh-keys/ssh-keys.component
'
;
import
{
AccountComponent
}
from
'
./account/account.component
'
;
import
{
CredentialsComponent
}
from
'
./credentials/credentials.component
'
;
//providers
import
{
DialogService
}
from
'
./dialog.service
'
;
...
...
@@ -27,12 +28,14 @@ import {DialogService} from './dialog.service';
ProfileComponent
,
SshKeysComponent
,
AccountComponent
,
CredentialsComponent
,
],
entryComponents
:
[
QuestionnaireComponent
,
ProfileComponent
,
SshKeysComponent
,
AccountComponent
,
CredentialsComponent
,
],
providers
:
[
DialogService
,
...
...
src/app/dialogues/questionnaire/questionnaire.component.html
View file @
b53457d3
<div
class=
"mat-typography"
>
<h2>
Data questionnaire
</h2>
<p>
The site {{ta
sk
Item.site.name}} needs the following data to give you access to the service {{
ta
sk
Item.service.name}}.
The site {{
s
ta
te
Item.site.name}} needs the following data to give you access to the service {{
s
ta
te
Item.service.name}}.
</p>
<form
class=
"form-vertical"
(ngSubmit)=
"sendAnswers()"
#questionnaireForm
="
ngForm
"
>
<mat-form-field
*ngFor=
"let key of ta
sk
Item.questionnaire | ObjKeys"
>
<mat-form-field
*ngFor=
"let key of
s
ta
te
Item.questionnaire | ObjKeys"
>
<input
matInput
required
placeholder=
"{{ta
sk
Item.questionnaire[key]}}"
[(ngModel)]=
"answers[key]"
name=
"key"
>
placeholder=
"{{
s
ta
te
Item.questionnaire[key]}}"
[(ngModel)]=
"answers[key]"
name=
"key"
>
</mat-form-field>
<button
mat-raised-button
color=
"primary"
type=
"submit"
[disabled]=
"!questionnaireForm.form.valid"
>
Submit
</button>
</form>
...
...
src/app/dialogues/questionnaire/questionnaire.component.ts
View file @
b53457d3
...
...
@@ -2,6 +2,7 @@ import {Component, OnInit,Inject} from '@angular/core';
import
{
MAT_DIALOG_DATA
}
from
'
@angular/material
'
;
import
{
UserService
}
from
'
../../user.service
'
;
import
*
as
t
from
'
../../types/types.module
'
;
@
Component
({
selector
:
'
app-questionnaire
'
,
...
...
@@ -10,13 +11,13 @@ import { UserService } from '../../user.service';
})
export
class
QuestionnaireComponent
implements
OnInit
{
public
answers
:
Object
=
{};
public
ta
sk
Item
:
any
;
public
s
ta
te
Item
:
t
.
DeploymentStateItem
;
constructor
(
public
userService
:
UserService
,
@
Inject
(
MAT_DIALOG_DATA
)
public
data
:
any
,
)
{
this
.
ta
sk
Item
=
data
.
ta
sk
Item
;
this
.
s
ta
te
Item
=
data
.
s
ta
te
Item
;
}
ngOnInit
()
{
...
...
@@ -24,7 +25,7 @@ export class QuestionnaireComponent implements OnInit {
sendAnswers
()
{
this
.
userService
.
sentQuestionnaire
(
this
.
ta
sk
Item
.
id
,
this
.
s
ta
te
Item
.
id
,
this
.
answers
,
);
}
...
...
src/app/dialogues/ssh-keys/ssh-keys.component.html
View file @
b53457d3
...
...
@@ -38,10 +38,10 @@
<ng-template
#not_uploading
>
<form
(ngSubmit)=
"uploadKey()"
#sshKeyForm
="
ngForm
"
>
<mat-form-field>
<input
matInput
placeholder=
"Name"
required
[(ngModel)]=
"
new
Key
N
ame"
name=
"name"
>
<input
matInput
placeholder=
"Name"
required
[(ngModel)]=
"
form
Key
.n
ame"
name=
"name"
>
</mat-form-field>
<mat-form-field>
<textarea
matInput
placeholder=
"Key"
required
[(ngModel)]=
"
new
Key
K
ey"
name=
"key"
></textarea>
<textarea
matInput
placeholder=
"Key"
required
[(ngModel)]=
"
form
Key
.k
ey"
name=
"key"
></textarea>
</mat-form-field>
<button
mat-raised-button
color=
"primary"
type=
"submit"
[disabled]=
"!sshKeyForm.form.valid"
>
Submit
</button>
</form>
...
...
src/app/dialogues/ssh-keys/ssh-keys.component.ts
View file @
b53457d3
import
{
Component
,
OnInit
}
from
'
@angular/core
'
;
import
{
MatTableDataSource
}
from
'
@angular/material
'
;
import
{
HttpClient
}
from
'
@angular/common/http
'
;
import
{
UserService
}
from
'
../../user.service
'
;
import
{
SSHKey
,
NewSSHKey
}
from
'
../../types/types.module
'
;
import
*
as
t
from
'
../../types/types.module
'
;
@
Component
({
selector
:
'
app-ssh-keys
'
,
templateUrl
:
'
./ssh-keys.component.html
'
,
...
...
@@ -11,32 +14,74 @@ import { SSHKey, NewSSHKey } from '../../types/types.module';
})
export
class
SshKeysComponent
implements
OnInit
{
columns
=
[
'
name
'
,
'
key
'
,
'
action
'
];
// does the user want to upload a key?
upload
:
boolean
;
newKeyName
:
string
;
newKeyKey
:
string
;
formKey
:
t
.
NewSSHKey
;
constructor
(
public
userService
:
UserService
)
{
}
public
userService
:
UserService
,
public
http
:
HttpClient
,
)
{
}
ngOnInit
()
{
this
.
upload
=
false
;
this
.
newKeyName
=
''
;
this
.
newKeyKey
=
''
;
this
.
formKey
=
{
name
:
''
,
key
:
''
,
}
}
p
ublic
uploadKey
()
{
const
newKey
:
NewSSHKe
y
=
{
name
:
this
.
newKeyName
,
key
:
this
.
newKeyK
ey
,
p
rivate
upload
Ssh
Key
(
key
:
t
.
NewSSHKey
)
{
const
bod
y
=
{
'
type
'
:
'
add
'
,
'
key
'
:
k
ey
,
};
this
.
userService
.
uploadSshKey
(
newKey
);
return
this
.
http
.
post
(
'
/backend/api/sshkey
'
,
body
).
subscribe
(
(
newKey
:
t
.
SSHKey
)
=>
{
if
(
newKey
)
{
this
.
userService
.
user
.
ssh_keys
.
push
(
newKey
);
}
},
(
err
)
=>
{
console
.
log
(
err
);
this
.
userService
.
update
();
}
);
}
private
removeSshKey
(
key
:
t
.
SSHKey
)
{
return
this
.
http
.
post
(
'
/backend/api/sshkey
'
,
{
'
type
'
:
'
remove
'
,
'
id
'
:
key
.
id
,
}).
subscribe
(
(
data
:
{
deleted
:
boolean
})
=>
{
if
(
data
&&
data
.
deleted
)
{
this
.
userService
.
user
.
ssh_keys
=
this
.
userService
.
user
.
ssh_keys
.
filter
(
k
=>
key
.
id
!=
k
.
id
);
}
},
(
err
)
=>
{
console
.
log
(
err
);
this
.
userService
.
update
();
}
);
}
public
_sshKeyTable
():
MatTableDataSource
<
any
>
{
return
new
MatTableDataSource
(
this
.
userService
.
user
.
ssh_keys
);
}
public
uploadKey
()
{
this
.
uploadSshKey
(
this
.
formKey
);
this
.
ngOnInit
();
}
public
deleteKey
(
key
:
SSHKey
)
{
this
.
userService
.
removeSshKey
(
key
);
this
.
removeSshKey
(
key
);
this
.
ngOnInit
();
}
}
...
...
src/app/mgmt/mgmt.component.html
View file @
b53457d3
<div
*ngIf=
"userService.loggedIn()"
>
<div
style=
"padding-bottom: 30px;"
>
<h2>
Services
</h2>
<mat-accordion
*ngIf=
"userService.
deploymentID
s.length > 0"
>
<app-service
*ngFor=
"let
dID
of userService.
deploymentID
s"
[deployment]=
"userService.getDeployment(
dID)
"
></app-service>
<mat-accordion
*ngIf=
"userService.
service
s.length > 0"
>
<app-service
*ngFor=
"let
service
of userService.
service
s"
[deployment]=
"userService.getDeployment(
service)"
[service]=
"service
"
></app-service>
</mat-accordion>
<p
*ngIf=
"userService.
deploymentID
s.length === 0"
>
<p
*ngIf=
"userService.
service
s.length === 0"
>
You have no available services.
<br/>
This is due services requiring users to be member of a certain group.
</p>
...
...
src/app/service/service.component.html
View file @
b53457d3
<mat-expansion-panel
*ngIf=
"
deployment
"
>
<mat-expansion-panel
*ngIf=
"
service
"
>
<mat-expansion-panel-header>
<mat-panel-title>
{{ service.name }}
</mat-panel-title>
<mat-panel-description>
{{ service.description }}
</mat-panel-description>
...
...
@@ -16,11 +16,12 @@
[ngSwitch]=
"taskState(site, key)"
class=
"childs-inline"
>
<!-- states with actions -->
<button
*ngSwitchCase=
"'deployed'"
mat-button
mat-icon-button
(click)=
"dialog.openCredentials(taskItem(site, key))"
matTooltip=
"The key {{key.name}} is deployed to the site. Click to see details."
>
<mat-icon
style=
"vertical-align: middle"
>
call_made
</mat-icon>
</button>
<button
*ngSwitchCase=
"'questionnaire'"
mat-button
mat-icon-button
(click)=
"dialog.openQuestionnaire(
userService.
taskItem(site,
service
))"
(click)=
"dialog.openQuestionnaire(taskItem(site,
y
))"
matTooltip=
"This site needs more data to deploy the keys. Please click to submit the data."
>
<mat-icon>
warning
</mat-icon>
</button>
...
...
@@ -31,18 +32,18 @@
<span
*ngSwitchCase=
"'removal_pending'"
mat-icon-button
matTooltip=
"Waiting for the removal of the key {{ key.name }} from the site"
>
<mat-progress-spinner
diameter=
"24"
mode=
"indeterminate"
></mat-progress-spinner>
</span>
<
spa
n
*ngSwitchCase=
"'not_deployed'"
mat-icon-button
matTooltip=
"The key {{ key.name }} is not deployed to this site."
>
<
butto
n
*ngSwitchCase=
"'not_deployed'"
mat-icon-button
matTooltip=
"The key {{ key.name }} is not deployed to this site."
>
<mat-icon
style=
"vertical-align: middle"
>
call_received
</mat-icon>
</
spa
n>
<
spa
n
*ngSwitchCase=
"'failed'"
mat-icon-button
matTooltip=
"This site failed to deploy the credentials. The deployment will be retried."
>
</
butto
n>
<
butto
n
*ngSwitchCase=
"'failed'"
mat-icon-button
matTooltip=
"This site failed to deploy the credentials. The deployment will be retried."
>
<mat-icon
style=
"vertical-align: middle"
>
error
</mat-icon>
</
spa
n>
<
spa
n
*ngSwitchCase=
"'rejected'"
mat-icon-button
matTooltip=
"This site rejected the deployment of the key {{ key.name }}."
>
</
butto
n>
<
butto
n
*ngSwitchCase=
"'rejected'"
mat-icon-button
matTooltip=
"This site rejected the deployment of the key {{ key.name }}."
>
<mat-icon
style=
"vertical-align: middle"
>
error
</mat-icon>
</
spa
n>
<!--
hacky solution
-->
<span
*ngSwitchDefault
mat-icon-button
matTooltip=
"
Receiving update from backend
"
>
<mat-
progress-spinner
diameter=
"24"
mode=
"indeterminate"
></mat-progress-spinner
>
</
butto
n>
<!--
if we have no deployment -> assume state == not_deployed
-->
<span
*ngSwitchDefault
mat-icon-button
matTooltip=
"
The key {{ key.name }} is not deployed to this site.
"
>
<mat-
icon
style=
"vertical-align: middle"
>
call_received
</mat-icon
>
</span>
</span>
</span>
...
...
@@ -50,11 +51,11 @@
</td>
</tr>
<tr>
<td
style=
"
padd
in
g
-right:
3
5px;"
*ngFor=
"let group of service.groups"
matTooltip=
"Can be used with membership of group {{ group.name }}"
>
<mat-icon
style=
"vertical-align: middle; padding-right: 5px;"
>
lock outline
</mat-icon>
{{ group.name }}
<td
*ngFor=
"let group of service.groups"
style=
"
marg
in-right:
1
5px;"
>
<span
matTooltip=
"Can be used with membership of group {{ group.name }}"
>
<mat-icon
style=
"vertical-align: middle; padding-right: 5px;"
>
lock outline
</mat-icon
>
{{ group.name }}
</span>
</td>
</tr>
</table>
...
...
src/app/service/service.component.ts
View file @
b53457d3
...
...
@@ -14,8 +14,8 @@ import * as t from '../types/types.module';
styleUrls
:
[
'
./service.component.css
'
]
})
export
class
ServiceComponent
implements
OnInit
{
@
Input
()
service
:
t
.
Service
;
@
Input
()
deployment
:
t
.
Deployment
;
public
service
:
t
.
Service
;
constructor
(
public
userService
:
UserService
,
...
...
@@ -25,7 +25,6 @@ export class ServiceComponent implements OnInit {
}
ngOnInit
()
{
this
.
service
=
this
.
deployment
.
service
;
}
public
isDeployed
(
key
:
t
.
SSHKeyRef
):
boolean
{
...
...
src/app/types/types.module.ts
View file @
b53457d3
...
...
@@ -51,12 +51,16 @@ export interface Service {
group
:
Group
[];
}
interface
JSONObject
{
[
key
:
string
]:
string
;
}
export
interface
DeploymentStateItem
{
id
:
number
;
site
:
Site
;
state
:
string
;
questionnaire
:
any
;
credentials
:
any
;
questionnaire
:
JSONObject
;
credentials
:
JSONObject
;
key
:
SSHKeyRef
;
service
:
Service
;
}
...
...
src/app/user.service.ts
View file @
b53457d3
...
...
@@ -24,8 +24,8 @@ export class UserService {
public
userState
:
t
.
UserState
;
public
messages
:
string
[]
=
[];
// local copy of
deployment
s
public
deploymentIDs
:
number
[]
=
[];
// local copy of
service
s
public
services
:
t
.
Service
[]
=
[];
constructor
(
...
...
@@ -94,14 +94,24 @@ export class UserService {
this
.
user
=
newUser
;
}
private
updateDeployments
(
newDeployments
:
t
.
Deployment
[]){
if
(
this
.
deploymentIDs
.
length
!==
newDeployments
.
length
)
{
for
(
let
dep
of
newDeployments
)
{
this
.
deploymentIDs
.
push
(
dep
.
id
);
private
updateServices
(
newServices
:
t
.
Service
[]){
if
(
this
.
services
.
length
!==
newServices
.
length
)
{
this
.
services
=
[];
for
(
let
service
of
newServices
)
{
this
.
services
.
push
(
service
);
}
}
}
private
_logout
()
{
this
.
_loggedIn
=
false
;
this
.
snackBar
.
open
(
'
Logged out
'
);
this
.
_stompService
.
disconnect
();
this
.
services
=
[];
this
.
user
=
null
;
this
.
userState
=
null
;
}
private
updateUserState
(
newState
:
t
.
UserState
)
{
// did a login occur?
let
login
=
(
!
this
.
_loggedIn
&&
newState
);
...
...
@@ -112,26 +122,30 @@ export class UserService {
if
(
login
)
{
this
.
_loggedIn
=
true
;
this
.
snackBar
.
open
(
'
Logged in
'
);
this
.
connectLiveUpdates
()
}
if
(
logout
)
{
this
.
_loggedIn
=
false
;
this
.
snackBar
.
open
(
'
Logged out
'
);
this
.
_stompService
.
disconnect
();
this
.
_logout
()
return
}
this
.
updateDeployments
(
newState
.
deployments
);
this
.
userState
=
newState
;
}
private
stateAPIUpdate
(
update
:
t
.
StateAPIResult
)
{
this
.
updateUser
(
update
.
user
)
this
.
updateUserState
(
update
.
user_state
);
// report an occured error
if
(
update
.
error
)
{
this
.
snackBar
.
open
(
update
.
error
);
if
(
update
)
{
this
.
updateUser
(
update
.
user
)
this
.
updateUserState
(
update
.
user_state
);
this
.
updateServices
(
update
.
services
);
// report an occured error
if
(
update
.
error
)
{
this
.
snackBar
.
open
(
update
.
error
);
}
}
else
{
console
.
log
(
"
Got null update
"
);
}
}
...
...
@@ -140,10 +154,10 @@ export class UserService {
}
// PUBLIC API
public
getDeployment
(
id
:
number
):
t
.
Deployment
{
public
getDeployment
(
service
:
t
.
Service
):
t
.
Deployment
{
return
this
.
userState
.
deployments
.
find
(
dep
=>
{
return
dep
.
id
==
id
return
dep
.
service
.
id
==
=
service
.
id
;
}
);
}
...
...
@@ -225,49 +239,16 @@ export class UserService {
this
.
http
.
post
(
'
/backend/auth/v1/logout
'
,
{}).
subscribe
(
(
data
:
t
.
StateAPIResult
)
=>
{
this
.
stateAPIUpdate
(
data
);
}
);
}
public
uploadSshKey
(
key
:
t
.
NewSSHKey
)
{
const
body
=
{
'
type
'
:
'
add
'
,
'
key
'
:
key
,
};
return
this
.
http
.
post
(
'
/backend/api/sshkey
'
,
body
).
subscribe
(
(
data
:
t
.
UserState
)
=>
{
this
.
updateUserState
(
data
);
},
(
err
)
=>
{
this
.
snackBar
.
open
(
'
Error uploading key
'
);
console
.
log
(
err
);
this
.
update
();
}
);
}
public
removeSshKey
(
key
:
t
.
SSHKey
)
{
const
body
=
{
'
type
'
:
'
remove
'
,
'
id
'
:
key
.
id
,
};
return
this
.
http
.
post
(
'
/backend/api/sshkey
'
,
body
).
subscribe
(
(
data
:
t
.
UserState
)
=>
{
this
.
updateUserState
(
data
);
this
.
user
.
ssh_keys
=
this
.
user
.
ssh_keys
.
filter
(
k
=>
key
.
id
==
k
.
id
);
},
(
err
)
=>
{
this
.
snackBar
.
open
(
'
Error deleting key
'
);
console
.
log
(
err
);
this
.
update
();
this
.
_logout
();
}
);
}
public
sentQuestionnaire
(
ta
sk
ItemID
:
number
,
answers
:
any
)
{
return
this
.
http
.
post
(
'
/backend/api/questionnaire?id=
'
+
String
(
ta
sk
ItemID
),
answers
).
subscribe
(
public
sentQuestionnaire
(
s
ta
te
ItemID
:
number
,
answers
:
any
)
{
return
this
.
http
.
post
(
'
/backend/api/questionnaire?id=
'
+
String
(
s
ta
te
ItemID
),
answers
).
subscribe
(
(
data
:
t
.
UserState
)
=>
{
this
.
snackBar
.
open
(
'
Uploaded questionnaire
'
);
//this.snackBar.open('Deployed key ' + key.name);
...
...
src/styles.css
View file @
b53457d3
...
...
@@ -23,7 +23,7 @@ body {
}
.mat-column-name
{
max-width
:
1
00px
;
max-width
:
2
00px
;
}
.mat-column-action
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment