mirror of
https://github.com/ivabus/gui
synced 2025-04-23 14:07:14 +03:00
add logging in renderer thread (#323)
* #322 add logging in renderer thread * #322 add more logging in main process * #322 improve logging * #322 cleanup data requested --------- Co-authored-by: neil molina <neil@neils-MacBook-Pro.local>
This commit is contained in:
parent
caec6b2e7b
commit
a50e7b9289
15 changed files with 249 additions and 153 deletions
4
.github/workflows/build-sign-notarize.yml
vendored
4
.github/workflows/build-sign-notarize.yml
vendored
|
@ -40,6 +40,8 @@ jobs:
|
|||
s3-artifacts-key: ${{ steps.s3-artifact-uploader.outputs.key }}
|
||||
steps:
|
||||
- uses: teaxyz/setup@v0
|
||||
with:
|
||||
version: 0.25.0
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: get gui version
|
||||
|
@ -156,6 +158,8 @@ jobs:
|
|||
- darwin+aarch64
|
||||
steps:
|
||||
- uses: teaxyz/setup@v0
|
||||
with:
|
||||
version: 0.25.0
|
||||
- uses: actions/checkout@v3
|
||||
- run: rm -rf ./*.{dmg,zip} || true
|
||||
|
||||
|
|
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
|
@ -35,6 +35,8 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: teaxyz/setup@v0
|
||||
with:
|
||||
version: 0.25.0
|
||||
- uses: actions/checkout@v3
|
||||
- name: install app dependencies
|
||||
run: tea -E xc setup
|
||||
|
@ -48,6 +50,8 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: teaxyz/setup@v0
|
||||
with:
|
||||
version: 0.25.0
|
||||
- uses: actions/checkout@v3
|
||||
- name: cache node_modules build
|
||||
# TODO: cache issue in our self-hosted macos runner ESPIPE: invalid seek, read
|
||||
|
|
|
@ -96,12 +96,11 @@ pnpm --filter tea exec pnpm dist
|
|||
|
||||
| Project | Version |
|
||||
|-----------------------------------|-----------|
|
||||
| nodejs.org | =18.13.0 |
|
||||
| pnpm.io | >=7.27 |
|
||||
| nodejs.org | =18.15.0 |
|
||||
| pnpm.io | =7.18.2 |
|
||||
| xcfile.dev | >=0.0.110 |
|
||||
| python.org | >=3.10 |
|
||||
|
||||
|
||||
[aws/cli]: https://aws.amazon.com/cli/
|
||||
[`xc`]: https://xcfile.dev
|
||||
[semver]: https://semver.org
|
||||
|
|
|
@ -4,11 +4,12 @@ import fs from "fs";
|
|||
import { getTeaPath } from "./tea-dir";
|
||||
import * as v1Client from "./v1-client";
|
||||
import { app } from "electron";
|
||||
import * as log from "electron-log";
|
||||
|
||||
const sessionFilePath = path.join(getTeaPath(), "tea.xyz/gui/tmp.dat");
|
||||
const sessionFolder = path.join(getTeaPath(), "tea.xyz/gui");
|
||||
|
||||
interface Session {
|
||||
export interface Session {
|
||||
device_id?: string;
|
||||
key?: string;
|
||||
user?: any;
|
||||
|
@ -18,14 +19,17 @@ interface Session {
|
|||
export async function readSessionData(): Promise<Session> {
|
||||
const locale = app.getLocale();
|
||||
try {
|
||||
log.info("reading session data");
|
||||
const sessionBuffer = await fs.readFileSync(sessionFilePath);
|
||||
const session = JSON.parse(sessionBuffer.toString()) as Session;
|
||||
session.locale = locale;
|
||||
return session;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
log.error(error);
|
||||
log.info("requesting device_id");
|
||||
const req = await v1Client.get<{ deviceId: string }>("/auth/registerDevice");
|
||||
const data = { device_id: req.deviceId, locale };
|
||||
log.info("got device_id", data);
|
||||
await writeSessionData(data);
|
||||
return data;
|
||||
}
|
||||
|
@ -33,11 +37,13 @@ export async function readSessionData(): Promise<Session> {
|
|||
|
||||
export async function writeSessionData(data: Session) {
|
||||
try {
|
||||
log.info("creating:", sessionFolder);
|
||||
await mkdirp(sessionFolder);
|
||||
log.info("writing session data:", data); // rm this
|
||||
await fs.writeFileSync(sessionFilePath, JSON.stringify(data), {
|
||||
encoding: "utf-8"
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
log.error(error);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ export async function openTerminal(cmd: string) {
|
|||
try {
|
||||
// TODO SECURITY: escape the cmd if possible or create whitelist of acceptable commands
|
||||
scriptPath = await createCommandScriptFile(cmd);
|
||||
if (!scriptPath) throw new Error("unable to create Applse Script");
|
||||
let stdout = ``;
|
||||
let stderr = ``;
|
||||
|
||||
|
@ -72,33 +73,38 @@ export async function openTerminal(cmd: string) {
|
|||
});
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("root:", error);
|
||||
log.error("openTerminal:", error);
|
||||
} finally {
|
||||
if (scriptPath) await fs.unlinkSync(scriptPath);
|
||||
}
|
||||
}
|
||||
|
||||
const createCommandScriptFile = async (cmd: string): Promise<string> => {
|
||||
const guiFolder = getGuiPath();
|
||||
const tmpFilePath = path.join(guiFolder, `${+new Date()}.scpt`);
|
||||
const command = `"${cmd.replace(/"/g, '\\"')}"`;
|
||||
const script = `
|
||||
tell application "iTerm"
|
||||
activate
|
||||
if application "iTerm" is running then
|
||||
try
|
||||
tell the first window to create tab with default profile
|
||||
on error
|
||||
create window with default profile
|
||||
end try
|
||||
end if
|
||||
try {
|
||||
const guiFolder = getGuiPath();
|
||||
const tmpFilePath = path.join(guiFolder, `${+new Date()}.scpt`);
|
||||
const command = `"${cmd.replace(/"/g, '\\"')}"`;
|
||||
const script = `
|
||||
tell application "iTerm"
|
||||
activate
|
||||
if application "iTerm" is running then
|
||||
try
|
||||
tell the first window to create tab with default profile
|
||||
on error
|
||||
create window with default profile
|
||||
end try
|
||||
end if
|
||||
|
||||
delay 0.1
|
||||
|
||||
tell the first window to tell current session to write text ${command}
|
||||
end tell
|
||||
`.trim();
|
||||
|
||||
delay 0.1
|
||||
|
||||
tell the first window to tell current session to write text ${command}
|
||||
end tell
|
||||
`.trim();
|
||||
|
||||
await fs.writeFileSync(tmpFilePath, script, "utf-8");
|
||||
return tmpFilePath;
|
||||
await fs.writeFileSync(tmpFilePath, script, "utf-8");
|
||||
return tmpFilePath;
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
|
|
@ -17,7 +17,9 @@ export const setProtocolPath = (path: string) => {
|
|||
export default function initializeHandlers() {
|
||||
ipcMain.handle("get-installed-packages", async () => {
|
||||
try {
|
||||
log.info("getting installed packages");
|
||||
const pkgs = await getInstalledPackages();
|
||||
log.info(`got installed packages: ${pkgs.length}`);
|
||||
return pkgs;
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
|
@ -27,7 +29,9 @@ export default function initializeHandlers() {
|
|||
|
||||
ipcMain.handle("get-session", async () => {
|
||||
try {
|
||||
log.info("getting session");
|
||||
const session = await readSessionData();
|
||||
log.info(session ? "found session data" : "no session data found");
|
||||
return session;
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
|
@ -37,6 +41,7 @@ export default function initializeHandlers() {
|
|||
|
||||
ipcMain.handle("update-session", async (_, data) => {
|
||||
try {
|
||||
log.info("updating session data with", data); // rm this
|
||||
await writeSessionData(data as Session);
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
|
@ -45,6 +50,7 @@ export default function initializeHandlers() {
|
|||
|
||||
ipcMain.handle("install-package", async (_, data) => {
|
||||
try {
|
||||
log.info("installing package:", data.full_name);
|
||||
const result = await installPackage(data.full_name);
|
||||
return result;
|
||||
} catch (error) {
|
||||
|
@ -58,9 +64,10 @@ export default function initializeHandlers() {
|
|||
try {
|
||||
// TODO: detect if mac or linux
|
||||
// current openTerminal is only design for Mac
|
||||
log.info("open terminal w/ cmd:", cmd);
|
||||
await openTerminal(cmd);
|
||||
} catch (error) {
|
||||
console.error("elast:", error);
|
||||
log.error(error);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -8,13 +8,12 @@ export default function initialize(mainWindow: BrowserWindow) {
|
|||
Pushy.listen();
|
||||
// Register device for push notifications
|
||||
Pushy.register({ appId: "64110fb47446e48a2a0e906d" })
|
||||
.then(async (token) => {
|
||||
.then(async (push_token) => {
|
||||
const { device_id } = await readSessionData();
|
||||
console.log("DEVICE_ID:", device_id, token);
|
||||
if (device_id)
|
||||
await post(`/auth/device/${device_id}/register-push-token`, { push_token: token });
|
||||
if (device_id) await post(`/auth/device/${device_id}/register-push-token`, { push_token });
|
||||
})
|
||||
.catch((err) => {
|
||||
log.error(err);
|
||||
// Display error dialog
|
||||
// Pushy.alert(mainWindow, 'Pushy registration error: ' + err.message);
|
||||
});
|
||||
|
|
|
@ -3,6 +3,7 @@ import fs from "fs";
|
|||
import path from "path";
|
||||
import { app } from "electron";
|
||||
import semver from "semver";
|
||||
import * as log from "electron-log";
|
||||
|
||||
type Dir = {
|
||||
name: string;
|
||||
|
@ -22,7 +23,7 @@ export const getGuiPath = () => {
|
|||
|
||||
export async function getInstalledPackages() {
|
||||
const pkgsPath = getTeaPath();
|
||||
|
||||
log.info("recusively reading:", pkgsPath);
|
||||
const folders = await deepReadDir({
|
||||
dir: pkgsPath,
|
||||
continueDeeper: (name: string) => !semver.valid(name),
|
||||
|
@ -40,6 +41,7 @@ export async function getInstalledPackages() {
|
|||
};
|
||||
});
|
||||
|
||||
log.info("found installed packages:", pkgs.length);
|
||||
return pkgs;
|
||||
}
|
||||
|
||||
|
@ -47,6 +49,7 @@ const semverTest =
|
|||
/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/g;
|
||||
|
||||
export const getPkgBottles = (packageDir: Dir): string[] => {
|
||||
log.info("getting installed bottle for ", packageDir);
|
||||
const bottles: string[] = [];
|
||||
|
||||
const pkg = packageDir.path.split(".tea/")[1];
|
||||
|
@ -63,7 +66,10 @@ export const getPkgBottles = (packageDir: Dir): string[] => {
|
|||
bottles.push(...childBottles);
|
||||
}
|
||||
|
||||
return bottles.filter((b) => b !== undefined).sort(); // ie: ["gohugo.io/v*", "gohugo.io/v0", "gohugo.io/v0.108", "gohugo.io/v0.108.0"]
|
||||
const foundBottles = bottles.filter((b) => b !== undefined).sort(); // ie: ["gohugo.io/v*", "gohugo.io/v0", "gohugo.io/v0.108", "gohugo.io/v0.108.0"]
|
||||
|
||||
log.info(`Found ${foundBottles.length} bottles from `, packageDir);
|
||||
return foundBottles;
|
||||
};
|
||||
|
||||
const deepReadDir = async ({
|
||||
|
@ -91,7 +97,7 @@ const deepReadDir = async ({
|
|||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
log.error(e);
|
||||
}
|
||||
return arrayOfFiles;
|
||||
};
|
||||
|
|
|
@ -1,31 +1,80 @@
|
|||
import axios from "axios";
|
||||
import path from "path";
|
||||
import * as log from "electron-log";
|
||||
import bcrypt from "bcryptjs";
|
||||
|
||||
import { readSessionData, type Session } from "./auth";
|
||||
|
||||
const base = "https://api.tea.xyz";
|
||||
const publicHeader = { Authorization: "public" };
|
||||
export async function get<T>(urlPath: string) {
|
||||
const url = new URL(path.join("v1", urlPath), base).toString();
|
||||
// TODO: add headers
|
||||
const req = await axios.request<T>({
|
||||
method: "GET",
|
||||
url,
|
||||
headers: {}
|
||||
});
|
||||
try {
|
||||
log.info(`GET /v1/${urlPath}`);
|
||||
|
||||
return req.data;
|
||||
const session = await readSessionData();
|
||||
const headers =
|
||||
session?.device_id && session?.user
|
||||
? await getHeaders(`GET/${urlPath}`, session)
|
||||
: publicHeader;
|
||||
|
||||
const url = new URL(path.join("v1", urlPath), base).toString();
|
||||
// TODO: add headers
|
||||
const req = await axios.request<T>({
|
||||
method: "GET",
|
||||
url,
|
||||
headers
|
||||
});
|
||||
|
||||
log.info("REQUEST:", urlPath, req.status);
|
||||
|
||||
return req.data;
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function post<T>(urlPath: string, data: { [key: string]: any }) {
|
||||
const url = new URL(path.join("v1", urlPath), base).toString();
|
||||
const req = await axios.request<T>({
|
||||
method: "POST",
|
||||
url,
|
||||
headers: {},
|
||||
data
|
||||
});
|
||||
try {
|
||||
log.info(`POST /v1/${urlPath}`);
|
||||
|
||||
console.log("REQ:", req.data);
|
||||
const session = await readSessionData();
|
||||
const headers =
|
||||
session?.device_id && session?.user
|
||||
? await getHeaders(`GET/${urlPath}`, session)
|
||||
: publicHeader;
|
||||
|
||||
return req.data;
|
||||
const url = new URL(path.join("v1", urlPath), base).toString();
|
||||
const req = await axios.request<T>({
|
||||
method: "POST",
|
||||
url,
|
||||
headers,
|
||||
data
|
||||
});
|
||||
|
||||
log.info("REQUEST:", urlPath, req.status);
|
||||
|
||||
return req.data;
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function getHeaders(path: string, session: Session) {
|
||||
const unixMs = new Date().getTime();
|
||||
const unixHexSecs = Math.round(unixMs / 1000).toString(16); // hex
|
||||
const deviceId = session.device_id?.split("-")[0];
|
||||
const preHash = [unixHexSecs, session.key, deviceId, path].join("");
|
||||
|
||||
const Authorization = bcrypt.hashSync(preHash, 10);
|
||||
|
||||
return {
|
||||
Authorization,
|
||||
["tea-ts"]: unixMs.toString(),
|
||||
["tea-uid"]: session.user?.developer_id,
|
||||
["tea-gui_id"]: session.device_id
|
||||
};
|
||||
}
|
||||
|
||||
export default get;
|
||||
|
|
|
@ -13,19 +13,40 @@
|
|||
|
||||
import semverCompare from "semver/functions/compare";
|
||||
import type { Package, Review, AirtablePost, Bottle } from "@tea/ui/types";
|
||||
import type { GUIPackage, Course, Category, DeviceAuth, Session } from "./types";
|
||||
import {
|
||||
type GUIPackage,
|
||||
type Course,
|
||||
type Category,
|
||||
type DeviceAuth,
|
||||
type Session,
|
||||
AuthStatus
|
||||
} from "./types";
|
||||
|
||||
import * as mock from "./native-mock";
|
||||
import { PackageStates } from "./types";
|
||||
import { installPackageCommand } from "./native/cli";
|
||||
|
||||
import { get as apiGet } from "$libs/v1-client";
|
||||
|
||||
const log = window.require("electron-log");
|
||||
const { ipcRenderer, shell } = window.require("electron");
|
||||
|
||||
let retryLimit = 0;
|
||||
async function getDistPackages(): Promise<Package[]> {
|
||||
let packages: Package[] = [];
|
||||
try {
|
||||
const resultingPackages = await apiGet<Package[]>("packages");
|
||||
if (resultingPackages) packages = resultingPackages;
|
||||
} catch (error) {
|
||||
retryLimit++;
|
||||
log.error("getDistPackagesList:", error);
|
||||
if (retryLimit < 3) packages = await getDistPackages();
|
||||
}
|
||||
return packages;
|
||||
}
|
||||
|
||||
export async function getPackages(): Promise<GUIPackage[]> {
|
||||
const [packages, installedPackages] = await Promise.all([
|
||||
apiGet<Package[]>("packages"),
|
||||
getDistPackages(),
|
||||
ipcRenderer.invoke("get-installed-packages") as { version: string; full_name: string }[]
|
||||
]);
|
||||
|
||||
|
@ -34,7 +55,7 @@ export async function getPackages(): Promise<GUIPackage[]> {
|
|||
|
||||
// NOTE: its not ideal to get bottles or set package states here maybe do it async in the package store init
|
||||
// --- it has noticeable slowness
|
||||
|
||||
log.info(`native: installed ${installedPackages.length} out of ${(packages || []).length}`);
|
||||
return (packages || []).map((pkg) => {
|
||||
const installedVersions = installedPackages
|
||||
.filter((p) => p.full_name === pkg.full_name)
|
||||
|
@ -67,22 +88,10 @@ export async function installPackage(pkg: GUIPackage, version?: string) {
|
|||
const specificVersion = version || latestVersion;
|
||||
await installPackageCommand(pkg.full_name + (specificVersion ? `@${specificVersion}` : ""));
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
log.error("installPackage:", error);
|
||||
}
|
||||
}
|
||||
|
||||
export async function getFeaturedCourses(): Promise<Course[]> {
|
||||
const posts = await apiGet<AirtablePost[]>("posts", { tag: "featured_course" });
|
||||
return posts.map((post) => {
|
||||
return {
|
||||
title: post.title,
|
||||
sub_title: post.sub_title,
|
||||
banner_image_url: post.thumb_image_url,
|
||||
link: post.link
|
||||
} as Course;
|
||||
});
|
||||
}
|
||||
|
||||
export async function getTopPackages(): Promise<GUIPackage[]> {
|
||||
const packages = await mock.getTopPackages();
|
||||
return packages;
|
||||
|
@ -90,47 +99,95 @@ export async function getTopPackages(): Promise<GUIPackage[]> {
|
|||
|
||||
export async function getAllPosts(tag?: string): Promise<AirtablePost[]> {
|
||||
// add filter here someday: tag = news | course
|
||||
const queryParams = {
|
||||
...(tag ? { tag } : {}),
|
||||
nocache: "true"
|
||||
};
|
||||
const posts = await apiGet<AirtablePost[]>("posts", queryParams);
|
||||
return posts;
|
||||
}
|
||||
|
||||
export async function getCategorizedPackages(): Promise<Category[]> {
|
||||
const categories = await apiGet<Category[]>("/packages/categorized");
|
||||
return categories;
|
||||
try {
|
||||
const queryParams = {
|
||||
...(tag ? { tag } : {}),
|
||||
nocache: "true"
|
||||
};
|
||||
const posts = await apiGet<AirtablePost[]>("posts", queryParams);
|
||||
return posts || [];
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function getDeviceAuth(deviceId: string): Promise<DeviceAuth> {
|
||||
const data = await apiGet<DeviceAuth>(`/auth/device/${deviceId}`);
|
||||
return data;
|
||||
let auth: DeviceAuth = {
|
||||
status: AuthStatus.UNKNOWN,
|
||||
key: ""
|
||||
};
|
||||
try {
|
||||
const data = await apiGet<DeviceAuth>(`/auth/device/${deviceId}`);
|
||||
if (data) auth = data;
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
auth = await getDeviceAuth(deviceId);
|
||||
}
|
||||
return auth;
|
||||
}
|
||||
|
||||
export async function getPackageBottles(packageName: string): Promise<Bottle[]> {
|
||||
console.log("getting bottles for ", packageName);
|
||||
const pkg: Package = await apiGet<Package>(`packages/${packageName.replaceAll("/", ":")}`);
|
||||
return pkg.bottles || [];
|
||||
try {
|
||||
const pkg = await apiGet<Package>(`packages/${packageName.replaceAll("/", ":")}`);
|
||||
log.info(`got ${pkg?.bottles?.length || 0} bottles for ${packageName}`);
|
||||
return (pkg && pkg.bottles) || [];
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
const retryGetPackage: { [key: string]: number } = {};
|
||||
export async function getPackage(packageName: string): Promise<Partial<Package>> {
|
||||
const pkg: Partial<Package> = await apiGet<Partial<Package>>(
|
||||
`packages/${packageName.replaceAll("/", ":")}`
|
||||
);
|
||||
let pkg: Partial<Package> = {};
|
||||
try {
|
||||
const data = await apiGet<Partial<Package>>(`packages/${packageName.replaceAll("/", ":")}`);
|
||||
if (data) {
|
||||
pkg = data;
|
||||
} else {
|
||||
throw new Error(`package:${packageName} not found`);
|
||||
}
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
retryGetPackage[packageName] = (retryGetPackage[packageName] || 0) + 1;
|
||||
if (retryGetPackage[packageName] < 3) {
|
||||
pkg = await getPackage(packageName);
|
||||
} else {
|
||||
log.info(`failed to get package:${packageName} after 3 tries`);
|
||||
}
|
||||
}
|
||||
|
||||
return pkg;
|
||||
}
|
||||
|
||||
export const getSession = async (): Promise<Session | null> => {
|
||||
const session = await ipcRenderer.invoke("get-session");
|
||||
return session;
|
||||
try {
|
||||
log.info("getting local session data");
|
||||
const session = await ipcRenderer.invoke("get-session");
|
||||
log.info("local session data ", session ? "found" : "not found");
|
||||
return session;
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export const updateSession = async (session: Partial<Session>) => {
|
||||
await ipcRenderer.invoke("update-session", session);
|
||||
try {
|
||||
await ipcRenderer.invoke("update-session", session);
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
export const openTerminal = (cmd: string) => ipcRenderer.invoke("open-terminal", { cmd });
|
||||
export const openTerminal = (cmd: string) => {
|
||||
try {
|
||||
ipcRenderer.invoke("open-terminal", { cmd });
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
export const shellOpenExternal = (link: string) => shell.openExternal(link);
|
||||
|
||||
|
|
|
@ -229,31 +229,6 @@ function delay(ms: number) {
|
|||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
export async function getFeaturedCourses(): Promise<Course[]> {
|
||||
const mockCourses: Course[] = [
|
||||
{
|
||||
title: "Developing With Tea",
|
||||
sub_title: "by Mxcl",
|
||||
link: "#",
|
||||
banner_image_url: "https://tea.xyz/Images/packages/mesonbuild_com.jpg"
|
||||
},
|
||||
{
|
||||
title: "Brewing Tea",
|
||||
sub_title: "by Mxcl",
|
||||
link: "#",
|
||||
banner_image_url: "https://tea.xyz/Images/packages/tea_xyz_gx_cc.jpg"
|
||||
},
|
||||
{
|
||||
title: "Harvesting Tea",
|
||||
sub_title: "by Mxcl",
|
||||
link: "#",
|
||||
banner_image_url: "https://tea.xyz/Images/packages/ipfs_tech.jpg"
|
||||
}
|
||||
];
|
||||
|
||||
return mockCourses;
|
||||
}
|
||||
|
||||
export async function getTopPackages(): Promise<GUIPackage[]> {
|
||||
await delay(500);
|
||||
return packages.slice(0, 9).map((pkg) => {
|
||||
|
@ -311,30 +286,6 @@ export async function getAllPosts(type: string): Promise<AirtablePost[]> {
|
|||
return posts;
|
||||
}
|
||||
|
||||
export async function getCategorizedPackages(): Promise<Category[]> {
|
||||
const mockPackages = packages.slice(0, 9).map((pkg) => ({
|
||||
...pkg,
|
||||
state: PackageStates.AVAILABLE
|
||||
}));
|
||||
return [
|
||||
{
|
||||
label: "framework essentials",
|
||||
cta_label: "View all essentials >",
|
||||
packages: mockPackages
|
||||
},
|
||||
{
|
||||
label: "star-struck heavyweights",
|
||||
cta_label: "View all star-strucks >",
|
||||
packages: mockPackages
|
||||
},
|
||||
{
|
||||
label: "simply delightful",
|
||||
cta_label: "View all delightful packages >",
|
||||
packages: mockPackages
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
export async function getDeviceAuth(deviceId: string): Promise<any> {
|
||||
const data = await v1Client.get<any>(`/auth/device/${deviceId}`);
|
||||
return data;
|
||||
|
|
|
@ -66,7 +66,7 @@ function initPosts() {
|
|||
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
getAllPosts().then(set);
|
||||
// getAllPosts().then(set);
|
||||
}
|
||||
|
||||
subscribe((v) => {
|
||||
|
|
|
@ -53,7 +53,7 @@ export default function initAuthStore() {
|
|||
key: data.key,
|
||||
user: data.user
|
||||
});
|
||||
user.set(data.user);
|
||||
user.set(data.user!);
|
||||
timer && clearInterval(timer);
|
||||
timer = null;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ import { notificationStore } from "../stores";
|
|||
import { openTerminal } from "@native";
|
||||
import { NotificationType } from "@tea/ui/types";
|
||||
|
||||
const log = window.require("electron-log");
|
||||
|
||||
const installTea = async () => {
|
||||
console.log("installing tea...");
|
||||
try {
|
||||
|
@ -28,20 +30,26 @@ export default function initPackagesStore() {
|
|||
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
getPackages().then((pkgs) => {
|
||||
getPackages().then(async (pkgs) => {
|
||||
packages.set(pkgs);
|
||||
packagesIndex = new Fuse(pkgs, {
|
||||
keys: ["name", "full_name", "desc", "categories"]
|
||||
});
|
||||
|
||||
const teaCliName = "tea.xyz";
|
||||
pkgs.forEach((pkg) => {
|
||||
if (pkg.full_name === teaCliName) {
|
||||
syncTeaCliPackage(pkg);
|
||||
} else if (pkg.state === PackageStates.INSTALLED) {
|
||||
syncPackageBottlesAndState(pkg.full_name);
|
||||
try {
|
||||
const teaCliName = "tea.xyz";
|
||||
for (const pkg of pkgs) {
|
||||
log.info(`syncing ${pkg.full_name}`);
|
||||
if (pkg.full_name === teaCliName) {
|
||||
await syncTeaCliPackage(pkg);
|
||||
} else if (pkg.state === PackageStates.INSTALLED) {
|
||||
await syncPackageBottlesAndState(pkg.full_name);
|
||||
}
|
||||
log.info(`synced ${pkg.full_name}`);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ export enum AuthStatus {
|
|||
|
||||
export type DeviceAuth = {
|
||||
status: AuthStatus;
|
||||
user: Developer;
|
||||
user?: Developer;
|
||||
key: string;
|
||||
};
|
||||
export interface Session {
|
||||
|
|
Loading…
Reference in a new issue