mirror of
https://github.com/45Drives/cockpit-navigator.git
synced 2025-07-30 09:05:23 +02:00
reorganize sources
This commit is contained in:
parent
192ff817f9
commit
1de5081d11
@ -10,6 +10,11 @@
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"jest.disabledWorkspaceFolders": ["Git Repo Root"]
|
||||
"vitest.disabledWorkspaceFolders": [
|
||||
"Git Repo Root"
|
||||
],
|
||||
"vitest.enable": true,
|
||||
"vitest.showFailMessages": false,
|
||||
"vitest.commandLine": "npx vitest"
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +0,0 @@
|
||||
module.exports = {
|
||||
transform: {
|
||||
"\\.[jt]sx?$": "babel-jest",
|
||||
},
|
||||
};
|
@ -1,10 +0,0 @@
|
||||
{
|
||||
"typeAcquisition": {
|
||||
"include": [
|
||||
"jest"
|
||||
]
|
||||
},
|
||||
"compilerOptions": {
|
||||
"jsx": "preserve",
|
||||
}
|
||||
}
|
@ -4,32 +4,33 @@
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"build": "vue-tsc --noEmit && vite build",
|
||||
"preview": "vite preview",
|
||||
"test": "jest"
|
||||
"test": "vitest run",
|
||||
"testui": "vitest --ui",
|
||||
"coverage": "vitest run --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"@45drives/regex": "^0.1.0",
|
||||
"vue": "^3.2.25"
|
||||
"vue": "^3.2.37"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@45drives/cockpit-css": "^0.1.5",
|
||||
"@45drives/cockpit-helpers": "^0.1.8",
|
||||
"@45drives/cockpit-syntaxes": "^0.1.4",
|
||||
"@babel/preset-env": "^7.18.2",
|
||||
"@fontsource/red-hat-text": "^4.5.4",
|
||||
"@headlessui/vue": "^1.5.0",
|
||||
"@heroicons/vue": "^1.0.6",
|
||||
"@tailwindcss/forms": "^0.5.0",
|
||||
"@types/jest": "^27.5.1",
|
||||
"@vitejs/plugin-vue": "^2.2.0",
|
||||
"@vitejs/plugin-vue": "^3.0.3",
|
||||
"@vitest/ui": "^0.22.0",
|
||||
"autoprefixer": "^10.4.2",
|
||||
"babel-jest": "^28.1.0",
|
||||
"jest": "^28.1.0",
|
||||
"postcss": "^8.4.8",
|
||||
"source-sans-pro": "^3.6.0",
|
||||
"tailwindcss": "^3.0.23",
|
||||
"vite": "^2.8.0",
|
||||
"vue-router": "^4.0.15"
|
||||
"typescript": "^4.7.4",
|
||||
"vite": "^3.0.8",
|
||||
"vitest": "^0.22.0",
|
||||
"vue-router": "^4.0.15",
|
||||
"vue-tsc": "^0.40.1"
|
||||
}
|
||||
}
|
||||
|
11
navigator/src/composables/SourceAdapter.ts
Normal file
11
navigator/src/composables/SourceAdapter.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { Source } from "../types/Source";
|
||||
import { Location } from "../types/Location";
|
||||
import { INotifications } from "../types/Notifications";
|
||||
|
||||
export interface SourceContext {
|
||||
notifications: INotifications;
|
||||
}
|
||||
|
||||
export function defineSource<SourceType extends Source<Location>>(factory: (ctx: SourceContext) => SourceType) {
|
||||
return factory;
|
||||
}
|
50
navigator/src/lib/Progress.test.ts
Normal file
50
navigator/src/lib/Progress.test.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import Progress from './Progress';
|
||||
|
||||
describe('classProgress', () => {
|
||||
describe('defaultconstructorvalues', () => {
|
||||
const prog = new Progress();
|
||||
it('startsat0', () => {
|
||||
expect(prog.start).to.equal(0);
|
||||
})
|
||||
it('endsat100', () => {
|
||||
expect(prog.end).to.equal(100);
|
||||
})
|
||||
it('initializesto0', () => {
|
||||
expect(prog.raw).to.equal(0);
|
||||
})
|
||||
})
|
||||
it('can maintain value state and report accurate percent and fractions throughout range', () => {
|
||||
function testProg(start: number, stop: number, step: number) {
|
||||
const prog = new Progress(start, stop);
|
||||
expect(prog.fraction).to.equal(0);
|
||||
expect(prog.percent).to.equal(0);
|
||||
for (let i = start; i <= stop; i += step) {
|
||||
prog.update(i);
|
||||
expect(prog.raw).to.equal(i);
|
||||
const expectedFrac = (i - start) / (stop - start);
|
||||
expect(prog.fraction).to.equal(expectedFrac);
|
||||
expect(prog.percent).to.equal(expectedFrac * 100);
|
||||
}
|
||||
expect(prog.fraction).to.equal(1);
|
||||
expect(prog.percent).to.equal(100);
|
||||
}
|
||||
testProg(0, 100, 1);
|
||||
testProg(0, 50, 1);
|
||||
testProg(0, 200, 1);
|
||||
testProg(50, 100, 2);
|
||||
testProg(3, 4, 1);
|
||||
describe('edge cases', () => {
|
||||
it('reports as finished if start === end', () => {
|
||||
function testProg(value: number) {
|
||||
const prog = new Progress(value, value);
|
||||
expect(prog.fraction).to.equal(1);
|
||||
expect(prog.percent).to.equal(100);
|
||||
}
|
||||
testProg(0);
|
||||
testProg(1);
|
||||
testProg(100);
|
||||
testProg(1/3);
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
32
navigator/src/lib/Progress.ts
Normal file
32
navigator/src/lib/Progress.ts
Normal file
@ -0,0 +1,32 @@
|
||||
export default class Progress {
|
||||
private readonly span: number;
|
||||
private value: number;
|
||||
/**
|
||||
* Represent progress of a task with arbitrary start and end values
|
||||
* @param start - value at 0%
|
||||
* @param end - value at 100%
|
||||
* @param initial - starting value
|
||||
* @param cap - restrict value to [0%, 100%] for {@link fraction}, {@link percent}, {@link raw}, and {@link update}
|
||||
*/
|
||||
constructor(public readonly start = 0, public readonly end = 100, initial = start, private readonly cap = false) {
|
||||
this.span = this.end - this.start;
|
||||
this.value = initial;
|
||||
}
|
||||
get fraction() {
|
||||
if (this.span === 0)
|
||||
return 1;
|
||||
return (this.raw - this.start) / this.span;
|
||||
}
|
||||
get percent() {
|
||||
return this.fraction * 100;
|
||||
}
|
||||
get raw() {
|
||||
return this.cap ? Math.max(this.start, Math.min(this.value, this.end)) : this.value;
|
||||
}
|
||||
update(value: number) {
|
||||
this.value = this.cap ? Math.max(this.start, Math.min(value, this.end)) : value;
|
||||
}
|
||||
toString() {
|
||||
return `${this.percent}%`;
|
||||
}
|
||||
}
|
8
navigator/src/lib/constants.ts
Normal file
8
navigator/src/lib/constants.ts
Normal file
@ -0,0 +1,8 @@
|
||||
/**
|
||||
* ASCII field delimiter
|
||||
*/
|
||||
export const UNIT_SEPARATOR = '\x1F';
|
||||
/**
|
||||
* ASCII record delimiter
|
||||
*/
|
||||
export const RECORD_SEPARATOR = '\x1E';
|
151
navigator/src/lib/sources/POSIX/find.ts
Normal file
151
navigator/src/lib/sources/POSIX/find.ts
Normal file
@ -0,0 +1,151 @@
|
||||
import { Source } from "../../../types/Source";
|
||||
import { ItemPosix, ItemPosixLink, ItemPosixNonLink, LsType } from "./types";
|
||||
import { UNIT_SEPARATOR, RECORD_SEPARATOR } from "../../constants";
|
||||
|
||||
const findPrintfDirectives = [
|
||||
'%p', // full path
|
||||
'%f', // name
|
||||
'%D', // dev id
|
||||
'%i', // inode
|
||||
'%m', // mode (octal)
|
||||
'%U', // uid
|
||||
'%u', // user
|
||||
'%G', // gid
|
||||
'%g', // group
|
||||
'%s', // size
|
||||
'%A@', // atime
|
||||
'%T@', // mtime
|
||||
'%C@', // ctime
|
||||
'%B@', // btime
|
||||
'%y', // type
|
||||
'%Y', // symlink target type or type if not symlink
|
||||
'%l', // symlink target name or '' if not symlink
|
||||
];
|
||||
|
||||
type FindRecord = [
|
||||
string, // full path
|
||||
string, // name
|
||||
string, // dev id
|
||||
string, // inode
|
||||
string, // mode (octal)
|
||||
string, // uid
|
||||
string, // user
|
||||
string, // gid
|
||||
string, // group
|
||||
string, // size
|
||||
string, // atime
|
||||
string, // mtime
|
||||
string, // ctime
|
||||
string, // btime
|
||||
ItemPosixNonLink["type"], // type
|
||||
ItemPosixNonLink["type"], // symlink target type or type if not symlink
|
||||
'', // symlink target name or '' if not symlink
|
||||
] | [
|
||||
string, // full path
|
||||
string, // name
|
||||
string, // dev id
|
||||
string, // inode
|
||||
string, // mode (octal)
|
||||
string, // uid
|
||||
string, // user
|
||||
string, // gid
|
||||
string, // group
|
||||
string, // size
|
||||
string, // atime
|
||||
string, // mtime
|
||||
string, // ctime
|
||||
string, // btime
|
||||
ItemPosixLink["type"], // type
|
||||
string, // symlink target type or type if not symlink
|
||||
ItemPosixLink["targetType"], // symlink target name or '' if not symlink
|
||||
]
|
||||
|
||||
const findPrintfArg = `${findPrintfDirectives.join(UNIT_SEPARATOR)}${RECORD_SEPARATOR}`;
|
||||
|
||||
const parseIntFunctor = (radix?: number) => (str: string) => {
|
||||
const num = parseInt(str, radix);
|
||||
return isNaN(num) ? undefined : num;
|
||||
}
|
||||
|
||||
function makeItem(record: string): Omit<ItemPosixLink, 'source'> | Omit<ItemPosixNonLink, 'source'> {
|
||||
const [
|
||||
path,
|
||||
name,
|
||||
st_devStr,
|
||||
st_inoStr,
|
||||
st_modeOctStr,
|
||||
st_uidStr,
|
||||
user,
|
||||
st_gidStr,
|
||||
group,
|
||||
st_sizeStr,
|
||||
st_atimeStr,
|
||||
st_mtimeStr,
|
||||
st_ctimeStr,
|
||||
st_btimeStr,
|
||||
type,
|
||||
target,
|
||||
targetType
|
||||
] = record.split(UNIT_SEPARATOR) as FindRecord;
|
||||
const [
|
||||
st_dev,
|
||||
st_ino,
|
||||
st_uid,
|
||||
st_gid,
|
||||
st_size,
|
||||
st_atime,
|
||||
st_mtime,
|
||||
st_ctime,
|
||||
st_btime
|
||||
] = [
|
||||
st_devStr,
|
||||
st_inoStr,
|
||||
st_uidStr,
|
||||
st_gidStr,
|
||||
st_sizeStr,
|
||||
st_atimeStr,
|
||||
st_mtimeStr,
|
||||
st_ctimeStr,
|
||||
st_btimeStr,
|
||||
].map(parseIntFunctor(10));
|
||||
const [st_mode] = [st_modeOctStr].map(parseIntFunctor(8));
|
||||
if (type === LsType.LINK) {
|
||||
return {
|
||||
path,
|
||||
name,
|
||||
st_dev,
|
||||
st_ino,
|
||||
st_mode,
|
||||
st_uid,
|
||||
user,
|
||||
st_gid,
|
||||
group,
|
||||
st_size,
|
||||
st_atime,
|
||||
st_mtime,
|
||||
st_ctime,
|
||||
st_btime,
|
||||
type,
|
||||
target,
|
||||
targetType,
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
path,
|
||||
name,
|
||||
st_dev,
|
||||
st_ino,
|
||||
st_mode,
|
||||
st_uid,
|
||||
user,
|
||||
st_gid,
|
||||
group,
|
||||
st_size,
|
||||
st_atime,
|
||||
st_mtime,
|
||||
st_ctime,
|
||||
st_btime,
|
||||
type,
|
||||
}
|
||||
}
|
||||
}
|
20
navigator/src/lib/sources/POSIX/index.ts
Normal file
20
navigator/src/lib/sources/POSIX/index.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { defineSource } from "../../../composables/SourceAdapter";
|
||||
import { Source } from "../../../types/Source";
|
||||
import { ItemPosix } from "./types";
|
||||
|
||||
export default defineSource(({ notifications }) => {
|
||||
return class SourcePosix implements Source<ItemPosix> {
|
||||
constructor(private root: string, private host: string) { }
|
||||
private async getRecords(location: string): Promise<string[]> {
|
||||
return [
|
||||
""
|
||||
]
|
||||
}
|
||||
async list(path: string = ""): Promise<(ItemPosix)[]> {
|
||||
return (await this.getRecords(this.root + path)).map(record => this.makeItem(record));
|
||||
}
|
||||
async lookup(path: string): Promise<ItemPosix> {
|
||||
return this.makeItem(this.getRecords(this.root + location)[0])
|
||||
}
|
||||
}
|
||||
})
|
109
navigator/src/lib/sources/POSIX/types.ts
Normal file
109
navigator/src/lib/sources/POSIX/types.ts
Normal file
@ -0,0 +1,109 @@
|
||||
import { Location } from "../../../types/Location";
|
||||
|
||||
export enum LsType {
|
||||
REGULAR_FILE = 'f',
|
||||
DIRECTORY = 'd',
|
||||
LINK = 'l',
|
||||
CHARACTER = 'c',
|
||||
BLOCK = 'b',
|
||||
FIFO = 'p',
|
||||
SOCKET = 's',
|
||||
UNKNOWN = 'U',
|
||||
LINK_LOOP = 'L',
|
||||
LINK_BROKEN = 'N',
|
||||
DOOR = 'D',
|
||||
}
|
||||
|
||||
export namespace LsType {
|
||||
export const humanReadableLut: { [key in LsType]: string } = {
|
||||
[LsType.REGULAR_FILE]: 'regular file',
|
||||
[LsType.DIRECTORY]: 'directory',
|
||||
[LsType.LINK]: 'symbolic link',
|
||||
[LsType.CHARACTER]: 'character device',
|
||||
[LsType.BLOCK]: 'block device',
|
||||
[LsType.FIFO]: 'FIFO (named pipe)',
|
||||
[LsType.SOCKET]: 'socket',
|
||||
[LsType.UNKNOWN]: 'unknown file type',
|
||||
[LsType.LINK_LOOP]: 'broken link (loop)',
|
||||
[LsType.LINK_BROKEN]: 'broken link (non-existent)',
|
||||
[LsType.DOOR]: 'door (Solaris)', // probably don't need this, but why not right?
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* POSIX-spec of stat output, minus st_nlink, st_rdev, st_blksz, st_blocks
|
||||
*/
|
||||
export interface ItemPosixBase extends Location {
|
||||
/**
|
||||
* Name of file
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* ID of device containing file
|
||||
*/
|
||||
st_dev?: number;
|
||||
/**
|
||||
* inode number
|
||||
*/
|
||||
st_ino?: number;
|
||||
/**
|
||||
* protection
|
||||
*/
|
||||
st_mode?: number;
|
||||
/**
|
||||
* user ID of owner
|
||||
*/
|
||||
st_uid?: number;
|
||||
/**
|
||||
* user name of owner
|
||||
*/
|
||||
user: string;
|
||||
/**
|
||||
* group ID of owner
|
||||
*/
|
||||
st_gid?: number;
|
||||
/**
|
||||
* group name of owner
|
||||
*/
|
||||
group: string;
|
||||
/**
|
||||
* total size, in bytes
|
||||
*/
|
||||
st_size?: number;
|
||||
/**
|
||||
* time of last access
|
||||
*/
|
||||
st_atime?: number;
|
||||
/**
|
||||
* time of last modification
|
||||
*/
|
||||
st_mtime?: number;
|
||||
/**
|
||||
* time of last status change
|
||||
*/
|
||||
st_ctime?: number;
|
||||
/**
|
||||
* Birth time (not supported on all filesystems)
|
||||
*/
|
||||
st_btime?: number;
|
||||
/**
|
||||
* File's type (like in ls -l), U=unknown type (shouldn't happen)
|
||||
*/
|
||||
type: LsType;
|
||||
}
|
||||
|
||||
export interface ItemPosixNonLink extends ItemPosixBase {
|
||||
type: Exclude<LsType, LsType.LINK | LsType.LINK_BROKEN | LsType.LINK_LOOP>;
|
||||
}
|
||||
|
||||
export interface ItemPosixLink extends ItemPosixBase {
|
||||
type: LsType.LINK;
|
||||
/**
|
||||
* Only if symbolic link:
|
||||
* File's type (like %y), plus follow symbolic links: `L'=loop, `N'=nonexistent, `?' for any other error
|
||||
*/
|
||||
targetType: LsType;
|
||||
target: string;
|
||||
}
|
||||
|
||||
export type ItemPosix = ItemPosixNonLink | ItemPosixLink;
|
13
navigator/src/types/FrontEnd.d.ts
vendored
Normal file
13
navigator/src/types/FrontEnd.d.ts
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
import { Location } from "./Location";
|
||||
|
||||
export namespace ItemDisplay {
|
||||
export type mimetype = `text/${string}` | `image/${string}` | `video/${string}`;
|
||||
}
|
||||
|
||||
export interface ItemDisplay<SourceItemType extends Location> {
|
||||
sourceItem: SourceItemType;
|
||||
name: string;
|
||||
displayType: 'file' | 'directory';
|
||||
isLink: true;
|
||||
mimetype?: ItemDisplay.mimetype;
|
||||
}
|
39
navigator/src/types/Item.d.ts
vendored
Normal file
39
navigator/src/types/Item.d.ts
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
import { Location } from "./Location";
|
||||
import { Source } from "./Source";
|
||||
|
||||
export namespace Item {
|
||||
export type Type = "file" | "directory" | "link";
|
||||
}
|
||||
|
||||
export interface ItemBase extends Location {
|
||||
type: Item.Type;
|
||||
}
|
||||
|
||||
export interface ItemFile extends ItemBase {
|
||||
type: "file";
|
||||
size?: number;
|
||||
}
|
||||
|
||||
export interface ItemDirectory extends ItemBase {
|
||||
type: "directory";
|
||||
}
|
||||
|
||||
export interface ItemLinkBase extends ItemBase {
|
||||
type: "link";
|
||||
link: ItemBase["path"];
|
||||
resolvedType: Omit<Item.Type, "link">
|
||||
}
|
||||
|
||||
export interface ItemLinkFile extends ItemLinkBase, ItemFile {
|
||||
resolvedType: "file";
|
||||
}
|
||||
|
||||
export interface ItemLinkDirectory extends ItemLinkBase, ItemDirectory {
|
||||
resolvedType: "directory";
|
||||
}
|
||||
|
||||
export interface ItemLinkBroken extends ItemLinkBase {
|
||||
broken: true;
|
||||
}
|
||||
|
||||
export type Item = ItemFile | ItemDirectory | ItemLinkFile | ItemLinkDirectory;
|
12
navigator/src/types/Location.d.ts
vendored
Normal file
12
navigator/src/types/Location.d.ts
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
import { Source } from "./Source";
|
||||
|
||||
export interface Location {
|
||||
/**
|
||||
* Reference to the source that contains the item
|
||||
*/
|
||||
source: Source;
|
||||
/**
|
||||
* Path to item relative to source's base path
|
||||
*/
|
||||
path: string;
|
||||
}
|
32
navigator/src/types/Notifications.d.ts
vendored
Normal file
32
navigator/src/types/Notifications.d.ts
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
export interface INotifications {
|
||||
info(header: string, body: string, actions?: INotificationAction[]): INotification;
|
||||
warn(header: string, body: string, actions?: INotificationAction[]): INotification;
|
||||
error(header: string, body: string, actions?: INotificationAction[]): INotification;
|
||||
success(header: string, body: string, actions?: INotificationAction[]): INotification;
|
||||
denied(header: string, body: string, actions?: INotificationAction[]): INotification;
|
||||
}
|
||||
|
||||
/**
|
||||
* An action related to a notification
|
||||
*/
|
||||
export interface INotificationAction {
|
||||
/**
|
||||
* Button text for action
|
||||
*/
|
||||
text: string;
|
||||
/**
|
||||
* The implementation of the action
|
||||
* @param removeNotif - Call this to remove the notification, equivalent to {@link INotification.remove}
|
||||
*/
|
||||
callback(removeNotif: () => void): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification handle returned by methods in INotifications
|
||||
*/
|
||||
export interface INotification {
|
||||
/**
|
||||
* Remove the notification
|
||||
*/
|
||||
remove(): void;
|
||||
}
|
64
navigator/src/types/Source.d.ts
vendored
Normal file
64
navigator/src/types/Source.d.ts
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
import { ItemDisplay } from "./FrontEnd";
|
||||
import { Location } from "./Location";
|
||||
|
||||
export interface ItemPermissions {
|
||||
owner: string | number;
|
||||
group: string | number;
|
||||
mode: number;
|
||||
}
|
||||
|
||||
export namespace Source {
|
||||
export interface CreateOptions {
|
||||
/**
|
||||
* If a file/link already exists at the specified path, and is the same type as what is being created, overwrite it.
|
||||
* Cannot overwrite directories.
|
||||
*/
|
||||
overwrite?: boolean;
|
||||
/**
|
||||
* If a file/link already exists at the specified path, overwrite it regardless of original type.
|
||||
* Cannot overwrite directories.
|
||||
*/
|
||||
forceOverwrite?: boolean;
|
||||
/**
|
||||
* If the path does not exist, create parent directories.
|
||||
* Analogous to `mkdir -p`
|
||||
*/
|
||||
parents?: boolean;
|
||||
}
|
||||
export interface DeleteOptions {
|
||||
/**
|
||||
* For directories, delete all children. If not specified for non-empty directory, deletion will fail.
|
||||
*/
|
||||
recursive?: boolean;
|
||||
}
|
||||
export interface DownloadOptions {
|
||||
/**
|
||||
* Compress files/directories into archive before downloading
|
||||
*/
|
||||
zip?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
export interface Source<ItemType extends Location, FileType extends Location = ItemType, DirectoryType extends Location = ItemType, LinkType extends Location = ItemType> {
|
||||
displayTransform(item: ItemType): ItemDisplay<ItemType>;
|
||||
|
||||
async list(path?: string): Promise<ItemType[]>;
|
||||
async lookup(path: string): Promise<ItemType>;
|
||||
|
||||
async createFile?(path: string, opts?: Source.CreateOptions): Promise<FileType>;
|
||||
async createDirectory?(path: string, opts?: Source.CreateOptions): Promise<DirectoryType>;
|
||||
async createLink?(path: string, targetLocation: string, opts?: Source.CreateOptions): Promise<LinkType>;
|
||||
|
||||
async delete?(item: ItemType, opts?: Source.DeleteOptions): Promise<ItemType>;
|
||||
async moveToTrash?(item: ItemType, opts?: Source.DeleteOptions): Promise<ItemType>;
|
||||
|
||||
async read?(item: FileType): Promise<Uint8Array>;
|
||||
async write?(item: FileType, data: Uint8Array): Promise<FileType>;
|
||||
|
||||
async getPermissions?(item: Location): Promise<Location & ItemPermissions>;
|
||||
async setPermissions?(item: Location & Partial<ItemPermissions>, newPermissions?: Partial<ItemPermissions>): Promise<Location & ItemPermissions>;
|
||||
|
||||
async download?(item: Location, options: Source.DownloadOptions): Promise<Location>;
|
||||
async download?(items: Location[], options: Source.DownloadOptions): Promise<Location>;
|
||||
async upload?(dataTransfer: DataTransfer): Promise<Location | Location[]>;
|
||||
}
|
3
navigator/src/types/cockpit.d.ts
vendored
Normal file
3
navigator/src/types/cockpit.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
declare global {
|
||||
var cockpit = {};
|
||||
}
|
7
navigator/src/vite-env.d.ts
vendored
Normal file
7
navigator/src/vite-env.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
declare module '*.vue' {
|
||||
import type { DefineComponent } from 'vue'
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
33
navigator/tsconfig.json
Normal file
33
navigator/tsconfig.json
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"strict": true,
|
||||
"jsx": "preserve",
|
||||
"sourceMap": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": [
|
||||
"ESNext",
|
||||
"DOM"
|
||||
],
|
||||
"skipLibCheck": true,
|
||||
"types": [
|
||||
"vitest/globals",
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.d.ts",
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.vue"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
}
|
||||
]
|
||||
}
|
11
navigator/tsconfig.node.json
Normal file
11
navigator/tsconfig.node.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": [
|
||||
"vite.config.ts"
|
||||
]
|
||||
}
|
16
navigator/types/cockpit/Problem.d.ts
vendored
16
navigator/types/cockpit/Problem.d.ts
vendored
@ -1,16 +0,0 @@
|
||||
export type ProblemCode =
|
||||
'access-denied' |
|
||||
'authentication-failed' |
|
||||
'internal-error' |
|
||||
'no-cockpit' |
|
||||
'no-session' |
|
||||
'not-found' |
|
||||
'terminated' |
|
||||
'timeout' |
|
||||
'unknown-hostkey' |
|
||||
'no-forwarding';
|
||||
|
||||
export interface Problem {
|
||||
message: string;
|
||||
problem: ProblemCode | null;
|
||||
}
|
55
navigator/types/cockpit/Spawn.d.ts
vendored
55
navigator/types/cockpit/Spawn.d.ts
vendored
@ -1,55 +0,0 @@
|
||||
import { Problem } from "./Problem";
|
||||
|
||||
export interface SpawnProblem extends Problem {
|
||||
exit_status: number | null;
|
||||
exit_signal: string | null;
|
||||
}
|
||||
|
||||
export type SpawnOptionsErr = "out" | "ignore" | "message"
|
||||
|
||||
export interface SpawnOptions {
|
||||
/**
|
||||
* If set to `true` then handle the input and output of the process as
|
||||
* arrays of binary bytes.
|
||||
*/
|
||||
binary?: boolean;
|
||||
/**
|
||||
* The directory to spawn the process in.
|
||||
*/
|
||||
directory?: string;
|
||||
/**
|
||||
* Controls where the standard error is sent. By default it is logged to the
|
||||
* journal.
|
||||
* If set to `"out"` it is included in with the output data.
|
||||
* If set to `"ignore"` then the error output is discarded.
|
||||
* If set to `"message"`, then it will be returned as the error message.
|
||||
* When the {@link SpawnOptions.pty} `"pty"` field is set, this field has no effect.
|
||||
*/
|
||||
err?: "out" | "ignore" | "message";
|
||||
/**
|
||||
* The remote host to spawn the process on. If an alternate user or port is
|
||||
* required it can be specified as `"user@myhost:port"`. If no host is
|
||||
* specified then the correct one will be automatically selected based on
|
||||
* the page calling this function.
|
||||
*/
|
||||
host?: string;
|
||||
/**
|
||||
* An optional array that contains strings to be used as additional
|
||||
* environment variables for the new process. These are "NAME=VALUE"
|
||||
* strings.
|
||||
*/
|
||||
environ?: string[];
|
||||
/**
|
||||
* Launch the process in its own PTY terminal, and send/receive terminal
|
||||
* input and output.
|
||||
*/
|
||||
pty?: boolean;
|
||||
/**
|
||||
* Batch data coming from the process in blocks of at least this size. This
|
||||
* is not a guarantee. After a short timeout the data will be sent even if
|
||||
* the data doesn't match the batch size. Defaults to zero.
|
||||
*/
|
||||
batch?: number;
|
||||
}
|
||||
|
||||
export type Spawn = () => void;
|
167
navigator/types/cockpit/index.d.ts
vendored
167
navigator/types/cockpit/index.d.ts
vendored
@ -1,167 +0,0 @@
|
||||
export import { Problem, ProblemCode } from './Problem';
|
||||
export import { Spawn, SpawnOptions, SpawnOptionsErr, SpawnProblem } from './Spawn';
|
||||
|
||||
export interface Cockpit {
|
||||
spawn: Spawn;
|
||||
}
|
||||
|
||||
declare global {
|
||||
declare var cockpit: Cockpit;
|
||||
}
|
||||
// interface Func1<T, R = void> {
|
||||
// (arg: T): R;
|
||||
// }
|
||||
|
||||
// interface Func2<T, K, R = void> {
|
||||
// (arg1: T, arg2: K): R;
|
||||
// }
|
||||
|
||||
// interface Func3<T, K, V, R = void> {
|
||||
// (arg1: T, arg2: K, arg3: V): R;
|
||||
// }
|
||||
|
||||
// type GUID = string;
|
||||
|
||||
// type Fail = {
|
||||
// message: string;
|
||||
// problem?: string;
|
||||
// };
|
||||
|
||||
// type SpawnFail = Fail & {
|
||||
// exit_status?: number;
|
||||
// exit_signal?: number;
|
||||
// };
|
||||
|
||||
// type ErrorConfig = 'message' | 'out' | 'ignore' | 'pty';
|
||||
// type Superuser = 'require' | 'try';
|
||||
// type ProblemCodes = 'access-denied' | 'authentication-failed' | 'internal-error' | 'no-cockpit' | 'no-session' | 'not-found' | 'terminated' | 'timeout' | 'unknown-hostkey' | 'no-forwarding';
|
||||
|
||||
// type SpawnConfig = {
|
||||
// err?: ErrorConfig;
|
||||
// binary?: boolean;
|
||||
// directory?: string;
|
||||
// host?: string;
|
||||
// environ?: string[];
|
||||
// pty?: boolean;
|
||||
// batch?: boolean;
|
||||
// latency?: number;
|
||||
// superuser?: Superuser;
|
||||
// };
|
||||
|
||||
// interface SyntaxParser<K> {
|
||||
// parse: Func1<string, K>;
|
||||
// stringify: Func1<K, string>;
|
||||
// }
|
||||
|
||||
// type FileConfig<K extends object = {}> = {
|
||||
// syntax?: SyntaxParser<K>;
|
||||
// binary?: boolean;
|
||||
// max_read_size?: number;
|
||||
// superuser?: Superuser;
|
||||
// host?: string;
|
||||
// };
|
||||
|
||||
// interface FileOperationsPromise extends JQuery.Promise<string> {}
|
||||
|
||||
// interface ClosableWithProblem { close(problem?: ProblemCodes): void; }
|
||||
|
||||
// interface FileOperations extends Closable {
|
||||
// read(): FileOperationsPromise;
|
||||
// replace(content: string | null, tag?: string): FileOperationsPromise;
|
||||
// modify(): FileOperationsPromise;
|
||||
// watch(callback: Func3<string, string, string> | Func2<string, string>): void;
|
||||
// /**
|
||||
// * A string containing the path that was passed to the `cockpit.file()` method.
|
||||
// */
|
||||
// path: string;
|
||||
// }
|
||||
|
||||
// interface SpawnPromise extends JQuery.Promise<string>, ClosableWithProblem {
|
||||
// stream(callback: Func1<string>): SpawnPromise;
|
||||
// input(data?: string | Uint8Array, stream?: boolean): SpawnPromise;
|
||||
// }
|
||||
|
||||
// interface Closable { close(): void; }
|
||||
|
||||
// function CacheProvider(provide: Func1<any>, key: any): Closable | null;
|
||||
|
||||
// interface UserInfo {
|
||||
// id: number;
|
||||
// name: string;
|
||||
// full_name: string;
|
||||
// groups: string[];
|
||||
// home: string;
|
||||
// shell: string;
|
||||
// }
|
||||
|
||||
// interface EventHandler<V, T = string> {
|
||||
// addEventListener(type: T, handler: Func1<CustomEvent<V>>);
|
||||
// removeEventListener(type: T, handler: Func1<CustomEvent<V>>);
|
||||
// dispatchEvent(event: Event);
|
||||
// }
|
||||
|
||||
// interface UserInfoPromise extends JQuery.Promise<UserInfo> {}
|
||||
|
||||
// type PermissionOptions = { group: string };
|
||||
|
||||
// type PermissionEvents = 'changed';
|
||||
|
||||
// interface PermissionInfo extends EventHandler<PermissionInfoPromise, PermissionEvents>, Closable {
|
||||
// allowed: boolean;
|
||||
// user: UserInfo;
|
||||
// };
|
||||
|
||||
// interface PermissionInfoPromise extends JQuery.Promise<PermissionInfo> {};
|
||||
|
||||
// type HttpHeaders = any;
|
||||
|
||||
// interface HttpOptions {
|
||||
// address: string;
|
||||
// connection: string;
|
||||
// superuser: Superuser;
|
||||
// }
|
||||
|
||||
// type HttpData = string | Uint8Array;
|
||||
|
||||
// declare const enum HttpMethod {
|
||||
// Get = 'GET',
|
||||
// Post = 'POST',
|
||||
// Head = 'HEAD'
|
||||
// }
|
||||
|
||||
// interface HttpRequestOptions {
|
||||
// body?: HttpData;
|
||||
// headers?: HttpHeaders;
|
||||
// method?: HttpMethod;
|
||||
// params?: any;
|
||||
// path?: string;
|
||||
// }
|
||||
|
||||
// interface HttpOperations extends ClosableWithProblem {
|
||||
// get(path: string, params: any, headers: HttpHeaders): HttpOperationsPromise;
|
||||
// post(path: string, body: string | any, headers: HttpHeaders): HttpOperationsPromise;
|
||||
// request(options: HttpRequestOptions): HttpOperationsPromise;
|
||||
// }
|
||||
|
||||
// interface HttpOperationsPromise extends JQuery.Promise<HttpData>, ClosableWithProblem {
|
||||
// response(handler: Func2<number, HttpHeaders>): HttpOperationsPromise;
|
||||
// stream(handler: Func1<HttpData>): HttpOperationsPromise;
|
||||
// input(handler: HttpData, stream?: boolean): HttpOperationsPromise;
|
||||
// }
|
||||
|
||||
// interface CockpitAPI {
|
||||
// spawn(path: string[], config?: SpawnConfig): SpawnPromise;
|
||||
// script(path: string, args?: string[], config?: SpawnConfig): SpawnPromise;
|
||||
// file(path: string): FileOperations;
|
||||
// cache(key: GUID, provider: CacheProvider, consumer: Func2<any, any>): Closable;
|
||||
// logout(reload: boolean): void;
|
||||
// user(): UserInfoPromise;
|
||||
// permission(options?: PermissionOptions): PermissionInfoPromise;
|
||||
// http(endpoint: string | number, options: HttpOptions): HttpOperations;
|
||||
// }
|
||||
|
||||
// declare var cockpit : CockpitAPI;
|
||||
// declare module 'cockpit' {
|
||||
// export default cockpit;
|
||||
// export { Superuser, ErrorConfig, ProblemCodes };
|
||||
// }
|
@ -1,3 +1,4 @@
|
||||
/// <reference types="vitest/config" />
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
@ -9,5 +10,8 @@ export default defineConfig({
|
||||
target: [
|
||||
"chrome87", "edge88", "firefox78", "safari14"
|
||||
]
|
||||
},
|
||||
test: {
|
||||
globals: true,
|
||||
}
|
||||
})
|
3238
navigator/yarn.lock
3238
navigator/yarn.lock
File diff suppressed because it is too large
Load Diff
@ -1,5 +0,0 @@
|
||||
module.exports = {
|
||||
projects: [
|
||||
'./navigator'
|
||||
]
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user