├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── arbiter-cases └── .gitignore ├── arbiter-docker └── elk │ ├── 02-beats-input.conf │ ├── 30-output.conf │ └── Dockerfile ├── arbiter-web ├── Dockerfile ├── Dockerfile_local ├── arbiter │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── asgi.py │ ├── common │ │ ├── __init__.py │ │ └── utils.py │ ├── core │ │ ├── __init__.py │ │ ├── apps.py │ │ ├── consumers.py │ │ ├── models.py │ │ ├── routing.py │ │ ├── templates │ │ │ └── case │ │ │ │ ├── component │ │ │ │ ├── arbiter-navbar.vue │ │ │ │ ├── case-float-btn.vue │ │ │ │ ├── case-paper.vue │ │ │ │ ├── code-float-btn.vue │ │ │ │ ├── code-paper.vue │ │ │ │ ├── menu-icon-button.vue │ │ │ │ ├── nav-slide.vue │ │ │ │ └── user-avatar.vue │ │ │ │ ├── index.html │ │ │ │ └── login.html │ │ ├── tests.py │ │ ├── urls.py │ │ ├── util │ │ │ ├── __init__.py │ │ │ └── askpass.py │ │ └── views.py │ ├── migrations │ │ ├── 0001_initial.py │ │ ├── 0002_case_run_info_status.py │ │ ├── 0003_auto_20180214_1452.py │ │ ├── 0004_auto_20180223_1416.py │ │ ├── 0005_case_run_info_deleted.py │ │ ├── 0006_auto_20180225_1306.py │ │ └── __init__.py │ ├── models.py │ ├── routing.py │ ├── settings.py │ ├── static │ │ └── arbiter │ │ │ ├── css │ │ │ ├── datatables │ │ │ │ ├── dataTables.bootstrap.css │ │ │ │ ├── dataTables.bootstrap.min.css │ │ │ │ ├── dataTables.bootstrap4.css │ │ │ │ ├── dataTables.bootstrap4.min.css │ │ │ │ ├── dataTables.foundation.css │ │ │ │ ├── dataTables.foundation.min.css │ │ │ │ ├── dataTables.jqueryui.css │ │ │ │ ├── dataTables.jqueryui.min.css │ │ │ │ ├── dataTables.material.css │ │ │ │ ├── dataTables.material.min.css │ │ │ │ ├── dataTables.semanticui.css │ │ │ │ ├── dataTables.semanticui.min.css │ │ │ │ ├── dataTables.uikit.css │ │ │ │ ├── dataTables.uikit.min.css │ │ │ │ ├── jquery.dataTables.css │ │ │ │ ├── jquery.dataTables.min.css │ │ │ │ └── jquery.dataTables_themeroller.css │ │ │ ├── element │ │ │ │ ├── fonts │ │ │ │ │ ├── element-icons.ttf │ │ │ │ │ └── element-icons.woff │ │ │ │ └── index.css │ │ │ ├── index.css │ │ │ ├── login.css │ │ │ ├── material-icons.css │ │ │ ├── materialize.css │ │ │ ├── materialize.min.css │ │ │ ├── muse │ │ │ │ ├── muse-ui.css │ │ │ │ ├── theme-teal.css │ │ │ │ └── theme-teal.min.css │ │ │ ├── navbar.css │ │ │ ├── scrollbar │ │ │ │ ├── app.css │ │ │ │ └── vue2-scrollbar.css │ │ │ └── wholog │ │ │ │ ├── index.css │ │ │ │ └── statistic-log.css │ │ │ ├── fonts │ │ │ ├── material │ │ │ │ └── o_1bgljqsqrvbv78v8lu1fsr1trca.woff2 │ │ │ └── roboto │ │ │ │ ├── Roboto-Bold.woff │ │ │ │ ├── Roboto-Bold.woff2 │ │ │ │ ├── Roboto-Light.woff │ │ │ │ ├── Roboto-Light.woff2 │ │ │ │ ├── Roboto-Medium.woff │ │ │ │ ├── Roboto-Medium.woff2 │ │ │ │ ├── Roboto-Regular.woff │ │ │ │ ├── Roboto-Regular.woff2 │ │ │ │ ├── Roboto-Thin.woff │ │ │ │ └── Roboto-Thin.woff2 │ │ │ ├── imgs │ │ │ ├── bg-pro.png │ │ │ ├── favicon.ico │ │ │ ├── progress.png │ │ │ └── team_logo.png │ │ │ └── js │ │ │ ├── common │ │ │ ├── ace │ │ │ │ ├── ace.js │ │ │ │ ├── mode-python.js │ │ │ │ ├── theme-ambiance.js │ │ │ │ ├── theme-chrome.js │ │ │ │ ├── theme-dawn.js │ │ │ │ ├── theme-github.js │ │ │ │ └── theme-iplastic.js │ │ │ ├── common.js │ │ │ ├── element │ │ │ │ └── index.js │ │ │ ├── get-res.js │ │ │ ├── index.js │ │ │ ├── muse │ │ │ │ └── muse-ui.js │ │ │ ├── snow.js │ │ │ └── vue │ │ │ │ ├── vue-resource.js │ │ │ │ ├── vue-resource.min.js │ │ │ │ ├── vue-router.js │ │ │ │ ├── vue-router.min.js │ │ │ │ ├── vue.js │ │ │ │ ├── vue.min.js │ │ │ │ ├── vue2-scrollbar.js │ │ │ │ └── vuex.js │ │ │ ├── core │ │ │ ├── app.js │ │ │ ├── component │ │ │ │ ├── arbiter-navbar.js │ │ │ │ ├── arbiter-slide.js │ │ │ │ ├── case-float-btn.js │ │ │ │ ├── case-paper.js │ │ │ │ ├── code-float-btn.js │ │ │ │ ├── code-paper.js │ │ │ │ ├── menu-icon-Button.js │ │ │ │ └── user-avatar.js │ │ │ └── route.js │ │ │ ├── echarts.js │ │ │ ├── login.js │ │ │ ├── store.js │ │ │ └── wholog │ │ │ ├── app.js │ │ │ ├── component │ │ │ ├── header-components.js │ │ │ ├── history-log.js │ │ │ ├── log-slide.js │ │ │ └── statistic-log.js │ │ │ └── route.js │ ├── urls.py │ ├── wholog │ │ ├── __init__.py │ │ ├── admin.py │ │ ├── apps.py │ │ ├── models.py │ │ ├── templates │ │ │ ├── component │ │ │ │ ├── arbiter-header.vue │ │ │ │ ├── case-float-btn.vue │ │ │ │ ├── history-log.vue │ │ │ │ ├── log-slide.vue │ │ │ │ ├── menu-icon-button.vue │ │ │ │ ├── statistic-log.vue │ │ │ │ └── user-avatar.vue │ │ │ └── index.html │ │ ├── tests.py │ │ ├── urls.py │ │ └── views.py │ └── wsgi.py ├── config.py ├── docker-compose.yml ├── docker_start.sh ├── initadmin.py ├── manage.py ├── requirements.txt └── stack-fix.c ├── doc ├── .gitignore └── import.gif └── tasks.todo /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js linguist-language = python 2 | *.css linguist-language = python 3 | *.html linguist-language = python -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # IDEA Files # 3 | 4 | *.iml 5 | *.ipr 6 | *.iws 7 | *.idea 8 | *.history 9 | 10 | __pycache__ 11 | !.gitignore 12 | arbiter-cases/* 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Image text](https://github.com/shimine/cua-arbiter/blob/master/doc/import.gif) 2 | ## arbiter是什么 3 | - python实现的web IDE,可以导入&编辑脚本工程,进行测试执行和编辑的操作 4 | - 可以对测试日志进行查询和统计 5 | 6 | ## 依赖环境 7 | - postgresql存储用户信息 8 | - redis保证实时websocket 9 | - elk保存日志 10 | 11 | ## 部署步骤: 12 | 1. clone code 13 | 2. 进入到 arbiter-web/ cd arbiter-web 14 | 3. 安装依赖文件 pip install -r requirements.txt 15 | 4. 安装好postgresql redis elk。在config.py中修改成相对应的配置属性 16 | 5. 修改运行时选项,设置 manage.py路径,脚本命令为runserver 17 | 6. 或直接使用 python manage.py runserver 18 | 19 | ## 浏览器支持 20 | - chrome 60+ 21 | - firefox 55+ 22 | 23 | ##### 交流QQ:693411960 24 | -------------------------------------------------------------------------------- /arbiter-cases/.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse Project Files # 2 | 3 | .classpath 4 | .project 5 | .settings 6 | 7 | # IntelliJ IDEA Files # 8 | 9 | *.iml 10 | *.ipr 11 | *.iws 12 | *.idea 13 | -------------------------------------------------------------------------------- /arbiter-docker/elk/02-beats-input.conf: -------------------------------------------------------------------------------- 1 | input { 2 | redis { 3 | data_type =>"list" 4 | key => "logstash-arbiter-list" 5 | host =>"redis" 6 | port =>6379 7 | db =>11 8 | codec =>"json" 9 | } 10 | } -------------------------------------------------------------------------------- /arbiter-docker/elk/30-output.conf: -------------------------------------------------------------------------------- 1 | output { 2 | elasticsearch { 3 | hosts => "localhost" 4 | index => "logstash-arbiter" 5 | 6 | } 7 | stdout { 8 | codec => rubydebug {} 9 | } 10 | } -------------------------------------------------------------------------------- /arbiter-docker/elk/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM sebp/elk 2 | 3 | RUN rm -rf /etc/logstash/conf.d/02-beats-input.conf 4 | ADD ./02-beats-input.conf /etc/logstash/conf.d/02-beats-input.conf 5 | RUN rm -rf /etc/logstash/conf.d/30-output.conf 6 | ADD ./30-output.conf /etc/logstash/conf.d/30-output.conf -------------------------------------------------------------------------------- /arbiter-web/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.6.2-alpine 2 | 3 | RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories 4 | RUN apk add --no-cache postgresql-dev libffi-dev gcc musl-dev libxml2-dev libxslt-dev git bash 5 | WORKDIR /usr/src/app 6 | COPY . . 7 | RUN gcc -shared -fPIC stack-fix.c -o stack-fix.so 8 | ENV LD_PRELOAD = /usr/src/app/stack-fix.so 9 | RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host pypi.tuna.tsinghua.edu.cn 10 | #RUN pip install --no-cache-dir -r requirements.txt 11 | EXPOSE 8000:8000 12 | 13 | CMD sh docker_start.sh -------------------------------------------------------------------------------- /arbiter-web/Dockerfile_local: -------------------------------------------------------------------------------- 1 | FROM shimine/cua-arbiter:1.3-alpine 2 | 3 | WORKDIR /usr/src/app 4 | COPY . . 5 | 6 | CMD sh docker_start.sh -------------------------------------------------------------------------------- /arbiter-web/arbiter/__init__.py: -------------------------------------------------------------------------------- 1 | default_app_config = 'arbiter.apps.CaseManagerConfig' -------------------------------------------------------------------------------- /arbiter-web/arbiter/admin.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from django.contrib import admin 3 | from django.contrib.auth import get_user_model 4 | from django.contrib.admin.widgets import FilteredSelectMultiple 5 | from django.contrib.auth.models import Group 6 | 7 | admin.AdminSite.site_header = "arbiter接口测试数据管理" 8 | 9 | User = get_user_model() 10 | 11 | 12 | # Create ModelForm based on the Group model. 13 | class GroupAdminForm(forms.ModelForm): 14 | class Meta: 15 | model = Group 16 | exclude = [] 17 | 18 | # Add the users field. 19 | users = forms.ModelMultipleChoiceField( 20 | queryset=User.objects.all(), 21 | required=False, 22 | # Use the pretty 'filter_horizontal widget'. 23 | widget=FilteredSelectMultiple('users', False) 24 | ) 25 | 26 | def __init__(self, *args, **kwargs): 27 | # Do the normal form initialisation. 28 | super(GroupAdminForm, self).__init__(*args, **kwargs) 29 | # If it is an existing group (saved objects have a pk). 30 | if self.instance.pk: 31 | # Populate the users field with the current Group users. 32 | self.fields['users'].initial = self.instance.user_set.all() 33 | 34 | def save_m2m(self): 35 | # Add the users to the Group. 36 | self.instance.user_set = self.cleaned_data['users'] 37 | 38 | def save(self, *args, **kwargs): 39 | # Default save 40 | instance = super(GroupAdminForm, self).save() 41 | # Save many-to-many data 42 | self.save_m2m() 43 | return instance 44 | 45 | 46 | # Unregister the original Group admin. 47 | admin.site.unregister(Group) 48 | 49 | 50 | # Create a new Group admin. 51 | class GroupAdmin(admin.ModelAdmin): 52 | # Use our custom form. 53 | form = GroupAdminForm 54 | # Filter permissions horizontal as well. 55 | filter_horizontal = ['permissions'] 56 | 57 | 58 | # Register the new Group ModelAdmin. 59 | admin.site.register(Group, GroupAdmin) 60 | # Register your models here. 61 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/apps.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from django.apps import AppConfig 4 | 5 | 6 | class CaseManagerConfig(AppConfig): 7 | name = 'arbiter' 8 | 9 | def ready(self): 10 | case_base_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), 11 | "arbiter-cases") 12 | case_path = os.getenv("CASEPATH") 13 | case_base_path = os.path.join(case_base_path, case_path.split('/')[0]) 14 | case_base_path = case_base_path.replace("\\", "/") 15 | os.environ["PYTHONPATH"] = case_base_path 16 | os.putenv("PYTHONPATH", case_base_path) 17 | from arbiter.models import Git_Info 18 | from arbiter.core.models import CaseList 19 | from arbiter.models import Case_List 20 | try: 21 | if Git_Info.objects.count() > 0: 22 | git_info = Git_Info.objects.all().first() 23 | os.environ['GIT_USERNAME'] = git_info.user_name 24 | os.environ['GIT_PASSWORD'] = git_info.password 25 | case_list = Case_List.objects.get() 26 | case_list.name = "arbiter_cases" 27 | case_list.data = CaseList.getList() 28 | case_list.save() 29 | except: 30 | pass 31 | os.environ['GIT_ASKPASS'] = os.path.join( 32 | os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'core'), 'util'), 33 | 'askpass.py') 34 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/asgi.py: -------------------------------------------------------------------------------- 1 | import os 2 | import channels.asgi 3 | 4 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "arbiter.settings") # 这里填的是你的配置文件settings.py的位置 5 | channel_layer = channels.asgi.get_channel_layer() 6 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/common/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuaFramework/cua-arbiter/61b2ea5d8b7c825b75d0f333d202e5703e0565a9/arbiter-web/arbiter/common/__init__.py -------------------------------------------------------------------------------- /arbiter-web/arbiter/common/utils.py: -------------------------------------------------------------------------------- 1 | import time 2 | import datetime 3 | import hashlib 4 | 5 | 6 | # 生成uuid 7 | def generate_id(): 8 | m = hashlib.md5(str(time.clock()).encode('utf-8')) 9 | return m.hexdigest() 10 | 11 | 12 | # 获取当前时间 13 | # typeid=1 ,格式:2017-09-05 13:58:41 14 | # typeid=1 ,格式:时间戳形式:1505112338.4971874 15 | def get_now_time(type_id): 16 | if type_id == 1: 17 | return datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f') 18 | if type_id == 2: 19 | return datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%fZ') 20 | 21 | 22 | # 处理logData数据 23 | def get_log_data(log_data): 24 | log_str = log_data.split("请求")[1].split("]")[0] # 获得请求类型+耗时+code部分数据 25 | if log_str is not None: 26 | result_list = log_str.split(" ") 27 | type_value = result_list[0].split(":")[1] 28 | consume_time = result_list[1].split(":")[1].split("m")[0] 29 | response_code = result_list[2].split(":")[1] 30 | response_value = {"request_type": type_value, "consume_time": consume_time, "response_code": response_code} 31 | return response_value 32 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuaFramework/cua-arbiter/61b2ea5d8b7c825b75d0f333d202e5703e0565a9/arbiter-web/arbiter/core/__init__.py -------------------------------------------------------------------------------- /arbiter-web/arbiter/core/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class CoreConfig(AppConfig): 5 | name = 'arbiter.core' 6 | 7 | 8 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/core/consumers.py: -------------------------------------------------------------------------------- 1 | from subprocess import Popen, PIPE, STDOUT 2 | from channels.sessions import channel_session 3 | from arbiter.models import Case_Run_Info 4 | from ..settings import redis_elk_pool 5 | import json 6 | import redis 7 | from ..common import utils 8 | 9 | # 一个管道大概会持续30s 10 | 11 | 12 | isEditFilesName = [] # 全局变量,保存正在被编辑的文件名 13 | # redis 配置 14 | 15 | # logstash 在redis key值 16 | logstash_redis_key = 'logstash-arbiter-list' 17 | # redis 连接 18 | re = redis.Redis(connection_pool=redis_elk_pool) 19 | 20 | 21 | # 当连接上时,发回去一个connect字符串 22 | @channel_session 23 | def ws_connect(message): 24 | message.reply_channel.send({"accept": True}) 25 | 26 | 27 | # 将发来的信息原样返回 28 | @channel_session 29 | def ws_message(message): 30 | cmd = message.content['text'] 31 | log_content = '' 32 | # 获得本次运行的用例id 33 | log_id = utils.generate_id() 34 | # 通过自定义字符分割需要的类型 35 | if cmd.split(' ')[0] == 'runCase': 36 | message.reply_channel.send({ 37 | "text": "**********************************************开始执行***********************************************" 38 | }, immediately=True) 39 | case_name = cmd.split(' ')[1] 40 | user_name = cmd.split(' ')[2] 41 | task_name = cmd.split(' ')[3] 42 | run_time = utils.get_now_time(1) 43 | runcmd = Popen(['nosetests', '-P', '--nologcapture', case_name], 44 | bufsize=0, stdout=PIPE, stderr=STDOUT) 45 | text = None 46 | while True: 47 | line = runcmd.stdout.readline() 48 | if not line: 49 | break 50 | text = line.decode('utf-8') 51 | if 'Ran' in text and 'test' in text: 52 | info_text = text 53 | # 拼接日志内容 54 | case_name = case_name 55 | create_time = utils.get_now_time(2) 56 | data = {'create_time': create_time, 'logId': log_id, 'case': case_name, 'author': user_name, 57 | 'logData': text} 58 | # 向redis中发送值 59 | logData = json.dumps(data) 60 | re.lpush(logstash_redis_key, logData) 61 | message.reply_channel.send({ 62 | "text": text 63 | }, immediately=True) 64 | 65 | message.reply_channel.send({ 66 | "text": "**********************************************结束执行***********************************************" 67 | }, immediately=True) 68 | num = info_text.split("Ran")[1].split("test")[0].strip() 69 | duration = info_text.split(" in")[1].split("s")[0].strip() 70 | # 存一条logId到mysql 71 | # 将日志存入mysql 72 | # mysql 存入格式和内容需要完善 73 | dic = {'log_id': log_id, 'case_name': case_name, 'run_time': run_time, 'author': user_name, 74 | 'duration': duration, 'num': num, 75 | 'task_name': task_name, 'result': text.split("(")[0].strip().replace("\n", "")} 76 | Case_Run_Info.objects.create(**dic) 77 | 78 | if cmd.split(' ')[0] == 'validateEdit': 79 | 80 | if cmd.split(' ')[1] == '0': 81 | if cmd.split(' ')[2] in isEditFilesName: 82 | message.reply_channel.send({ 83 | "text": "isBusy" 84 | }, immediately=True) 85 | isEditFilesName.append(cmd.split(' ')[2]) 86 | if cmd.split(' ')[1] == '1': 87 | isEditFilesName.remove(cmd.split(' ')[2]) 88 | 89 | 90 | # 断开连接时发送一个disconnect字符串 91 | @channel_session 92 | def ws_disconnect(message): 93 | message.reply_channel.send({"disc": True}) 94 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/core/models.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | from subprocess import Popen, PIPE, STDOUT 3 | import os 4 | from django.contrib.auth.models import Group 5 | 6 | 7 | # Create your models here. 8 | # case模型 9 | def Splitmap(src_map, i): 10 | dst_map = {} 11 | for case_path, case_name in src_map.items(): 12 | path_arry = case_path.split(":")[0].split(".") 13 | if len(path_arry) > i + 1: 14 | if path_arry[i] not in dst_map: 15 | dst_map[path_arry[i]] = {} 16 | dst_map[path_arry[i]][case_path] = case_name 17 | else: 18 | dst_map[case_path] = case_name 19 | i = i + 1 20 | for k, y in dst_map.items(): 21 | if isinstance(y, dict): 22 | dst_map[k] = Splitmap(y, i) 23 | return dst_map 24 | 25 | 26 | def restructure(src_map): 27 | dst_map = {} 28 | for model, cases in src_map.items(): 29 | if model not in dst_map: 30 | dst_map[model] = {} 31 | dst_map[model] = Splitmap(cases, 2) 32 | return dst_map 33 | 34 | 35 | class CaseList: 36 | 37 | @staticmethod 38 | def getList(): 39 | runcmd = Popen(['nosetests', '-vvv', '--collect-only', '-w', '../arbiter-cases'], bufsize=0, 40 | stdout=PIPE, stderr=STDOUT) 41 | log_list = [] 42 | case_path = os.getenv("CASEPATH") 43 | case_path_obj = case_path.split('/')[0] 44 | case_path_fd = case_path.split('/')[1] 45 | case_class = case_path_obj + "." + case_path_fd 46 | for line in runcmd.stdout: 47 | log_list.append(line.decode('utf-8').rstrip()) 48 | # 修改显示名称 49 | case_list = [] 50 | res_tree = {} 51 | case_map = {} 52 | case_name = None 53 | for elem in log_list: 54 | if elem.find("Preparing test case ") != -1: 55 | if elem.find("(") != -1: 56 | x = elem.split("Preparing test case ")[1] 57 | temp = x.split(" (" + case_path_obj + ".")[1].split(")")[0] + "." + x.split(" (")[0] 58 | else: 59 | temp = elem.split("Preparing test case " + case_path_obj + ".")[1] 60 | 61 | model = temp.split(".")[1] 62 | case_name = temp[::-1].replace(".", ":", 2).replace(":", ".", 1)[::-1] 63 | if model not in res_tree: 64 | res_tree[model] = {} 65 | case_map = res_tree[model] 66 | case_map[case_name] = temp[::-1].replace(".", ":", 2).replace(":", ".", 1)[::-1] 67 | case_list.append( 68 | temp[::-1].replace(".", ":", 2).replace(":", ".", 1)[::-1]) 69 | elif elem.find(" ... ok") != -1: 70 | des_str = elem.split(" ...")[0] 71 | if elem.find("(") != -1: 72 | temp_str = des_str.split(")")[0].split(".") 73 | des_str = temp_str[len(temp_str) - 1] + "." + des_str.split(" (")[0] 74 | if case_class in des_str: 75 | des_str = des_str.split(case_class + ".")[1].split(".", 1)[1] 76 | case_map[case_name] = des_str 77 | res_tree = restructure(res_tree) 78 | return res_tree 79 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/core/routing.py: -------------------------------------------------------------------------------- 1 | from channels.routing import route 2 | 3 | from . import consumers 4 | 5 | case_manager_routing = [ 6 | # route("http.request", consumers.http_consumer), 这个表项比较特殊,他响应的是http.request,也就是说有HTTP请求时就会响应,同时urls.py里面的表单会失效 7 | route("websocket.connect", consumers.ws_connect), # 当WebSocket请求连接上时调用consumers.ws_connect函数 8 | route("websocket.receive", consumers.ws_message), # 当WebSocket请求发来消息时。。。 9 | route("websocket.disconnect", consumers.ws_disconnect), # 当WebSocket请求断开连接时。。。 10 | ] 11 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/core/templates/case/component/arbiter-navbar.vue: -------------------------------------------------------------------------------- 1 | {% verbatim %} 2 | 19 | {% endverbatim %} -------------------------------------------------------------------------------- /arbiter-web/arbiter/core/templates/case/component/case-float-btn.vue: -------------------------------------------------------------------------------- 1 | {% verbatim %} 2 | 22 | {% endverbatim %} -------------------------------------------------------------------------------- /arbiter-web/arbiter/core/templates/case/component/case-paper.vue: -------------------------------------------------------------------------------- 1 | {% verbatim %} 2 | 58 | {% endverbatim %} -------------------------------------------------------------------------------- /arbiter-web/arbiter/core/templates/case/component/code-float-btn.vue: -------------------------------------------------------------------------------- 1 | {% verbatim %} 2 | 26 | {% endverbatim %} -------------------------------------------------------------------------------- /arbiter-web/arbiter/core/templates/case/component/code-paper.vue: -------------------------------------------------------------------------------- 1 | {% verbatim %} 2 | 7 | {% endverbatim %} -------------------------------------------------------------------------------- /arbiter-web/arbiter/core/templates/case/component/menu-icon-button.vue: -------------------------------------------------------------------------------- 1 | {% verbatim %} 2 | 15 | {% endverbatim %} -------------------------------------------------------------------------------- /arbiter-web/arbiter/core/templates/case/component/nav-slide.vue: -------------------------------------------------------------------------------- 1 | {% verbatim %} 2 | 48 | {% endverbatim %} -------------------------------------------------------------------------------- /arbiter-web/arbiter/core/templates/case/component/user-avatar.vue: -------------------------------------------------------------------------------- 1 | {% verbatim %} 2 | 20 | {% endverbatim %} 21 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/core/templates/case/index.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | {% load i18n %} 3 | {% load staticfiles %} 4 | 5 | 6 | 7 | 8 | 9 | 10 | arbiter 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {% block head %} 19 | {% endblock head %} 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | {% verbatim %} 31 |
32 | 33 |
34 |
35 | 36 | 37 |
38 |
39 | 40 |
41 |
42 |
43 |
44 |
45 | {% endverbatim %} 46 |
47 | {% include "case/component/menu-icon-button.vue" %} 48 | {% include "case/component/user-avatar.vue" %} 49 | {% include "case/component/arbiter-navbar.vue" %} 50 | {% include "case/component/nav-slide.vue" %} 51 | {% include "case/component/case-paper.vue" %} 52 | {% include "case/component/code-paper.vue" %} 53 | {% include "case/component/code-float-btn.vue" %} 54 | {% include "case/component/case-float-btn.vue" %} 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/core/templates/case/login.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | {% load i18n %} 3 | {% load staticfiles %} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 登录 11 | 12 | 13 | 14 | 15 | {% block head %} 16 | {% endblock head %} 17 | 18 | 19 | 20 | 21 | {% verbatim %} 22 |
23 |
24 |
25 |
{{ prompt}}
26 |
27 | 29 |
30 |
31 | 33 |
34 |
35 | 37 |
38 |
39 |
40 | 41 |
42 | {% endverbatim %} 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/core/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | from arbiter.common import utils 3 | import re 4 | 5 | 6 | # Create your tests here. 7 | class Test: 8 | 9 | def id_test(self): 10 | log_id = utils.generate_id() 11 | print(log_id) 12 | 13 | def spilt_demo(self): 14 | text = "2017-12-27 10:09:12,655 - INFO - [https://www.v2ex.com:443/signin {} {} " \ 15 | "请求类型:GET 耗时:215.734ms 返回码:200] - at utils.arbiter_logger.get_response(http_client.py:38)" 16 | t1 = text.split("请求")[1].split("]")[0] 17 | print(t1) 18 | result_str = t1.split(" ") 19 | print(result_str) 20 | type = result_str[0].split(":")[1] 21 | time = result_str[1].split(":")[1].split("m")[0] 22 | code = result_str[2].split(":")[1] 23 | 24 | print("type:"+type+"time:"+time+"code:"+code) 25 | 26 | if __name__ == '__main__': 27 | test = Test() 28 | result = test.spilt_demo() 29 | 30 | 31 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/core/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | from . import views 3 | from rest_framework_jwt.views import obtain_jwt_token 4 | 5 | urlpatterns = [ 6 | url(r'^login', views.login, name='login'), 7 | url(r'^api-token-auth', obtain_jwt_token), 8 | url(r'^getUserDetail', views.auth_restful.get_user_detail), 9 | url(r'^save', views.auth_restful.save_case_file, name='save'), 10 | url(r'^delete', views.auth_restful.delete_case_file, name='delete'), 11 | url(r'^copy', views.auth_restful.copy_case_file, name='copy'), 12 | url(r'^getCaseList', views.restful.get_case_list), 13 | url(r'^cloneCaseObj', views.restful.get_caseobj), 14 | url(r'^$', views.index, name='index'), 15 | url(r'^.*$', views.index), 16 | ] 17 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/core/util/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuaFramework/cua-arbiter/61b2ea5d8b7c825b75d0f333d202e5703e0565a9/arbiter-web/arbiter/core/util/__init__.py -------------------------------------------------------------------------------- /arbiter-web/arbiter/core/util/askpass.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Short & sweet script for use with git clone and fetch credentials. 4 | # Requires GIT_USERNAME and GIT_PASSWORD environment variables, 5 | # intended to be called by Git via GIT_ASKPASS. 6 | # 7 | 8 | from sys import argv 9 | from os import environ 10 | 11 | if "Username for" in argv[1]: 12 | print(environ['GIT_USERNAME']) 13 | exit() 14 | 15 | if "Password for" in argv[1]: 16 | print(environ['GIT_PASSWORD']) 17 | exit() 18 | 19 | exit(1) 20 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/core/views.py: -------------------------------------------------------------------------------- 1 | import codecs 2 | import json 3 | import os 4 | import stat 5 | import shutil 6 | import time 7 | import git 8 | from django.core.files import File 9 | from django.http import HttpResponse, JsonResponse 10 | from django.shortcuts import render 11 | from rest_framework import permissions 12 | from rest_framework.authtoken.models import Token 13 | from rest_framework.decorators import api_view, permission_classes 14 | from rest_framework.permissions import IsAuthenticated 15 | from rest_framework.views import APIView 16 | 17 | from arbiter.core.models import CaseList 18 | from arbiter.models import Case_List, Git_Info 19 | 20 | 21 | # 登录 22 | def login(request): 23 | return render(request, 'case/login.html') 24 | 25 | 26 | def index(request): 27 | return render(request, 'case/index.html') 28 | 29 | 30 | class restful(APIView): 31 | # 获取测试用例树 32 | def __init__(self, **kwargs): 33 | super().__init__(**kwargs) 34 | self.body = None 35 | 36 | @api_view(['POST']) 37 | @permission_classes([permissions.AllowAny, ]) 38 | def get_case_list(self): 39 | try: 40 | cases_results = Case_List.objects.filter(name="arbiter_cases").first().data 41 | return JsonResponse(cases_results) 42 | except AttributeError: 43 | cases_results = CaseList.getList() 44 | Case_List.objects.create(name="arbiter_cases", data=cases_results) 45 | return JsonResponse(cases_results) 46 | 47 | # 获取测试用例GIT工程 48 | @api_view(['POST']) 49 | @permission_classes([permissions.AllowAny, ]) 50 | def get_caseobj(self): 51 | case_path = os.getenv("CASEPATH") 52 | json_obj = json.loads(self.body) 53 | if Git_Info.objects.count() > 0: 54 | info = Git_Info.objects.get() 55 | info.git_url = json_obj.get('url') 56 | info.user_name = json_obj.get("git_username") 57 | info.password = json_obj.get("git_password") 58 | info.save() 59 | 60 | def set_rw(operation, name, exc): 61 | os.chmod(name, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) 62 | os.remove(name) 63 | return True 64 | 65 | shutil.rmtree('../arbiter-cases', onerror=set_rw) 66 | else: 67 | Git_Info.objects.create(user_name=json_obj.get("git_username"), password=json_obj.get("git_password"), 68 | git_url=json_obj.get('url')) 69 | 70 | repo = git.Repo.clone_from(json_obj.get('url'), '../arbiter-cases/' + case_path.split('/')[0], branch='master') 71 | response_data = {'success': True} 72 | if Case_List.objects.count() > 0: 73 | case_list = Case_List.objects.get() 74 | case_list.name = "arbiter_cases" 75 | case_list.data = CaseList.getList() 76 | case_list.save() 77 | else: 78 | Case_List.objects.create(name="arbiter_cases", data=CaseList.getList()) 79 | return JsonResponse(response_data) 80 | 81 | 82 | # 下列接口需要登录验证 83 | class auth_restful(APIView): 84 | # 设置permission_classes为必须登陆才能访问下列接口 85 | permission_classes = (IsAuthenticated,) 86 | 87 | # 获取用户信息 88 | def __init__(self, **kwargs): 89 | super().__init__(**kwargs) 90 | self.user = None 91 | self.method = None 92 | self.body = None 93 | 94 | @api_view(['POST']) 95 | def get_user_detail(self): 96 | response_data = {'username': self.user.username, 97 | 'role': list(self.user.groups.values_list('name', flat=True))} 98 | return JsonResponse(response_data) 99 | 100 | # 注销 101 | @api_view(['GET']) 102 | def logout(self): 103 | Token.objects.get(user_id=self.user.id).delete() 104 | Token.objects.create(user_id=self.user.id) 105 | response_data = {'success': True} 106 | return JsonResponse(response_data, content_type="application/json") 107 | 108 | # 复制文件方法 109 | @api_view(['POST']) 110 | def copy_case_file(self): 111 | case_path = os.getenv("CASEPATH") 112 | # 获取发送的请求 113 | json_str = self.body 114 | json_obj = json.loads(json_str) 115 | git_path = '../arbiter-cases/' + case_path.split("/")[0] 116 | root_path = '../arbiter-cases/' + case_path + '/' 117 | old_case_path = json_obj.get('oldPath') 118 | new_case_path = json_obj.get('newPath') 119 | shutil.copyfile(root_path + old_case_path, 120 | root_path + new_case_path) 121 | repo = git.Repo(git_path) 122 | repo_index = repo.index 123 | repo_index.add([case_path.split("/")[1] + "/" + new_case_path]) 124 | repo_index.commit(self.user.username + "复制文件" + old_case_path + "到" + new_case_path) 125 | # 获取远程仓库 126 | remote = repo.remote() 127 | remote.pull() 128 | # 推送本地修改到远程仓库 129 | remote.push() 130 | # 同步最新用例列表到数据库 131 | case_list = Case_List.objects.get() 132 | case_list.name = "arbiter_cases" 133 | case_list.data = CaseList.getList() 134 | case_list.save() 135 | return HttpResponse(json.dumps({"result": 'ok'}), content_type="application/json") 136 | # 复制文件方法 137 | 138 | @api_view(['POST']) 139 | def delete_case_file(self): 140 | case_path = os.getenv("CASEPATH") 141 | # 获取发送的请求 142 | json_str = self.body 143 | json_obj = json.loads(json_str) 144 | git_path = '../arbiter-cases/' + case_path.split("/")[0] 145 | root_path = '../arbiter-cases/' + case_path + '/' 146 | delete_case_path = case_path = json_obj.get('deleteFilePath') 147 | os.remove(root_path + delete_case_path) 148 | repo = git.Repo(git_path) 149 | repo.git.add(update=True) 150 | repo_index = repo.index 151 | repo_index.commit(self.user.username + "删除文件" + delete_case_path) 152 | # 获取远程仓库 153 | remote = repo.remote() 154 | remote.pull() 155 | # 推送本地修改到远程仓库 156 | remote.push() 157 | # 同步最新用例列表到数据库 158 | case_list = Case_List.objects.get() 159 | case_list.name = "arbiter_cases" 160 | case_list.data = CaseList.getList() 161 | case_list.save() 162 | return HttpResponse(json.dumps({"result": 'ok'}), content_type="application/json") 163 | 164 | # 保存文件方法 165 | @api_view(['POST']) 166 | def save_case_file(self): 167 | case_path = os.getenv("CASEPATH") 168 | case_path_obj = case_path.split('/')[0] 169 | # 获取发送的请求 170 | json_str = self.body 171 | json_obj = json.loads(json_str) 172 | case_path = json_obj.get('casepath').split(':')[0].replace('.', '/') + '.py' 173 | time_str = time.strftime("%Y-%m-%d %H_%M_%S") 174 | # rename 原文件+时间格式(2017-07-20 18_34_48) 175 | os.rename('../arbiter-cases/' + case_path_obj + '/' + case_path, 176 | '../arbiter-cases/' + case_path_obj + '/' + case_path + '_' + time_str + '.history') 177 | # 使用codecs解决乱码问题 178 | with codecs.open('../arbiter-cases/' + case_path_obj + '/' + case_path, 'w', 'utf-8') as f: 179 | mfile = File(f) 180 | mfile.write(json_obj.get('content')) 181 | mfile.flush() 182 | mfile.seek(0) 183 | mfile.close() 184 | if mfile.closed: 185 | result = 'ok' 186 | repo = git.Repo('../arbiter-cases/' + case_path_obj) 187 | repo.git.add(update=True) 188 | repo_index = repo.index 189 | repo_index.commit(self.user.username + "修改文件" + case_path) 190 | # 获取远程仓库 191 | remote = repo.remote() 192 | remote.pull() 193 | # 推送本地修改到远程仓库 194 | remote.push() 195 | # 同步最新用例列表到数据库 196 | case_list = Case_List.objects.get() 197 | case_list.name = "arbiter_cases" 198 | case_list.data = CaseList.getList() 199 | case_list.save() 200 | return HttpResponse(json.dumps({"result": result}), content_type="application/json") 201 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.7 on 2018-02-11 09:59 3 | from __future__ import unicode_literals 4 | 5 | import django.contrib.postgres.fields.jsonb 6 | from django.db import migrations, models 7 | import django.utils.timezone 8 | 9 | 10 | class Migration(migrations.Migration): 11 | 12 | initial = True 13 | 14 | dependencies = [ 15 | ] 16 | 17 | operations = [ 18 | migrations.CreateModel( 19 | name='Case_List', 20 | fields=[ 21 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 22 | ('name', models.CharField(max_length=200)), 23 | ('data', django.contrib.postgres.fields.jsonb.JSONField()), 24 | ], 25 | ), 26 | migrations.CreateModel( 27 | name='Case_Run_Info', 28 | fields=[ 29 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 30 | ('log_id', models.UUIDField()), 31 | ('case_name', models.TextField(max_length=200)), 32 | ('run_time', models.DateTimeField()), 33 | ('author', models.CharField(max_length=50)), 34 | ('result', models.CharField(default='done', max_length=50)), 35 | ('version', models.IntegerField(default='10000000')), 36 | ], 37 | ), 38 | migrations.CreateModel( 39 | name='Case_Save_Info', 40 | fields=[ 41 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 42 | ('case_name', models.TextField(max_length=200)), 43 | ('version', models.IntegerField(default=10000000)), 44 | ('author', models.CharField(max_length=50)), 45 | ('save_time', models.DateTimeField(default=django.utils.timezone.now)), 46 | ], 47 | ), 48 | migrations.CreateModel( 49 | name='Case_Version_Info', 50 | fields=[ 51 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 52 | ('case_name', models.TextField(max_length=200)), 53 | ('latest_version', models.IntegerField(default=10000000)), 54 | ('update_time', models.DateTimeField(default=django.utils.timezone.now)), 55 | ], 56 | ), 57 | migrations.CreateModel( 58 | name='Git_Info', 59 | fields=[ 60 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 61 | ('user_name', models.CharField(max_length=50)), 62 | ('password', models.CharField(max_length=50)), 63 | ], 64 | ), 65 | ] 66 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/migrations/0002_case_run_info_status.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.7 on 2018-02-13 03:00 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('arbiter', '0001_initial'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='case_run_info', 17 | name='status', 18 | field=models.CharField(default='done', max_length=50), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/migrations/0003_auto_20180214_1452.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.7 on 2018-02-14 06:52 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('arbiter', '0002_case_run_info_status'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='case_run_info', 17 | name='task_name', 18 | field=models.TextField(default='noName', max_length=200), 19 | ), 20 | migrations.AlterField( 21 | model_name='case_run_info', 22 | name='case_name', 23 | field=models.TextField(max_length=5000), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/migrations/0004_auto_20180223_1416.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.7 on 2018-02-23 06:16 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('arbiter', '0003_auto_20180214_1452'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='case_run_info', 17 | name='duration', 18 | field=models.CharField(default='0', max_length=50), 19 | ), 20 | migrations.AddField( 21 | model_name='case_run_info', 22 | name='num', 23 | field=models.CharField(default='0', max_length=50), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/migrations/0005_case_run_info_deleted.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.7 on 2018-02-24 09:59 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('arbiter', '0004_auto_20180223_1416'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='case_run_info', 17 | name='deleted', 18 | field=models.IntegerField(default=0, max_length=50), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/migrations/0006_auto_20180225_1306.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.5 on 2018-02-25 05:06 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('arbiter', '0005_case_run_info_deleted'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='git_info', 17 | name='git_url', 18 | field=models.CharField(default='null', max_length=200), 19 | ), 20 | migrations.AlterField( 21 | model_name='case_run_info', 22 | name='deleted', 23 | field=models.IntegerField(default=0), 24 | ), 25 | migrations.AlterField( 26 | model_name='case_run_info', 27 | name='result', 28 | field=models.CharField(default='FAILED', max_length=50), 29 | ), 30 | ] 31 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuaFramework/cua-arbiter/61b2ea5d8b7c825b75d0f333d202e5703e0565a9/arbiter-web/arbiter/migrations/__init__.py -------------------------------------------------------------------------------- /arbiter-web/arbiter/models.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | from django.db import models 3 | from django.contrib.auth.models import Group 4 | from django.contrib.postgres.fields import JSONField 5 | import django.utils.timezone as timezone 6 | 7 | 8 | # GIT权限信息 9 | class Git_Info(models.Model): 10 | git_url = models.CharField(max_length=200, default='null') 11 | user_name = models.CharField(max_length=50) 12 | password = models.CharField(max_length=50) 13 | 14 | 15 | # 用例列表 16 | class Case_List(models.Model): 17 | name = models.CharField(max_length=200) 18 | data = JSONField() 19 | 20 | 21 | # 运行日志信息模型 22 | class Case_Run_Info(models.Model): 23 | log_id = models.UUIDField() 24 | task_name = models.TextField(max_length=200, default='noName') 25 | case_name = models.TextField(max_length=5000) 26 | run_time = models.DateTimeField() 27 | author = models.CharField(max_length=50) 28 | num = models.CharField(max_length=50, default='0') 29 | duration = models.CharField(max_length=50,default='0') 30 | status = models.CharField(max_length=50, default='done') 31 | result = models.CharField(max_length=50, default='FAILED') 32 | deleted = models.IntegerField(default=0) 33 | version = models.IntegerField(default='10000000') 34 | 35 | 36 | # 用例版本号信息 37 | class Case_Version_Info(models.Model): 38 | case_name = models.TextField(max_length=200) # 用例名,.py文件 39 | latest_version = models.IntegerField(default=10000000) # 版本号 八位 40 | update_time = models.DateTimeField(default=timezone.now) 41 | 42 | 43 | # 运行记录 44 | class Case_Save_Info(models.Model): 45 | case_name = models.TextField(max_length=200) # 用例名+方法 46 | version = models.IntegerField(default=10000000) 47 | author = models.CharField(max_length=50) 48 | save_time = models.DateTimeField(default=timezone.now) 49 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/routing.py: -------------------------------------------------------------------------------- 1 | from channels.routing import route, include 2 | 3 | from .core import consumers 4 | from .core.routing import case_manager_routing 5 | 6 | routing = [ 7 | # You can use a string import path as the first argument as well. 8 | include(case_manager_routing, path=r"^/arbiter"), 9 | ] -------------------------------------------------------------------------------- /arbiter-web/arbiter/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for arbiter project. 3 | 4 | Generated by 'django-admin startproject' using Django 1.11. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.11/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/1.11/ref/settings/ 11 | """ 12 | 13 | import os 14 | import datetime 15 | import redis 16 | from psycopg2.pool import ThreadedConnectionPool 17 | from config import arbiter_prod_config as env_config 18 | 19 | # mongodb_host = env_config['mongodb_host'] 20 | # mongodb_port = env_config['mongodb_port'] 21 | elk_url = env_config['elk_url'] 22 | redis_host = env_config['redis_host'] 23 | redis_port = env_config['redis_port'] 24 | redis_dj_db = env_config['redis_dj_db'] 25 | redis_arbiter_db = env_config['redis_arbiter_db'] 26 | redis_elk_db = env_config['redis_elk_db'] 27 | redis_url = 'redis://' + redis_host + ':' + str(redis_port) + '/' + str(redis_dj_db) 28 | pgsql_host = env_config['pgsql_host'] 29 | pgsql_port = env_config['pgsql_port'] 30 | pgsql_user = env_config['pgsql_user'] 31 | pgsql_password = env_config['pgsql_password'] 32 | pgsql_dbname = env_config['pgsql_dbname'] 33 | case_path = env_config['case_path'] 34 | os.environ["CASEPATH"] = case_path 35 | os.putenv("CASEPATH", case_path) 36 | case_obj_name = case_path.split('/')[0] 37 | redis_arbiter_pool = redis.ConnectionPool(host=redis_host, decode_responses=True, port=redis_port, db=redis_arbiter_db) 38 | redis_elk_pool = redis.ConnectionPool(host=redis_host, port=redis_port, db=redis_elk_db) 39 | pgsql_pool = ThreadedConnectionPool(1, 10, port=pgsql_port, host=pgsql_host,dbname=pgsql_dbname, user=pgsql_user, password=pgsql_password) 40 | 41 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 42 | PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) 43 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 44 | ARBITER_SHELL_ROOT = os.path.dirname(BASE_DIR) 45 | 46 | # Quick-start development settings - unsuitable for production 47 | # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ 48 | 49 | # SECURITY WARNING: keep the secret key used in production secret! 50 | SECRET_KEY = '4d*!@um+nv9-lx#k215nrr=6oijv-l&)sdn585_bjzlljlmszg' 51 | 52 | # SECURITY WARNING: don't run with debug turned on in production! 53 | DEBUG = True 54 | APPEND_SLASH = False 55 | PREPEND_WWW = False 56 | ALLOWED_HOSTS = ['*'] 57 | 58 | CHANNEL_LAYERS = { 59 | "default": { 60 | "BACKEND": "asgi_redis.RedisChannelLayer", 61 | "ROUTING": "arbiter.routing.routing", 62 | "CONFIG": { 63 | "hosts": [redis_url], 64 | "symmetric_encryption_keys": [SECRET_KEY], 65 | }, 66 | }, 67 | } 68 | 69 | # Application definition 70 | 71 | INSTALLED_APPS = [ 72 | 'django.contrib.admin', 73 | 'django.contrib.auth', 74 | 'django.contrib.contenttypes', 75 | 'django.contrib.sessions', 76 | 'django.contrib.messages', 77 | 'django.contrib.staticfiles', 78 | 'channels', 79 | 'arbiter', 80 | 'arbiter.core', 81 | 'arbiter.wholog' 82 | ] 83 | 84 | MIDDLEWARE = [ 85 | 'django.middleware.security.SecurityMiddleware', 86 | 'django.contrib.sessions.middleware.SessionMiddleware', 87 | 'django.middleware.common.CommonMiddleware', 88 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 89 | 'django.contrib.messages.middleware.MessageMiddleware', 90 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 91 | ] 92 | 93 | ROOT_URLCONF = 'arbiter.urls' 94 | 95 | TEMPLATES = [ 96 | { 97 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 98 | 'DIRS': [ 99 | os.path.join(PROJECT_ROOT, 'templates'), 100 | ], 101 | 'APP_DIRS': True, 102 | 'OPTIONS': { 103 | 'context_processors': [ 104 | 'django.template.context_processors.debug', 105 | 'django.template.context_processors.request', 106 | 'django.contrib.auth.context_processors.auth', 107 | 'django.contrib.messages.context_processors.messages', 108 | ], 109 | }, 110 | }, 111 | ] 112 | 113 | WSGI_APPLICATION = 'arbiter.wsgi.application' 114 | 115 | # Rest framework 116 | REST_FRAMEWORK = { 117 | 'DEFAULT_PERMISSION_CLASSES': ( 118 | 'rest_framework.permissions.IsAuthenticated', 119 | ), 120 | 'DEFAULT_AUTHENTICATION_CLASSES': ( 121 | 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', 122 | 'rest_framework.authentication.SessionAuthentication', 123 | 'rest_framework.authentication.BasicAuthentication', 124 | ), 125 | } 126 | 127 | # jwt 128 | JWT_AUTH = { 129 | 'JWT_ENCODE_HANDLER': 130 | 'rest_framework_jwt.utils.jwt_encode_handler', 131 | 132 | 'JWT_DECODE_HANDLER': 133 | 'rest_framework_jwt.utils.jwt_decode_handler', 134 | 135 | 'JWT_PAYLOAD_HANDLER': 136 | 'rest_framework_jwt.utils.jwt_payload_handler', 137 | 138 | 'JWT_PAYLOAD_GET_USER_ID_HANDLER': 139 | 'rest_framework_jwt.utils.jwt_get_user_id_from_payload_handler', 140 | 141 | 'JWT_RESPONSE_PAYLOAD_HANDLER': 142 | 'rest_framework_jwt.utils.jwt_response_payload_handler', 143 | 144 | # 'JWT_SECRET_KEY': settings.SECRET_KEY, 145 | 'JWT_GET_USER_SECRET_KEY': None, 146 | 'JWT_PUBLIC_KEY': None, 147 | 'JWT_PRIVATE_KEY': None, 148 | 'JWT_ALGORITHM': 'HS256', 149 | 'JWT_VERIFY': True, 150 | 'JWT_VERIFY_EXPIRATION': True, 151 | 'JWT_LEEWAY': 0, 152 | 'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=3000), 153 | 'JWT_AUDIENCE': None, 154 | 'JWT_ISSUER': None, 155 | 156 | 'JWT_ALLOW_REFRESH': False, 157 | 'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7), 158 | 159 | 'JWT_AUTH_HEADER_PREFIX': 'JWT', 160 | 'JWT_AUTH_COOKIE': None, 161 | 162 | } 163 | 164 | # Database 165 | # https://docs.djangoproject.com/en/1.11/ref/settings/#databases 166 | 167 | DATABASES = { 168 | 'default': { 169 | 'ENGINE': 'django.db.backends.postgresql', 170 | 'NAME': 'arbiter_dj', 171 | 'USER': 'luna', # 你的数据库用户名 172 | 'PASSWORD': 'luna', # 你的数据库密码 173 | 'HOST': pgsql_host, # 你的数据库主机,留空默认为localhost 174 | 'PORT': pgsql_port, # 你的数据库端口 175 | 'OPTIONS': { 176 | 'client_encoding': 'utf8', 177 | }, 178 | } 179 | } 180 | # AUTHENTICATION_BACKENDS = ('mongoengine.django.auth.MongoEngineBackend',) 181 | # Password validation 182 | # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators 183 | 184 | AUTH_PASSWORD_VALIDATORS = [ 185 | { 186 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 187 | }, 188 | { 189 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 190 | }, 191 | { 192 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 193 | }, 194 | { 195 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 196 | }, 197 | ] 198 | 199 | # Internationalization 200 | # https://docs.djangoproject.com/en/1.11/topics/i18n/ 201 | 202 | LANGUAGE_CODE = 'en-us' 203 | 204 | TIME_ZONE = 'UTC' 205 | 206 | USE_I18N = True 207 | 208 | USE_L10N = True 209 | 210 | # 09-11 为支持create_time查询排序修改为true 211 | USE_TZ = True 212 | 213 | # Static files (CSS, JavaScript, Images) 214 | # https://docs.djangoproject.com/en/1.11/howto/static-files/ 215 | # STATIC_ROOT = os.path.join(ARBITER_SHELL_ROOT, "shell") 216 | STATIC_URL = '/static/' 217 | 218 | STATICFILES_DIRS = [ 219 | os.path.join(PROJECT_ROOT, "static"), os.path.join(ARBITER_SHELL_ROOT, "arbiter-cases/" + case_obj_name), 220 | ] 221 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/css/datatables/dataTables.bootstrap.css: -------------------------------------------------------------------------------- 1 | table.dataTable { 2 | clear: both; 3 | margin-top: 6px !important; 4 | margin-bottom: 6px !important; 5 | max-width: none !important; 6 | border-collapse: separate !important; 7 | } 8 | table.dataTable td, 9 | table.dataTable th { 10 | -webkit-box-sizing: content-box; 11 | box-sizing: content-box; 12 | } 13 | table.dataTable td.dataTables_empty, 14 | table.dataTable th.dataTables_empty { 15 | text-align: center; 16 | } 17 | table.dataTable.nowrap th, 18 | table.dataTable.nowrap td { 19 | white-space: nowrap; 20 | } 21 | 22 | div.dataTables_wrapper div.dataTables_length label { 23 | font-weight: normal; 24 | text-align: left; 25 | white-space: nowrap; 26 | } 27 | div.dataTables_wrapper div.dataTables_length select { 28 | width: 75px; 29 | display: inline-block; 30 | } 31 | div.dataTables_wrapper div.dataTables_filter { 32 | text-align: right; 33 | } 34 | div.dataTables_wrapper div.dataTables_filter label { 35 | font-weight: normal; 36 | white-space: nowrap; 37 | text-align: left; 38 | } 39 | div.dataTables_wrapper div.dataTables_filter input { 40 | margin-left: 0.5em; 41 | display: inline-block; 42 | width: auto; 43 | } 44 | div.dataTables_wrapper div.dataTables_info { 45 | padding-top: 8px; 46 | white-space: nowrap; 47 | } 48 | div.dataTables_wrapper div.dataTables_paginate { 49 | margin: 0; 50 | white-space: nowrap; 51 | text-align: right; 52 | } 53 | div.dataTables_wrapper div.dataTables_paginate ul.pagination { 54 | margin: 2px 0; 55 | white-space: nowrap; 56 | } 57 | div.dataTables_wrapper div.dataTables_processing { 58 | position: absolute; 59 | top: 50%; 60 | left: 50%; 61 | width: 200px; 62 | margin-left: -100px; 63 | margin-top: -26px; 64 | text-align: center; 65 | padding: 1em 0; 66 | } 67 | 68 | table.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting, 69 | table.dataTable thead > tr > td.sorting_asc, 70 | table.dataTable thead > tr > td.sorting_desc, 71 | table.dataTable thead > tr > td.sorting { 72 | padding-right: 30px; 73 | } 74 | table.dataTable thead > tr > th:active, 75 | table.dataTable thead > tr > td:active { 76 | outline: none; 77 | } 78 | table.dataTable thead .sorting, 79 | table.dataTable thead .sorting_asc, 80 | table.dataTable thead .sorting_desc, 81 | table.dataTable thead .sorting_asc_disabled, 82 | table.dataTable thead .sorting_desc_disabled { 83 | cursor: pointer; 84 | position: relative; 85 | } 86 | table.dataTable thead .sorting:after, 87 | table.dataTable thead .sorting_asc:after, 88 | table.dataTable thead .sorting_desc:after, 89 | table.dataTable thead .sorting_asc_disabled:after, 90 | table.dataTable thead .sorting_desc_disabled:after { 91 | position: absolute; 92 | bottom: 8px; 93 | right: 8px; 94 | display: block; 95 | font-family: 'Glyphicons Halflings'; 96 | opacity: 0.5; 97 | } 98 | table.dataTable thead .sorting:after { 99 | opacity: 0.2; 100 | content: "\e150"; 101 | /* sort */ 102 | } 103 | table.dataTable thead .sorting_asc:after { 104 | content: "\e155"; 105 | /* sort-by-attributes */ 106 | } 107 | table.dataTable thead .sorting_desc:after { 108 | content: "\e156"; 109 | /* sort-by-attributes-alt */ 110 | } 111 | table.dataTable thead .sorting_asc_disabled:after, 112 | table.dataTable thead .sorting_desc_disabled:after { 113 | color: #eee; 114 | } 115 | 116 | div.dataTables_scrollHead table.dataTable { 117 | margin-bottom: 0 !important; 118 | } 119 | 120 | div.dataTables_scrollBody > table { 121 | border-top: none; 122 | margin-top: 0 !important; 123 | margin-bottom: 0 !important; 124 | } 125 | div.dataTables_scrollBody > table > thead .sorting:after, 126 | div.dataTables_scrollBody > table > thead .sorting_asc:after, 127 | div.dataTables_scrollBody > table > thead .sorting_desc:after { 128 | display: none; 129 | } 130 | div.dataTables_scrollBody > table > tbody > tr:first-child > th, 131 | div.dataTables_scrollBody > table > tbody > tr:first-child > td { 132 | border-top: none; 133 | } 134 | 135 | div.dataTables_scrollFoot > table { 136 | margin-top: 0 !important; 137 | border-top: none; 138 | } 139 | 140 | @media screen and (max-width: 767px) { 141 | div.dataTables_wrapper div.dataTables_length, 142 | div.dataTables_wrapper div.dataTables_filter, 143 | div.dataTables_wrapper div.dataTables_info, 144 | div.dataTables_wrapper div.dataTables_paginate { 145 | text-align: center; 146 | } 147 | } 148 | table.dataTable.table-condensed > thead > tr > th { 149 | padding-right: 20px; 150 | } 151 | table.dataTable.table-condensed .sorting:after, 152 | table.dataTable.table-condensed .sorting_asc:after, 153 | table.dataTable.table-condensed .sorting_desc:after { 154 | top: 6px; 155 | right: 6px; 156 | } 157 | 158 | table.table-bordered.dataTable th, 159 | table.table-bordered.dataTable td { 160 | border-left-width: 0; 161 | } 162 | table.table-bordered.dataTable th:last-child, table.table-bordered.dataTable th:last-child, 163 | table.table-bordered.dataTable td:last-child, 164 | table.table-bordered.dataTable td:last-child { 165 | border-right-width: 0; 166 | } 167 | table.table-bordered.dataTable tbody th, 168 | table.table-bordered.dataTable tbody td { 169 | border-bottom-width: 0; 170 | } 171 | 172 | div.dataTables_scrollHead table.table-bordered { 173 | border-bottom-width: 0; 174 | } 175 | 176 | div.table-responsive > div.dataTables_wrapper > div.row { 177 | margin: 0; 178 | } 179 | div.table-responsive > div.dataTables_wrapper > div.row > div[class^="col-"]:first-child { 180 | padding-left: 0; 181 | } 182 | div.table-responsive > div.dataTables_wrapper > div.row > div[class^="col-"]:last-child { 183 | padding-right: 0; 184 | } 185 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/css/datatables/dataTables.bootstrap.min.css: -------------------------------------------------------------------------------- 1 | table.dataTable{clear:both;margin-top:6px !important;margin-bottom:6px !important;max-width:none !important;border-collapse:separate !important}table.dataTable td,table.dataTable th{-webkit-box-sizing:content-box;box-sizing:content-box}table.dataTable td.dataTables_empty,table.dataTable th.dataTables_empty{text-align:center}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}div.dataTables_wrapper div.dataTables_length label{font-weight:normal;text-align:left;white-space:nowrap}div.dataTables_wrapper div.dataTables_length select{width:75px;display:inline-block}div.dataTables_wrapper div.dataTables_filter{text-align:right}div.dataTables_wrapper div.dataTables_filter label{font-weight:normal;white-space:nowrap;text-align:left}div.dataTables_wrapper div.dataTables_filter input{margin-left:0.5em;display:inline-block;width:auto}div.dataTables_wrapper div.dataTables_info{padding-top:8px;white-space:nowrap}div.dataTables_wrapper div.dataTables_paginate{margin:0;white-space:nowrap;text-align:right}div.dataTables_wrapper div.dataTables_paginate ul.pagination{margin:2px 0;white-space:nowrap}div.dataTables_wrapper div.dataTables_processing{position:absolute;top:50%;left:50%;width:200px;margin-left:-100px;margin-top:-26px;text-align:center;padding:1em 0}table.dataTable thead>tr>th.sorting_asc,table.dataTable thead>tr>th.sorting_desc,table.dataTable thead>tr>th.sorting,table.dataTable thead>tr>td.sorting_asc,table.dataTable thead>tr>td.sorting_desc,table.dataTable thead>tr>td.sorting{padding-right:30px}table.dataTable thead>tr>th:active,table.dataTable thead>tr>td:active{outline:none}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{cursor:pointer;position:relative}table.dataTable thead .sorting:after,table.dataTable thead .sorting_asc:after,table.dataTable thead .sorting_desc:after,table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_desc_disabled:after{position:absolute;bottom:8px;right:8px;display:block;font-family:'Glyphicons Halflings';opacity:0.5}table.dataTable thead .sorting:after{opacity:0.2;content:"\e150"}table.dataTable thead .sorting_asc:after{content:"\e155"}table.dataTable thead .sorting_desc:after{content:"\e156"}table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_desc_disabled:after{color:#eee}div.dataTables_scrollHead table.dataTable{margin-bottom:0 !important}div.dataTables_scrollBody>table{border-top:none;margin-top:0 !important;margin-bottom:0 !important}div.dataTables_scrollBody>table>thead .sorting:after,div.dataTables_scrollBody>table>thead .sorting_asc:after,div.dataTables_scrollBody>table>thead .sorting_desc:after{display:none}div.dataTables_scrollBody>table>tbody>tr:first-child>th,div.dataTables_scrollBody>table>tbody>tr:first-child>td{border-top:none}div.dataTables_scrollFoot>table{margin-top:0 !important;border-top:none}@media screen and (max-width: 767px){div.dataTables_wrapper div.dataTables_length,div.dataTables_wrapper div.dataTables_filter,div.dataTables_wrapper div.dataTables_info,div.dataTables_wrapper div.dataTables_paginate{text-align:center}}table.dataTable.table-condensed>thead>tr>th{padding-right:20px}table.dataTable.table-condensed .sorting:after,table.dataTable.table-condensed .sorting_asc:after,table.dataTable.table-condensed .sorting_desc:after{top:6px;right:6px}table.table-bordered.dataTable th,table.table-bordered.dataTable td{border-left-width:0}table.table-bordered.dataTable th:last-child,table.table-bordered.dataTable th:last-child,table.table-bordered.dataTable td:last-child,table.table-bordered.dataTable td:last-child{border-right-width:0}table.table-bordered.dataTable tbody th,table.table-bordered.dataTable tbody td{border-bottom-width:0}div.dataTables_scrollHead table.table-bordered{border-bottom-width:0}div.table-responsive>div.dataTables_wrapper>div.row{margin:0}div.table-responsive>div.dataTables_wrapper>div.row>div[class^="col-"]:first-child{padding-left:0}div.table-responsive>div.dataTables_wrapper>div.row>div[class^="col-"]:last-child{padding-right:0} 2 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/css/datatables/dataTables.bootstrap4.css: -------------------------------------------------------------------------------- 1 | table.dataTable { 2 | clear: both; 3 | margin-top: 6px !important; 4 | margin-bottom: 6px !important; 5 | max-width: none !important; 6 | border-collapse: separate !important; 7 | } 8 | table.dataTable td, 9 | table.dataTable th { 10 | -webkit-box-sizing: content-box; 11 | box-sizing: content-box; 12 | } 13 | table.dataTable td.dataTables_empty, 14 | table.dataTable th.dataTables_empty { 15 | text-align: center; 16 | } 17 | table.dataTable.nowrap th, 18 | table.dataTable.nowrap td { 19 | white-space: nowrap; 20 | } 21 | 22 | div.dataTables_wrapper div.dataTables_length label { 23 | font-weight: normal; 24 | text-align: left; 25 | white-space: nowrap; 26 | } 27 | div.dataTables_wrapper div.dataTables_length select { 28 | width: 75px; 29 | display: inline-block; 30 | } 31 | div.dataTables_wrapper div.dataTables_filter { 32 | text-align: right; 33 | } 34 | div.dataTables_wrapper div.dataTables_filter label { 35 | font-weight: normal; 36 | white-space: nowrap; 37 | text-align: left; 38 | } 39 | div.dataTables_wrapper div.dataTables_filter input { 40 | margin-left: 0.5em; 41 | display: inline-block; 42 | width: auto; 43 | } 44 | div.dataTables_wrapper div.dataTables_info { 45 | padding-top: 0.85em; 46 | white-space: nowrap; 47 | } 48 | div.dataTables_wrapper div.dataTables_paginate { 49 | margin: 0; 50 | white-space: nowrap; 51 | text-align: right; 52 | } 53 | div.dataTables_wrapper div.dataTables_paginate ul.pagination { 54 | margin: 2px 0; 55 | white-space: nowrap; 56 | justify-content: flex-end; 57 | } 58 | div.dataTables_wrapper div.dataTables_processing { 59 | position: absolute; 60 | top: 50%; 61 | left: 50%; 62 | width: 200px; 63 | margin-left: -100px; 64 | margin-top: -26px; 65 | text-align: center; 66 | padding: 1em 0; 67 | } 68 | 69 | table.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting, 70 | table.dataTable thead > tr > td.sorting_asc, 71 | table.dataTable thead > tr > td.sorting_desc, 72 | table.dataTable thead > tr > td.sorting { 73 | padding-right: 30px; 74 | } 75 | table.dataTable thead > tr > th:active, 76 | table.dataTable thead > tr > td:active { 77 | outline: none; 78 | } 79 | table.dataTable thead .sorting, 80 | table.dataTable thead .sorting_asc, 81 | table.dataTable thead .sorting_desc, 82 | table.dataTable thead .sorting_asc_disabled, 83 | table.dataTable thead .sorting_desc_disabled { 84 | cursor: pointer; 85 | position: relative; 86 | } 87 | table.dataTable thead .sorting:before, table.dataTable thead .sorting:after, 88 | table.dataTable thead .sorting_asc:before, 89 | table.dataTable thead .sorting_asc:after, 90 | table.dataTable thead .sorting_desc:before, 91 | table.dataTable thead .sorting_desc:after, 92 | table.dataTable thead .sorting_asc_disabled:before, 93 | table.dataTable thead .sorting_asc_disabled:after, 94 | table.dataTable thead .sorting_desc_disabled:before, 95 | table.dataTable thead .sorting_desc_disabled:after { 96 | position: absolute; 97 | bottom: 0.9em; 98 | display: block; 99 | opacity: 0.3; 100 | } 101 | table.dataTable thead .sorting:before, 102 | table.dataTable thead .sorting_asc:before, 103 | table.dataTable thead .sorting_desc:before, 104 | table.dataTable thead .sorting_asc_disabled:before, 105 | table.dataTable thead .sorting_desc_disabled:before { 106 | right: 1em; 107 | content: "\2191"; 108 | } 109 | table.dataTable thead .sorting:after, 110 | table.dataTable thead .sorting_asc:after, 111 | table.dataTable thead .sorting_desc:after, 112 | table.dataTable thead .sorting_asc_disabled:after, 113 | table.dataTable thead .sorting_desc_disabled:after { 114 | right: 0.5em; 115 | content: "\2193"; 116 | } 117 | table.dataTable thead .sorting_asc:before, 118 | table.dataTable thead .sorting_desc:after { 119 | opacity: 1; 120 | } 121 | table.dataTable thead .sorting_asc_disabled:before, 122 | table.dataTable thead .sorting_desc_disabled:after { 123 | opacity: 0; 124 | } 125 | 126 | div.dataTables_scrollHead table.dataTable { 127 | margin-bottom: 0 !important; 128 | } 129 | 130 | div.dataTables_scrollBody table { 131 | border-top: none; 132 | margin-top: 0 !important; 133 | margin-bottom: 0 !important; 134 | } 135 | div.dataTables_scrollBody table thead .sorting:after, 136 | div.dataTables_scrollBody table thead .sorting_asc:after, 137 | div.dataTables_scrollBody table thead .sorting_desc:after { 138 | display: none; 139 | } 140 | div.dataTables_scrollBody table tbody tr:first-child th, 141 | div.dataTables_scrollBody table tbody tr:first-child td { 142 | border-top: none; 143 | } 144 | 145 | div.dataTables_scrollFoot table { 146 | margin-top: 0 !important; 147 | border-top: none; 148 | } 149 | 150 | @media screen and (max-width: 767px) { 151 | div.dataTables_wrapper div.dataTables_length, 152 | div.dataTables_wrapper div.dataTables_filter, 153 | div.dataTables_wrapper div.dataTables_info, 154 | div.dataTables_wrapper div.dataTables_paginate { 155 | text-align: center; 156 | } 157 | } 158 | table.dataTable.table-condensed > thead > tr > th { 159 | padding-right: 20px; 160 | } 161 | table.dataTable.table-condensed .sorting:after, 162 | table.dataTable.table-condensed .sorting_asc:after, 163 | table.dataTable.table-condensed .sorting_desc:after { 164 | top: 6px; 165 | right: 6px; 166 | } 167 | 168 | table.table-bordered.dataTable th, 169 | table.table-bordered.dataTable td { 170 | border-left-width: 0; 171 | } 172 | table.table-bordered.dataTable th:last-child, table.table-bordered.dataTable th:last-child, 173 | table.table-bordered.dataTable td:last-child, 174 | table.table-bordered.dataTable td:last-child { 175 | border-right-width: 0; 176 | } 177 | table.table-bordered.dataTable tbody th, 178 | table.table-bordered.dataTable tbody td { 179 | border-bottom-width: 0; 180 | } 181 | 182 | div.dataTables_scrollHead table.table-bordered { 183 | border-bottom-width: 0; 184 | } 185 | 186 | div.table-responsive > div.dataTables_wrapper > div.row { 187 | margin: 0; 188 | } 189 | div.table-responsive > div.dataTables_wrapper > div.row > div[class^="col-"]:first-child { 190 | padding-left: 0; 191 | } 192 | div.table-responsive > div.dataTables_wrapper > div.row > div[class^="col-"]:last-child { 193 | padding-right: 0; 194 | } 195 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/css/datatables/dataTables.bootstrap4.min.css: -------------------------------------------------------------------------------- 1 | table.dataTable{clear:both;margin-top:6px !important;margin-bottom:6px !important;max-width:none !important;border-collapse:separate !important}table.dataTable td,table.dataTable th{-webkit-box-sizing:content-box;box-sizing:content-box}table.dataTable td.dataTables_empty,table.dataTable th.dataTables_empty{text-align:center}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}div.dataTables_wrapper div.dataTables_length label{font-weight:normal;text-align:left;white-space:nowrap}div.dataTables_wrapper div.dataTables_length select{width:75px;display:inline-block}div.dataTables_wrapper div.dataTables_filter{text-align:right}div.dataTables_wrapper div.dataTables_filter label{font-weight:normal;white-space:nowrap;text-align:left}div.dataTables_wrapper div.dataTables_filter input{margin-left:0.5em;display:inline-block;width:auto}div.dataTables_wrapper div.dataTables_info{padding-top:0.85em;white-space:nowrap}div.dataTables_wrapper div.dataTables_paginate{margin:0;white-space:nowrap;text-align:right}div.dataTables_wrapper div.dataTables_paginate ul.pagination{margin:2px 0;white-space:nowrap;justify-content:flex-end}div.dataTables_wrapper div.dataTables_processing{position:absolute;top:50%;left:50%;width:200px;margin-left:-100px;margin-top:-26px;text-align:center;padding:1em 0}table.dataTable thead>tr>th.sorting_asc,table.dataTable thead>tr>th.sorting_desc,table.dataTable thead>tr>th.sorting,table.dataTable thead>tr>td.sorting_asc,table.dataTable thead>tr>td.sorting_desc,table.dataTable thead>tr>td.sorting{padding-right:30px}table.dataTable thead>tr>th:active,table.dataTable thead>tr>td:active{outline:none}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{cursor:pointer;position:relative}table.dataTable thead .sorting:before,table.dataTable thead .sorting:after,table.dataTable thead .sorting_asc:before,table.dataTable thead .sorting_asc:after,table.dataTable thead .sorting_desc:before,table.dataTable thead .sorting_desc:after,table.dataTable thead .sorting_asc_disabled:before,table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_desc_disabled:before,table.dataTable thead .sorting_desc_disabled:after{position:absolute;bottom:0.9em;display:block;opacity:0.3}table.dataTable thead .sorting:before,table.dataTable thead .sorting_asc:before,table.dataTable thead .sorting_desc:before,table.dataTable thead .sorting_asc_disabled:before,table.dataTable thead .sorting_desc_disabled:before{right:1em;content:"\2191"}table.dataTable thead .sorting:after,table.dataTable thead .sorting_asc:after,table.dataTable thead .sorting_desc:after,table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_desc_disabled:after{right:0.5em;content:"\2193"}table.dataTable thead .sorting_asc:before,table.dataTable thead .sorting_desc:after{opacity:1}table.dataTable thead .sorting_asc_disabled:before,table.dataTable thead .sorting_desc_disabled:after{opacity:0}div.dataTables_scrollHead table.dataTable{margin-bottom:0 !important}div.dataTables_scrollBody table{border-top:none;margin-top:0 !important;margin-bottom:0 !important}div.dataTables_scrollBody table thead .sorting:after,div.dataTables_scrollBody table thead .sorting_asc:after,div.dataTables_scrollBody table thead .sorting_desc:after{display:none}div.dataTables_scrollBody table tbody tr:first-child th,div.dataTables_scrollBody table tbody tr:first-child td{border-top:none}div.dataTables_scrollFoot table{margin-top:0 !important;border-top:none}@media screen and (max-width: 767px){div.dataTables_wrapper div.dataTables_length,div.dataTables_wrapper div.dataTables_filter,div.dataTables_wrapper div.dataTables_info,div.dataTables_wrapper div.dataTables_paginate{text-align:center}}table.dataTable.table-condensed>thead>tr>th{padding-right:20px}table.dataTable.table-condensed .sorting:after,table.dataTable.table-condensed .sorting_asc:after,table.dataTable.table-condensed .sorting_desc:after{top:6px;right:6px}table.table-bordered.dataTable th,table.table-bordered.dataTable td{border-left-width:0}table.table-bordered.dataTable th:last-child,table.table-bordered.dataTable th:last-child,table.table-bordered.dataTable td:last-child,table.table-bordered.dataTable td:last-child{border-right-width:0}table.table-bordered.dataTable tbody th,table.table-bordered.dataTable tbody td{border-bottom-width:0}div.dataTables_scrollHead table.table-bordered{border-bottom-width:0}div.table-responsive>div.dataTables_wrapper>div.row{margin:0}div.table-responsive>div.dataTables_wrapper>div.row>div[class^="col-"]:first-child{padding-left:0}div.table-responsive>div.dataTables_wrapper>div.row>div[class^="col-"]:last-child{padding-right:0} 2 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/css/datatables/dataTables.foundation.css: -------------------------------------------------------------------------------- 1 | table.dataTable { 2 | clear: both; 3 | margin: 0.5em 0 !important; 4 | max-width: none !important; 5 | width: 100%; 6 | } 7 | table.dataTable td, 8 | table.dataTable th { 9 | -webkit-box-sizing: content-box; 10 | box-sizing: content-box; 11 | } 12 | table.dataTable td.dataTables_empty, 13 | table.dataTable th.dataTables_empty { 14 | text-align: center; 15 | } 16 | table.dataTable.nowrap th, table.dataTable.nowrap td { 17 | white-space: nowrap; 18 | } 19 | 20 | div.dataTables_wrapper { 21 | position: relative; 22 | } 23 | div.dataTables_wrapper div.dataTables_length label { 24 | float: left; 25 | text-align: left; 26 | margin-bottom: 0; 27 | } 28 | div.dataTables_wrapper div.dataTables_length select { 29 | width: 75px; 30 | margin-bottom: 0; 31 | } 32 | div.dataTables_wrapper div.dataTables_filter label { 33 | float: right; 34 | margin-bottom: 0; 35 | } 36 | div.dataTables_wrapper div.dataTables_filter input { 37 | display: inline-block !important; 38 | width: auto !important; 39 | margin-bottom: 0; 40 | margin-left: 0.5em; 41 | } 42 | div.dataTables_wrapper div.dataTables_info { 43 | padding-top: 2px; 44 | } 45 | div.dataTables_wrapper div.dataTables_paginate { 46 | float: right; 47 | margin: 0; 48 | } 49 | div.dataTables_wrapper div.dataTables_processing { 50 | position: absolute; 51 | top: 50%; 52 | left: 50%; 53 | width: 200px; 54 | margin-left: -100px; 55 | margin-top: -26px; 56 | text-align: center; 57 | padding: 1rem 0; 58 | } 59 | 60 | table.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting, 61 | table.dataTable thead > tr > td.sorting_asc, 62 | table.dataTable thead > tr > td.sorting_desc, 63 | table.dataTable thead > tr > td.sorting { 64 | padding-right: 1.5rem; 65 | } 66 | table.dataTable thead > tr > th:active, 67 | table.dataTable thead > tr > td:active { 68 | outline: none; 69 | } 70 | table.dataTable thead .sorting, 71 | table.dataTable thead .sorting_asc, 72 | table.dataTable thead .sorting_desc, 73 | table.dataTable thead .sorting_asc_disabled, 74 | table.dataTable thead .sorting_desc_disabled { 75 | cursor: pointer; 76 | } 77 | table.dataTable thead .sorting, 78 | table.dataTable thead .sorting_asc, 79 | table.dataTable thead .sorting_desc, 80 | table.dataTable thead .sorting_asc_disabled, 81 | table.dataTable thead .sorting_desc_disabled { 82 | background-repeat: no-repeat; 83 | background-position: center right; 84 | } 85 | table.dataTable thead .sorting { 86 | background-image: url("../images/sort_both.png"); 87 | } 88 | table.dataTable thead .sorting_asc { 89 | background-image: url("../images/sort_asc.png"); 90 | } 91 | table.dataTable thead .sorting_desc { 92 | background-image: url("../images/sort_desc.png"); 93 | } 94 | table.dataTable thead .sorting_asc_disabled { 95 | background-image: url("../images/sort_asc_disabled.png"); 96 | } 97 | table.dataTable thead .sorting_desc_disabled { 98 | background-image: url("../images/sort_desc_disabled.png"); 99 | } 100 | 101 | div.dataTables_scrollHead table { 102 | margin-bottom: 0 !important; 103 | } 104 | 105 | div.dataTables_scrollBody table { 106 | border-top: none; 107 | margin-top: 0 !important; 108 | margin-bottom: 0 !important; 109 | } 110 | div.dataTables_scrollBody table tbody tr:first-child th, 111 | div.dataTables_scrollBody table tbody tr:first-child td { 112 | border-top: none; 113 | } 114 | 115 | div.dataTables_scrollFoot table { 116 | margin-top: 0 !important; 117 | border-top: none; 118 | } 119 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/css/datatables/dataTables.foundation.min.css: -------------------------------------------------------------------------------- 1 | table.dataTable{clear:both;margin:0.5em 0 !important;max-width:none !important;width:100%}table.dataTable td,table.dataTable th{-webkit-box-sizing:content-box;box-sizing:content-box}table.dataTable td.dataTables_empty,table.dataTable th.dataTables_empty{text-align:center}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}div.dataTables_wrapper{position:relative}div.dataTables_wrapper div.dataTables_length label{float:left;text-align:left;margin-bottom:0}div.dataTables_wrapper div.dataTables_length select{width:75px;margin-bottom:0}div.dataTables_wrapper div.dataTables_filter label{float:right;margin-bottom:0}div.dataTables_wrapper div.dataTables_filter input{display:inline-block !important;width:auto !important;margin-bottom:0;margin-left:0.5em}div.dataTables_wrapper div.dataTables_info{padding-top:2px}div.dataTables_wrapper div.dataTables_paginate{float:right;margin:0}div.dataTables_wrapper div.dataTables_processing{position:absolute;top:50%;left:50%;width:200px;margin-left:-100px;margin-top:-26px;text-align:center;padding:1rem 0}table.dataTable thead>tr>th.sorting_asc,table.dataTable thead>tr>th.sorting_desc,table.dataTable thead>tr>th.sorting,table.dataTable thead>tr>td.sorting_asc,table.dataTable thead>tr>td.sorting_desc,table.dataTable thead>tr>td.sorting{padding-right:1.5rem}table.dataTable thead>tr>th:active,table.dataTable thead>tr>td:active{outline:none}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{cursor:pointer}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{background-repeat:no-repeat;background-position:center right}table.dataTable thead .sorting{background-image:url("../images/sort_both.png")}table.dataTable thead .sorting_asc{background-image:url("../images/sort_asc.png")}table.dataTable thead .sorting_desc{background-image:url("../images/sort_desc.png")}table.dataTable thead .sorting_asc_disabled{background-image:url("../images/sort_asc_disabled.png")}table.dataTable thead .sorting_desc_disabled{background-image:url("../images/sort_desc_disabled.png")}div.dataTables_scrollHead table{margin-bottom:0 !important}div.dataTables_scrollBody table{border-top:none;margin-top:0 !important;margin-bottom:0 !important}div.dataTables_scrollBody table tbody tr:first-child th,div.dataTables_scrollBody table tbody tr:first-child td{border-top:none}div.dataTables_scrollFoot table{margin-top:0 !important;border-top:none} 2 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/css/datatables/dataTables.material.css: -------------------------------------------------------------------------------- 1 | div.dataTables_wrapper div.dataTables_filter { 2 | text-align: right; 3 | } 4 | div.dataTables_wrapper div.dataTables_filter input { 5 | margin-left: 0.5em; 6 | } 7 | div.dataTables_wrapper div.dataTables_info { 8 | padding-top: 10px; 9 | white-space: nowrap; 10 | } 11 | div.dataTables_wrapper div.dataTables_processing { 12 | position: absolute; 13 | top: 50%; 14 | left: 50%; 15 | width: 200px; 16 | margin-left: -100px; 17 | text-align: center; 18 | } 19 | div.dataTables_wrapper div.dataTables_paginate { 20 | text-align: right; 21 | } 22 | div.dataTables_wrapper div.mdl-grid.dt-table { 23 | padding-top: 0; 24 | padding-bottom: 0; 25 | } 26 | div.dataTables_wrapper div.mdl-grid.dt-table > div.mdl-cell { 27 | margin-top: 0; 28 | margin-bottom: 0; 29 | } 30 | 31 | table.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting, 32 | table.dataTable thead > tr > td.sorting_asc, 33 | table.dataTable thead > tr > td.sorting_desc, 34 | table.dataTable thead > tr > td.sorting { 35 | padding-right: 30px; 36 | } 37 | table.dataTable thead > tr > th:active, 38 | table.dataTable thead > tr > td:active { 39 | outline: none; 40 | } 41 | table.dataTable thead .sorting, 42 | table.dataTable thead .sorting_asc, 43 | table.dataTable thead .sorting_desc, 44 | table.dataTable thead .sorting_asc_disabled, 45 | table.dataTable thead .sorting_desc_disabled { 46 | cursor: pointer; 47 | position: relative; 48 | } 49 | table.dataTable thead .sorting:before, table.dataTable thead .sorting:after, 50 | table.dataTable thead .sorting_asc:before, 51 | table.dataTable thead .sorting_asc:after, 52 | table.dataTable thead .sorting_desc:before, 53 | table.dataTable thead .sorting_desc:after, 54 | table.dataTable thead .sorting_asc_disabled:before, 55 | table.dataTable thead .sorting_asc_disabled:after, 56 | table.dataTable thead .sorting_desc_disabled:before, 57 | table.dataTable thead .sorting_desc_disabled:after { 58 | position: absolute; 59 | bottom: 11px; 60 | display: block; 61 | opacity: 0.3; 62 | font-size: 1.3em; 63 | } 64 | table.dataTable thead .sorting:before, 65 | table.dataTable thead .sorting_asc:before, 66 | table.dataTable thead .sorting_desc:before, 67 | table.dataTable thead .sorting_asc_disabled:before, 68 | table.dataTable thead .sorting_desc_disabled:before { 69 | right: 1em; 70 | content: "\2191"; 71 | } 72 | table.dataTable thead .sorting:after, 73 | table.dataTable thead .sorting_asc:after, 74 | table.dataTable thead .sorting_desc:after, 75 | table.dataTable thead .sorting_asc_disabled:after, 76 | table.dataTable thead .sorting_desc_disabled:after { 77 | right: 0.5em; 78 | content: "\2193"; 79 | } 80 | table.dataTable thead .sorting_asc:before, 81 | table.dataTable thead .sorting_desc:after { 82 | opacity: 1; 83 | } 84 | table.dataTable thead .sorting_asc_disabled:before, 85 | table.dataTable thead .sorting_desc_disabled:after { 86 | opacity: 0; 87 | } 88 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/css/datatables/dataTables.material.min.css: -------------------------------------------------------------------------------- 1 | div.dataTables_wrapper div.dataTables_filter{text-align:right}div.dataTables_wrapper div.dataTables_filter input{margin-left:0.5em}div.dataTables_wrapper div.dataTables_info{padding-top:10px;white-space:nowrap}div.dataTables_wrapper div.dataTables_processing{position:absolute;top:50%;left:50%;width:200px;margin-left:-100px;text-align:center}div.dataTables_wrapper div.dataTables_paginate{text-align:right}div.dataTables_wrapper div.mdl-grid.dt-table{padding-top:0;padding-bottom:0}div.dataTables_wrapper div.mdl-grid.dt-table>div.mdl-cell{margin-top:0;margin-bottom:0}table.dataTable thead>tr>th.sorting_asc,table.dataTable thead>tr>th.sorting_desc,table.dataTable thead>tr>th.sorting,table.dataTable thead>tr>td.sorting_asc,table.dataTable thead>tr>td.sorting_desc,table.dataTable thead>tr>td.sorting{padding-right:30px}table.dataTable thead>tr>th:active,table.dataTable thead>tr>td:active{outline:none}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{cursor:pointer;position:relative}table.dataTable thead .sorting:before,table.dataTable thead .sorting:after,table.dataTable thead .sorting_asc:before,table.dataTable thead .sorting_asc:after,table.dataTable thead .sorting_desc:before,table.dataTable thead .sorting_desc:after,table.dataTable thead .sorting_asc_disabled:before,table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_desc_disabled:before,table.dataTable thead .sorting_desc_disabled:after{position:absolute;bottom:11px;display:block;opacity:0.3;font-size:1.3em}table.dataTable thead .sorting:before,table.dataTable thead .sorting_asc:before,table.dataTable thead .sorting_desc:before,table.dataTable thead .sorting_asc_disabled:before,table.dataTable thead .sorting_desc_disabled:before{right:1em;content:"\2191"}table.dataTable thead .sorting:after,table.dataTable thead .sorting_asc:after,table.dataTable thead .sorting_desc:after,table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_desc_disabled:after{right:0.5em;content:"\2193"}table.dataTable thead .sorting_asc:before,table.dataTable thead .sorting_desc:after{opacity:1}table.dataTable thead .sorting_asc_disabled:before,table.dataTable thead .sorting_desc_disabled:after{opacity:0} 2 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/css/datatables/dataTables.semanticui.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Styling for DataTables with Semantic UI 3 | */ 4 | table.dataTable.table { 5 | margin: 0; 6 | } 7 | table.dataTable.table thead th, 8 | table.dataTable.table thead td { 9 | position: relative; 10 | } 11 | table.dataTable.table thead th.sorting, table.dataTable.table thead th.sorting_asc, table.dataTable.table thead th.sorting_desc, 12 | table.dataTable.table thead td.sorting, 13 | table.dataTable.table thead td.sorting_asc, 14 | table.dataTable.table thead td.sorting_desc { 15 | padding-right: 20px; 16 | } 17 | table.dataTable.table thead th.sorting:after, table.dataTable.table thead th.sorting_asc:after, table.dataTable.table thead th.sorting_desc:after, 18 | table.dataTable.table thead td.sorting:after, 19 | table.dataTable.table thead td.sorting_asc:after, 20 | table.dataTable.table thead td.sorting_desc:after { 21 | position: absolute; 22 | top: 12px; 23 | right: 8px; 24 | display: block; 25 | font-family: Icons; 26 | } 27 | table.dataTable.table thead th.sorting:after, 28 | table.dataTable.table thead td.sorting:after { 29 | content: "\f0dc"; 30 | color: #ddd; 31 | font-size: 0.8em; 32 | } 33 | table.dataTable.table thead th.sorting_asc:after, 34 | table.dataTable.table thead td.sorting_asc:after { 35 | content: "\f0de"; 36 | } 37 | table.dataTable.table thead th.sorting_desc:after, 38 | table.dataTable.table thead td.sorting_desc:after { 39 | content: "\f0dd"; 40 | } 41 | table.dataTable.table td, 42 | table.dataTable.table th { 43 | -webkit-box-sizing: content-box; 44 | box-sizing: content-box; 45 | } 46 | table.dataTable.table td.dataTables_empty, 47 | table.dataTable.table th.dataTables_empty { 48 | text-align: center; 49 | } 50 | table.dataTable.table.nowrap th, 51 | table.dataTable.table.nowrap td { 52 | white-space: nowrap; 53 | } 54 | 55 | div.dataTables_wrapper div.dataTables_length select { 56 | vertical-align: middle; 57 | min-height: 2.7142em; 58 | } 59 | div.dataTables_wrapper div.dataTables_length .ui.selection.dropdown { 60 | min-width: 0; 61 | } 62 | div.dataTables_wrapper div.dataTables_filter input { 63 | margin-left: 0.5em; 64 | } 65 | div.dataTables_wrapper div.dataTables_info { 66 | padding-top: 13px; 67 | white-space: nowrap; 68 | } 69 | div.dataTables_wrapper div.dataTables_processing { 70 | position: absolute; 71 | top: 50%; 72 | left: 50%; 73 | width: 200px; 74 | margin-left: -100px; 75 | text-align: center; 76 | } 77 | div.dataTables_wrapper div.row.dt-table { 78 | padding: 0; 79 | } 80 | div.dataTables_wrapper div.dataTables_scrollHead table.dataTable { 81 | border-bottom-right-radius: 0; 82 | border-bottom-left-radius: 0; 83 | border-bottom: none; 84 | } 85 | div.dataTables_wrapper div.dataTables_scrollBody thead .sorting:after, 86 | div.dataTables_wrapper div.dataTables_scrollBody thead .sorting_asc:after, 87 | div.dataTables_wrapper div.dataTables_scrollBody thead .sorting_desc:after { 88 | display: none; 89 | } 90 | div.dataTables_wrapper div.dataTables_scrollBody table.dataTable { 91 | border-radius: 0; 92 | border-top: none; 93 | border-bottom-width: 0; 94 | } 95 | div.dataTables_wrapper div.dataTables_scrollBody table.dataTable.no-footer { 96 | border-bottom-width: 1px; 97 | } 98 | div.dataTables_wrapper div.dataTables_scrollFoot table.dataTable { 99 | border-top-right-radius: 0; 100 | border-top-left-radius: 0; 101 | border-top: none; 102 | } 103 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/css/datatables/dataTables.semanticui.min.css: -------------------------------------------------------------------------------- 1 | table.dataTable.table{margin:0}table.dataTable.table thead th,table.dataTable.table thead td{position:relative}table.dataTable.table thead th.sorting,table.dataTable.table thead th.sorting_asc,table.dataTable.table thead th.sorting_desc,table.dataTable.table thead td.sorting,table.dataTable.table thead td.sorting_asc,table.dataTable.table thead td.sorting_desc{padding-right:20px}table.dataTable.table thead th.sorting:after,table.dataTable.table thead th.sorting_asc:after,table.dataTable.table thead th.sorting_desc:after,table.dataTable.table thead td.sorting:after,table.dataTable.table thead td.sorting_asc:after,table.dataTable.table thead td.sorting_desc:after{position:absolute;top:12px;right:8px;display:block;font-family:Icons}table.dataTable.table thead th.sorting:after,table.dataTable.table thead td.sorting:after{content:"\f0dc";color:#ddd;font-size:0.8em}table.dataTable.table thead th.sorting_asc:after,table.dataTable.table thead td.sorting_asc:after{content:"\f0de"}table.dataTable.table thead th.sorting_desc:after,table.dataTable.table thead td.sorting_desc:after{content:"\f0dd"}table.dataTable.table td,table.dataTable.table th{-webkit-box-sizing:content-box;box-sizing:content-box}table.dataTable.table td.dataTables_empty,table.dataTable.table th.dataTables_empty{text-align:center}table.dataTable.table.nowrap th,table.dataTable.table.nowrap td{white-space:nowrap}div.dataTables_wrapper div.dataTables_length select{vertical-align:middle;min-height:2.7142em}div.dataTables_wrapper div.dataTables_length .ui.selection.dropdown{min-width:0}div.dataTables_wrapper div.dataTables_filter input{margin-left:0.5em}div.dataTables_wrapper div.dataTables_info{padding-top:13px;white-space:nowrap}div.dataTables_wrapper div.dataTables_processing{position:absolute;top:50%;left:50%;width:200px;margin-left:-100px;text-align:center}div.dataTables_wrapper div.row.dt-table{padding:0}div.dataTables_wrapper div.dataTables_scrollHead table.dataTable{border-bottom-right-radius:0;border-bottom-left-radius:0;border-bottom:none}div.dataTables_wrapper div.dataTables_scrollBody thead .sorting:after,div.dataTables_wrapper div.dataTables_scrollBody thead .sorting_asc:after,div.dataTables_wrapper div.dataTables_scrollBody thead .sorting_desc:after{display:none}div.dataTables_wrapper div.dataTables_scrollBody table.dataTable{border-radius:0;border-top:none;border-bottom-width:0}div.dataTables_wrapper div.dataTables_scrollBody table.dataTable.no-footer{border-bottom-width:1px}div.dataTables_wrapper div.dataTables_scrollFoot table.dataTable{border-top-right-radius:0;border-top-left-radius:0;border-top:none} 2 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/css/datatables/dataTables.uikit.css: -------------------------------------------------------------------------------- 1 | table.dataTable { 2 | clear: both; 3 | margin-top: 6px !important; 4 | margin-bottom: 6px !important; 5 | max-width: none !important; 6 | } 7 | table.dataTable td, 8 | table.dataTable th { 9 | -webkit-box-sizing: content-box; 10 | box-sizing: content-box; 11 | } 12 | table.dataTable td.dataTables_empty, 13 | table.dataTable th.dataTables_empty { 14 | text-align: center; 15 | } 16 | table.dataTable.nowrap th, 17 | table.dataTable.nowrap td { 18 | white-space: nowrap; 19 | } 20 | 21 | div.dataTables_wrapper div.row.uk-grid.dt-merge-grid { 22 | margin-top: 5px; 23 | } 24 | div.dataTables_wrapper div.dataTables_length label { 25 | font-weight: normal; 26 | text-align: left; 27 | white-space: nowrap; 28 | } 29 | div.dataTables_wrapper div.dataTables_length select { 30 | width: 75px; 31 | display: inline-block; 32 | } 33 | div.dataTables_wrapper div.dataTables_filter { 34 | text-align: right; 35 | } 36 | div.dataTables_wrapper div.dataTables_filter label { 37 | font-weight: normal; 38 | white-space: nowrap; 39 | text-align: left; 40 | } 41 | div.dataTables_wrapper div.dataTables_filter input { 42 | margin-left: 0.5em; 43 | display: inline-block; 44 | width: auto; 45 | } 46 | div.dataTables_wrapper div.dataTables_info { 47 | padding-top: 8px; 48 | white-space: nowrap; 49 | } 50 | div.dataTables_wrapper div.dataTables_paginate { 51 | margin: 0; 52 | white-space: nowrap; 53 | text-align: right; 54 | } 55 | div.dataTables_wrapper div.dataTables_paginate ul.pagination { 56 | margin: 2px 0; 57 | white-space: nowrap; 58 | } 59 | div.dataTables_wrapper div.dataTables_processing { 60 | position: absolute; 61 | top: 50%; 62 | left: 50%; 63 | width: 200px; 64 | margin-left: -100px; 65 | margin-top: -26px; 66 | text-align: center; 67 | padding: 1em 0; 68 | } 69 | 70 | table.dataTable thead > tr > th, 71 | table.dataTable thead > tr > td { 72 | position: relative; 73 | } 74 | table.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting, 75 | table.dataTable thead > tr > td.sorting_asc, 76 | table.dataTable thead > tr > td.sorting_desc, 77 | table.dataTable thead > tr > td.sorting { 78 | padding-right: 30px; 79 | } 80 | table.dataTable thead > tr > th.sorting:after, table.dataTable thead > tr > th.sorting_asc:after, table.dataTable thead > tr > th.sorting_desc:after, 81 | table.dataTable thead > tr > td.sorting:after, 82 | table.dataTable thead > tr > td.sorting_asc:after, 83 | table.dataTable thead > tr > td.sorting_desc:after { 84 | position: absolute; 85 | top: 7px; 86 | right: 8px; 87 | display: block; 88 | font-family: 'FontAwesome'; 89 | } 90 | table.dataTable thead > tr > th.sorting:after, 91 | table.dataTable thead > tr > td.sorting:after { 92 | content: "\f0dc"; 93 | color: #ddd; 94 | font-size: 0.8em; 95 | padding-top: 0.12em; 96 | } 97 | table.dataTable thead > tr > th.sorting_asc:after, 98 | table.dataTable thead > tr > td.sorting_asc:after { 99 | content: "\f0de"; 100 | } 101 | table.dataTable thead > tr > th.sorting_desc:after, 102 | table.dataTable thead > tr > td.sorting_desc:after { 103 | content: "\f0dd"; 104 | } 105 | 106 | div.dataTables_scrollHead table.dataTable { 107 | margin-bottom: 0 !important; 108 | } 109 | 110 | div.dataTables_scrollBody table { 111 | border-top: none; 112 | margin-top: 0 !important; 113 | margin-bottom: 0 !important; 114 | } 115 | div.dataTables_scrollBody table thead .sorting:after, 116 | div.dataTables_scrollBody table thead .sorting_asc:after, 117 | div.dataTables_scrollBody table thead .sorting_desc:after { 118 | display: none; 119 | } 120 | div.dataTables_scrollBody table tbody tr:first-child th, 121 | div.dataTables_scrollBody table tbody tr:first-child td { 122 | border-top: none; 123 | } 124 | 125 | div.dataTables_scrollFoot table { 126 | margin-top: 0 !important; 127 | border-top: none; 128 | } 129 | 130 | @media screen and (max-width: 767px) { 131 | div.dataTables_wrapper div.dataTables_length, 132 | div.dataTables_wrapper div.dataTables_filter, 133 | div.dataTables_wrapper div.dataTables_info, 134 | div.dataTables_wrapper div.dataTables_paginate { 135 | text-align: center; 136 | } 137 | } 138 | table.dataTable.uk-table-condensed > thead > tr > th { 139 | padding-right: 20px; 140 | } 141 | table.dataTable.uk-table-condensed .sorting:after, 142 | table.dataTable.uk-table-condensed .sorting_asc:after, 143 | table.dataTable.uk-table-condensed .sorting_desc:after { 144 | top: 6px; 145 | right: 6px; 146 | } 147 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/css/datatables/dataTables.uikit.min.css: -------------------------------------------------------------------------------- 1 | table.dataTable{clear:both;margin-top:6px !important;margin-bottom:6px !important;max-width:none !important}table.dataTable td,table.dataTable th{-webkit-box-sizing:content-box;box-sizing:content-box}table.dataTable td.dataTables_empty,table.dataTable th.dataTables_empty{text-align:center}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}div.dataTables_wrapper div.row.uk-grid.dt-merge-grid{margin-top:5px}div.dataTables_wrapper div.dataTables_length label{font-weight:normal;text-align:left;white-space:nowrap}div.dataTables_wrapper div.dataTables_length select{width:75px;display:inline-block}div.dataTables_wrapper div.dataTables_filter{text-align:right}div.dataTables_wrapper div.dataTables_filter label{font-weight:normal;white-space:nowrap;text-align:left}div.dataTables_wrapper div.dataTables_filter input{margin-left:0.5em;display:inline-block;width:auto}div.dataTables_wrapper div.dataTables_info{padding-top:8px;white-space:nowrap}div.dataTables_wrapper div.dataTables_paginate{margin:0;white-space:nowrap;text-align:right}div.dataTables_wrapper div.dataTables_paginate ul.pagination{margin:2px 0;white-space:nowrap}div.dataTables_wrapper div.dataTables_processing{position:absolute;top:50%;left:50%;width:200px;margin-left:-100px;margin-top:-26px;text-align:center;padding:1em 0}table.dataTable thead>tr>th,table.dataTable thead>tr>td{position:relative}table.dataTable thead>tr>th.sorting_asc,table.dataTable thead>tr>th.sorting_desc,table.dataTable thead>tr>th.sorting,table.dataTable thead>tr>td.sorting_asc,table.dataTable thead>tr>td.sorting_desc,table.dataTable thead>tr>td.sorting{padding-right:30px}table.dataTable thead>tr>th.sorting:after,table.dataTable thead>tr>th.sorting_asc:after,table.dataTable thead>tr>th.sorting_desc:after,table.dataTable thead>tr>td.sorting:after,table.dataTable thead>tr>td.sorting_asc:after,table.dataTable thead>tr>td.sorting_desc:after{position:absolute;top:7px;right:8px;display:block;font-family:'FontAwesome'}table.dataTable thead>tr>th.sorting:after,table.dataTable thead>tr>td.sorting:after{content:"\f0dc";color:#ddd;font-size:0.8em;padding-top:0.12em}table.dataTable thead>tr>th.sorting_asc:after,table.dataTable thead>tr>td.sorting_asc:after{content:"\f0de"}table.dataTable thead>tr>th.sorting_desc:after,table.dataTable thead>tr>td.sorting_desc:after{content:"\f0dd"}div.dataTables_scrollHead table.dataTable{margin-bottom:0 !important}div.dataTables_scrollBody table{border-top:none;margin-top:0 !important;margin-bottom:0 !important}div.dataTables_scrollBody table thead .sorting:after,div.dataTables_scrollBody table thead .sorting_asc:after,div.dataTables_scrollBody table thead .sorting_desc:after{display:none}div.dataTables_scrollBody table tbody tr:first-child th,div.dataTables_scrollBody table tbody tr:first-child td{border-top:none}div.dataTables_scrollFoot table{margin-top:0 !important;border-top:none}@media screen and (max-width: 767px){div.dataTables_wrapper div.dataTables_length,div.dataTables_wrapper div.dataTables_filter,div.dataTables_wrapper div.dataTables_info,div.dataTables_wrapper div.dataTables_paginate{text-align:center}}table.dataTable.uk-table-condensed>thead>tr>th{padding-right:20px}table.dataTable.uk-table-condensed .sorting:after,table.dataTable.uk-table-condensed .sorting_asc:after,table.dataTable.uk-table-condensed .sorting_desc:after{top:6px;right:6px} 2 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/css/element/fonts/element-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuaFramework/cua-arbiter/61b2ea5d8b7c825b75d0f333d202e5703e0565a9/arbiter-web/arbiter/static/arbiter/css/element/fonts/element-icons.ttf -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/css/element/fonts/element-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuaFramework/cua-arbiter/61b2ea5d8b7c825b75d0f333d202e5703e0565a9/arbiter-web/arbiter/static/arbiter/css/element/fonts/element-icons.woff -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/css/index.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | background-color: #f2f2f2; 4 | } 5 | 6 | .mu-drawer { 7 | background-color: #f2f2f2; 8 | } 9 | 10 | #slide-nav { 11 | white-space: nowrap; 12 | } 13 | 14 | .log-dialog { 15 | max-width: 1000px; 16 | } 17 | 18 | .log-dialog h3 { 19 | padding: 4px 4px 3px; 20 | } 21 | 22 | .log-dialog p { 23 | margin: 2px; 24 | font-size: 12px; 25 | } 26 | 27 | #root-case { 28 | display: none; 29 | } 30 | 31 | #code-paper { 32 | top: 0; 33 | height: 600px; 34 | bottom: 0; 35 | } 36 | 37 | #case-paper { 38 | position: fixed; 39 | left: 0; 40 | top: 60px; 41 | right: 0; 42 | width: auto; 43 | bottom: 0; 44 | overflow-y: auto; 45 | size: 14px; 46 | z-index: -1; 47 | } 48 | 49 | .flex-between { 50 | display: flex; 51 | align-items: center; 52 | justify-content: space-between; 53 | width: 100%; 54 | 55 | } 56 | 57 | .grey-text { 58 | color: #9e9e9e; 59 | } 60 | 61 | .brown800-text { 62 | color: #4e342e; 63 | } 64 | 65 | .paper-casename { 66 | margin-left: 30px; 67 | } 68 | 69 | .paper-pyname { 70 | margin-left: 30px; 71 | cursor: pointer; 72 | } 73 | 74 | .red-icon { 75 | color: #ff5722; 76 | } 77 | 78 | .blue-icon { 79 | color: #6fa9ff; 80 | } 81 | 82 | .green-icon { 83 | color: #8bc34a; 84 | } 85 | 86 | .long-large-paper { 87 | margin-right: 100px; 88 | margin-left: 20px; 89 | } 90 | 91 | .long-little-paper { 92 | height: 45px; 93 | margin-bottom: 20px; 94 | margin-right: 130px; 95 | margin-left: 30px; 96 | position: relative; 97 | } -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/css/login.css: -------------------------------------------------------------------------------- 1 | body { 2 | text-align: center; 3 | background: rgba(0,0,0,0.05); 4 | vertical-align:middle; 5 | } 6 | 7 | .login { 8 | margin:auto; 9 | width: 400px; 10 | height: 320px; 11 | position:absolute; 12 | z-index:99; 13 | top: 25%; 14 | left: 40%; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/css/material-icons.css: -------------------------------------------------------------------------------- 1 | /* fallback */ 2 | @font-face { 3 | font-family: 'Material Icons'; 4 | font-style: normal; 5 | font-weight: 400; 6 | src: local('Material Icons'), local('MaterialIcons-Regular'), url("../fonts/material/o_1bgljqsqrvbv78v8lu1fsr1trca.woff2") format('woff2'); 7 | } 8 | 9 | .material-icons { 10 | font-family: 'Material Icons'; 11 | font-weight: normal; 12 | font-style: normal; 13 | font-size: 24px; 14 | line-height: 1; 15 | letter-spacing: normal; 16 | text-transform: none; 17 | display: inline-block; 18 | white-space: nowrap; 19 | word-wrap: normal; 20 | direction: ltr; 21 | -webkit-font-feature-settings: 'liga'; 22 | -webkit-font-smoothing: antialiased; 23 | } -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/css/navbar.css: -------------------------------------------------------------------------------- 1 | .mu-appbar { 2 | height: 56px; 3 | } 4 | 5 | .mu-appbar-title { 6 | line-height: 56px; 7 | } 8 | 9 | .appbar-search-field { 10 | color: #FFF; 11 | margin-bottom: 0; 12 | } 13 | 14 | #arbiter-header { 15 | position: fixed; 16 | left: 0; 17 | right: 0; 18 | top: 0; 19 | width: auto; 20 | } 21 | #arbiter-navbar { 22 | position: fixed; 23 | left: 0; 24 | right: 0; 25 | top: 0; 26 | width: auto; 27 | } 28 | 29 | .slider-open { 30 | left: 256px !important; 31 | } 32 | 33 | #arbiter-navbar h2 { 34 | width: 300px; 35 | } 36 | 37 | #arbiter-header .mu-avatar { 38 | margin: 30px; 39 | cursor: pointer; 40 | } 41 | 42 | #arbiter-navbar .mu-avatar { 43 | margin: 30px; 44 | cursor: pointer; 45 | } 46 | 47 | #arbiter-navbar .mu-text-field { 48 | 49 | width: 80%; 50 | 51 | } 52 | 53 | .appbar-search-field.focus-state { 54 | color: #FFF; 55 | } 56 | 57 | .appbar-search-field .mu-text-field-hint { 58 | color: rgba(255, 255, 255, 0.54); 59 | } 60 | 61 | .appbar-search-field .mu-text-field-input { 62 | color: #FFF; 63 | } 64 | 65 | .appbar-search-field .mu-text-field-focus-line { 66 | background-color: #FFF; 67 | } 68 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/css/scrollbar/app.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | .my-scrollbar { 4 | max-height: 100%; 5 | } 6 | 7 | .scroll-me { 8 | background: #EEE; 9 | /*min-width: 750px;*/ 10 | } 11 | 12 | .kolom { 13 | display: inline-block; 14 | margin: 15px; 15 | } 16 | 17 | .clearfix { 18 | clear: both; 19 | } 20 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/css/scrollbar/vue2-scrollbar.css: -------------------------------------------------------------------------------- 1 | .vue-scrollbar-transition, .vue-scrollbar__scrollbar-vertical, .vue-scrollbar__scrollbar-horizontal { 2 | transition: all 0.5s ease; 3 | -moz-transition: all 0.5s ease; 4 | -webkit-transition: all 0.5s ease; 5 | -o-transition: all 0.5s ease; 6 | } 7 | .vue-scrollbar-transition--scrollbar { 8 | transition: opacity 0.5s linear; 9 | -moz-transition: opacity 0.5s linear; 10 | -webkit-transition: opacity 0.5s linear; 11 | -o-transition: opacity 0.5s linear; 12 | } 13 | 14 | .vue-scrollbar__wrapper { 15 | margin: 0 auto; 16 | overflow: hidden; 17 | position: relative; 18 | } 19 | .vue-scrollbar__wrapper:hover .vue-scrollbar__scrollbar-vertical, .vue-scrollbar__wrapper:hover .vue-scrollbar__scrollbar-horizontal { 20 | opacity: 1; 21 | } 22 | .vue-scrollbar__scrollbar-vertical, .vue-scrollbar__scrollbar-horizontal { 23 | opacity: 0.5; 24 | position: absolute; 25 | background: transparent; 26 | } 27 | .vue-scrollbar__scrollbar-vertical:hover, .vue-scrollbar__scrollbar-horizontal:hover { 28 | background: rgba(0, 0, 0, 0.3); 29 | } 30 | .vue-scrollbar__scrollbar-vertical .scrollbar, .vue-scrollbar__scrollbar-horizontal .scrollbar { 31 | position: relative; 32 | background: rgba(0, 0, 0, 0.5); 33 | cursor: default; 34 | } 35 | .vue-scrollbar__scrollbar-vertical { 36 | width: 10px; 37 | height: 100%; 38 | top: 0; 39 | right: 0; 40 | } 41 | .vue-scrollbar__scrollbar-vertical .scrollbar { 42 | width: 10px; 43 | } 44 | .vue-scrollbar__scrollbar-horizontal { 45 | height: 10px; 46 | width: 100%; 47 | bottom: 0; 48 | right: 0; 49 | } 50 | .vue-scrollbar__scrollbar-horizontal .scrollbar { 51 | height: 10px; 52 | } 53 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/css/wholog/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | 3 | } 4 | 5 | #log-root { 6 | background: rgba(0, 0, 0, 0.05); 7 | vertical-align: middle; 8 | height: 100%; 9 | width: 100%; 10 | margin: 10px; 11 | 12 | } 13 | 14 | .query { 15 | display: flex; 16 | justify-content: center; 17 | margin-bottom: 20px; 18 | } 19 | 20 | .query-content span { 21 | font-weight: 500; 22 | font-size: large; 23 | } 24 | 25 | .query-button { 26 | display: flex; 27 | justify-content: center; 28 | } 29 | 30 | a { 31 | text-decoration: underline; 32 | color: #6495ED; 33 | } 34 | .red-icon { 35 | color: #ff5722; 36 | } 37 | .blue-icon { 38 | color: #6fa9ff; 39 | } 40 | a:hover { 41 | font-size: 120%; 42 | } 43 | .log-table-expand { 44 | font-size: 0; 45 | } 46 | .log-table-expand label { 47 | width: 90px; 48 | color: #99a9bf; 49 | } 50 | .log-table-expand .el-form-item { 51 | margin-right: 0; 52 | margin-bottom: 0; 53 | width: 30%; 54 | } 55 | 56 | #history-log { 57 | position: fixed; 58 | left: 0; 59 | top: 60px; 60 | right: 0; 61 | width: auto; 62 | bottom: 0; 63 | overflow-y: auto; 64 | size: 14px; 65 | z-index: -1; 66 | } 67 | 68 | .log-dialog { 69 | max-height: 360px; 70 | } 71 | 72 | .log-dialog p { 73 | margin: 5px; 74 | font-size: 12px; 75 | } 76 | 77 | .login-popup-top { 78 | width: 80%; 79 | opacity: .6; 80 | height: 48px; 81 | line-height: 48px; 82 | display: flex; 83 | align-items: center; 84 | justify-content: center; 85 | max-width: 375px; 86 | margin-top: 5px; 87 | color: red; 88 | background-color: #6495ED; 89 | } 90 | 91 | #arbiter-header { 92 | background-color: #6495ED; 93 | } 94 | 95 | .mu-appbar { 96 | background-color: #6495ED; 97 | } 98 | 99 | .login-dialog { 100 | padding-right: 20px; 101 | padding-bottom: 20px; 102 | height: 360px; 103 | width: 320px; 104 | } 105 | 106 | .login-dialog-btn { 107 | margin-right: 30px; 108 | margin-left: 25px; 109 | margin-top: 25px; 110 | width: 90%; 111 | } -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/css/wholog/statistic-log.css: -------------------------------------------------------------------------------- 1 | body { 2 | 3 | background: rgba(0, 0, 0, 0.05); 4 | vertical-align: middle; 5 | } 6 | 7 | #statistic-log { 8 | position: fixed; 9 | left: 0; 10 | top: 60px; 11 | right: 0; 12 | width: auto; 13 | bottom: 0; 14 | overflow-y: auto; 15 | size: 14px; 16 | z-index: -1; 17 | } 18 | 19 | #main { 20 | margin: 0 auto; 21 | width: 1000px; 22 | height: auto; 23 | } 24 | 25 | #result-content { 26 | margin: 0 auto; 27 | width: 1400px; 28 | height: 680px; 29 | } 30 | 31 | #main-chart { 32 | width: 1400px; 33 | height: 680px; 34 | } 35 | 36 | .login-dialog { 37 | padding-right: 20px; 38 | padding-bottom: 20px; 39 | height: 360px; 40 | width: 320px; 41 | } 42 | 43 | .login-dialog-btn { 44 | margin-right: 30px; 45 | margin-left: 25px; 46 | margin-top: 25px; 47 | width: 90%; 48 | } 49 | 50 | .log-dialog { 51 | max-height: 360px; 52 | } 53 | 54 | .log-dialog p { 55 | margin: 5px; 56 | font-size: 12px; 57 | } 58 | .log-chart-tooltip { 59 | word-wrap: break-word; 60 | word-break: break-all; 61 | } -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/fonts/material/o_1bgljqsqrvbv78v8lu1fsr1trca.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuaFramework/cua-arbiter/61b2ea5d8b7c825b75d0f333d202e5703e0565a9/arbiter-web/arbiter/static/arbiter/fonts/material/o_1bgljqsqrvbv78v8lu1fsr1trca.woff2 -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/fonts/roboto/Roboto-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuaFramework/cua-arbiter/61b2ea5d8b7c825b75d0f333d202e5703e0565a9/arbiter-web/arbiter/static/arbiter/fonts/roboto/Roboto-Bold.woff -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/fonts/roboto/Roboto-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuaFramework/cua-arbiter/61b2ea5d8b7c825b75d0f333d202e5703e0565a9/arbiter-web/arbiter/static/arbiter/fonts/roboto/Roboto-Bold.woff2 -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/fonts/roboto/Roboto-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuaFramework/cua-arbiter/61b2ea5d8b7c825b75d0f333d202e5703e0565a9/arbiter-web/arbiter/static/arbiter/fonts/roboto/Roboto-Light.woff -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/fonts/roboto/Roboto-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuaFramework/cua-arbiter/61b2ea5d8b7c825b75d0f333d202e5703e0565a9/arbiter-web/arbiter/static/arbiter/fonts/roboto/Roboto-Light.woff2 -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/fonts/roboto/Roboto-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuaFramework/cua-arbiter/61b2ea5d8b7c825b75d0f333d202e5703e0565a9/arbiter-web/arbiter/static/arbiter/fonts/roboto/Roboto-Medium.woff -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/fonts/roboto/Roboto-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuaFramework/cua-arbiter/61b2ea5d8b7c825b75d0f333d202e5703e0565a9/arbiter-web/arbiter/static/arbiter/fonts/roboto/Roboto-Medium.woff2 -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/fonts/roboto/Roboto-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuaFramework/cua-arbiter/61b2ea5d8b7c825b75d0f333d202e5703e0565a9/arbiter-web/arbiter/static/arbiter/fonts/roboto/Roboto-Regular.woff -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/fonts/roboto/Roboto-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuaFramework/cua-arbiter/61b2ea5d8b7c825b75d0f333d202e5703e0565a9/arbiter-web/arbiter/static/arbiter/fonts/roboto/Roboto-Regular.woff2 -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/fonts/roboto/Roboto-Thin.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuaFramework/cua-arbiter/61b2ea5d8b7c825b75d0f333d202e5703e0565a9/arbiter-web/arbiter/static/arbiter/fonts/roboto/Roboto-Thin.woff -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/fonts/roboto/Roboto-Thin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuaFramework/cua-arbiter/61b2ea5d8b7c825b75d0f333d202e5703e0565a9/arbiter-web/arbiter/static/arbiter/fonts/roboto/Roboto-Thin.woff2 -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/imgs/bg-pro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuaFramework/cua-arbiter/61b2ea5d8b7c825b75d0f333d202e5703e0565a9/arbiter-web/arbiter/static/arbiter/imgs/bg-pro.png -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/imgs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuaFramework/cua-arbiter/61b2ea5d8b7c825b75d0f333d202e5703e0565a9/arbiter-web/arbiter/static/arbiter/imgs/favicon.ico -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/imgs/progress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuaFramework/cua-arbiter/61b2ea5d8b7c825b75d0f333d202e5703e0565a9/arbiter-web/arbiter/static/arbiter/imgs/progress.png -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/imgs/team_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuaFramework/cua-arbiter/61b2ea5d8b7c825b75d0f333d202e5703e0565a9/arbiter-web/arbiter/static/arbiter/imgs/team_logo.png -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/common/ace/mode-python.js: -------------------------------------------------------------------------------- 1 | define("ace/mode/python_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){var e="and|as|assert|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|not|or|pass|print|raise|return|try|while|with|yield",t="True|False|None|NotImplemented|Ellipsis|__debug__",n="abs|divmod|input|open|staticmethod|all|enumerate|int|ord|str|any|eval|isinstance|pow|sum|basestring|execfile|issubclass|print|super|binfile|iter|property|tuple|bool|filter|len|range|type|bytearray|float|list|raw_input|unichr|callable|format|locals|reduce|unicode|chr|frozenset|long|reload|vars|classmethod|getattr|map|repr|xrange|cmp|globals|max|reversed|zip|compile|hasattr|memoryview|round|__import__|complex|hash|min|set|apply|delattr|help|next|setattr|buffer|dict|hex|object|slice|coerce|dir|id|oct|sorted|intern",r=this.createKeywordMapper({"invalid.deprecated":"debugger","support.function":n,"constant.language":t,keyword:e},"identifier"),i="(?:r|u|ur|R|U|UR|Ur|uR)?",s="(?:(?:[1-9]\\d*)|(?:0))",o="(?:0[oO]?[0-7]+)",u="(?:0[xX][\\dA-Fa-f]+)",a="(?:0[bB][01]+)",f="(?:"+s+"|"+o+"|"+u+"|"+a+")",l="(?:[eE][+-]?\\d+)",c="(?:\\.\\d+)",h="(?:\\d+)",p="(?:(?:"+h+"?"+c+")|(?:"+h+"\\.))",d="(?:(?:"+p+"|"+h+")"+l+")",v="(?:"+d+"|"+p+")",m="\\\\(x[0-9A-Fa-f]{2}|[0-7]{3}|[\\\\abfnrtv'\"]|U[0-9A-Fa-f]{8}|u[0-9A-Fa-f]{4})";this.$rules={start:[{token:"comment",regex:"#.*$"},{token:"string",regex:i+'"{3}',next:"qqstring3"},{token:"string",regex:i+'"(?=.)',next:"qqstring"},{token:"string",regex:i+"'{3}",next:"qstring3"},{token:"string",regex:i+"'(?=.)",next:"qstring"},{token:"constant.numeric",regex:"(?:"+v+"|\\d+)[jJ]\\b"},{token:"constant.numeric",regex:v},{token:"constant.numeric",regex:f+"[lL]\\b"},{token:"constant.numeric",regex:f+"\\b"},{token:r,regex:"[a-zA-Z_$][a-zA-Z0-9_$]*\\b"},{token:"keyword.operator",regex:"\\+|\\-|\\*|\\*\\*|\\/|\\/\\/|%|<<|>>|&|\\||\\^|~|<|>|<=|=>|==|!=|<>|="},{token:"paren.lparen",regex:"[\\[\\(\\{]"},{token:"paren.rparen",regex:"[\\]\\)\\}]"},{token:"text",regex:"\\s+"}],qqstring3:[{token:"constant.language.escape",regex:m},{token:"string",regex:'"{3}',next:"start"},{defaultToken:"string"}],qstring3:[{token:"constant.language.escape",regex:m},{token:"string",regex:"'{3}",next:"start"},{defaultToken:"string"}],qqstring:[{token:"constant.language.escape",regex:m},{token:"string",regex:"\\\\$",next:"qqstring"},{token:"string",regex:'"|$',next:"start"},{defaultToken:"string"}],qstring:[{token:"constant.language.escape",regex:m},{token:"string",regex:"\\\\$",next:"qstring"},{token:"string",regex:"'|$",next:"start"},{defaultToken:"string"}]}};r.inherits(s,i),t.PythonHighlightRules=s}),define("ace/mode/folding/pythonic",["require","exports","module","ace/lib/oop","ace/mode/folding/fold_mode"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("./fold_mode").FoldMode,s=t.FoldMode=function(e){this.foldingStartMarker=new RegExp("([\\[{])(?:\\s*)$|("+e+")(?:\\s*)(?:#.*)?$")};r.inherits(s,i),function(){this.getFoldWidgetRange=function(e,t,n){var r=e.getLine(n),i=r.match(this.foldingStartMarker);if(i)return i[1]?this.openingBracketBlock(e,i[1],n,i.index):i[2]?this.indentationBlock(e,n,i.index+i[2].length):this.indentationBlock(e,n)}}.call(s.prototype)}),define("ace/mode/python",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/python_highlight_rules","ace/mode/folding/pythonic","ace/range"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./python_highlight_rules").PythonHighlightRules,o=e("./folding/pythonic").FoldMode,u=e("../range").Range,a=function(){this.HighlightRules=s,this.foldingRules=new o("\\:"),this.$behaviour=this.$defaultBehaviour};r.inherits(a,i),function(){this.lineCommentStart="#",this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t),i=this.getTokenizer().getLineTokens(t,e),s=i.tokens;if(s.length&&s[s.length-1].type=="comment")return r;if(e=="start"){var o=t.match(/^.*[\{\(\[:]\s*$/);o&&(r+=n)}return r};var e={pass:1,"return":1,raise:1,"break":1,"continue":1};this.checkOutdent=function(t,n,r){if(r!=="\r\n"&&r!=="\r"&&r!=="\n")return!1;var i=this.getTokenizer().getLineTokens(n.trim(),t).tokens;if(!i)return!1;do var s=i.pop();while(s&&(s.type=="comment"||s.type=="text"&&s.value.match(/^\s+$/)));return s?s.type=="keyword"&&e[s.value]:!1},this.autoOutdent=function(e,t,n){n+=1;var r=this.$getIndent(t.getLine(n)),i=t.getTabString();r.slice(-i.length)==i&&t.remove(new u(n,r.length-i.length,n,r.length))},this.$id="ace/mode/python"}.call(a.prototype),t.Mode=a}) -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/common/ace/theme-chrome.js: -------------------------------------------------------------------------------- 1 | define("ace/theme/chrome",["require","exports","module","ace/lib/dom"],function(e,t,n){t.isDark=!1,t.cssClass="ace-chrome",t.cssText='.ace-chrome .ace_gutter {background: #ebebeb;color: #333;overflow : hidden;}.ace-chrome .ace_print-margin {width: 1px;background: #e8e8e8;}.ace-chrome {background-color: #FFFFFF;color: black;}.ace-chrome .ace_cursor {color: black;}.ace-chrome .ace_invisible {color: rgb(191, 191, 191);}.ace-chrome .ace_constant.ace_buildin {color: rgb(88, 72, 246);}.ace-chrome .ace_constant.ace_language {color: rgb(88, 92, 246);}.ace-chrome .ace_constant.ace_library {color: rgb(6, 150, 14);}.ace-chrome .ace_invalid {background-color: rgb(153, 0, 0);color: white;}.ace-chrome .ace_fold {}.ace-chrome .ace_support.ace_function {color: rgb(60, 76, 114);}.ace-chrome .ace_support.ace_constant {color: rgb(6, 150, 14);}.ace-chrome .ace_support.ace_type,.ace-chrome .ace_support.ace_class.ace-chrome .ace_support.ace_other {color: rgb(109, 121, 222);}.ace-chrome .ace_variable.ace_parameter {font-style:italic;color:#FD971F;}.ace-chrome .ace_keyword.ace_operator {color: rgb(104, 118, 135);}.ace-chrome .ace_comment {color: #236e24;}.ace-chrome .ace_comment.ace_doc {color: #236e24;}.ace-chrome .ace_comment.ace_doc.ace_tag {color: #236e24;}.ace-chrome .ace_constant.ace_numeric {color: rgb(0, 0, 205);}.ace-chrome .ace_variable {color: rgb(49, 132, 149);}.ace-chrome .ace_xml-pe {color: rgb(104, 104, 91);}.ace-chrome .ace_entity.ace_name.ace_function {color: #0000A2;}.ace-chrome .ace_heading {color: rgb(12, 7, 255);}.ace-chrome .ace_list {color:rgb(185, 6, 144);}.ace-chrome .ace_marker-layer .ace_selection {background: rgb(181, 213, 255);}.ace-chrome .ace_marker-layer .ace_step {background: rgb(252, 255, 0);}.ace-chrome .ace_marker-layer .ace_stack {background: rgb(164, 229, 101);}.ace-chrome .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgb(192, 192, 192);}.ace-chrome .ace_marker-layer .ace_active-line {background: rgba(0, 0, 0, 0.07);}.ace-chrome .ace_gutter-active-line {background-color : #dcdcdc;}.ace-chrome .ace_marker-layer .ace_selected-word {background: rgb(250, 250, 255);border: 1px solid rgb(200, 200, 250);}.ace-chrome .ace_storage,.ace-chrome .ace_keyword,.ace-chrome .ace_meta.ace_tag {color: rgb(147, 15, 128);}.ace-chrome .ace_string.ace_regex {color: rgb(255, 0, 0)}.ace-chrome .ace_string {color: #1A1AA6;}.ace-chrome .ace_entity.ace_other.ace_attribute-name {color: #994409;}.ace-chrome .ace_indent-guide {background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==") right repeat-y;}';var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)}) -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/common/ace/theme-dawn.js: -------------------------------------------------------------------------------- 1 | define("ace/theme/dawn",["require","exports","module","ace/lib/dom"],function(e,t,n){t.isDark=!1,t.cssClass="ace-dawn",t.cssText=".ace-dawn .ace_gutter {background: #ebebeb;color: #333}.ace-dawn .ace_print-margin {width: 1px;background: #e8e8e8}.ace-dawn {background-color: #F9F9F9;color: #080808}.ace-dawn .ace_cursor {color: #000000}.ace-dawn .ace_marker-layer .ace_selection {background: rgba(39, 95, 255, 0.30)}.ace-dawn.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px #F9F9F9;}.ace-dawn .ace_marker-layer .ace_step {background: rgb(255, 255, 0)}.ace-dawn .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgba(75, 75, 126, 0.50)}.ace-dawn .ace_marker-layer .ace_active-line {background: rgba(36, 99, 180, 0.12)}.ace-dawn .ace_gutter-active-line {background-color : #dcdcdc}.ace-dawn .ace_marker-layer .ace_selected-word {border: 1px solid rgba(39, 95, 255, 0.30)}.ace-dawn .ace_invisible {color: rgba(75, 75, 126, 0.50)}.ace-dawn .ace_keyword,.ace-dawn .ace_meta {color: #794938}.ace-dawn .ace_constant,.ace-dawn .ace_constant.ace_character,.ace-dawn .ace_constant.ace_character.ace_escape,.ace-dawn .ace_constant.ace_other {color: #811F24}.ace-dawn .ace_invalid.ace_illegal {text-decoration: underline;font-style: italic;color: #F8F8F8;background-color: #B52A1D}.ace-dawn .ace_invalid.ace_deprecated {text-decoration: underline;font-style: italic;color: #B52A1D}.ace-dawn .ace_support {color: #691C97}.ace-dawn .ace_support.ace_constant {color: #B4371F}.ace-dawn .ace_fold {background-color: #794938;border-color: #080808}.ace-dawn .ace_list,.ace-dawn .ace_markup.ace_list,.ace-dawn .ace_support.ace_function {color: #693A17}.ace-dawn .ace_storage {font-style: italic;color: #A71D5D}.ace-dawn .ace_string {color: #0B6125}.ace-dawn .ace_string.ace_regexp {color: #CF5628}.ace-dawn .ace_comment {font-style: italic;color: #5A525F}.ace-dawn .ace_heading,.ace-dawn .ace_markup.ace_heading {color: #19356D}.ace-dawn .ace_variable {color: #234A97}.ace-dawn .ace_indent-guide {background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYLh/5+x/AAizA4hxNNsZAAAAAElFTkSuQmCC) right repeat-y}";var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)}) -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/common/ace/theme-github.js: -------------------------------------------------------------------------------- 1 | define("ace/theme/github",["require","exports","module","ace/lib/dom"],function(e,t,n){t.isDark=!1,t.cssClass="ace-github",t.cssText='.ace-github .ace_gutter {background: #e8e8e8;color: #AAA;}.ace-github {background: #fff;color: #000;}.ace-github .ace_keyword {font-weight: bold;}.ace-github .ace_string {color: #D14;}.ace-github .ace_variable.ace_class {color: teal;}.ace-github .ace_constant.ace_numeric {color: #099;}.ace-github .ace_constant.ace_buildin {color: #0086B3;}.ace-github .ace_support.ace_function {color: #0086B3;}.ace-github .ace_comment {color: #998;font-style: italic;}.ace-github .ace_variable.ace_language {color: #0086B3;}.ace-github .ace_paren {font-weight: bold;}.ace-github .ace_boolean {font-weight: bold;}.ace-github .ace_string.ace_regexp {color: #009926;font-weight: normal;}.ace-github .ace_variable.ace_instance {color: teal;}.ace-github .ace_constant.ace_language {font-weight: bold;}.ace-github .ace_cursor {color: black;}.ace-github.ace_focus .ace_marker-layer .ace_active-line {background: rgb(255, 255, 204);}.ace-github .ace_marker-layer .ace_active-line {background: rgb(245, 245, 245);}.ace-github .ace_marker-layer .ace_selection {background: rgb(181, 213, 255);}.ace-github.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px white;}.ace-github.ace_nobold .ace_line > span {font-weight: normal !important;}.ace-github .ace_marker-layer .ace_step {background: rgb(252, 255, 0);}.ace-github .ace_marker-layer .ace_stack {background: rgb(164, 229, 101);}.ace-github .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgb(192, 192, 192);}.ace-github .ace_gutter-active-line {background-color : rgba(0, 0, 0, 0.07);}.ace-github .ace_marker-layer .ace_selected-word {background: rgb(250, 250, 255);border: 1px solid rgb(200, 200, 250);}.ace-github .ace_invisible {color: #BFBFBF}.ace-github .ace_print-margin {width: 1px;background: #e8e8e8;}.ace-github .ace_indent-guide {background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==") right repeat-y;}';var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)}) -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/common/ace/theme-iplastic.js: -------------------------------------------------------------------------------- 1 | define("ace/theme/iplastic",["require","exports","module","ace/lib/dom"],function(e,t,n){t.isDark=!1,t.cssClass="ace-iplastic",t.cssText=".ace-iplastic .ace_gutter {background: #dddddd;color: #666666}.ace-iplastic .ace_print-margin {width: 1px;background: #bbbbbb}.ace-iplastic {background-color: #eeeeee;color: #333333}.ace-iplastic .ace_cursor {color: #333}.ace-iplastic .ace_marker-layer .ace_selection {background: #BAD6FD;}.ace-iplastic.ace_multiselect .ace_selection.ace_start {border-radius: 4px}.ace-iplastic .ace_marker-layer .ace_step {background: #444444}.ace-iplastic .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid #49483E;background: #FFF799}.ace-iplastic .ace_marker-layer .ace_active-line {background: #e5e5e5}.ace-iplastic .ace_gutter-active-line {background-color: #eeeeee}.ace-iplastic .ace_marker-layer .ace_selected-word {border: 1px solid #555555;border-radius:4px}.ace-iplastic .ace_invisible {color: #999999}.ace-iplastic .ace_entity.ace_name.ace_tag,.ace-iplastic .ace_keyword,.ace-iplastic .ace_meta.ace_tag,.ace-iplastic .ace_storage {color: #0000FF}.ace-iplastic .ace_punctuation,.ace-iplastic .ace_punctuation.ace_tag {color: #000}.ace-iplastic .ace_constant {color: #333333;font-weight: 700}.ace-iplastic .ace_constant.ace_character,.ace-iplastic .ace_constant.ace_language,.ace-iplastic .ace_constant.ace_numeric,.ace-iplastic .ace_constant.ace_other {color: #0066FF;font-weight: 700}.ace-iplastic .ace_constant.ace_numeric{font-weight: 100}.ace-iplastic .ace_invalid {color: #F8F8F0;background-color: #F92672}.ace-iplastic .ace_invalid.ace_deprecated {color: #F8F8F0;background-color: #AE81FF}.ace-iplastic .ace_support.ace_constant,.ace-iplastic .ace_support.ace_function {color: #333333;font-weight: 700}.ace-iplastic .ace_fold {background-color: #464646;border-color: #F8F8F2}.ace-iplastic .ace_storage.ace_type,.ace-iplastic .ace_support.ace_class,.ace-iplastic .ace_support.ace_type {color: #3333fc;font-weight: 700}.ace-iplastic .ace_entity.ace_name.ace_function,.ace-iplastic .ace_entity.ace_other,.ace-iplastic .ace_entity.ace_other.ace_attribute-name,.ace-iplastic .ace_variable {color: #3366cc;font-style: italic}.ace-iplastic .ace_variable.ace_parameter {font-style: italic;color: #2469E0}.ace-iplastic .ace_string {color: #a55f03}.ace-iplastic .ace_comment {color: #777777;font-style: italic}.ace-iplastic .ace_fold-widget {background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42mWKsQ0AMAzC8ixLlrzQjzmBiEjp0A6WwBCSPgKAXoLkqSot7nN3yMwR7pZ32NzpKkVoDBUxKAAAAABJRU5ErkJggg==);}.ace-iplastic .ace_indent-guide {background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAABlJREFUeNpi+P//PwMzMzPzfwAAAAD//wMAGRsECSML/RIAAAAASUVORK5CYII=) right repeat-y}";var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)}) -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/common/common.js: -------------------------------------------------------------------------------- 1 | let run_socket = new WebSocket("ws://" + window.location.host + "/arbiter/"); 2 | let edit_socket = new WebSocket("ws://" + window.location.host + "/arbiter/"); 3 | 4 | function deleteAllCookies() { 5 | let cookies = document.cookie.split(";"); 6 | 7 | for (let i = 0; i < cookies.length; i++) { 8 | let cookie = cookies[i]; 9 | let eqPos = cookie.indexOf("="); 10 | let name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie; 11 | document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT"; 12 | } 13 | } 14 | 15 | Date.prototype.format = function (fmt) { 16 | var o = { 17 | "M+": this.getMonth() + 1, 18 | "d+": this.getDate(), 19 | "H+": this.getHours(), 20 | "m+": this.getMinutes(), 21 | "s+": this.getSeconds(), 22 | "S+": this.getMilliseconds() 23 | }; 24 | 25 | //因位date.getFullYear()出来的结果是number类型的,所以为了让结果变成字符串型,下面有两种方法: 26 | 27 | 28 | if (/(y+)/.test(fmt)) { 29 | //第一种:利用字符串连接符“+”给date.getFullYear()+"",加一个空字符串便可以将number类型转换成字符串。 30 | 31 | fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); 32 | } 33 | for (var k in o) { 34 | if (new RegExp("(" + k + ")").test(fmt)) { 35 | 36 | //第二种:使用String()类型进行强制数据类型转换String(date.getFullYear()),这种更容易理解。 37 | 38 | fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(String(o[k]).length))); 39 | } 40 | } 41 | return fmt; 42 | }; 43 | 44 | 45 | /** 46 | * 验证是否可编辑 47 | * @constructor 48 | */ 49 | function ValidateEditWebSocket(fileName) { 50 | if ("WebSocket" in window) { 51 | edit_socket.onmessage = function (e) { 52 | console.log(e.data); 53 | 54 | }; 55 | edit_socket.onopen = function () { 56 | //发送validateEdit 0 查询 57 | edit_socket.send("validateEdit 0 " + fileName); 58 | }; 59 | // Call onopen directly if edit_socket is already open 60 | if (edit_socket.readyState === WebSocket.OPEN) 61 | edit_socket.onopen(); 62 | } 63 | else { 64 | // 浏览器不支持 WebSocket 65 | alert("您的浏览器不支持 WebSocket!"); 66 | } 67 | } 68 | 69 | 70 | function getusername() { 71 | let storage = window.localStorage; 72 | let username = storage['username']; 73 | return username ? username : null; 74 | } 75 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/common/get-res.js: -------------------------------------------------------------------------------- 1 | function getRes(requestPath,requestBody,jwtHeader) { 2 | return fetch(requestPath, 3 | { 4 | method: "POST", 5 | headers: { 6 | 'Accept': 'application/json, text/plain, */*', 7 | 'Content-Type': 'application/json', 8 | 'Authorization': (jwtHeader !== null) ? ("JWT "+jwtHeader) :"" 9 | }, 10 | body: JSON.stringify(requestBody) 11 | }).then((response) => { 12 | if(response.status === 401){ 13 | console.log("权限验证失败,状态码为:" + response.status); 14 | window.location.href = "/arbiter/login"; 15 | } 16 | else if (response.status !== 200) { 17 | console.log("存在一个问题,状态码为:" + response.status); 18 | const error = new Error(response.statusText); 19 | error.response = response; 20 | throw error; 21 | } 22 | else 23 | return response.json(); 24 | }) 25 | } -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/common/index.js: -------------------------------------------------------------------------------- 1 | //所有用到的组件 2 | let Event = new Vue(); 3 | 4 | let getfilePath = function (key) { 5 | let casepath = key.substring(key.indexOf(".") + 1); 6 | casepath = casepath.substring(casepath.indexOf(".") + 1); 7 | let pyfilepath = casepath.split(":")[0].replace(/\./g, "/") + ".py"; 8 | return pyfilepath; 9 | }; 10 | let topaperMap = function (caseMap) { 11 | let paperMap = {}; 12 | for (let [key, value] of Object.entries(caseMap)) { 13 | if (typeof value !== "object") { 14 | let pyfilepath = getfilePath(key); 15 | if (!!paperMap[pyfilepath] === false) { 16 | paperMap[pyfilepath] = {}; 17 | } 18 | paperMap[pyfilepath][key] = value; 19 | } 20 | } 21 | return paperMap; 22 | }; 23 | let toAllpaperMap = function (caseMap) { 24 | let paperMap = {}; 25 | for (let [key, value] of Object.entries(caseMap)) { 26 | if (typeof value !== "object") { 27 | let pyfilepath = getfilePath(key); 28 | if (!!paperMap[pyfilepath] === false) { 29 | paperMap[pyfilepath] = {}; 30 | } 31 | paperMap[pyfilepath][key] = value; 32 | } 33 | else { 34 | for (let [k, y] of Object.entries(value)) { 35 | 36 | let pyfilepath = getfilePath(key); 37 | if (!!paperMap[pyfilepath] === false) { 38 | paperMap[pyfilepath] = {}; 39 | } 40 | paperMap[pyfilepath][k] = y; 41 | } 42 | } 43 | 44 | } 45 | return paperMap; 46 | }; 47 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/common/snow.js: -------------------------------------------------------------------------------- 1 | const snow=function () { 2 | let canvas = document.querySelector('canvas'); 3 | let ctx = canvas.getContext('2d'); 4 | canvas.width = window.innerWidth; 5 | canvas.height = window.innerHeight; 6 | ctx.lineWidth = .3; 7 | ctx.strokeStyle = (new Color()).style; 8 | 9 | let dots = { 10 | nb: 40, 11 | distance: 50, 12 | d_radius: 100, 13 | array: [] 14 | }; 15 | 16 | function createColorStyle() { 17 | return 'rgba(0,0,0,0.1)'; 18 | } 19 | 20 | function Color() { 21 | 22 | this.style = createColorStyle(); 23 | } 24 | 25 | function Dot() { 26 | this.x = Math.random() * canvas.width; 27 | this.y = Math.random() * canvas.height; 28 | 29 | this.vx = -.5 + Math.random(); 30 | this.vy = -.5 + Math.random(); 31 | 32 | this.radius = Math.random() * 4; 33 | 34 | this.color = new Color(); 35 | } 36 | 37 | Dot.prototype = { 38 | draw: function () { 39 | ctx.beginPath(); 40 | ctx.fillStyle = this.color.style; 41 | ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false); 42 | ctx.fill(); 43 | } 44 | }; 45 | 46 | function createDots() { 47 | for (let i = 0; i < dots.nb; i++) { 48 | dots.array.push(new Dot()); 49 | } 50 | } 51 | 52 | function moveDots() { 53 | for (let i = 0; i < dots.nb; i++) { 54 | 55 | let dot = dots.array[i]; 56 | 57 | if (dot.y < 0 || dot.y > canvas.height) { 58 | 59 | dot.vy = -dot.vy; 60 | } 61 | else if (dot.x < 0 || dot.x > canvas.width) { 62 | dot.vx = -dot.vx; 63 | } 64 | dot.x += dot.vx; 65 | dot.y += dot.vy; 66 | } 67 | } 68 | 69 | function drawDots() { 70 | for (let i = 0; i < dots.nb; i++) { 71 | let dot = dots.array[i]; 72 | dot.draw(); 73 | } 74 | } 75 | 76 | function animateDots() { 77 | ctx.clearRect(0, 0, canvas.width, canvas.height); 78 | moveDots(); 79 | // connectDots(); 80 | drawDots(); 81 | 82 | requestAnimationFrame(animateDots); 83 | } 84 | 85 | 86 | createDots(); 87 | requestAnimationFrame(animateDots); 88 | }; 89 | snow(); -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/core/app.js: -------------------------------------------------------------------------------- 1 | let app = new Vue({ 2 | router, 3 | el: '#app', store, 4 | data() { 5 | return {modelList: {}} 6 | }, 7 | mounted() { 8 | this.flushAllCases().then( 9 | (json) => { 10 | Event.$emit('change-paper', json); 11 | document.getElementsByTagName("body")[0].style.display = ""; 12 | this.modelList = json; 13 | }).catch((err) => { 14 | console.log("请求错误:" + err); 15 | }); 16 | }, 17 | methods: { 18 | ...Vuex.mapActions(['flushAllCases']), 19 | 20 | }, 21 | components: { //要把组件写入到components里面,如果没有放的话在切换的时候就会找不到 组件 22 | 'ArbiterNavbar': ArbiterNavbar, 23 | 'ArbiterSlide': ArbiterSlide, 24 | 'CaseFloatBtn': CaseFloatBtn, 25 | 'CasePaper': CasePaper, 26 | } 27 | }); 28 | 29 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/core/component/arbiter-navbar.js: -------------------------------------------------------------------------------- 1 | //顶部bar组件 2 | const ArbiterNavbar = { 3 | template: '#arbiterNavbar', 4 | store, 5 | computed: { 6 | usernameAbbreviation() { 7 | if (!!this.username()) { 8 | return this.username().substr(0, 2) 9 | } 10 | else 11 | return null; 12 | } 13 | }, 14 | data: function () { 15 | return { 16 | message: { 17 | href: 'login', 18 | }, 19 | sliderIsOpen: true, 20 | } 21 | }, 22 | mounted() { 23 | this.refreshJwtToken(); 24 | getRes("/arbiter/getUserDetail", null, this.jwtHeader()).then( 25 | json => { 26 | let storage = window.localStorage; 27 | storage["username"] = json["username"]; 28 | storage["role"] = json["role"]; 29 | // this.$store.commit('setUserName', json["username"]); 30 | this.setUserName(json["username"]); 31 | 32 | } 33 | ).catch((err) => { 34 | console.log("请求错误:" + err); 35 | }); 36 | }, 37 | methods: { 38 | ...Vuex.mapMutations(['setUserName', 'refreshJwtToken','setSlideOpen']), 39 | ...Vuex.mapGetters(['username', 'jwtHeader']), 40 | toggleSlide() { 41 | this.sliderIsOpen = !this.sliderIsOpen; 42 | this.setSlideOpen(); 43 | } 44 | }, 45 | components: { //要把组件写入到components里面,如果没有放的话在切换的时候就会找不到 组件 46 | 'userAvatar': userAvatar, 47 | 'menuIconButton': menuIconButton, 48 | } 49 | 50 | }; -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/core/component/arbiter-slide.js: -------------------------------------------------------------------------------- 1 | //侧边菜单组件 2 | const ArbiterSlide = { 3 | props: {modelList: {}}, 4 | template: '#arbiterNavSlide', 5 | store, 6 | data() { 7 | return { 8 | open: true, 9 | docked: true, 10 | value: "", 11 | dialog: false, 12 | gitInfo: {}, 13 | gitCloneStatus: 'finish', 14 | } 15 | }, 16 | computed: { 17 | slideOpen() { 18 | return this.getSlideOpen(); 19 | }, 20 | }, 21 | watch: { 22 | slideOpen(val) { 23 | this.open = val; 24 | }, 25 | 26 | }, 27 | methods: { 28 | ...Vuex.mapGetters(['getSlideOpen', 'jwtHeader']), 29 | handleChange(val) { 30 | this.value = val; 31 | }, 32 | openImportDialog() { 33 | this.dialog = true; 34 | 35 | }, 36 | closeImportDialog() { 37 | this.dialog = false 38 | }, 39 | cloneCaseObj() { 40 | this.gitCloneStatus = 'running'; 41 | 42 | getRes("./cloneCaseObj", this.gitInfo, this.jwtHeader()).then( 43 | json => { 44 | window.location.href = window.location.href; 45 | }).catch((err) => { 46 | this.gitCloneStatus = 'finish'; 47 | console.log("请求错误:" + err); 48 | }); 49 | }, 50 | 51 | toggle() { 52 | this.open = !this.open; 53 | }, 54 | loadCasePaper(casemodel) { 55 | this.$router.push({name: 'casepath', params: {casemodel: casemodel}}); 56 | }, 57 | 58 | } 59 | }; -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/core/component/case-float-btn.js: -------------------------------------------------------------------------------- 1 | //用例列表中的fab组件 2 | const CaseFloatBtn = { 3 | template: '#caseFloatBtn', 4 | data: function () { 5 | return { 6 | modalShow: true, 7 | seen: false, 8 | testCase: "", 9 | testName: "", 10 | logDialog: false, 11 | logContent: [], 12 | } 13 | }, mounted() { 14 | let _this = this; 15 | Event.$on('run-case', function (value) { 16 | 17 | _this.testCase = value.testCase; 18 | _this.testName = value.testName; 19 | _this.run(); 20 | }); 21 | 22 | }, 23 | methods: { 24 | ...Vuex.mapGetters(['username', 'jwtHeader']), 25 | openLogDialog() { 26 | this.logDialog = true; 27 | 28 | }, 29 | closeLogDialog() { 30 | this.logDialog = false 31 | }, 32 | onMouseEnterCodeFAB() { 33 | this.seen = true; 34 | }, 35 | onMouseleaveCodeFAB() { 36 | this.seen = false; 37 | }, 38 | log() { 39 | this.logDialog = true; 40 | }, 41 | cleanLog() { 42 | this.logContent = []; 43 | }, 44 | run() { 45 | 46 | run_socket.onmessage = (res) => { 47 | this.logContent.push(res.data); 48 | // document.getElementById("insert").innerHTML += "

" + e.data + "

"; 49 | 50 | }; 51 | run_socket.onopen = () => { 52 | run_socket.send("runCase " + this.testCase + " " + this.username()+ " " + this.testName); 53 | }; 54 | // Call onopen directly if socket is already open 55 | if (run_socket.readyState === WebSocket.OPEN) 56 | run_socket.onopen(); 57 | 58 | this.logDialog = true; 59 | } 60 | , 61 | add() { 62 | 63 | }, 64 | } 65 | }; -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/core/component/case-paper.js: -------------------------------------------------------------------------------- 1 | //每个case的paper组件 2 | const CasePaper = { 3 | props: {casemodel: "", pyname: ""}, store, 4 | template: '#casePaper', 5 | components: { 6 | 'CodePaper': CodePaper, 7 | 'CodeFloatBtn': CodeFloatBtn, 8 | }, 9 | data() { 10 | return { 11 | caseMap: {}, 12 | cpath: null, 13 | copyDialog: false, 14 | deleteDialog: false, 15 | copyStatus: "finish", 16 | deleteStatus: "finish", 17 | fileInfo: { 18 | oldName: "", 19 | newName: "", 20 | }, 21 | deleteFilePath: "", 22 | }; 23 | }, 24 | computed: { 25 | slideOpen() { 26 | return this.getSlideOpen(); 27 | }, 28 | }, 29 | watch: { 30 | casemodel: function (val) { 31 | if (val.split(".").length < 3) { 32 | Event.$emit('change-paper', this.getAllCases()); 33 | } 34 | else { 35 | Event.$emit('change-paper-all', this.getAllCases()); 36 | } 37 | } 38 | }, 39 | mounted() { 40 | let _this = this; 41 | Event.$on('change-paper', (caseMap) => { 42 | _this.caseMap = caseMap; 43 | _this.casemodel.split(".").forEach((element, index) => { 44 | _this.caseMap = _this.caseMap[element]; 45 | }); 46 | _this.caseMap = topaperMap(_this.caseMap); 47 | }); 48 | 49 | Event.$on('change-paper-all', (caseMap) => { 50 | _this.caseMap = caseMap; 51 | _this.casemodel.split(".").forEach((element, index) => { 52 | _this.caseMap = _this.caseMap[element]; 53 | }); 54 | _this.caseMap = toAllpaperMap(_this.caseMap); 55 | }); 56 | 57 | if (!!_this.getAllCases()) { 58 | Event.$emit('change-paper', _this.getAllCases()); 59 | } 60 | 61 | } 62 | , 63 | methods: { 64 | ...Vuex.mapGetters(['getAllCases', 'jwtHeader','getSlideOpen']), 65 | run(testCase,testName) { 66 | Event.$emit('run-case', {testCase:testCase,testName:testName,}); 67 | }, 68 | openDeleteDialog(value) { 69 | this.deleteDialog = true; 70 | this.deleteStatus = 'finish'; 71 | let caseNamePath = null; 72 | for (let [k, v] of Object.entries(value)) { 73 | caseNamePath = k; 74 | } 75 | caseNamePath = caseNamePath.split(":")[0]; 76 | let deletePath = caseNamePath.split(".").join("/") + ".py"; 77 | this.deleteFilePath = deletePath.substring(deletePath.indexOf('/') + 1); 78 | 79 | }, 80 | closeDeleteDialog() { 81 | this.deleteDialog = false 82 | }, 83 | openCopyDialog(value) { 84 | this.copyDialog = true; 85 | this.copyStatus = 'finish'; 86 | let caseNamePath = null; 87 | for (let [k, v] of Object.entries(value)) { 88 | caseNamePath = k; 89 | } 90 | caseNamePath = caseNamePath.split(":")[0]; 91 | let oldpath = caseNamePath.split(".").join("/") + ".py"; 92 | let newpath = caseNamePath.split(".").join("/") + "_copy.py"; 93 | this.fileInfo.oldName = oldpath.substring(oldpath.indexOf('/') + 1); 94 | this.fileInfo.newName = newpath.substring(newpath.indexOf('/') + 1); 95 | }, 96 | closeCopyDialog() { 97 | this.copyDialog = false 98 | }, 99 | showcode(key, value) { 100 | if (this.$router.currentRoute.name !== 'casepathpy') { 101 | this.$router.push({name: 'casepathpy', params: {pyname: key}}); 102 | } 103 | else { 104 | this.$router.push({name: 'casepath', params: {casemodel: this.casemodel}}); 105 | } 106 | 107 | let caseNamePath = null; 108 | for (let [k, v] of Object.entries(value)) { 109 | caseNamePath = k; 110 | } 111 | caseNamePath = caseNamePath.split(":")[0]; 112 | this.cpath = caseNamePath.split(".").join("/") + ".py"; 113 | }, 114 | copyFile() { 115 | this.copyStatus = 'running'; 116 | getRes("/arbiter/copy", { 117 | oldPath: this.fileInfo.oldName, 118 | newPath: this.fileInfo.newName 119 | }, this.jwtHeader()).then( 120 | json => { 121 | window.location.href = window.location.href; 122 | }).catch((err) => { 123 | this.copyStatus = 'fail'; 124 | console.log("请求错误:" + err); 125 | }); 126 | }, 127 | deleteFile() { 128 | this.deleteStatus = 'running'; 129 | getRes("/arbiter/delete", {deleteFilePath: this.deleteFilePath}, this.jwtHeader()).then( 130 | json => { 131 | window.location.href = window.location.href; 132 | }).catch((err) => { 133 | this.deleteStatus = 'fail'; 134 | console.log("请求错误:" + err); 135 | }); 136 | }, 137 | 138 | } 139 | }; -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/core/component/code-float-btn.js: -------------------------------------------------------------------------------- 1 | //py文件paper中的fab组件 2 | const CodeFloatBtn = { 3 | template: '#codeFloatBtn', store, 4 | props: { 5 | pypath: null, 6 | casemodel: null 7 | 8 | }, 9 | data: function () { 10 | return { 11 | modalShow: true, 12 | seen: false, 13 | editIcon: "mode_edit", 14 | saveDialog: false, 15 | logDialog: false, 16 | saveStatus: 'finish', 17 | logContent: [], 18 | path: null 19 | } 20 | }, mounted() { 21 | this.path = this.pypath; 22 | 23 | }, 24 | methods: { 25 | ...Vuex.mapMutations(['setUserName', 'refreshJwtToken',]), 26 | ...Vuex.mapGetters(['username', 'jwtHeader']), 27 | openSaveDialog() { 28 | this.saveDialog = true; 29 | 30 | }, 31 | openLogDialog() { 32 | this.logDialog = true; 33 | 34 | }, 35 | closeLogDialog() { 36 | this.logDialog = false 37 | }, 38 | onMouseEnterCodeFAB() { 39 | this.seen = true; 40 | }, 41 | onMouseleaveCodeFAB() { 42 | this.seen = false; 43 | }, 44 | log() { 45 | this.logDialog = true; 46 | }, 47 | cleanLog() { 48 | this.logContent = []; 49 | }, 50 | edit() { 51 | let codeContent = ace.edit("code-paper"); 52 | if (this.editIcon === "mode_edit") { 53 | 54 | codeContent.setReadOnly(false);//设置为可编辑模式 55 | codeContent.setTheme("ace/theme/chrome");//设置可编辑状态主题 56 | this.editIcon = "save"; 57 | } 58 | else if (this.editIcon === "save") { 59 | let caseNamePath = null; 60 | for (let [k, v] of Object.entries(this.path)) { 61 | if (k) { 62 | caseNamePath = k; 63 | break; 64 | } 65 | } 66 | this.saveStatus = "running"; 67 | this.saveDialog = true; 68 | let newCodeContent = codeContent.getValue(); 69 | //检查响应文本 70 | getRes("/arbiter/save/", { 71 | casepath: caseNamePath, 72 | content: newCodeContent 73 | }, this.jwtHeader()).then((data) => { 74 | if (data['result'] === "ok") { 75 | this.editIcon = "mode_edit"; 76 | let codeContent = ace.edit("code-paper"); 77 | codeContent.setReadOnly(true);//设置为不可编辑模式 78 | this.saveDialog = false; 79 | this.$router.push({name: 'casepath', params: {casemodel: this.casemodel}}); 80 | } else { 81 | alert("文件保存失败!"); 82 | } 83 | }).catch((err) => { 84 | console.log("请求错误:" + err); 85 | }) 86 | } 87 | } 88 | } 89 | }; -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/core/component/code-paper.js: -------------------------------------------------------------------------------- 1 | //py文件的paper组件 2 | const CodePaper = { 3 | props: {pypathx: null,}, 4 | data: function () { 5 | return {path: null} 6 | }, 7 | template: '#codePaper', 8 | mounted() { 9 | 10 | this.path = this.pypathx; 11 | if (!!this.path) { 12 | for (let [k, v] of Object.entries(this.path)) { 13 | if (k) { 14 | caseNamePath = k; 15 | break; 16 | } 17 | } 18 | caseNamePath = caseNamePath.split(":")[0]; 19 | this.path = caseNamePath.split(".").join("/") + ".py"; 20 | 21 | this.loadCaseFile(this.path) 22 | } 23 | 24 | }, 25 | methods: { 26 | showcode(key, value) { 27 | this.$router.push({name: 'casepathpy', params: {pyname: key}}); 28 | let caseNamePath = null; 29 | 30 | for (let [k, v] of Object.entries(value)) { 31 | caseNamePath = k; 32 | } 33 | caseNamePath = caseNamePath.split(":")[0]; 34 | this.path = caseNamePath.split(".").join("/") + ".py"; 35 | 36 | }, 37 | loadCaseFile(caseNamePath) { 38 | 39 | // document.getElementById("codecontent").style.fontSize = "14px"; 40 | // document.getElementById("codecontent").style.height = "600px"; 41 | let codeContent = ace.edit(this.$el); 42 | codeContent.setTheme("ace/theme/github"); 43 | codeContent.setReadOnly(true);//设置只读 44 | codeContent.$blockScrolling = Infinity; 45 | codeContent.session.setMode("ace/mode/python"); 46 | // setBtn("edit"); 47 | /*查询可编辑状态*/ 48 | new ValidateEditWebSocket(caseNamePath); 49 | let xhr = new XMLHttpRequest(); 50 | xhr.open('GET', '/static/' + caseNamePath, true); 51 | xhr.setRequestHeader("If-Modified-Since", "0"); 52 | xhr.onreadystatechange = function () { 53 | if (xhr.readyState === 4) { 54 | codeContent.setValue(xhr.responseText, -1);//设置显示内容,并将光标移动到start处 55 | } 56 | }; 57 | xhr.send(null); 58 | } 59 | 60 | } 61 | }; -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/core/component/menu-icon-Button.js: -------------------------------------------------------------------------------- 1 | //菜单图标和其下拉菜单组件 2 | const menuIconButton = { 3 | template: '#menuIconButton', store, 4 | props: {usernameAbbreviation: null}, 5 | data: function () { 6 | return { 7 | appMenuTrigger: null, 8 | appMenuOpen: false, 9 | } 10 | }, 11 | mounted() { 12 | this.appMenuTrigger = this.$refs.appIcon.$el; 13 | }, 14 | methods: { 15 | ...Vuex.mapMutations(['setUserName', 'refreshJwtToken',]), 16 | ...Vuex.mapGetters(['username', 'jwtHeader']), 17 | appMenuToggle() { 18 | this.appMenuOpen = !this.appMenuOpen 19 | }, 20 | appMenuHandleClose(e) { 21 | this.appMenuOpen = false 22 | }, 23 | } 24 | }; -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/core/component/user-avatar.js: -------------------------------------------------------------------------------- 1 | //用户图标和其下拉菜单组件 2 | const userAvatar = { 3 | template: '#userAvatar', 4 | store, 5 | props: {usernameAbbreviation: null}, 6 | data: function () { 7 | return { 8 | userMenuTrigger: null, 9 | userMenuOpen: false, 10 | } 11 | }, 12 | mounted() { 13 | this.userMenuTrigger = this.$refs.UserAvatar.$el; 14 | }, 15 | methods: { 16 | ...Vuex.mapMutations(['setUserName', 'refreshJwtToken',]), 17 | userMenuToggle() { 18 | this.userMenuOpen = !this.userMenuOpen 19 | }, 20 | userMenuHandleClose(e) { 21 | this.userMenuOpen = false 22 | }, logout() { 23 | deleteAllCookies(); 24 | let storage = window.localStorage; 25 | storage.clear(); 26 | this.setUserName(null); 27 | this.refreshJwtToken(); 28 | }, 29 | } 30 | }; -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/core/route.js: -------------------------------------------------------------------------------- 1 | const router = new VueRouter({ 2 | mode: 'history', 3 | base: "arbiter", 4 | routes: [ 5 | {path: '/'}, 6 | { 7 | path: '/:casemodel', 8 | name: 'casepath', 9 | components: {paper: CasePaper,}, 10 | props: {paper: true,} 11 | }, 12 | { 13 | path: '/:casemodel/:pyname', 14 | name: 'casepathpy', 15 | components: {paper: CasePaper, codefab: CodeFloatBtn}, 16 | props: {paper: true, codefab: true} 17 | }, 18 | 19 | ] 20 | }); -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/login.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Administrator on 2017/8/6. 3 | */ 4 | 5 | const login_app = new Vue({ 6 | el: '#login-form', 7 | data: { 8 | inputtext: {}, 9 | prompt: "", 10 | }, 11 | methods: { 12 | submit(e) { 13 | fetch("api-token-auth", 14 | { 15 | method: "POST", 16 | credentials: "same-origin", 17 | headers: { 18 | 'Accept': 'application/json, text/plain, */*', 19 | 'Content-Type': 'application/json' 20 | }, 21 | body: JSON.stringify(this.inputtext) 22 | }).then((response) => { 23 | if (response.status !== 200 24 | ) { 25 | this.prompt = "账号或密码错误"; 26 | const error = new Error(response.statusText); 27 | error.response = response; 28 | throw error; 29 | } 30 | else 31 | return response.json(); 32 | }).then( 33 | (msg) => { 34 | if (msg.token) { 35 | let storage = window.localStorage; 36 | storage["token"] = msg.token; 37 | window.location.href ="." 38 | } 39 | else { 40 | this.prompt = "获取登陆密钥失败"; 41 | } 42 | } 43 | ).catch((err) => { 44 | console.log("登陆失败,服务端返回状态为:" + err); 45 | } 46 | ); 47 | } 48 | } 49 | }); 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/store.js: -------------------------------------------------------------------------------- 1 | //vuex:管理各个公用变量的store 2 | 3 | //vuex用户模块:管理登陆的用户数据 4 | const userModule = { 5 | state: { 6 | username: null, 7 | jwtToken: null, 8 | avatarPicPath: null, 9 | nickName: null, 10 | role: null, 11 | email: null, 12 | searchHistory: null, 13 | settings: {} 14 | }, 15 | mutations: { 16 | setUserName(state, username) { 17 | state.username = username; 18 | }, 19 | refreshJwtToken(state) { 20 | state.jwtToken = window.localStorage["token"]; 21 | } 22 | }, 23 | actions: { 24 | setAvatarPicPath(state, avatarPicPath) { 25 | state.avatarPicPath = avatarPicPath; 26 | } 27 | }, 28 | getters: { 29 | username: state => { 30 | return state.username 31 | }, 32 | jwtHeader: state => { 33 | return state.jwtToken 34 | } 35 | } 36 | }; 37 | //vuex用例模块:管理当前项目的所有用例 38 | const caseModule = { 39 | state: { 40 | allCases: null, 41 | packageList: null, 42 | caseList: null, 43 | checkedCases: [], 44 | currentPyPath: null 45 | }, 46 | mutations: { 47 | setAllCases(state, allCases) { 48 | state.allCases = allCases; 49 | }, 50 | }, 51 | actions: { 52 | flushAllCases({state, commit, rootState, rootGetters}) { 53 | return getRes("/arbiter/getCaseList", null, rootGetters.jwtHeader).then((json) => { 54 | commit("setAllCases", json); 55 | return json; 56 | }); 57 | } 58 | }, 59 | getters: { 60 | getAllCases: state => { 61 | return state.allCases 62 | } 63 | } 64 | // actions: { ... } 65 | }; 66 | 67 | //vuex页面状态模块 68 | const pageModule = { 69 | state: {slideOpen: true}, 70 | mutations: { 71 | setSlideOpen(state) { 72 | state.slideOpen = !state.slideOpen; 73 | }, 74 | }, 75 | getters: { 76 | getSlideOpen: state => { 77 | return state.slideOpen 78 | } 79 | } 80 | // actions: { ... } 81 | }; 82 | 83 | //store:所有vuex模块的集合 84 | const store = new Vuex.Store({ 85 | modules: { 86 | user: userModule, 87 | case: caseModule, 88 | page: pageModule 89 | } 90 | }); -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/wholog/app.js: -------------------------------------------------------------------------------- 1 | let app = new Vue({ 2 | router, 3 | el: '#app', store, 4 | data: {}, 5 | 6 | /*组件集合*/ 7 | components: { 8 | 'ArbiterHeader': ArbiterHeader, 9 | 'historyLog': historyLog, 10 | 'statisticLog':statisticLog, 11 | 'logSlide': logSlide, 12 | 'CaseFloatBtn': CaseFloatBtn, 13 | 14 | }, 15 | }); -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/wholog/component/header-components.js: -------------------------------------------------------------------------------- 1 | //所有用到的组件 2 | let Event = new Vue(); 3 | //****以下为所有用到的组件: 4 | //用户图标和其下拉菜单组件 5 | const userAvatar = { 6 | template: '#userAvatar', 7 | store, 8 | props: {usernameAbbreviation: null}, 9 | data: function () { 10 | return { 11 | userMenuTrigger: null, 12 | userMenuOpen: false, 13 | } 14 | }, 15 | mounted() { 16 | this.userMenuTrigger = this.$refs.UserAvatar.$el; 17 | }, 18 | methods: { 19 | ...Vuex.mapMutations(['setUserName', 'refreshJwtToken',]), 20 | userMenuToggle() { 21 | this.userMenuOpen = !this.userMenuOpen 22 | }, 23 | userMenuHandleClose(e) { 24 | this.userMenuOpen = false 25 | }, logout() { 26 | deleteAllCookies(); 27 | let storage = window.localStorage; 28 | storage.clear(); 29 | this.setUserName(null); 30 | this.refreshJwtToken(); 31 | }, 32 | } 33 | }; 34 | //菜单图标和其下拉菜单组件 35 | const menuIconButton = { 36 | template: '#menuIconButton', store, 37 | props: {usernameAbbreviation: null}, 38 | data: function () { 39 | return { 40 | appMenuTrigger: null, 41 | appMenuOpen: false, 42 | dialog: false, 43 | gitUrlPrefix: '', 44 | gitCloneStatus: 'finish', 45 | } 46 | }, 47 | mounted() { 48 | this.appMenuTrigger = this.$refs.appIcon.$el; 49 | }, 50 | methods: { 51 | ...Vuex.mapMutations(['setUserName', 'refreshJwtToken',]), 52 | ...Vuex.mapGetters(['username', 'jwtHeader']), 53 | appMenuToggle() { 54 | this.appMenuOpen = !this.appMenuOpen 55 | }, 56 | appMenuHandleClose(e) { 57 | this.appMenuOpen = false 58 | }, 59 | closeImportDialog() { 60 | this.dialog = false 61 | }, 62 | cloneCaseObj() { 63 | this.gitCloneStatus = 'running'; 64 | 65 | getRes("./cloneCaseObj", {url: this.gitUrlPrefix}, this.jwtHeader()).then( 66 | json => { 67 | this.gitCloneStatus = 'finish'; 68 | window.location.href = window.location.href; 69 | }).catch((err) => { 70 | this.gitCloneStatus = 'fail'; 71 | console.log("请求错误:" + err); 72 | }); 73 | }, 74 | } 75 | }; 76 | //顶部组件 77 | const ArbiterHeader = { 78 | template: '#arbiterHeader', 79 | store, 80 | computed: { 81 | usernameAbbreviation() { 82 | if (!!this.username()) { 83 | return this.username().substr(0, 2) 84 | } 85 | else 86 | return null; 87 | } 88 | }, 89 | data: function () { 90 | return { 91 | message: { 92 | href: 'login', 93 | }, 94 | sliderIsOpen: true, 95 | loginDialog: { 96 | switch: false, 97 | username: "", 98 | password: "", 99 | 100 | }, 101 | } 102 | }, 103 | mounted() { 104 | this.refreshJwtToken(); 105 | 106 | getRes("./getUserDetail", null, this.jwtHeader()).then( 107 | json => { 108 | let storage = window.localStorage; 109 | storage["username"] = json["username"]; 110 | storage["role"] = json["role"]; 111 | // this.$store.commit('setUserName', json["username"]); 112 | this.setUserName(json["username"]); 113 | } 114 | ).catch((err) => { 115 | console.log("请求错误:" + err); 116 | }); 117 | }, 118 | methods: { 119 | ...Vuex.mapMutations(['setUserName', 'refreshJwtToken','setSlideOpen']), 120 | ...Vuex.mapGetters(['username', 'jwtHeader']), 121 | toggleSlide() { 122 | this.sliderIsOpen = !this.sliderIsOpen; 123 | this.setSlideOpen(); 124 | }, 125 | /*点击登录*/ 126 | toLogin() { 127 | this.openLoginDialog(); 128 | }, 129 | submit() { 130 | 131 | }, 132 | /*打开和关闭登录对话框*/ 133 | openLoginDialog() { 134 | this.loginDialog.switch = true; 135 | }, 136 | closeLoginDialog() { 137 | this.loginDialog.switch = false; 138 | }, 139 | }, 140 | components: { //要把组件写入到components里面,如果没有放的话在切换的时候就会找不到 组件 141 | 'userAvatar': userAvatar, 142 | 'menuIconButton': menuIconButton, 143 | } 144 | 145 | }; -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/wholog/component/history-log.js: -------------------------------------------------------------------------------- 1 | /*所有组件*/ 2 | /**/ 3 | const historyLog = { 4 | template: '#historyLog', 5 | store, 6 | data: function () { 7 | let now = new Date(); 8 | now.setDate(now.getDate() + 1); 9 | return { 10 | loginPopup: false, /*未登录是提示popup*/ 11 | startDate: new Date().format("yyyy-MM-dd"), 12 | startTime: '00:00', 13 | endDate: now.format("yyyy-MM-dd"), 14 | endTime: '00:00', 15 | tableData: [], 16 | tableTotal: 0, 17 | logDialog: { 18 | menus: [], 19 | content: [], 20 | switch: false, 21 | } 22 | } 23 | }, 24 | computed: { 25 | slideOpen() { 26 | return this.getSlideOpen(); 27 | }, 28 | }, 29 | mounted() { 30 | this.refreshJwtToken(); 31 | this.queryData(); 32 | }, 33 | /*方法*/ 34 | methods: { 35 | /*存到vuex map 方便调用store里函数*/ 36 | ...Vuex.mapMutations(['setUserName', 'refreshJwtToken',]), 37 | ...Vuex.mapGetters(['username', 'jwtHeader', 'getSlideOpen']), 38 | /*查询运行列表*/ 39 | queryData() { 40 | let startTime = this.startDate + " " + this.startTime; 41 | let endTime = this.endDate + " " + this.endTime; 42 | fetch('../wholog/getAllLog', 43 | { 44 | method: 'POST', 45 | credentials: "same-origin", 46 | headers: { 47 | 'Accept': 'application/json, text/plain, */*', 48 | 'Content-Type': 'application/json', 49 | 'Authorization': "JWT " + this.jwtHeader(), 50 | }, 51 | body: JSON.stringify({startTime: startTime, endTime: endTime}) 52 | }).then((response) => { 53 | /*判断请求状态码*/ 54 | if (response.status !== 200) { 55 | if (response.status === 401) { 56 | this.openLoginPopup(); 57 | /*判断未登录时 去打开登录提示*/ 58 | } else { 59 | console.log("请求失败,状态码为:" + response.status); 60 | 61 | } 62 | } else { 63 | return response.json(); 64 | } 65 | }).then((json) => { 66 | /*给tableData赋值*/ 67 | this.tableData = json['data']; 68 | this.tableTotal = json['total']; 69 | }).catch((err) => { 70 | console.log("请求wholog/getAllLog出错:" + err); 71 | }); 72 | 73 | }, 74 | /*删除一条记录*/ 75 | deleteLog(logId) { 76 | getRes("/arbiter/wholog/deleteLog", { 77 | log_id: logId, 78 | }, this.jwtHeader()).then((json) => { 79 | this.queryData() 80 | }) 81 | 82 | }, 83 | /*查询对应记录下的详细运行日志记录*/ 84 | queryDetailData(logId) { 85 | /*对logId进行处理兼容es*/ 86 | logId = logId.replace(/-/g, ""); 87 | fetch('../wholog/queryLogData', 88 | { 89 | method: 'POST', 90 | credentials: "same-origin", 91 | headers: { 92 | 'Accept': 'application/json, text/plain, */*', 93 | 'Content-Type': 'application/json', 94 | 'Authorization': "JWT " + this.jwtHeader() 95 | }, 96 | body: JSON.stringify({logId: logId}) 97 | }).then((response) => { 98 | /*判断请求状态码*/ 99 | if (response.status !== 200) { 100 | if (response.status === 401) { 101 | this.openLoginPopup(); 102 | /*判断未登录时 去打开登录提示*/ 103 | } else { 104 | console.log("请求失败,状态码为:" + response.status); 105 | } 106 | } else { 107 | return response.json(); 108 | } 109 | }).then((json) => { 110 | console.log("请求成功,打开dialog"); 111 | this.logDialog.menus = json['data']; 112 | this.openDialog(); 113 | }).catch((err) => { 114 | console.log("请求wholog/queryLogData出错:" + err); 115 | }); 116 | 117 | }, /*queryDetailData end*/ 118 | filterTag(value, row) { 119 | return row.result === value; 120 | }, 121 | /*打开和关闭日志运行详情对话框*/ 122 | openDialog() { 123 | this.logDialog.switch = true; 124 | }, 125 | closeDialog() { 126 | this.logDialog.switch = false; 127 | }, 128 | /*打开登录提示框*/ 129 | openLoginPopup() { 130 | this.loginPopup = true; 131 | }, 132 | run(testCase,testName) { 133 | Event.$emit('run-case', {testCase:testCase,testName:testName,}); 134 | }, 135 | }, /*method end*/ 136 | 137 | watch: { 138 | loginPopup(val) { 139 | if (val) { 140 | setTimeout(() => { 141 | this.loginPopup = false; 142 | }, 1500); 143 | } 144 | } 145 | }, /*watch end*/ 146 | 147 | }; 148 | 149 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/wholog/component/log-slide.js: -------------------------------------------------------------------------------- 1 | //侧边菜单组件 2 | const logSlide = { 3 | template: '#logSlide', 4 | store, 5 | data() { 6 | return { 7 | open: true, 8 | docked: true, 9 | value: "" 10 | } 11 | }, 12 | computed: { 13 | slideOpen() { 14 | return this.getSlideOpen(); 15 | }, 16 | }, 17 | watch: { 18 | slideOpen(val) { 19 | this.open = val; 20 | }, 21 | 22 | }, 23 | 24 | methods: { 25 | ...Vuex.mapGetters(['getSlideOpen']), 26 | handleChange(val) { 27 | this.typeList = val; 28 | }, 29 | 30 | toggle() { 31 | this.open = !this.open; 32 | }, 33 | //路由跳转-index 34 | routerToIndex() { 35 | this.$router.push({name: 'index'}); 36 | }, 37 | //路由跳转-历史日志 38 | routerToHistoryLog() { 39 | //this.$router.push({name: 'casepath', params: {casemodel: casemodel}}); 40 | this.$router.push({name: 'historyLog'}); 41 | }, 42 | //路由跳转-图表日志 43 | routerToStatisticLog() { 44 | this.$router.push({name: 'statisticLog'}); 45 | } 46 | 47 | 48 | } 49 | }; -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/wholog/component/statistic-log.js: -------------------------------------------------------------------------------- 1 | /*所有组件*/ 2 | /**/ 3 | const statisticLog = { 4 | template: '#statisticLog', store, 5 | data: function () { 6 | return { 7 | api_name: null, 8 | total: null, 9 | apiData: {}, 10 | logDialog: { 11 | menus: [], 12 | content: [], 13 | switch: false, 14 | } 15 | } 16 | }, 17 | computed: { 18 | slideOpen() { 19 | return this.getSlideOpen(); 20 | }, 21 | }, 22 | methods: { 23 | /*存到vuex map 方便调用store里函数*/ 24 | ...Vuex.mapMutations(['setUserName', 'refreshJwtToken',]), 25 | ...Vuex.mapGetters(['username', 'jwtHeader', 'getSlideOpen']), 26 | queryData() { 27 | if (this.api_name !== null) { 28 | fetch('../wholog/query-api-data/?api_name=' + this.api_name, { 29 | method: 'get' 30 | }).then((response) => { 31 | return response.json(); 32 | }).then((json) => { 33 | this.apiData = json['data']; 34 | if (json['status'] == "true") { 35 | console.log("重新开始draw") 36 | this.draw(); 37 | } else { 38 | console.log(json['msg']); 39 | } 40 | }).catch((err) => { 41 | console.log(err) 42 | }); 43 | } else { 44 | alert("请先输入要查询的内容"); 45 | } 46 | }, 47 | //echarts绘制方法 48 | draw() { 49 | // 指定图表的配置项和数据 50 | var option = { 51 | title: { 52 | text: "Api请求信息", 53 | subtext: "每个接口请求的统计" 54 | }, 55 | tooltip: { 56 | trigger: "axis", 57 | formatter: (params) => { 58 | var result = ''; 59 | params.forEach((item) => { 60 | result += 61 | '

' + "耗时:" + this.apiData.consume_time[item.dataIndex] + "ms" + '

' + 62 | '

' + "用例名:" + this.apiData.case_name[item.dataIndex] + '

' + 63 | '

' + "请求时间:" + this.apiData.create_time[item.dataIndex] + '

' + 64 | '

' + "请求类型:" + this.apiData.request_type[item.dataIndex] + '

' + 65 | '

' + "返回Code:" + this.apiData.response_code[item.dataIndex] + '

' 66 | ; 67 | }); 68 | return result; 69 | } 70 | }, 71 | legend: { 72 | data: ["耗时"] 73 | }, 74 | toolbox: { 75 | show: true, 76 | feature: { 77 | mark: { 78 | show: true 79 | }, 80 | dataView: { 81 | show: true, 82 | readOnly: true 83 | }, 84 | magicType: { 85 | show: false, 86 | type: ["line", "bar", "stack", "tiled"] 87 | }, 88 | restore: { 89 | show: true 90 | }, 91 | saveAsImage: { 92 | show: true 93 | } 94 | } 95 | }, 96 | calculable: true, 97 | xAxis: [ 98 | { 99 | name: "运行次数", 100 | type: "category", 101 | boundaryGap: false, 102 | data: this.apiData.num, 103 | nameLocation: "end" 104 | } 105 | ], 106 | yAxis: [ 107 | { 108 | name: "耗时", 109 | type: "value", 110 | axisLabel: { 111 | formatter: '{value} ms' 112 | } 113 | } 114 | ], 115 | series: [ 116 | { 117 | name: "耗时", 118 | type: "line", 119 | smooth: true, 120 | itemStyle: { 121 | normal: { 122 | areaStyle: { 123 | type: "default" 124 | } 125 | } 126 | }, 127 | data: this.apiData.consume_time 128 | } 129 | ] 130 | }; 131 | 132 | // 使用刚指定的配置项和数据显示图表。 133 | this.myChart.setOption(option); 134 | }, 135 | 136 | 137 | //todo 登录提示 138 | /*查询对应记录下的详细运行日志记录*/ 139 | queryDetailData(logId) { 140 | /*对logId进行处理兼容es*/ 141 | logId = logId.replace(/\-/g, ""); 142 | fetch('../wholog/queryLogData', 143 | { 144 | method: 'POST', 145 | credentials: "same-origin", 146 | headers: { 147 | 'Accept': 'application/json, text/plain, */*', 148 | 'Content-Type': 'application/json', 149 | 'Authorization': "JWT " + this.jwtHeader() 150 | }, 151 | body: JSON.stringify({logId: logId}) 152 | }).then((response) => { 153 | /*判断请求状态码*/ 154 | if (response.status !== 200) { 155 | if (response.status === 401) { 156 | this.openLoginPopup(); 157 | /*判断未登录时 去打开登录提示*/ 158 | } else { 159 | console.log("请求失败,状态码为:" + response.status); 160 | } 161 | return; 162 | } else { 163 | return response.json(); 164 | } 165 | }).then((json) => { 166 | console.log("请求成功,打开dialog"); 167 | this.logDialog.menus = json['data']; 168 | this.openDialog(); 169 | }).catch((err) => { 170 | console.log("请求wholog/queryLogData出错:" + err); 171 | }); 172 | 173 | }, /*queryDetailData end*/ 174 | 175 | /*打开和关闭日志运行详情对话框*/ 176 | openDialog() { 177 | this.logDialog.switch = true; 178 | }, 179 | closeDialog() { 180 | this.logDialog.switch = false; 181 | }, 182 | 183 | }, 184 | 185 | watch: { //数据变化时自动重画,在控制台修改message,会自动重画 186 | message: () => { 187 | 188 | this.draw(); 189 | } 190 | }, 191 | mounted() { 192 | this.refreshJwtToken(); 193 | this.$nextTick(() => { 194 | this.myChart = echarts.init(document.getElementById('main-chart')); //初始化echarts实例 195 | this.draw(); 196 | this.myChart.on('click', (params) => { 197 | //打开对话框,查询数据 198 | this.openDialog(); 199 | this.queryDetailData(this.apiData.log_id[params.dataIndex]); 200 | }); 201 | }) 202 | }, 203 | 204 | 205 | }; 206 | 207 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/static/arbiter/js/wholog/route.js: -------------------------------------------------------------------------------- 1 | const router = new VueRouter({ 2 | mode: 'history', 3 | base: "/arbiter/wholog/", 4 | routes: [ 5 | 6 | { 7 | path: '/index', 8 | name:'index', 9 | components: {rootView:historyLog}, 10 | }, 11 | { 12 | path: '/historyLog', 13 | name:'historyLog', 14 | components: {mainView:historyLog}, 15 | }, 16 | { 17 | path: '/statisticLog', 18 | name:'statisticLog', 19 | components: {mainView:statisticLog}, 20 | }, 21 | 22 | ] 23 | }); -------------------------------------------------------------------------------- /arbiter-web/arbiter/urls.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/1.11/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.conf.urls import url, include 14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 15 | """ 16 | from django.conf.urls import include, url 17 | from django.contrib import admin 18 | 19 | urlpatterns = [ 20 | # url(r'^jet/', include('jet.urls', 'jet')), # Django JET URLS 21 | # url(r'^jet/dashboard/', include('jet.dashboard.urls', 'jet-dashboard')), # Django JET dashboard URLS 22 | url(r'^admin/', include(admin.site.urls)), 23 | url(r'^arbiter/wholog/', include("arbiter.wholog.urls", namespace="arbiter-wholog")), 24 | url(r'^arbiter/', include("arbiter.core.urls", namespace="arbiter")), 25 | 26 | ] 27 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/wholog/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuaFramework/cua-arbiter/61b2ea5d8b7c825b75d0f333d202e5703e0565a9/arbiter-web/arbiter/wholog/__init__.py -------------------------------------------------------------------------------- /arbiter-web/arbiter/wholog/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/wholog/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class LogManageConfig(AppConfig): 5 | name = 'arbiter.wholog' 6 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/wholog/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/wholog/templates/component/arbiter-header.vue: -------------------------------------------------------------------------------- 1 | {% verbatim %} 2 | 28 | {% endverbatim %} -------------------------------------------------------------------------------- /arbiter-web/arbiter/wholog/templates/component/case-float-btn.vue: -------------------------------------------------------------------------------- 1 | {% verbatim %} 2 | 22 | {% endverbatim %} -------------------------------------------------------------------------------- /arbiter-web/arbiter/wholog/templates/component/history-log.vue: -------------------------------------------------------------------------------- 1 | {% verbatim %} 2 | 94 | {% endverbatim %} -------------------------------------------------------------------------------- /arbiter-web/arbiter/wholog/templates/component/log-slide.vue: -------------------------------------------------------------------------------- 1 | {% verbatim %} 2 | 23 | {% endverbatim %} -------------------------------------------------------------------------------- /arbiter-web/arbiter/wholog/templates/component/menu-icon-button.vue: -------------------------------------------------------------------------------- 1 | {% verbatim %} 2 | 14 | {% endverbatim %} -------------------------------------------------------------------------------- /arbiter-web/arbiter/wholog/templates/component/statistic-log.vue: -------------------------------------------------------------------------------- 1 | {% verbatim %} 2 | 26 | {% endverbatim %} -------------------------------------------------------------------------------- /arbiter-web/arbiter/wholog/templates/component/user-avatar.vue: -------------------------------------------------------------------------------- 1 | {% verbatim %} 2 | 20 | {% endverbatim %} 21 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/wholog/templates/index.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | {% load i18n %} 3 | {% load staticfiles %} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 日志查询 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | {% block head %} 22 | {% endblock head %} 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | {% verbatim %} 34 |
35 | 36 | 37 |
38 | 39 | 40 |
41 |
42 | 43 |
44 |
45 |
46 |
47 | {% endverbatim %} 48 | {% include "component/menu-icon-button.vue" %} 49 | {% include "component/user-avatar.vue" %} 50 | {% include "component/history-log.vue" %} 51 | {% include "component/statistic-log.vue" %} 52 | {% include "component/arbiter-header.vue" %} 53 | {% include "component/log-slide.vue" %} 54 | 55 | {% include "component/case-float-btn.vue" %} 56 | 57 | 58 | 59 | 60 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/wholog/tests.py: -------------------------------------------------------------------------------- 1 | import time 2 | from arbiter.common import utils 3 | 4 | 5 | # Create your tests here. 6 | class Test: 7 | def test_test(self): 8 | log_id = utils.generate_id() 9 | print(log_id) 10 | 11 | def test_time(self): 12 | t1 = time.time() 13 | print(t1) 14 | print(t1 * 10000000) 15 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/wholog/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | 3 | from . import views 4 | 5 | urlpatterns = [ 6 | url(r'^query-api-data', views.query_api_data, name='query-api-data'), 7 | url(r'^api-count', views.api_count, name='api-count'), 8 | url(r'^getAllLog', views.get_all_log, name='getAllLog'), 9 | url(r'^deleteLog', views.delete_log, name='deleteLog'), 10 | # todo 登录登出抽离出来,现在core和wholog下的view均有 11 | url(r'^getUserDetail', views.auth_restful.get_user_detail, name='getUserDetail'), 12 | url(r'^queryLogData', views.queryLogData, name='queryLogData'), 13 | url(r'^home', views.home, name='home'), 14 | url(r'^index', views.index, name='index'), 15 | url(r'^.*$', views.index), 16 | 17 | ] 18 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for arbiter project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "arbiter.settings") 15 | application = get_wsgi_application() 16 | -------------------------------------------------------------------------------- /arbiter-web/config.py: -------------------------------------------------------------------------------- 1 | arbiter_prod_config = \ 2 | dict(redis_host='10.104.102.142', 3 | redis_port=6379, 4 | redis_dj_db=13, 5 | redis_arbiter_db=9, 6 | redis_elk_db=11, 7 | pgsql_host='10.104.104.39', 8 | pgsql_port='5432', 9 | pgsql_dbname='arbiter_dj', 10 | pgsql_user='luna', 11 | pgsql_password='luna', 12 | elk_url='10.104.104.57:9200', 13 | case_path='caseobj/case') 14 | 15 | arbiter_docker_config = \ 16 | dict(redis_host='redis', 17 | redis_port=6379, 18 | redis_dj_db=3, 19 | redis_arbiter_db=9, 20 | redis_elk_db=11, 21 | pgsql_host='pgdb', 22 | pgsql_port='5432', 23 | pgsql_user='luna', 24 | pgsql_dbname='arbiter_dj', 25 | pgsql_password='luna', 26 | elk_url='elk:9200', 27 | case_path='caseobj/case') 28 | -------------------------------------------------------------------------------- /arbiter-web/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | web: 4 | image: shimine/cua-arbiter-alpine 5 | ports: 6 | - "8000:8000" 7 | depends_on: 8 | - db 9 | command: python ./manage.py makemigrations arbiter&& python ./manage.py migrate && python ./manage.py shell < initadmin.py 10 | 11 | db: 12 | image: postgres 13 | ports: 14 | - "5432:5432" 15 | environment: 16 | - POSTGRES_PASSWORD=123456 17 | - POSTGRES_DB=arbiter_dj 18 | - POSTGRES_USER=luna 19 | - POSTGRES_PASSWORD=luna 20 | 21 | redis: 22 | image: redis 23 | 24 | elk: 25 | image: shimine/cua-arbiter-elk 26 | ports: 27 | - "5601:5601" 28 | - "9200:9200" 29 | - "5044:5044" 30 | -------------------------------------------------------------------------------- /arbiter-web/docker_start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | python ./manage.py makemigrations arbiter&& python ./manage.py migrate && python ./manage.py shell < initadmin.py && python ./manage.py runserver 0.0.0.0:8000 -------------------------------------------------------------------------------- /arbiter-web/initadmin.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.models import User 2 | 3 | # 如果没用用户 就新建一个 4 | if User.objects.count() == 0: 5 | User.objects.create_superuser('admin', 'admin@example.com', 'admin') 6 | else: 7 | print('Admin accounts can only be initialized if no Accounts exist. Now Accounts num is ' + str( 8 | User.objects.all().count())) 9 | -------------------------------------------------------------------------------- /arbiter-web/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "arbiter.settings") 7 | 8 | try: 9 | from django.core.management import execute_from_command_line 10 | except ImportError: 11 | # The above import may fail for some other reason. Ensure that the 12 | # issue is really that Django is missing to avoid masking other 13 | # exceptions on Python 2. 14 | try: 15 | import django 16 | except ImportError: 17 | raise ImportError( 18 | "Couldn't import Django. Are you sure it's installed and " 19 | "available on your PYTHONPATH environment variable? Did you " 20 | "forget to activate a virtual environment?" 21 | ) 22 | raise 23 | execute_from_command_line(sys.argv) 24 | -------------------------------------------------------------------------------- /arbiter-web/requirements.txt: -------------------------------------------------------------------------------- 1 | 2 | ####### dj ####### 3 | Django==1.11.15 4 | django-redis==4.8.0 5 | dj-database-url==0.4.2 6 | djangorestframework-jwt==1.11.0 7 | djangorestframework==3.7.3 8 | channels==1.1.8 9 | Twisted[tls,http2]==17.9.0 10 | ####### db ####### 11 | psycopg2==2.7.3.2 12 | asgi_redis==1.4.3 13 | redis==2.10.6 14 | ####### elk ####### 15 | elasticsearch==5.4.0 16 | ####### git ####### 17 | gitpython==2.1.7 18 | ####### for tests ####### 19 | requests==2.20.0 20 | bs4==0.0.1 21 | lxml==4.1.0 22 | nose==1.3.7 23 | ######others####### 24 | bleach>=2.1.3 25 | Markdown==2.6.9 26 | cloudinary==1.8.0 27 | cryptography==2.3 28 | -------------------------------------------------------------------------------- /arbiter-web/stack-fix.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef int (*func_t)(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg); 6 | 7 | int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg) { 8 | 9 | pthread_attr_t local; 10 | int used = 0, ret; 11 | 12 | if (!attr) { 13 | used = 1; 14 | pthread_attr_init(&local); 15 | attr = &local; 16 | } 17 | pthread_attr_setstacksize((void*)attr, 2 * 1024 * 1024); // 2 MB 18 | 19 | func_t orig = (func_t)dlsym(RTLD_NEXT, "pthread_create"); 20 | 21 | ret = orig(thread, attr, start_routine, arg); 22 | 23 | if (used) { 24 | pthread_attr_destroy(&local); 25 | } 26 | 27 | return ret; 28 | } -------------------------------------------------------------------------------- /doc/.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse Project Files # 2 | 3 | .classpath 4 | .project 5 | .settings 6 | 7 | # IntelliJ IDEA Files # 8 | 9 | *.iml 10 | *.ipr 11 | *.iws 12 | *.idea 13 | -------------------------------------------------------------------------------- /doc/import.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuaFramework/cua-arbiter/61b2ea5d8b7c825b75d0f333d202e5703e0565a9/doc/import.gif -------------------------------------------------------------------------------- /tasks.todo: -------------------------------------------------------------------------------- 1 | cua-arbiter里程碑: 2 | cua-arbiter_v1.0: 3 | ✔ 权限管理 4 | ✔ 用例页面展示 5 | ✔ 用例脚本页面编辑 6 | ✔ 执行用例脚本 7 | 8 | cua-arbiter_v1.5: 9 | ✔ 使用 muse-ui 前端重构 10 | 11 | cua-arbiter_v2.0: 12 | ✔ 用例脚本与GIT仓库同步(增/删/改) 13 | ✔ 用例批量执行(任务执行) 14 | ✔ 管理历史日志记录(删/查) 15 | ✔ 历史任务重新执行 16 | ☐ 根据历史日志生成图表 17 | ☐ 报告输出(pdf/html/email) 18 | 19 | backlog: 20 | ☐ 用例列表增量修改 21 | ☐ 细化权限管理(按钮权限与用例状态&登陆角色关联) 22 | ☐ 需求/项目管理 23 | ☐ checkList管理 24 | ☐ 需求-checkList关联 25 | ☐ 需求-用例脚本关联 --------------------------------------------------------------------------------