mirror of
https://github.com/m1k1o/neko-rooms.git
synced 2026-11-02 22:51:34 -06:00
pull images.
This commit is contained in:
@@ -100,6 +100,118 @@ export interface BrowserPolicyExtension {
|
||||
*/
|
||||
'url'?: string;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface PullLayer
|
||||
*/
|
||||
export interface PullLayer {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof PullLayer
|
||||
*/
|
||||
'status'?: string;
|
||||
/**
|
||||
*
|
||||
* @type {PullLayerProgressDetail}
|
||||
* @memberof PullLayer
|
||||
*/
|
||||
'progressDetail'?: PullLayerProgressDetail;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof PullLayer
|
||||
*/
|
||||
'progress'?: string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof PullLayer
|
||||
*/
|
||||
'id'?: string;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface PullLayerProgressDetail
|
||||
*/
|
||||
export interface PullLayerProgressDetail {
|
||||
/**
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof PullLayerProgressDetail
|
||||
*/
|
||||
'current'?: number;
|
||||
/**
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof PullLayerProgressDetail
|
||||
*/
|
||||
'total'?: number;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface PullStart
|
||||
*/
|
||||
export interface PullStart {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof PullStart
|
||||
*/
|
||||
'neko_image'?: string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof PullStart
|
||||
*/
|
||||
'registry_user'?: string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof PullStart
|
||||
*/
|
||||
'registry_pass'?: string;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface PullStatus
|
||||
*/
|
||||
export interface PullStatus {
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof PullStatus
|
||||
*/
|
||||
'active'?: boolean;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof PullStatus
|
||||
*/
|
||||
'started'?: string;
|
||||
/**
|
||||
*
|
||||
* @type {{ [key: string]: PullLayer; }}
|
||||
* @memberof PullStatus
|
||||
*/
|
||||
'layers'?: { [key: string]: PullLayer; };
|
||||
/**
|
||||
*
|
||||
* @type {Array<string>}
|
||||
* @memberof PullStatus
|
||||
*/
|
||||
'status'?: Array<string>;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof PullStatus
|
||||
*/
|
||||
'finished'?: string;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
@@ -577,6 +689,231 @@ export class ConfigApi extends BaseAPI {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* DefaultApi - axios parameter creator
|
||||
* @export
|
||||
*/
|
||||
export const DefaultApiAxiosParamCreator = function (configuration?: Configuration) {
|
||||
return {
|
||||
/**
|
||||
*
|
||||
* @summary Start new pull
|
||||
* @param {PullStart} [pullStart]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
pullStart: async (pullStart?: PullStart, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
const localVarPath = `/api/pull`;
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
|
||||
|
||||
localVarHeaderParameter['Content-Type'] = 'application/json';
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
localVarRequestOptions.data = serializeDataIfNeeded(pullStart, localVarRequestOptions, configuration)
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary Get pull status
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
pullStatus: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
const localVarPath = `/api/pull`;
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary Stop existing pull in progress
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
pullStop: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
const localVarPath = `/api/pull`;
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = { method: 'DELETE', ...baseOptions, ...options};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* DefaultApi - functional programming interface
|
||||
* @export
|
||||
*/
|
||||
export const DefaultApiFp = function(configuration?: Configuration) {
|
||||
const localVarAxiosParamCreator = DefaultApiAxiosParamCreator(configuration)
|
||||
return {
|
||||
/**
|
||||
*
|
||||
* @summary Start new pull
|
||||
* @param {PullStart} [pullStart]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async pullStart(pullStart?: PullStart, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<PullStatus>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.pullStart(pullStart, options);
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary Get pull status
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async pullStatus(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<PullStatus>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.pullStatus(options);
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary Stop existing pull in progress
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async pullStop(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.pullStop(options);
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* DefaultApi - factory interface
|
||||
* @export
|
||||
*/
|
||||
export const DefaultApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
|
||||
const localVarFp = DefaultApiFp(configuration)
|
||||
return {
|
||||
/**
|
||||
*
|
||||
* @summary Start new pull
|
||||
* @param {PullStart} [pullStart]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
pullStart(pullStart?: PullStart, options?: any): AxiosPromise<PullStatus> {
|
||||
return localVarFp.pullStart(pullStart, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary Get pull status
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
pullStatus(options?: any): AxiosPromise<PullStatus> {
|
||||
return localVarFp.pullStatus(options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary Stop existing pull in progress
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
pullStop(options?: any): AxiosPromise<void> {
|
||||
return localVarFp.pullStop(options).then((request) => request(axios, basePath));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* DefaultApi - object-oriented interface
|
||||
* @export
|
||||
* @class DefaultApi
|
||||
* @extends {BaseAPI}
|
||||
*/
|
||||
export class DefaultApi extends BaseAPI {
|
||||
/**
|
||||
*
|
||||
* @summary Start new pull
|
||||
* @param {PullStart} [pullStart]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof DefaultApi
|
||||
*/
|
||||
public pullStart(pullStart?: PullStart, options?: AxiosRequestConfig) {
|
||||
return DefaultApiFp(this.configuration).pullStart(pullStart, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @summary Get pull status
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof DefaultApi
|
||||
*/
|
||||
public pullStatus(options?: AxiosRequestConfig) {
|
||||
return DefaultApiFp(this.configuration).pullStatus(options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @summary Stop existing pull in progress
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof DefaultApi
|
||||
*/
|
||||
public pullStop(options?: AxiosRequestConfig) {
|
||||
return DefaultApiFp(this.configuration).pullStop(options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* RoomsApi - axios parameter creator
|
||||
* @export
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<span>
|
||||
<v-btn
|
||||
@click="dialog = true"
|
||||
:loading="loading"
|
||||
color="info"
|
||||
dark
|
||||
>
|
||||
<v-icon class="mr-2" color="white">mdi-cloud-download-outline</v-icon> Pull neko images
|
||||
</v-btn>
|
||||
|
||||
<v-dialog v-model="dialog" max-width="920px">
|
||||
<v-card>
|
||||
<v-card-title class="headline">
|
||||
Pull neko images
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<template v-if="status.layers.length > 0">
|
||||
<pre v-for="layer in status.layers" :key="layer.id">{{ layer.id }} {{ layer.progress && layer.progress + ' ' }}{{ layer.status }}</pre>
|
||||
<br />
|
||||
</template>
|
||||
<template v-if="status.status.length > 0">
|
||||
<pre v-for="text in status.status" :key="text">{{ text }}</pre>
|
||||
</template>
|
||||
<pre v-else>Preparing docker image pull</pre>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<template v-if="!status.active">
|
||||
<v-select
|
||||
v-model="nekoImage"
|
||||
:items="nekoImages"
|
||||
dense
|
||||
outlined
|
||||
hide-details
|
||||
label="Neko image"
|
||||
></v-select>
|
||||
<v-btn color="green" class="ml-2" :loading="loading" @click="Start">
|
||||
Start
|
||||
</v-btn>
|
||||
</template>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn v-if="status.active" color="red" text :loading="loading" @click="Stop">
|
||||
Stop
|
||||
</v-btn>
|
||||
<v-btn v-else color="grey" text @click="dialog = false">
|
||||
Close
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Vue, Component } from 'vue-property-decorator'
|
||||
|
||||
@Component({
|
||||
components: {}
|
||||
})
|
||||
export default class PUll extends Vue {
|
||||
private dialog = false
|
||||
private loading = false
|
||||
private nekoImage = ''
|
||||
|
||||
get status() {
|
||||
return this.$store.state.pullStatus
|
||||
}
|
||||
|
||||
get nekoImages() {
|
||||
return this.$store.state.roomsConfig.neko_images
|
||||
}
|
||||
|
||||
async Start() {
|
||||
this.loading = true
|
||||
|
||||
try {
|
||||
await this.$store.dispatch('PULL_START', this.nekoImage)
|
||||
} catch(e) {
|
||||
if (e.response) {
|
||||
this.$swal({
|
||||
title: 'Server error',
|
||||
text: e.response.data,
|
||||
icon: 'error',
|
||||
})
|
||||
} else {
|
||||
this.$swal({
|
||||
title: 'Network error',
|
||||
text: String(e),
|
||||
icon: 'error',
|
||||
})
|
||||
}
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
async Stop() {
|
||||
this.loading = true
|
||||
|
||||
try {
|
||||
await this.$store.dispatch('PULL_STOP')
|
||||
} catch(e) {
|
||||
if (e.response) {
|
||||
this.$swal({
|
||||
title: 'Server error',
|
||||
text: e.response.data,
|
||||
icon: 'error',
|
||||
})
|
||||
} else {
|
||||
this.$swal({
|
||||
title: 'Network error',
|
||||
text: String(e),
|
||||
icon: 'error',
|
||||
})
|
||||
}
|
||||
} finally {
|
||||
this.loading = false
|
||||
this.dialog = false
|
||||
}
|
||||
}
|
||||
|
||||
private interval!: number
|
||||
|
||||
async mounted() {
|
||||
await this.$store.dispatch('PULL_STATUS')
|
||||
|
||||
this.interval = window.setInterval(async () => {
|
||||
if (!this.status.active) return
|
||||
|
||||
try {
|
||||
await this.$store.dispatch('PULL_STATUS')
|
||||
} catch(e) {
|
||||
console.error(e)
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
beforeDestroy() {
|
||||
window.clearInterval(this.interval)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -9,6 +9,8 @@ import {
|
||||
RoomSettings,
|
||||
RoomStats,
|
||||
RoomsApi,
|
||||
DefaultApi,
|
||||
PullStatus,
|
||||
} from '@/api/index'
|
||||
|
||||
import { state, State } from './state'
|
||||
@@ -21,6 +23,7 @@ const configuration = new Configuration({
|
||||
|
||||
const configApi = new ConfigApi(configuration)
|
||||
const roomsApi = new RoomsApi(configuration)
|
||||
const defaultApi = new DefaultApi(configuration)
|
||||
|
||||
export default new Vuex.Store({
|
||||
state,
|
||||
@@ -55,6 +58,9 @@ export default new Vuex.Store({
|
||||
const roomEntries = state.rooms.filter(({ id }) => id != roomId)
|
||||
Vue.set(state, 'rooms', roomEntries)
|
||||
},
|
||||
PULL_STATUS(state: State, pullStatus: PullStatus) {
|
||||
Vue.set(state, 'pullStatus', pullStatus)
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
async ROOMS_CONFIG({ commit }: ActionContext<State, State>) {
|
||||
@@ -112,6 +118,23 @@ export default new Vuex.Store({
|
||||
commit('ROOMS_PUT', res.data)
|
||||
return res.data
|
||||
},
|
||||
|
||||
async PULL_START({ commit }: ActionContext<State, State>, nekoImage: string) {
|
||||
const res = await defaultApi.pullStart({
|
||||
// eslint-disable-next-line
|
||||
neko_image: nekoImage,
|
||||
})
|
||||
commit('PULL_STATUS', res.data)
|
||||
return res.data
|
||||
},
|
||||
async PULL_STATUS({ commit }: ActionContext<State, State>) {
|
||||
const res = await defaultApi.pullStatus()
|
||||
commit('PULL_STATUS', res.data)
|
||||
},
|
||||
async PULL_STOP() {
|
||||
const res = await defaultApi.pullStop()
|
||||
return res.data
|
||||
},
|
||||
},
|
||||
modules: {
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
BrowserPolicyContent,
|
||||
BrowserPolicyTypeEnum,
|
||||
BrowserPolicyExtension,
|
||||
PullStatus,
|
||||
} from '@/api/index'
|
||||
|
||||
export interface BrowserPolicyConfig {
|
||||
@@ -208,6 +209,13 @@ export const state = {
|
||||
// eslint-disable-next-line
|
||||
persistent_data: false,
|
||||
} as BrowserPolicyContent,
|
||||
|
||||
//
|
||||
// default
|
||||
//
|
||||
pullStatus: {
|
||||
active: false,
|
||||
} as PullStatus
|
||||
}
|
||||
|
||||
export type State = typeof state
|
||||
|
||||
@@ -58,6 +58,10 @@
|
||||
</v-row>
|
||||
|
||||
<RoomsList :loading="loading" />
|
||||
|
||||
<div class="mt-5 text-center">
|
||||
<Pull />
|
||||
</div>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
@@ -66,6 +70,7 @@ import { Component, Vue, Watch } from 'vue-property-decorator'
|
||||
import RoomsList from '@/components/RoomsList.vue'
|
||||
import RoomsQuick from '@/components/RoomsQuick.vue'
|
||||
import RoomsCreate from '@/components/RoomsCreate.vue'
|
||||
import Pull from '@/components/Pull.vue'
|
||||
import { RoomEntry } from '@/api/index'
|
||||
|
||||
@Component({
|
||||
@@ -73,6 +78,7 @@ import { RoomEntry } from '@/api/index'
|
||||
RoomsList,
|
||||
RoomsQuick,
|
||||
RoomsCreate,
|
||||
Pull,
|
||||
}
|
||||
})
|
||||
export default class Home extends Vue {
|
||||
|
||||
Reference in New Issue
Block a user