|
|
|
<template>
|
|
|
|
<card class="card-user" style="max-height:100%">
|
|
|
|
|
|
|
|
<div class="author">
|
|
|
|
<img class="avatar border-white" src="@/assets/img/academy.png" alt="..."
|
|
|
|
v-if="datadir"
|
|
|
|
>
|
|
|
|
<img class="avatar border-white" src="@/assets/img/library.png" alt="..."
|
|
|
|
v-else
|
|
|
|
>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<v-wait for="myRunInstancetutor1">
|
|
|
|
<template slot="waiting">
|
|
|
|
<div>
|
|
|
|
<img src="@/assets/loading.gif" />
|
|
|
|
Enter Lab_room...
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
</v-wait>
|
|
|
|
|
|
|
|
<b-container fluid class="bv-example-row"
|
|
|
|
v-show="datadir"
|
|
|
|
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- timeline -->
|
|
|
|
|
|
|
|
<b-container class="container" >
|
|
|
|
<div class="row justify-content-center myscrool">
|
|
|
|
<div class="col-xl-10 col-12">
|
|
|
|
<div class="timeline timeline-line-solid">
|
|
|
|
<span class="timeline-label">
|
|
|
|
<span class="label">{{datatitle}}</span>
|
|
|
|
</span>
|
|
|
|
<!-- timeline -->
|
|
|
|
<div class="timeline-item"
|
|
|
|
v-for="(course, i) in coursesview"
|
|
|
|
>
|
|
|
|
<div
|
|
|
|
v-if="!course.exercise_file"
|
|
|
|
>
|
|
|
|
<div class="timeline-point timeline-point"></div>
|
|
|
|
<div class="timeline-event shadow p-3 mb-5 bg-white rounded">
|
|
|
|
<div class="widget has-shadow" >
|
|
|
|
<div class="widget-header d-flex align-items-center"
|
|
|
|
:class="{ active: i === activeItem}"
|
|
|
|
>
|
|
|
|
<div class="user-image">
|
|
|
|
<img class="rounded-circle" src="@/assets/img/penguinfledgling.png" alt="...">
|
|
|
|
</div>
|
|
|
|
<div class="d-flex flex-column mr-auto">
|
|
|
|
<div class="title">
|
|
|
|
<span class="username">{{ course.title }} </span>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!--
|
|
|
|
<div class="widget-options">
|
|
|
|
<div class="dropdown">
|
|
|
|
<button type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" class="dropdown-toggle">
|
|
|
|
<i class="la la-ellipsis-h"></i>
|
|
|
|
</button>
|
|
|
|
<div class="dropdown-menu">
|
|
|
|
<a href="#" class="dropdown-item">
|
|
|
|
<i class="la la-edit"></i>Edit Post
|
|
|
|
</a>
|
|
|
|
<a href="#" class="dropdown-item">
|
|
|
|
<i class="la la-trash"></i>Delete Post
|
|
|
|
</a>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
-->
|
|
|
|
</div>
|
|
|
|
<div class="widget-body">
|
|
|
|
<p>
|
|
|
|
{{ course.subtitle}}
|
|
|
|
</p>
|
|
|
|
<small>{{ course.desc}}</small>
|
|
|
|
</div>
|
|
|
|
<div class="widget-footer d-flex align-items-center">
|
|
|
|
<div class="col-12 no-padding d-flex justify-content-end">
|
|
|
|
<div class="meta">
|
|
|
|
<ul class="list-group list-group-horizontal">
|
|
|
|
<li
|
|
|
|
v-if="course.doc_file"
|
|
|
|
>
|
|
|
|
<a href="#"
|
|
|
|
@click="viewllo(course,'asciidoc',i)"
|
|
|
|
><small > </small> <span title="doc" class="rounded-circle bg-dark text-white ti-book"></span></a>
|
|
|
|
</li>
|
|
|
|
<li
|
|
|
|
v-if="course.code_file"
|
|
|
|
>
|
|
|
|
<a href="#"
|
|
|
|
@click="viewllo(course,'asciinema',i)"
|
|
|
|
><small > </small><span title="asciinema" class="rounded-circle text-success ti-shortcode"></span></a>
|
|
|
|
</li>
|
|
|
|
<li
|
|
|
|
v-if="course.video_file"
|
|
|
|
>
|
|
|
|
<a href="#"
|
|
|
|
@click="viewllo(course,'video',i)"
|
|
|
|
><small > </small><span title="video" class="text-info ti-video-camera"></span></a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- timeline right -->
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div class="col-xl-10 col-12">
|
|
|
|
<div class="timeline timeline-line-solid">
|
|
|
|
<span class="timeline-label">
|
|
|
|
<span class="label">Exercises</span>
|
|
|
|
</span>
|
|
|
|
<!-- timeline -->
|
|
|
|
<div class="timeline-item"
|
|
|
|
v-for="(course, i) in coursesview"
|
|
|
|
>
|
|
|
|
|
|
|
|
<div
|
|
|
|
v-if="course.exercise_file"
|
|
|
|
>
|
|
|
|
<div class="timeline-point timeline-point"></div>
|
|
|
|
<div class="timeline-event shadow p-3 mb-5 bg-white rounded">
|
|
|
|
<div class="widget has-shadow" >
|
|
|
|
<div class="widget-header d-flex align-items-center"
|
|
|
|
:class="{ active: i === activeItem}"
|
|
|
|
>
|
|
|
|
<div class="user-image">
|
|
|
|
<img class="rounded-circle" src="@/assets/img/penguinfledgling.png" alt="...">
|
|
|
|
</div>
|
|
|
|
<div class="d-flex flex-column mr-auto">
|
|
|
|
<div class="title">
|
|
|
|
<span class="username">{{ course.title }} </span>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!--
|
|
|
|
<div class="widget-options">
|
|
|
|
<div class="dropdown">
|
|
|
|
<button type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" class="dropdown-toggle">
|
|
|
|
<i class="la la-ellipsis-h"></i>
|
|
|
|
</button>
|
|
|
|
<div class="dropdown-menu">
|
|
|
|
<a href="#" class="dropdown-item">
|
|
|
|
<i class="la la-edit"></i>Edit Post
|
|
|
|
</a>
|
|
|
|
<a href="#" class="dropdown-item">
|
|
|
|
<i class="la la-trash"></i>Delete Post
|
|
|
|
</a>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
-->
|
|
|
|
</div>
|
|
|
|
<div class="widget-body">
|
|
|
|
<p>
|
|
|
|
{{ course.subtitle}}
|
|
|
|
</p>
|
|
|
|
<small>{{ course.desc}}</small>
|
|
|
|
</div>
|
|
|
|
<div class="widget-footer d-flex align-items-center">
|
|
|
|
<div class="col-12 no-padding d-flex justify-content-end">
|
|
|
|
<div class="meta">
|
|
|
|
<ul class="list-group list-group-horizontal">
|
|
|
|
<li
|
|
|
|
v-if="course.exercise_file"
|
|
|
|
>
|
|
|
|
<a href="#"
|
|
|
|
@click="viewllo(course,'exercise',i)"
|
|
|
|
><small > </small> <span title="Challenge" class="rounded-circle bg-dark text-white ti-book"></span></a>
|
|
|
|
</li>
|
|
|
|
<li
|
|
|
|
v-if="course.exercise_answerfile"
|
|
|
|
>
|
|
|
|
<a href="#"
|
|
|
|
@click="viewllo(course,'exerciseanswer',i)"
|
|
|
|
><small > </small><span title="Answer" class="text-info ti-book"></span></a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- timeline right -->
|
|
|
|
<span class="timeline-label">
|
|
|
|
<span class="label">{{datatitle}}</span>
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</b-container>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!--
|
|
|
|
<div class="list-group myscrool"
|
|
|
|
>
|
|
|
|
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start"
|
|
|
|
v-for="(course, i) in courses"
|
|
|
|
@click="viewllo(course,i)"
|
|
|
|
:class="{ active: i === activeItem}"
|
|
|
|
>
|
|
|
|
<div class="d-flex w-100 justify-content-between">
|
|
|
|
<h5 class="mb-1">{{course.title}}</h5>
|
|
|
|
|
|
|
|
<small
|
|
|
|
:class="checkClass(course)"
|
|
|
|
> {{ course.type }}
|
|
|
|
<small class="ti-shortcode"
|
|
|
|
v-if="course.type=='asciinema'"
|
|
|
|
> </small>
|
|
|
|
<small class="ti-video-camera"
|
|
|
|
v-if="course.type=='video'"
|
|
|
|
> </small>
|
|
|
|
<small class="ti-book"
|
|
|
|
v-if="course.type=='asciidoc'"
|
|
|
|
> </small>
|
|
|
|
<small class="ti-help-alt text-exercise"
|
|
|
|
v-if="course.type=='exercise'"
|
|
|
|
> </small>
|
|
|
|
</small>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
<small>{{ course.desc}}</small>
|
|
|
|
</a>
|
|
|
|
-->
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</b-container>
|
|
|
|
<br>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<b-container fluid class="bv-example-row">
|
|
|
|
<div class="progress"
|
|
|
|
v-show="datadir"
|
|
|
|
>
|
|
|
|
<div class="progress-bar progress-bar-striped bg-secondary" role="progressbar" :style="{ width: progress + '%' }" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100">{{ progress }}</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="input-group input-group-sm sm-3">
|
|
|
|
|
|
|
|
<input type="text"
|
|
|
|
class="form-control"
|
|
|
|
aria-label="Small" aria-describedby="inputGroup-sizing-sm"
|
|
|
|
placeholder="Search by Name"
|
|
|
|
v-model="searchFor"
|
|
|
|
@keyup.enter="setFilter"
|
|
|
|
>
|
|
|
|
|
|
|
|
<div class="input-group-prepend">
|
|
|
|
<select
|
|
|
|
class="custom-select custom-select-sm" v-model="searchcourselang">
|
|
|
|
<option value="0" selected>Lang...</option>
|
|
|
|
<option value="1">English</option>
|
|
|
|
<option value="2">Ελληνικά</option>
|
|
|
|
</select>
|
|
|
|
</div>
|
|
|
|
<div class="input-group-prepend">
|
|
|
|
<select
|
|
|
|
class="custom-select custom-select-sm" v-model="searchcourselevel">
|
|
|
|
<option value="0" selected>Level...</option>
|
|
|
|
<option value="1">Elementary</option>
|
|
|
|
<option value="2">Intermediate</option>
|
|
|
|
<option value="3">Advanced</option>
|
|
|
|
<option value="4">Expert</option>
|
|
|
|
<option value="5">Guru</option>
|
|
|
|
</select>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="input-group-append">
|
|
|
|
<button
|
|
|
|
class="btn btn-outline-primary"
|
|
|
|
round
|
|
|
|
type="button"
|
|
|
|
@click="setFilter">
|
|
|
|
Go</button>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="input-group-append">
|
|
|
|
<button class="btn btn-outline-secondary"
|
|
|
|
round
|
|
|
|
type="button"
|
|
|
|
@click="resetFilter">
|
|
|
|
Reset</button>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="white h-100 flex-fixed-width-item"
|
|
|
|
<vuetable
|
|
|
|
ref="vuetable"
|
|
|
|
:key="vuetablekeyf"
|
|
|
|
:api-url='apiurl'
|
|
|
|
:api-mode="true"
|
|
|
|
:http-options="httpOptions"
|
|
|
|
:fields="fields"
|
|
|
|
:item-actions="itemActions"
|
|
|
|
:sort-order="sortOrder"
|
|
|
|
:show-sort-icons="true"
|
|
|
|
:multi-sort="multiSort"
|
|
|
|
:per-page="perpage"
|
|
|
|
pagination-path="links.pagination"
|
|
|
|
:pagination-component="paginationComponent"
|
|
|
|
:append-params="moreParams"
|
|
|
|
wrapper-class="vuetable-wrapper"
|
|
|
|
loading-class="loading"
|
|
|
|
detail-row-id="id"
|
|
|
|
@vuetable:pagination-data="onPaginationData"
|
|
|
|
@vuetable:load-success="loadsuccess"
|
|
|
|
@vuetable:load-error="onLoadError"
|
|
|
|
:css="css.table"
|
|
|
|
>
|
|
|
|
|
|
|
|
<div slot="actions" slot-scope="props">
|
|
|
|
<button
|
|
|
|
v-if="actionrowindex == props.rowIndex"
|
|
|
|
class="ti-more-alt btn btn-secondary btn-sm"
|
|
|
|
title="View Course Details"
|
|
|
|
round
|
|
|
|
@click="onAction('run-more', props.rowData, props.rowIndex)">
|
|
|
|
</button>
|
|
|
|
<button
|
|
|
|
v-else
|
|
|
|
class="ti-more btn btn-outline-secondary btn-sm"
|
|
|
|
title="View Course Details"
|
|
|
|
round
|
|
|
|
@click="onAction('run-more', props.rowData, props.rowIndex)">
|
|
|
|
</button>
|
|
|
|
<button
|
|
|
|
class="ti-info btn btn-outline-secondary btn-sm"
|
|
|
|
title="View Course Info"
|
|
|
|
round
|
|
|
|
@click="onAction('run-info', props.rowData, props.rowIndex)">
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
</vuetable>
|
|
|
|
<div class="vuetable-pagination ui basic segment grid">
|
|
|
|
<vuetable-pagination-info
|
|
|
|
ref="paginationInfo"
|
|
|
|
:css="css.paginationInfo"
|
|
|
|
>
|
|
|
|
</vuetable-pagination-info>
|
|
|
|
<vuetable-pagination
|
|
|
|
:css="css.pagination"
|
|
|
|
ref="pagination"
|
|
|
|
@vuetable-pagination:change-page="onChangePage"
|
|
|
|
>
|
|
|
|
</vuetable-pagination>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</b-container>
|
|
|
|
</card>
|
|
|
|
</template>
|
|
|
|
<script>
|
|
|
|
import store from '@/store/index'
|
|
|
|
import {mapState, mapGetters, mapActions,dispatch} from 'vuex'
|
|
|
|
import Vue from 'vue'
|
|
|
|
import {Vuetable, VuetablePaginationDropdown} from 'vuetable-2'
|
|
|
|
import VuetablePaginationInfo from 'vuetable-2/src/components/VuetablePaginationInfo'
|
|
|
|
import VuetablePagination from 'vuetable-2/src/components/VuetablePagination'
|
|
|
|
import CssConfig from 'vuetable-2/src/components/VuetableCssConfig.js'
|
|
|
|
import card from '@/components/Card.vue'
|
|
|
|
import {ApiConfig} from "@/config/index";
|
|
|
|
export default {
|
|
|
|
components: {
|
|
|
|
card,
|
|
|
|
Vuetable,
|
|
|
|
VuetablePagination,
|
|
|
|
VuetablePaginationInfo,
|
|
|
|
VuetablePaginationDropdown
|
|
|
|
},
|
|
|
|
props: {
|
|
|
|
},
|
|
|
|
data() {
|
|
|
|
return{
|
|
|
|
coursesview:{},
|
|
|
|
actionrowindex:'',
|
|
|
|
activeItem: null,
|
|
|
|
playbookInfo: {},
|
|
|
|
token: '',
|
|
|
|
playbook: {
|
|
|
|
'title':'',
|
|
|
|
'name':'',
|
|
|
|
'description':''
|
|
|
|
},
|
|
|
|
datadir:'',
|
|
|
|
datatitle:'',
|
|
|
|
progress:0,
|
|
|
|
searchcourselevel:0,
|
|
|
|
searchcourselang:0,
|
|
|
|
courses:[],
|
|
|
|
courseshow:false,
|
|
|
|
container:{
|
|
|
|
name:'',
|
|
|
|
view:0
|
|
|
|
},
|
|
|
|
pipeline:{},
|
|
|
|
selected: 'hybrid',
|
|
|
|
options: [
|
|
|
|
{ text: 'Packages', value: 'packages' },
|
|
|
|
{ text: 'Images', value: 'images' },
|
|
|
|
{ text: 'Scripts', value: 'scripts' }
|
|
|
|
],
|
|
|
|
showModal: false,
|
|
|
|
visibility: [],
|
|
|
|
active:false,
|
|
|
|
vuetablekeyf:0,
|
|
|
|
fielddata:{},
|
|
|
|
fields: [
|
|
|
|
{
|
|
|
|
name: 'title',
|
|
|
|
title: '<span class="orange"></span>Name',
|
|
|
|
sortField: 'title',
|
|
|
|
visible:true,
|
|
|
|
dataClass: 'text-left text-wrap text-break break-word',
|
|
|
|
width: '20%'
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'subtitle',
|
|
|
|
title: '<span class="orange"></span>Course',
|
|
|
|
//sortField: 'subtitle',
|
|
|
|
visible:true,
|
|
|
|
dataClass: 'left aligned w-25',
|
|
|
|
width: '25%'
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: '_id',
|
|
|
|
title: '<span class="orange"></span>mongo',
|
|
|
|
visible:false
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'desc',
|
|
|
|
title: '<span class="orange"></span>Description',
|
|
|
|
//sortField: 'desc',
|
|
|
|
titleClass: 'center aligned',
|
|
|
|
visible:true,
|
|
|
|
width: '30%'
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'lang',
|
|
|
|
title: '<span class="orange"></span>Lang',
|
|
|
|
sortField: 'lang',
|
|
|
|
titleClass: 'center aligned',
|
|
|
|
dataClass: 'text-center',
|
|
|
|
visible:true,
|
|
|
|
width: '10%'
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: '__slot:actions', // <----
|
|
|
|
title: '<span class="d-flex justify-content-center">Actions</span>',
|
|
|
|
titleClass: 'center aligned',
|
|
|
|
dataClass: 'text-center',
|
|
|
|
width: '15%'
|
|
|
|
}
|
|
|
|
],
|
|
|
|
apiurl:ApiConfig.url_80+"/get_llo",
|
|
|
|
//apiurl:ApiConfig.swarmlab_url_80+"/swarmlabhybridservices",
|
|
|
|
css: CssConfig,
|
|
|
|
perpage: 5,
|
|
|
|
searchFor: '',
|
|
|
|
sortOrder: [{
|
|
|
|
field: 'title',
|
|
|
|
direction: 'asc'
|
|
|
|
}],
|
|
|
|
multiSort: true,
|
|
|
|
paginationComponent: 'vuetable-pagination',
|
|
|
|
itemActions: [
|
|
|
|
{ name: 'view-item', label: '', icon: 'glyphicon glyphicon-zoom-in', class: 'btn btn-info', extra: {'title': 'View', 'data-toggle':"tooltip", 'data-placement': "left"} },
|
|
|
|
{ name: 'edit-item', label: '', icon: 'glyphicon glyphicon-pencil', class: 'btn btn-warning', extra: {title: 'Edit', 'data-toggle':"tooltip", 'data-placement': "top"} },
|
|
|
|
{ name: 'delete-item', label: '', icon: 'glyphicon glyphicon-remove', class: 'btn btn-danger', extra: {title: 'Delete', 'data-toggle':"tooltip", 'data-placement': "right" } }
|
|
|
|
],
|
|
|
|
moreParams: {
|
|
|
|
'filter': '',
|
|
|
|
'level': '',
|
|
|
|
'type': 'scripts',
|
|
|
|
'tutor': 'yes'
|
|
|
|
},
|
|
|
|
|
|
|
|
}
|
|
|
|
},
|
|
|
|
mounted() {
|
|
|
|
this.$root.$on('hybrid_progress_refresh', () => {
|
|
|
|
Vue.nextTick( () => this.getprogress(this.datadir))
|
|
|
|
})
|
|
|
|
this.$root.$on('hybrid_refresh_dockerservices', () => {
|
|
|
|
//Vue.nextTick( () => this.$refs.vuetable.refresh())
|
|
|
|
})
|
|
|
|
//refresh from socket mytable
|
|
|
|
this.$root.$on('hybrid_refresh_table', (v) => {
|
|
|
|
this.$nextTick(function () {
|
|
|
|
Vue.nextTick( () => this.$refs.vuetable.refresh())
|
|
|
|
this.viewhybridoptions = false
|
|
|
|
})
|
|
|
|
})
|
|
|
|
},
|
|
|
|
created() {
|
|
|
|
var url_string = window.location.href
|
|
|
|
var url = new URL(url_string);
|
|
|
|
this.token = url.searchParams.get("token");
|
|
|
|
//console.log("token "+ this.token);
|
|
|
|
|
|
|
|
},
|
|
|
|
beforeDestroy () {
|
|
|
|
this.$root.$off('hybrid_progress_refresh')
|
|
|
|
this.$root.$off('hybrid_refresh_dockerservices')
|
|
|
|
this.$root.$off('hybrid_refresh_table')
|
|
|
|
},
|
|
|
|
computed: {
|
|
|
|
httpOptions() {
|
|
|
|
var token = this.token
|
|
|
|
var p="headers: {Authorization: token}}"; //table props -> :http-options="httpOptions"
|
|
|
|
return {headers: {Authorization: 'Bearer ' + token}} //table props -> :http-options="httpOptions"
|
|
|
|
},
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
methods: {
|
|
|
|
async getprogress(course){
|
|
|
|
//console.log('course '+course)
|
|
|
|
var value1 = {}
|
|
|
|
value1.course = this.datadir
|
|
|
|
var llo = await store.dispatch('pipelineLLO/getprogress', value1)
|
|
|
|
var sprogress = llo.data.data.progress.progress
|
|
|
|
var synolochapter = this.courses.length
|
|
|
|
//synolochapter--
|
|
|
|
var synolo = Math.floor((sprogress/synolochapter)*100)
|
|
|
|
this.progress = synolo
|
|
|
|
},
|
|
|
|
checkClass(course){
|
|
|
|
if(course.type == 'video'){
|
|
|
|
return 'text-primary'
|
|
|
|
} else if(course.type == 'asciidoc'){
|
|
|
|
return 'text-success'
|
|
|
|
} else if(course.type == 'asciinema'){
|
|
|
|
return 'text-info'
|
|
|
|
} else if(course.type == 'exercise'){
|
|
|
|
return 'text-warning'
|
|
|
|
}else{
|
|
|
|
return 'text-secondary'
|
|
|
|
}
|
|
|
|
},
|
|
|
|
onError (type,description) {
|
|
|
|
var winfo=description
|
|
|
|
var info='<h5>Bootstrap '+type+'</h5>'
|
|
|
|
this.$swal({
|
|
|
|
type: type,
|
|
|
|
html: info+winfo,
|
|
|
|
showCloseButton: true,
|
|
|
|
showLoaderOnConfirm: false,
|
|
|
|
allowOutsideClick: false,
|
|
|
|
cancelButtonText: 'No, cancel!',
|
|
|
|
showCancelButton: false,
|
|
|
|
showLoaderOnConfirm: false,
|
|
|
|
reverseButtons: true,
|
|
|
|
focusCancel: true,
|
|
|
|
confirmButtonText: 'Ok!'
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
setFilter () {
|
|
|
|
this.moreParams = {
|
|
|
|
'filter': this.searchFor,
|
|
|
|
'level': this.searchcourselevel,
|
|
|
|
'lang': this.searchcourselang,
|
|
|
|
'type': this.selected
|
|
|
|
}
|
|
|
|
Vue.nextTick( () => this.$refs.vuetable.refresh())
|
|
|
|
},
|
|
|
|
resetFilter () {
|
|
|
|
this.moreParams = {}
|
|
|
|
this.searchFor = ''
|
|
|
|
Vue.nextTick( () => this.$refs.vuetable.refresh())
|
|
|
|
},
|
|
|
|
onPaginationData (paginationData) {
|
|
|
|
this.$refs.pagination.setPaginationData(paginationData)
|
|
|
|
this.$refs.paginationInfo.setPaginationData(paginationData)
|
|
|
|
},
|
|
|
|
onChangePage (page) {
|
|
|
|
this.$refs.vuetable.changePage(page)
|
|
|
|
},
|
|
|
|
editRow(rowData) {
|
|
|
|
alert("You clicked edit on"+ JSON.stringify(rowData));
|
|
|
|
},
|
|
|
|
async viewllo (course,coursetype,i) {
|
|
|
|
|
|
|
|
this.courseshow = true
|
|
|
|
if(coursetype == 'video' ){
|
|
|
|
//console.log(JSON.stringify(course))
|
|
|
|
var value = {}
|
|
|
|
value.type = coursetype
|
|
|
|
value.course = course.video_file
|
|
|
|
value.llo = this.datadir
|
|
|
|
this.$root.$emit('hybrid_llo_viecourse',value)
|
|
|
|
}else if(coursetype == 'asciidoc' ){
|
|
|
|
var value1 = {}
|
|
|
|
value1.dir = this.datadir
|
|
|
|
value1.file = course.doc_file
|
|
|
|
//console.log('asciidoc '+JSON.stringify(value1))
|
|
|
|
var llo = await store.dispatch('pipelineLLO/get_llo_course_ascii', value1)
|
|
|
|
//console.log('asciidoc '+JSON.stringify(llo))
|
|
|
|
//this.courses = JSON.parse(llo.data)
|
|
|
|
var value = {}
|
|
|
|
value.type = coursetype
|
|
|
|
value.code = llo.data.data
|
|
|
|
value.course = course.doc_file
|
|
|
|
value.llo = this.datadir
|
|
|
|
this.$root.$emit('hybrid_llo_viecourse',value)
|
|
|
|
}else if(coursetype == 'asciinema' ){
|
|
|
|
//console.log(JSON.stringify(course))
|
|
|
|
var value = {}
|
|
|
|
value.type = coursetype
|
|
|
|
value.course = course.code_file
|
|
|
|
value.llo = this.datadir
|
|
|
|
this.$root.$emit('hybrid_llo_viecourse',value)
|
|
|
|
}else if(coursetype == 'exercise' ){
|
|
|
|
var value1 = {}
|
|
|
|
value1.dir = this.datadir
|
|
|
|
value1.file = course.exercise_file
|
|
|
|
//console.log('asciidoc '+JSON.stringify(value1))
|
|
|
|
var llo = await store.dispatch('pipelineLLO/get_llo_course_ascii', value1)
|
|
|
|
//console.log('asciidoc '+JSON.stringify(llo))
|
|
|
|
//this.courses = JSON.parse(llo.data)
|
|
|
|
var value = {}
|
|
|
|
value.type = 'asciidoc'
|
|
|
|
value.code = llo.data.data
|
|
|
|
value.course = course.exercise_file
|
|
|
|
value.llo = this.datadir
|
|
|
|
this.$root.$emit('hybrid_llo_viecourse',value)
|
|
|
|
}else if(coursetype == 'exerciseanswer' ){
|
|
|
|
var value1 = {}
|
|
|
|
value1.dir = this.datadir
|
|
|
|
value1.file = course.exercise_answerfile
|
|
|
|
//console.log('asciidoc '+JSON.stringify(value1))
|
|
|
|
var llo = await store.dispatch('pipelineLLO/get_llo_course_ascii', value1)
|
|
|
|
//console.log('asciidoc '+JSON.stringify(llo))
|
|
|
|
//this.courses = JSON.parse(llo.data)
|
|
|
|
var value = {}
|
|
|
|
value.type = 'asciidoc'
|
|
|
|
value.code = llo.data.data
|
|
|
|
value.course = course.exercise_answerfile
|
|
|
|
value.llo = this.datadir
|
|
|
|
this.$root.$emit('hybrid_llo_viecourse',value)
|
|
|
|
}
|
|
|
|
this.activeItem = i;
|
|
|
|
this.getprogress(this.datadir)
|
|
|
|
},
|
|
|
|
async onAction (action, data, index) {
|
|
|
|
//console.log('index '+this.actionrowindex)
|
|
|
|
if(action == 'run-more' ){
|
|
|
|
this.actionrowindex = index
|
|
|
|
this.datadir = data.dir
|
|
|
|
this.datatitle = data.title
|
|
|
|
var llo = await store.dispatch('pipelineLLO/get_llo_course', data.dir)
|
|
|
|
this.courses = llo.data
|
|
|
|
var countchapter = Math.max.apply(Math, this.courses.map(function(o){return o.chapter;}))
|
|
|
|
//console.log('countchapter '+ JSON.stringify(countchapter))
|
|
|
|
var coursesnew1 = []
|
|
|
|
for(var i = 1; i <= countchapter; i++) {
|
|
|
|
//console.log('count '+ JSON.stringify(i))
|
|
|
|
var coursesnew = {}
|
|
|
|
var coursetmp = this.courses.filter(x => x.chapter === i);
|
|
|
|
var countcourse1 = coursetmp.length
|
|
|
|
|
|
|
|
/*
|
|
|
|
coursesnew.video_file = coursetmp[ii].file
|
|
|
|
coursesnew.video_service = coursetmp[ii].service
|
|
|
|
coursesnew.doc_file = coursetmp[ii].file
|
|
|
|
coursesnew.code_file = coursetmp[ii].file
|
|
|
|
coursesnew.exercise_file = coursetmp[ii].file
|
|
|
|
coursesnew.exercise_difficulty = coursetmp[ii].difficulty
|
|
|
|
|
|
|
|
coursesnew.chapter = i
|
|
|
|
coursesnew.title = coursetmp[ii].title
|
|
|
|
coursesnew.subtitle = coursetmp[ii].subtitle
|
|
|
|
coursesnew.desc = coursetmp[ii].desc
|
|
|
|
*/
|
|
|
|
|
|
|
|
for(var ii = 0; ii < countcourse1; ii++) {
|
|
|
|
//console.log('for '+ JSON.stringify(coursetmp))
|
|
|
|
if( coursetmp[ii].type == 'video'){
|
|
|
|
coursesnew.video_file = coursetmp[ii].file
|
|
|
|
coursesnew.video_service = coursetmp[ii].service
|
|
|
|
}else if( coursetmp[ii].type == 'asciidoc'){
|
|
|
|
coursesnew.doc_file = coursetmp[ii].file
|
|
|
|
}else if( coursetmp[ii].type == 'asciinema'){
|
|
|
|
coursesnew.code_file = coursetmp[ii].file
|
|
|
|
}else if( coursetmp[ii].type == 'exercise'){
|
|
|
|
coursesnew.exercise_file = coursetmp[ii].file
|
|
|
|
coursesnew.exercise_answerfile = coursetmp[ii].answerfile
|
|
|
|
coursesnew.exercise_difficulty = coursetmp[ii].difficulty
|
|
|
|
}
|
|
|
|
|
|
|
|
if(coursesnew.chapter == '' || coursesnew.chapter == undefined){
|
|
|
|
coursesnew.chapter = i
|
|
|
|
}
|
|
|
|
if(coursesnew.title == '' || coursesnew.title == undefined){
|
|
|
|
coursesnew.title = coursetmp[ii].title
|
|
|
|
}
|
|
|
|
if(coursesnew.subtitle == '' || coursesnew.subtitle == undefined){
|
|
|
|
coursesnew.subtitle = coursetmp[ii].subtitle
|
|
|
|
}
|
|
|
|
if(coursesnew.desc == '' || coursesnew.desc == undefined){
|
|
|
|
coursesnew.desc = coursetmp[ii].desc
|
|
|
|
}
|
|
|
|
if(coursesnew.course == '' || coursesnew.course == undefined){
|
|
|
|
coursesnew.course = this.datatitle
|
|
|
|
}
|
|
|
|
}
|
|
|
|
coursesnew1.push(coursesnew)
|
|
|
|
}
|
|
|
|
this.coursesview = coursesnew1
|
|
|
|
//console.log('new '+JSON.stringify(coursesnew1))
|
|
|
|
|
|
|
|
//this.courses = JSON.parse(llo.data)
|
|
|
|
}else if(action == 'run-info' ){
|
|
|
|
//console.log(JSON.stringify(data))
|
|
|
|
// {"title":"linux","subtitle":"Basics","level":"Intermediate","desc":"description","dir":"hybrid-linux"}
|
|
|
|
var info = `
|
|
|
|
<table class="table table-hover table-sm text-left">
|
|
|
|
<tbody>
|
|
|
|
<tr>
|
|
|
|
<th ><b>Title</b></th>
|
|
|
|
<td>${data.title}</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td><b>Subtitle</b></td>
|
|
|
|
<td>${data.subtitle}</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th ><b>Level</b></th>
|
|
|
|
<td>${data.level}</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td ><b>Description</b></td>
|
|
|
|
<td>${data.desc}</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td ><b>Language</b></td>
|
|
|
|
<td>${data.lang}</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td ><b>License</b></td>
|
|
|
|
<td>${data.license}</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td ><b>More Info</b></td>
|
|
|
|
<td>${data.url}</td>
|
|
|
|
</tr>
|
|
|
|
</tbody>
|
|
|
|
</table>`
|
|
|
|
this.$swal({
|
|
|
|
type: 'Info',
|
|
|
|
title: 'Course Info!',
|
|
|
|
icon:'info',
|
|
|
|
html: info,
|
|
|
|
showCloseButton: true,
|
|
|
|
showLoaderOnConfirm: false,
|
|
|
|
allowOutsideClick: false,
|
|
|
|
cancelButtonText: 'No, cancel!',
|
|
|
|
showCancelButton: false,
|
|
|
|
showLoaderOnConfirm: false,
|
|
|
|
reverseButtons: true,
|
|
|
|
focusCancel: true,
|
|
|
|
confirmButtonText: 'Ok!'
|
|
|
|
})
|
|
|
|
}
|
|
|
|
this.getprogress(this.datadir)
|
|
|
|
},
|
|
|
|
refreshVuetable() {
|
|
|
|
this.$nextTick(()=>{
|
|
|
|
this.vuetablekeyf += 1
|
|
|
|
})
|
|
|
|
},
|
|
|
|
playbookinfoShow(value) {
|
|
|
|
return this.visibility[value]=true
|
|
|
|
},
|
|
|
|
playbookinfo(value) {
|
|
|
|
return this.playbookInfo=value
|
|
|
|
},
|
|
|
|
rowClicked(row, event) {
|
|
|
|
return {
|
|
|
|
html: true,
|
|
|
|
title: () => { return 'Hello <b>Popover:</b> ' + (++this.counter) },
|
|
|
|
content: () => { return 'The date is:<br><em>' + new Date() + '</em>' }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
loadsuccess(response) {
|
|
|
|
var data = response.data.data
|
|
|
|
this.fielddata=data
|
|
|
|
var n = data.length
|
|
|
|
n=n-1
|
|
|
|
},
|
|
|
|
onLoadError(payload) {
|
|
|
|
/*
|
|
|
|
//error2 "invalid_token" join-service.vue:684
|
|
|
|
//error2 "The access token provided has expired" join-service.vue:685
|
|
|
|
//error2 "Unauthorized" join-service.vue:686
|
|
|
|
//error2 401
|
|
|
|
*/
|
|
|
|
if(payload.response.status == '401'){
|
|
|
|
window.location.href = 'https://api-login.swarmlab.io:8089';
|
|
|
|
Vue.nextTick( () => window.location.href = 'https://api-login.swarmlab.io:8089')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
actions: {
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
</script>
|
|
|
|
<style>
|
|
|
|
.flex-fixed-width-item {
|
|
|
|
flex: 0 0 100px;
|
|
|
|
}
|
|
|
|
.modalinfo {
|
|
|
|
z-index: 10000000 !important;
|
|
|
|
position:fixed;
|
|
|
|
}
|
|
|
|
/* a container with flex-direction column */
|
|
|
|
|
|
|
|
.vue-notifyjs.notifications{
|
|
|
|
.alert{
|
|
|
|
z-index: 100;
|
|
|
|
}
|
|
|
|
.list-move {
|
|
|
|
transition: transform 0.3s, opacity 0.4s;
|
|
|
|
}
|
|
|
|
.list-item {
|
|
|
|
display: inline-block;
|
|
|
|
margin-right: 10px;
|
|
|
|
|
|
|
|
}
|
|
|
|
.list-enter-active {
|
|
|
|
transition: transform 0.2s ease-in, opacity 0.4s ease-in;
|
|
|
|
}
|
|
|
|
.list-leave-active {
|
|
|
|
transition: transform 1s ease-out, opacity 0.4s ease-out;
|
|
|
|
}
|
|
|
|
|
|
|
|
.list-enter {
|
|
|
|
opacity: 0;
|
|
|
|
transform: scale(1.1);
|
|
|
|
|
|
|
|
}
|
|
|
|
.list-leave-to {
|
|
|
|
opacity: 0;
|
|
|
|
transform: scale(1.2, 0.7);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.myscrool {
|
|
|
|
height: 500px;
|
|
|
|
max-height: 500px;
|
|
|
|
overflow-y: auto;
|
|
|
|
//margin-bottom: 10px;
|
|
|
|
-webkit-overflow-scrolling: touch;
|
|
|
|
}
|
|
|
|
pre {
|
|
|
|
//background-color: rgb(255, 247, 229);
|
|
|
|
background-color: #eff0f1;
|
|
|
|
border: 1px solid blue;
|
|
|
|
//white-space: pre-line;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.timeline {
|
|
|
|
width: 100%;
|
|
|
|
position: relative;
|
|
|
|
padding: 1px 0;
|
|
|
|
list-style: none;
|
|
|
|
font-weight: 500
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-item {
|
|
|
|
padding-left: 0;
|
|
|
|
padding-right: 30px
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-item.timeline-item-right,
|
|
|
|
.timeline .timeline-item:nth-of-type(even):not(.timeline-item-left) {
|
|
|
|
padding-left: 30px;
|
|
|
|
padding-right: 0
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-item .timeline-event {
|
|
|
|
width: 100%
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline:before {
|
|
|
|
border-right-style: solid
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline:before,
|
|
|
|
.timeline:after {
|
|
|
|
content: " ";
|
|
|
|
display: block
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline:after {
|
|
|
|
clear: both
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline:before {
|
|
|
|
content: "";
|
|
|
|
position: absolute;
|
|
|
|
top: 0;
|
|
|
|
left: 0;
|
|
|
|
bottom: 0;
|
|
|
|
width: 50%;
|
|
|
|
height: 100%!important;
|
|
|
|
margin-left: 2px;
|
|
|
|
border-right-width: 4px;
|
|
|
|
border-right-style: solid;
|
|
|
|
border-right-color: rgba(52, 40, 104, .1)
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-label .label {
|
|
|
|
background-color: #e76c90;
|
|
|
|
border-radius: 35px;
|
|
|
|
color: #fff;
|
|
|
|
display: inline;
|
|
|
|
font-size: .85rem;
|
|
|
|
font-weight: 600;
|
|
|
|
line-height: 1;
|
|
|
|
padding: .65rem 1.4rem;
|
|
|
|
text-align: center;
|
|
|
|
vertical-align: baseline;
|
|
|
|
white-space: nowrap
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline.timeline-line-solid:before {
|
|
|
|
border-right-style: solid
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline.timeline-line-dotted:before {
|
|
|
|
border-right-style: dotted
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline.timeline-line-dashed:before {
|
|
|
|
border-right-style: dashed
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-item {
|
|
|
|
position: relative;
|
|
|
|
float: left;
|
|
|
|
clear: left;
|
|
|
|
width: 50%;
|
|
|
|
margin-bottom: 20px
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-item:before,
|
|
|
|
.timeline .timeline-item:after {
|
|
|
|
content: "";
|
|
|
|
display: table
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-item:after {
|
|
|
|
clear: both
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-item:last-child {
|
|
|
|
margin-bottom: 0!important
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-item.timeline-item-right>.timeline-event,
|
|
|
|
.timeline .timeline-item:nth-of-type(even):not(.timeline-item-left)>.timeline-event {
|
|
|
|
float: right!important
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-item.timeline-item-right>.timeline-event:before,
|
|
|
|
.timeline .timeline-item:nth-of-type(even):not(.timeline-item-left)>.timeline-event:before,
|
|
|
|
.timeline .timeline-item.timeline-item-right>.timeline-event:after,
|
|
|
|
.timeline .timeline-item:nth-of-type(even):not(.timeline-item-left)>.timeline-event:after {
|
|
|
|
right: auto!important;
|
|
|
|
border-left-width: 0!important
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-item.timeline-item-right>.timeline-event:before,
|
|
|
|
.timeline .timeline-item:nth-of-type(even):not(.timeline-item-left)>.timeline-event:before {
|
|
|
|
left: -15px!important;
|
|
|
|
border-right-width: 15px!important
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-item.timeline-item-right>.timeline-event:after,
|
|
|
|
.timeline .timeline-item:nth-of-type(even):not(.timeline-item-left)>.timeline-event:after {
|
|
|
|
left: -14px!important;
|
|
|
|
border-right-width: 14px!important
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-item>.timeline-event:before {
|
|
|
|
top: 10px;
|
|
|
|
right: -15px;
|
|
|
|
border-top: 15px solid transparent;
|
|
|
|
border-left-width: 15px;
|
|
|
|
border-left-style: solid;
|
|
|
|
border-right-width: 0;
|
|
|
|
border-right-style: solid;
|
|
|
|
border-bottom: 15px solid transparent
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-item>.timeline-event:after {
|
|
|
|
top: 11px;
|
|
|
|
right: -14px;
|
|
|
|
border-top: 14px solid transparent;
|
|
|
|
border-left-width: 14px;
|
|
|
|
border-left-style: solid;
|
|
|
|
border-right-width: 0;
|
|
|
|
border-right-style: solid;
|
|
|
|
border-bottom: 14px solid transparent
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-item>.timeline-point {
|
|
|
|
top: 25px
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-item:nth-of-type(2) {
|
|
|
|
margin-top: 40px
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-item.timeline-item-left,
|
|
|
|
.timeline .timeline-item.timeline-item-right {
|
|
|
|
clear: both!important
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-item.timeline-item-right,
|
|
|
|
.timeline .timeline-item:nth-of-type(even):not(.timeline-item-left) {
|
|
|
|
float: right;
|
|
|
|
clear: right
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-item.timeline-item-right>.timeline-point,
|
|
|
|
.timeline .timeline-item:nth-of-type(even):not(.timeline-item-left)>.timeline-point {
|
|
|
|
left: -14px
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-item>.timeline-event {
|
|
|
|
position: relative;
|
|
|
|
float: left
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-item>.timeline-event:before {
|
|
|
|
border-left-color: rgba(52, 40, 104, .04);
|
|
|
|
border-right-color: rgba(52, 40, 104, .04)
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-item>.timeline-event:after {
|
|
|
|
border-left-color: rgba(52, 40, 104, .04);
|
|
|
|
border-right-color: rgba(52, 40, 104, .04)
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-item>.timeline-event:before,
|
|
|
|
.timeline .timeline-item>.timeline-event:after {
|
|
|
|
content: "";
|
|
|
|
display: inline-block;
|
|
|
|
position: absolute
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-item>.timeline-point {
|
|
|
|
color: #5d5386;
|
|
|
|
background: #5d5386;
|
|
|
|
right: -14px;
|
|
|
|
width: 12px;
|
|
|
|
height: 12px;
|
|
|
|
margin-top: -6px;
|
|
|
|
margin-left: 8px;
|
|
|
|
margin-right: 8px;
|
|
|
|
position: absolute;
|
|
|
|
z-index: 100;
|
|
|
|
border-width: 3px;
|
|
|
|
border-style: solid;
|
|
|
|
border-radius: 100%;
|
|
|
|
line-height: 20px;
|
|
|
|
text-align: center;
|
|
|
|
box-shadow: 0 0 0 5px #f2f3f8
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-label {
|
|
|
|
position: relative;
|
|
|
|
float: left;
|
|
|
|
clear: left;
|
|
|
|
width: 50%;
|
|
|
|
margin-bottom: 20px;
|
|
|
|
top: 1px;
|
|
|
|
width: 100%;
|
|
|
|
margin-left: auto;
|
|
|
|
margin-right: auto;
|
|
|
|
padding: 0;
|
|
|
|
text-align: center
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-label:before,
|
|
|
|
.timeline .timeline-label:after {
|
|
|
|
content: "";
|
|
|
|
display: table
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-label:after {
|
|
|
|
clear: both
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-label:last-child {
|
|
|
|
margin-bottom: 0!important
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-label + .timeline-item {
|
|
|
|
margin-top: 0
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .timeline-label + .timeline-item + .timeline-item {
|
|
|
|
margin-top: 40px
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .time-right {
|
|
|
|
color: rgba(52, 40, 104, .5);
|
|
|
|
position: absolute;
|
|
|
|
bottom: 0;
|
|
|
|
right: 0;
|
|
|
|
font-size: .85rem;
|
|
|
|
font-weight: 500
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .time-left {
|
|
|
|
color: rgba(52, 40, 104, .5);
|
|
|
|
position: absolute;
|
|
|
|
bottom: 0;
|
|
|
|
left: 0;
|
|
|
|
font-size: .85rem;
|
|
|
|
font-weight: 500
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .widget-header .user-image {
|
|
|
|
display: inline-block;
|
|
|
|
vertical-align: middle;
|
|
|
|
margin-right: 1.07rem
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .widget-header .user-image img {
|
|
|
|
width: 50px
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .widget-header .title {
|
|
|
|
color: #2c304d;
|
|
|
|
font-size: 1rem
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .widget-header .username {
|
|
|
|
color: #e76c90
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .widget-header .time {
|
|
|
|
font-size: .85rem
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .widget-body {
|
|
|
|
padding: 1rem 1.4rem
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .widget-footer {
|
|
|
|
border-top: 1px solid #eee;
|
|
|
|
margin: 0 1.4rem;
|
|
|
|
padding: 1.07rem 0
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .users-like {
|
|
|
|
padding: 0
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .users-like a {
|
|
|
|
margin: 0 -1.6rem 0 0;
|
|
|
|
transition: all 0.4s ease
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .users-like a:hover {
|
|
|
|
margin-right: -.3rem
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .users-like img {
|
|
|
|
width: 40px;
|
|
|
|
border: .25rem solid #fff
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .users-like a.view-more {
|
|
|
|
background: #5d5386;
|
|
|
|
color: #fff;
|
|
|
|
width: 40px;
|
|
|
|
height: 40px;
|
|
|
|
border: .25rem solid #fff;
|
|
|
|
border-radius: 50%;
|
|
|
|
vertical-align: middle;
|
|
|
|
font-size: .85rem;
|
|
|
|
text-align: center;
|
|
|
|
line-height: 30px;
|
|
|
|
margin-right: 0
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .widget-footer .meta li {
|
|
|
|
display: inline-block;
|
|
|
|
margin-right: .5rem
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .widget-footer .meta li:last-child {
|
|
|
|
margin-right: 0
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .widget-footer .meta li a {
|
|
|
|
color: rgba(52, 40, 104, .3)
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .widget-footer .meta li a:hover {
|
|
|
|
color: rgba(52, 40, 104, .9)
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .widget-footer .meta li i {
|
|
|
|
font-size: 1.8rem;
|
|
|
|
vertical-align: middle;
|
|
|
|
margin-right: .3rem
|
|
|
|
}
|
|
|
|
|
|
|
|
.timeline .widget-footer .meta li .numb {
|
|
|
|
vertical-align: middle
|
|
|
|
}
|
|
|
|
|
|
|
|
@media screen and (max-width:768px) {
|
|
|
|
.timeline.timeline {
|
|
|
|
width: 100%;
|
|
|
|
max-width: 100%
|
|
|
|
}
|
|
|
|
.timeline.timeline .timeline-item {
|
|
|
|
padding-left: 72px;
|
|
|
|
padding-right: 0
|
|
|
|
}
|
|
|
|
.timeline.timeline .timeline-item.timeline-item-right,
|
|
|
|
.timeline.timeline .timeline-item:nth-of-type(even):not(.timeline-item-left) {
|
|
|
|
padding-left: 72px;
|
|
|
|
padding-right: 0
|
|
|
|
}
|
|
|
|
.timeline.timeline .timeline-item .timeline-event {
|
|
|
|
width: 100%
|
|
|
|
}
|
|
|
|
.timeline.timeline:before {
|
|
|
|
left: 42px;
|
|
|
|
width: 0;
|
|
|
|
margin-left: -1px
|
|
|
|
}
|
|
|
|
.timeline.timeline .timeline-item {
|
|
|
|
width: 100%;
|
|
|
|
margin-bottom: 20px
|
|
|
|
}
|
|
|
|
.timeline.timeline .timeline-item:nth-of-type(even) {
|
|
|
|
margin-top: 0
|
|
|
|
}
|
|
|
|
.timeline.timeline .timeline-item>.timeline-event {
|
|
|
|
float: right!important
|
|
|
|
}
|
|
|
|
.timeline.timeline .timeline-item>.timeline-event:before,
|
|
|
|
.timeline.timeline .timeline-item>.timeline-event:after {
|
|
|
|
right: auto!important;
|
|
|
|
border-left-width: 0!important
|
|
|
|
}
|
|
|
|
.timeline.timeline .timeline-item>.timeline-event:before {
|
|
|
|
left: -15px!important;
|
|
|
|
border-right-width: 15px!important
|
|
|
|
}
|
|
|
|
.timeline.timeline .timeline-item>.timeline-event:after {
|
|
|
|
left: -14px!important;
|
|
|
|
border-right-width: 14px!important
|
|
|
|
}
|
|
|
|
.timeline.timeline .timeline-item>.timeline-point {
|
|
|
|
transform: translateX(-50%);
|
|
|
|
left: 42px!important;
|
|
|
|
margin-left: 0
|
|
|
|
}
|
|
|
|
.timeline.timeline .timeline-label {
|
|
|
|
transform: translateX(-50%);
|
|
|
|
margin: 0 0 20px 42px
|
|
|
|
}
|
|
|
|
.timeline.timeline .timeline-label + .timeline-item + .timeline-item {
|
|
|
|
margin-top: 0
|
|
|
|
}
|
|
|
|
.timeline .time-right {
|
|
|
|
left: 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.rounded-widget .widget {
|
|
|
|
border-radius: 4px
|
|
|
|
}
|
|
|
|
|
|
|
|
.rounded-widget .widget-image {
|
|
|
|
border-radius: 4px
|
|
|
|
}
|
|
|
|
|
|
|
|
.rounded-widget .widget-header {
|
|
|
|
border-radius: 4px 4px 0 0
|
|
|
|
}
|
|
|
|
|
|
|
|
.rounded-widget .widget-footer {
|
|
|
|
border-radius: 0 0 4px 4px
|
|
|
|
}
|
|
|
|
|
|
|
|
.widget {
|
|
|
|
background: #fff;
|
|
|
|
border-radius: 0;
|
|
|
|
border: none;
|
|
|
|
margin-bottom: 30px
|
|
|
|
}
|
|
|
|
|
|
|
|
.widget-image {
|
|
|
|
background: #fff;
|
|
|
|
border-radius: 0;
|
|
|
|
border: none;
|
|
|
|
margin-bottom: 30px;
|
|
|
|
position: relative
|
|
|
|
}
|
|
|
|
|
|
|
|
.widget-header {
|
|
|
|
background: #fff;
|
|
|
|
padding: .85rem 1.4rem;
|
|
|
|
position: relative;
|
|
|
|
width: 100%
|
|
|
|
}
|
|
|
|
|
|
|
|
.widget-header.bordered {
|
|
|
|
border-bottom: .07rem solid #eee
|
|
|
|
}
|
|
|
|
|
|
|
|
.widget-header.no-actions {
|
|
|
|
padding: 1.49rem
|
|
|
|
}
|
|
|
|
|
|
|
|
.widget-options .dropdown-toggle {
|
|
|
|
color: #98a8b4;
|
|
|
|
background: none;
|
|
|
|
border: none;
|
|
|
|
padding: 0;
|
|
|
|
font-size: 1.7rem;
|
|
|
|
}
|
|
|
|
|
|
|
|
.widget-header h1,
|
|
|
|
.widget-header h2,
|
|
|
|
.widget-header h3,
|
|
|
|
.widget-header h4,
|
|
|
|
.widget-header h5,
|
|
|
|
.widget-header h6 {
|
|
|
|
color: #2c304d;
|
|
|
|
margin-bottom: 0
|
|
|
|
}
|
|
|
|
|
|
|
|
.section-title h1,
|
|
|
|
.section-title h2,
|
|
|
|
.section-title h3,
|
|
|
|
.section-title h4,
|
|
|
|
.section-title h5,
|
|
|
|
.section-title h6 {
|
|
|
|
color: #2c304d;
|
|
|
|
font-weight: 600;
|
|
|
|
margin-bottom: 0
|
|
|
|
}
|
|
|
|
|
|
|
|
.widget-header h2 {
|
|
|
|
color: #2c304d;
|
|
|
|
font-size: 1.2rem;
|
|
|
|
display: table-cell;
|
|
|
|
vertical-align: middle;
|
|
|
|
margin-right: auto
|
|
|
|
}
|
|
|
|
|
|
|
|
.widget-header h2 i {
|
|
|
|
color: #aea9c3;
|
|
|
|
font-size: 1.8rem;
|
|
|
|
padding-right: .5rem;
|
|
|
|
vertical-align: middle
|
|
|
|
}
|
|
|
|
|
|
|
|
.widget-body {
|
|
|
|
padding: 1.4rem
|
|
|
|
}
|
|
|
|
|
|
|
|
.widget-image-footer {
|
|
|
|
background: #fff;
|
|
|
|
position: absolute;
|
|
|
|
bottom: 0;
|
|
|
|
width: 100%;
|
|
|
|
padding: 1.2rem 0;
|
|
|
|
z-index: 1
|
|
|
|
}
|
|
|
|
|
|
|
|
.widget-footer {
|
|
|
|
background: #fff;
|
|
|
|
padding: 1rem 1.07rem;
|
|
|
|
position: relative
|
|
|
|
}
|
|
|
|
|
|
|
|
.widget-footer.big {
|
|
|
|
padding: 2.1rem 1.07rem
|
|
|
|
}
|
|
|
|
|
|
|
|
.no-border {
|
|
|
|
border: 0 none!important;
|
|
|
|
}
|
|
|
|
|
|
|
|
.no-bg {
|
|
|
|
background: none!important;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</style>
|