Merge branch 'dev' into release/v0.7.0
This commit is contained in:
commit
94d9304c0b
@ -1,24 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
make clean
|
||||
|
||||
# To reproduce https://github.com/menloresearch/jan/pull/5463
|
||||
TAURI_TOOLKIT_PATH="${XDG_CACHE_HOME:-$HOME/.cache}/tauri"
|
||||
mkdir -p "$TAURI_TOOLKIT_PATH"
|
||||
wget https://github.com/linuxdeploy/linuxdeploy/releases/download/1-alpha-20250213-2/linuxdeploy-x86_64.AppImage -O "$TAURI_TOOLKIT_PATH/linuxdeploy-x86_64.AppImage"
|
||||
chmod +x "$TAURI_TOOLKIT_PATH/linuxdeploy-x86_64.AppImage"
|
||||
|
||||
jq '.bundle.resources = ["resources/pre-install/**/*"] | .bundle.externalBin = ["binaries/cortex-server", "resources/bin/uv"]' ./src-tauri/tauri.conf.json > /tmp/tauri.conf.json
|
||||
mv /tmp/tauri.conf.json ./src-tauri/tauri.conf.json
|
||||
|
||||
make build-tauri
|
||||
|
||||
cp ./src-tauri/resources/bin/bun ./src-tauri/target/release/bundle/appimage/Jan.AppDir/usr/bin/bun
|
||||
mkdir -p ./src-tauri/target/release/bundle/appimage/Jan.AppDir/usr/lib/Jan/binaries/engines
|
||||
cp -f ./src-tauri/binaries/deps/*.so* ./src-tauri/target/release/bundle/appimage/Jan.AppDir/usr/lib/Jan/binaries/
|
||||
cp -f ./src-tauri/binaries/*.so* ./src-tauri/target/release/bundle/appimage/Jan.AppDir/usr/lib/Jan/binaries/
|
||||
cp -rf ./src-tauri/binaries/engines ./src-tauri/target/release/bundle/appimage/Jan.AppDir/usr/lib/Jan/binaries/
|
||||
APP_IMAGE=./src-tauri/target/release/bundle/appimage/$(ls ./src-tauri/target/release/bundle/appimage/ | grep AppImage | head -1)
|
||||
echo $APP_IMAGE
|
||||
rm -f $APP_IMAGE
|
||||
/opt/bin/appimagetool ./src-tauri/target/release/bundle/appimage/Jan.AppDir $APP_IMAGE
|
||||
@ -14,7 +14,3 @@ sudo apt install -yqq libwebkit2gtk-4.1-dev \
|
||||
librsvg2-dev \
|
||||
xdg-utils \
|
||||
libfuse2
|
||||
|
||||
sudo mkdir -p /opt/bin
|
||||
sudo wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O /opt/bin/appimagetool
|
||||
sudo chmod +x /opt/bin/appimagetool
|
||||
1
.github/ISSUE_TEMPLATE/2-feature-request.md
vendored
1
.github/ISSUE_TEMPLATE/2-feature-request.md
vendored
@ -2,6 +2,7 @@
|
||||
name: 🚀 Feature Request
|
||||
about: Suggest an idea for this project 😻!
|
||||
title: 'idea: '
|
||||
type: Idea
|
||||
---
|
||||
|
||||
## Problem Statement
|
||||
|
||||
215
.github/workflows/jan-electron-build-nightly.yml
vendored
215
.github/workflows/jan-electron-build-nightly.yml
vendored
@ -1,215 +0,0 @@
|
||||
name: Electron Builder - Nightly / Manual
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 20 * * 1,2,3' # At 8 PM UTC on Monday, Tuesday, and Wednesday which is 3 AM UTC+7 Tuesday, Wednesday, and Thursday
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
public_provider:
|
||||
type: choice
|
||||
description: 'Public Provider'
|
||||
options:
|
||||
- none
|
||||
- aws-s3
|
||||
default: none
|
||||
pull_request:
|
||||
branches:
|
||||
- release/**
|
||||
|
||||
jobs:
|
||||
set-public-provider:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
public_provider: ${{ steps.set-public-provider.outputs.public_provider }}
|
||||
ref: ${{ steps.set-public-provider.outputs.ref }}
|
||||
steps:
|
||||
- name: Set public provider
|
||||
id: set-public-provider
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
|
||||
echo "::set-output name=public_provider::${{ github.event.inputs.public_provider }}"
|
||||
echo "::set-output name=ref::${{ github.ref }}"
|
||||
else
|
||||
if [ "${{ github.event_name }}" == "schedule" ]; then
|
||||
echo "::set-output name=public_provider::aws-s3"
|
||||
echo "::set-output name=ref::refs/heads/dev"
|
||||
elif [ "${{ github.event_name }}" == "push" ]; then
|
||||
echo "::set-output name=public_provider::aws-s3"
|
||||
echo "::set-output name=ref::${{ github.ref }}"
|
||||
elif [ "${{ github.event_name }}" == "pull_request_review" ]; then
|
||||
echo "::set-output name=public_provider::none"
|
||||
echo "::set-output name=ref::${{ github.ref }}"
|
||||
else
|
||||
echo "::set-output name=public_provider::none"
|
||||
echo "::set-output name=ref::${{ github.ref }}"
|
||||
fi
|
||||
fi
|
||||
# Job create Update app version based on latest release tag with build number and save to output
|
||||
get-update-version:
|
||||
uses: ./.github/workflows/template-get-update-version.yml
|
||||
|
||||
build-tauri-macos:
|
||||
uses: ./.github/workflows/template-tauri-build-macos.yml
|
||||
secrets: inherit
|
||||
needs: [get-update-version, set-public-provider]
|
||||
with:
|
||||
ref: ${{ needs.set-public-provider.outputs.ref }}
|
||||
public_provider: ${{ needs.set-public-provider.outputs.public_provider }}
|
||||
new_version: ${{ needs.get-update-version.outputs.new_version }}
|
||||
channel: nightly
|
||||
cortex_api_port: "39261"
|
||||
|
||||
build-tauri-windows-x64:
|
||||
uses: ./.github/workflows/template-tauri-build-windows-x64.yml
|
||||
secrets: inherit
|
||||
needs: [get-update-version, set-public-provider]
|
||||
with:
|
||||
ref: ${{ needs.set-public-provider.outputs.ref }}
|
||||
public_provider: ${{ needs.set-public-provider.outputs.public_provider }}
|
||||
new_version: ${{ needs.get-update-version.outputs.new_version }}
|
||||
channel: nightly
|
||||
cortex_api_port: "39261"
|
||||
|
||||
build-tauri-linux-x64:
|
||||
uses: ./.github/workflows/template-tauri-build-linux-x64.yml
|
||||
secrets: inherit
|
||||
needs: [get-update-version, set-public-provider]
|
||||
with:
|
||||
ref: ${{ needs.set-public-provider.outputs.ref }}
|
||||
public_provider: ${{ needs.set-public-provider.outputs.public_provider }}
|
||||
new_version: ${{ needs.get-update-version.outputs.new_version }}
|
||||
channel: nightly
|
||||
cortex_api_port: "39261"
|
||||
|
||||
sync-temp-to-latest:
|
||||
needs: [get-update-version, set-public-provider, build-tauri-windows-x64, build-tauri-linux-x64, build-tauri-macos]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Getting the repo
|
||||
uses: actions/checkout@v3
|
||||
- name: Install jq
|
||||
uses: dcarbone/install-jq-action@v2.0.1
|
||||
- name: create latest.json file
|
||||
run: |
|
||||
VERSION=${{ needs.get-update-version.outputs.new_version }}
|
||||
PUB_DATE=$(date -u +"%Y-%m-%dT%H:%M:%S.%3NZ")
|
||||
LINUX_SIGNATURE="${{ needs.build-tauri-linux-x64.outputs.APPIMAGE_SIG }}"
|
||||
LINUX_URL="https://delta.jan.ai/nightly/${{ needs.build-tauri-linux-x64.outputs.APPIMAGE_FILE_NAME }}"
|
||||
WINDOWS_SIGNATURE="${{ needs.build-tauri-windows-x64.outputs.WIN_SIG }}"
|
||||
WINDOWS_URL="https://delta.jan.ai/nightly/${{ needs.build-tauri-windows-x64.outputs.FILE_NAME }}"
|
||||
DARWIN_SIGNATURE="${{ needs.build-tauri-macos.outputs.MAC_UNIVERSAL_SIG }}"
|
||||
DARWIN_URL="https://delta.jan.ai/nightly/Jan-nightly_${{ needs.get-update-version.outputs.new_version }}.app.tar.gz"
|
||||
|
||||
jq --arg version "$VERSION" \
|
||||
--arg pub_date "$PUB_DATE" \
|
||||
--arg linux_signature "$LINUX_SIGNATURE" \
|
||||
--arg linux_url "$LINUX_URL" \
|
||||
--arg windows_signature "$WINDOWS_SIGNATURE" \
|
||||
--arg windows_url "$WINDOWS_URL" \
|
||||
--arg darwin_arm_signature "$DARWIN_SIGNATURE" \
|
||||
--arg darwin_arm_url "$DARWIN_URL" \
|
||||
--arg darwin_amd_signature "$DARWIN_SIGNATURE" \
|
||||
--arg darwin_amd_url "$DARWIN_URL" \
|
||||
'.version = $version
|
||||
| .pub_date = $pub_date
|
||||
| .platforms["linux-x86_64"].signature = $linux_signature
|
||||
| .platforms["linux-x86_64"].url = $linux_url
|
||||
| .platforms["windows-x86_64"].signature = $windows_signature
|
||||
| .platforms["windows-x86_64"].url = $windows_url
|
||||
| .platforms["darwin-aarch64"].signature = $darwin_arm_signature
|
||||
| .platforms["darwin-aarch64"].url = $darwin_arm_url
|
||||
| .platforms["darwin-x86_64"].signature = $darwin_amd_signature
|
||||
| .platforms["darwin-x86_64"].url = $darwin_amd_url' \
|
||||
src-tauri/latest.json.template > latest.json
|
||||
cat latest.json
|
||||
- name: Sync temp to latest
|
||||
if: ${{ needs.set-public-provider.outputs.public_provider == 'aws-s3' }}
|
||||
run: |
|
||||
aws s3 cp ./latest.json s3://${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}/temp-nightly/latest.json
|
||||
aws s3 sync s3://${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}/temp-nightly/ s3://${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}/nightly/
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.DELTA_AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.DELTA_AWS_SECRET_ACCESS_KEY }}
|
||||
AWS_DEFAULT_REGION: ${{ secrets.DELTA_AWS_REGION }}
|
||||
AWS_EC2_METADATA_DISABLED: "true"
|
||||
|
||||
noti-discord-nightly-and-update-url-readme:
|
||||
needs: [
|
||||
build-tauri-macos,
|
||||
build-tauri-windows-x64,
|
||||
build-tauri-linux-x64,
|
||||
get-update-version,
|
||||
set-public-provider,
|
||||
sync-temp-to-latest
|
||||
]
|
||||
secrets: inherit
|
||||
if: github.event_name == 'schedule'
|
||||
uses: ./.github/workflows/template-noti-discord-and-update-url-readme.yml
|
||||
with:
|
||||
ref: refs/heads/dev
|
||||
build_reason: Nightly
|
||||
push_to_branch: dev
|
||||
new_version: ${{ needs.get-update-version.outputs.new_version }}
|
||||
|
||||
noti-discord-pre-release-and-update-url-readme:
|
||||
needs: [
|
||||
build-tauri-macos,
|
||||
build-tauri-windows-x64,
|
||||
build-tauri-linux-x64,
|
||||
get-update-version,
|
||||
set-public-provider,
|
||||
sync-temp-to-latest
|
||||
]
|
||||
secrets: inherit
|
||||
if: github.event_name == 'push'
|
||||
uses: ./.github/workflows/template-noti-discord-and-update-url-readme.yml
|
||||
with:
|
||||
ref: refs/heads/dev
|
||||
build_reason: Pre-release
|
||||
push_to_branch: dev
|
||||
new_version: ${{ needs.get-update-version.outputs.new_version }}
|
||||
|
||||
noti-discord-manual-and-update-url-readme:
|
||||
needs: [
|
||||
build-tauri-macos,
|
||||
build-tauri-windows-x64,
|
||||
build-tauri-linux-x64,
|
||||
get-update-version,
|
||||
set-public-provider,
|
||||
sync-temp-to-latest
|
||||
]
|
||||
secrets: inherit
|
||||
if: github.event_name == 'workflow_dispatch' && github.event.inputs.public_provider == 'aws-s3'
|
||||
uses: ./.github/workflows/template-noti-discord-and-update-url-readme.yml
|
||||
with:
|
||||
ref: refs/heads/dev
|
||||
build_reason: Manual
|
||||
push_to_branch: dev
|
||||
new_version: ${{ needs.get-update-version.outputs.new_version }}
|
||||
|
||||
|
||||
# comment-pr-build-url:
|
||||
# needs: [
|
||||
# build-tauri-macos,
|
||||
# build-tauri-windows-x64,
|
||||
# build-tauri-linux-x64,
|
||||
# get-update-version,
|
||||
# set-public-provider,
|
||||
# sync-temp-to-latest
|
||||
# ]
|
||||
# runs-on: ubuntu-latest
|
||||
# if: github.event_name == 'pull_request_review'
|
||||
# steps:
|
||||
# - name: Set up GitHub CLI
|
||||
# run: |
|
||||
# curl -sSL https://github.com/cli/cli/releases/download/v2.33.0/gh_2.33.0_linux_amd64.tar.gz | tar xz
|
||||
# sudo cp gh_2.33.0_linux_amd64/bin/gh /usr/local/bin/
|
||||
|
||||
# - name: Comment build URL on PR
|
||||
# env:
|
||||
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# run: |
|
||||
# PR_URL=${{ github.event.pull_request.html_url }}
|
||||
# RUN_ID=${{ github.run_id }}
|
||||
# COMMENT="This is the build for this pull request. You can download it from the Artifacts section here: [Build URL](https://github.com/${{ github.repository }}/actions/runs/${RUN_ID})."
|
||||
# gh pr comment $PR_URL --body "$COMMENT"
|
||||
131
.github/workflows/jan-electron-build.yml
vendored
131
.github/workflows/jan-electron-build.yml
vendored
@ -1,131 +0,0 @@
|
||||
name: Electron Builder - Tag
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: ["v[0-9]+.[0-9]+.[0-9]+"]
|
||||
|
||||
jobs:
|
||||
# Job create Update app version based on latest release tag with build number and save to output
|
||||
get-update-version:
|
||||
uses: ./.github/workflows/template-get-update-version.yml
|
||||
|
||||
create-draft-release:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
||||
outputs:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
version: ${{ steps.get_version.outputs.version }}
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Extract tag name without v prefix
|
||||
id: get_version
|
||||
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV && echo "::set-output name=version::${GITHUB_REF#refs/tags/v}"
|
||||
env:
|
||||
GITHUB_REF: ${{ github.ref }}
|
||||
- name: Create Draft Release
|
||||
id: create_release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ github.ref_name }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
name: "${{ env.VERSION }}"
|
||||
draft: true
|
||||
prerelease: false
|
||||
|
||||
build-electron-macos:
|
||||
uses: ./.github/workflows/template-electron-build-macos.yml
|
||||
secrets: inherit
|
||||
needs: [get-update-version]
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
public_provider: github
|
||||
beta: false
|
||||
nightly: false
|
||||
new_version: ${{ needs.get-update-version.outputs.new_version }}
|
||||
|
||||
build-electron-windows-x64:
|
||||
uses: ./.github/workflows/template-electron-build-windows-x64.yml
|
||||
secrets: inherit
|
||||
needs: [get-update-version]
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
public_provider: github
|
||||
beta: false
|
||||
nightly: false
|
||||
new_version: ${{ needs.get-update-version.outputs.new_version }}
|
||||
|
||||
build-electron-linux-x64:
|
||||
uses: ./.github/workflows/template-electron-build-linux-x64.yml
|
||||
secrets: inherit
|
||||
needs: [get-update-version]
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
public_provider: github
|
||||
beta: false
|
||||
nightly: false
|
||||
new_version: ${{ needs.get-update-version.outputs.new_version }}
|
||||
|
||||
# build-tauri-macos:
|
||||
# uses: ./.github/workflows/template-tauri-build-macos.yml
|
||||
# secrets: inherit
|
||||
# needs: [get-update-version, create-draft-release]
|
||||
# with:
|
||||
# ref: ${{ github.ref }}
|
||||
# public_provider: github
|
||||
# channel: stable
|
||||
# new_version: ${{ needs.get-update-version.outputs.new_version }}
|
||||
# upload_url: ${{ needs.create-draft-release.outputs.upload_url }}
|
||||
|
||||
# build-tauri-windows-x64:
|
||||
# uses: ./.github/workflows/template-tauri-build-windows-x64.yml
|
||||
# secrets: inherit
|
||||
# needs: [get-update-version, create-draft-release]
|
||||
# with:
|
||||
# ref: ${{ github.ref }}
|
||||
# public_provider: github
|
||||
# channel: stable
|
||||
# new_version: ${{ needs.get-update-version.outputs.new_version }}
|
||||
# upload_url: ${{ needs.create-draft-release.outputs.upload_url }}
|
||||
|
||||
# build-tauri-linux-x64:
|
||||
# uses: ./.github/workflows/template-tauri-build-linux-x64.yml
|
||||
# secrets: inherit
|
||||
# needs: [get-update-version, create-draft-release]
|
||||
# with:
|
||||
# ref: ${{ github.ref }}
|
||||
# public_provider: github
|
||||
# channel: stable
|
||||
# new_version: ${{ needs.get-update-version.outputs.new_version }}
|
||||
# upload_url: ${{ needs.create-draft-release.outputs.upload_url }}
|
||||
|
||||
update_release_draft:
|
||||
needs: [
|
||||
build-electron-windows-x64,
|
||||
build-electron-linux-x64,
|
||||
build-electron-macos,
|
||||
build-tauri-windows-x64,
|
||||
build-tauri-linux-x64,
|
||||
build-tauri-macos
|
||||
]
|
||||
permissions:
|
||||
# write permission is required to create a github release
|
||||
contents: write
|
||||
# write permission is required for autolabeler
|
||||
# otherwise, read permission is required at least
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# (Optional) GitHub Enterprise requires GHE_HOST variable set
|
||||
#- name: Set GHE_HOST
|
||||
# run: |
|
||||
# echo "GHE_HOST=${GITHUB_SERVER_URL##https:\/\/}" >> $GITHUB_ENV
|
||||
|
||||
# Drafts your next Release notes as Pull Requests are merged into "master"
|
||||
- uses: release-drafter/release-drafter@v5
|
||||
# (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml
|
||||
# with:
|
||||
# config-name: my-config.yml
|
||||
# disable-autolabeler: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
435
.github/workflows/jan-electron-linter-and-test.yml
vendored
435
.github/workflows/jan-electron-linter-and-test.yml
vendored
@ -1,435 +0,0 @@
|
||||
name: Test - Linter & Playwright
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- dev
|
||||
paths:
|
||||
- 'electron/**'
|
||||
- .github/workflows/jan-electron-linter-and-test.yml
|
||||
- 'web/**'
|
||||
- 'joi/**'
|
||||
- 'package.json'
|
||||
- 'node_modules/**'
|
||||
- 'yarn.lock'
|
||||
- 'core/**'
|
||||
- 'extensions/**'
|
||||
- '!README.md'
|
||||
- 'Makefile'
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- dev
|
||||
- release/**
|
||||
paths:
|
||||
- 'electron/**'
|
||||
- .github/workflows/jan-electron-linter-and-test.yml
|
||||
- 'web/**'
|
||||
- 'joi/**'
|
||||
- 'package.json'
|
||||
- 'node_modules/**'
|
||||
- 'yarn.lock'
|
||||
- 'Makefile'
|
||||
- 'extensions/**'
|
||||
- 'core/**'
|
||||
- 'src-tauri/**'
|
||||
- 'web-app/**'
|
||||
- '!README.md'
|
||||
|
||||
jobs:
|
||||
base_branch_cov:
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.base_ref }}
|
||||
- name: Use Node.js 20.x
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
make config-yarn
|
||||
yarn
|
||||
yarn build:core
|
||||
|
||||
- name: Run test coverage
|
||||
run: yarn test:coverage
|
||||
|
||||
- name: Upload code coverage for ref branch
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ref-lcov.info
|
||||
path: ./coverage/lcov.info
|
||||
|
||||
test-on-macos:
|
||||
if: (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || github.event_name == 'push' || github.event_name == 'workflow_dispatch'
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Getting the repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Installing node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Set IS_TEST environment variable
|
||||
run: |
|
||||
echo "IS_TEST=true" >> $GITHUB_ENV
|
||||
|
||||
- name: 'Cleanup cache'
|
||||
continue-on-error: true
|
||||
run: |
|
||||
rm -rf ~/jan
|
||||
make clean
|
||||
|
||||
- name: Get Commit Message for PR
|
||||
if: github.event_name == 'pull_request'
|
||||
run: |
|
||||
echo "REPORT_PORTAL_DESCRIPTION=${{github.event.after}})" >> $GITHUB_ENV
|
||||
|
||||
- name: Get Commit Message for push event
|
||||
if: github.event_name == 'push'
|
||||
run: |
|
||||
echo "REPORT_PORTAL_DESCRIPTION=${{github.sha}})" >> $GITHUB_ENV
|
||||
|
||||
# - name: 'Config report portal'
|
||||
# run: |
|
||||
# make update-playwright-config REPORT_PORTAL_URL=${{ secrets.REPORT_PORTAL_URL }} REPORT_PORTAL_API_KEY=${{ secrets.REPORT_PORTAL_API_KEY }} REPORT_PORTAL_PROJECT_NAME=${{ secrets.REPORT_PORTAL_PROJECT_NAME }} REPORT_PORTAL_LAUNCH_NAME="Jan App macos" REPORT_PORTAL_DESCRIPTION="${{env.REPORT_PORTAL_DESCRIPTION}}"
|
||||
|
||||
- name: Linter and test
|
||||
run: |
|
||||
make test
|
||||
env:
|
||||
CSC_IDENTITY_AUTO_DISCOVERY: 'false'
|
||||
|
||||
test-on-macos-pr-target:
|
||||
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Getting the repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Installing node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: 'Cleanup cache'
|
||||
continue-on-error: true
|
||||
run: |
|
||||
rm -rf ~/jan
|
||||
make clean
|
||||
|
||||
- name: Linter and test
|
||||
run: |
|
||||
make test
|
||||
env:
|
||||
CSC_IDENTITY_AUTO_DISCOVERY: 'false'
|
||||
|
||||
test-on-windows:
|
||||
if: github.event_name == 'push'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
antivirus-tools: ['mcafee', 'default-windows-security', 'bit-defender']
|
||||
runs-on: windows-desktop-${{ matrix.antivirus-tools }}
|
||||
steps:
|
||||
- name: Getting the repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Installing node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Install tauri-driver dependencies
|
||||
run: |
|
||||
cargo install tauri-driver --locked
|
||||
|
||||
# Clean cache, continue on error
|
||||
- name: 'Cleanup cache'
|
||||
shell: powershell
|
||||
continue-on-error: true
|
||||
run: |
|
||||
$path = "$Env:APPDATA\jan"
|
||||
if (Test-Path $path) {
|
||||
Remove-Item "\\?\$path" -Recurse -Force
|
||||
} else {
|
||||
Write-Output "Folder does not exist."
|
||||
}
|
||||
make clean
|
||||
|
||||
- name: Get Commit Message for push event
|
||||
if: github.event_name == 'push'
|
||||
shell: bash
|
||||
run: |
|
||||
echo "REPORT_PORTAL_DESCRIPTION=${{github.sha}}" >> $GITHUB_ENV
|
||||
|
||||
# - name: 'Config report portal'
|
||||
# shell: bash
|
||||
# run: |
|
||||
# make update-playwright-config REPORT_PORTAL_URL=${{ secrets.REPORT_PORTAL_URL }} REPORT_PORTAL_API_KEY=${{ secrets.REPORT_PORTAL_API_KEY }} REPORT_PORTAL_PROJECT_NAME=${{ secrets.REPORT_PORTAL_PROJECT_NAME }} REPORT_PORTAL_LAUNCH_NAME="Jan App Windows ${{ matrix.antivirus-tools }}" REPORT_PORTAL_DESCRIPTION="${{env.REPORT_PORTAL_DESCRIPTION}}"
|
||||
|
||||
- name: Linter and test
|
||||
shell: powershell
|
||||
run: |
|
||||
make test
|
||||
|
||||
test-on-windows-pr:
|
||||
if: (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || github.event_name == 'workflow_dispatch'
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Getting the repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/cache@v4 # v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
target/
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-${{ hashFiles('**/yarn.lock') }}
|
||||
|
||||
- name: Installing node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Install tauri-driver dependencies
|
||||
run: |
|
||||
cargo install tauri-driver --locked
|
||||
|
||||
# Clean cache, continue on error
|
||||
- name: 'Cleanup cache'
|
||||
shell: powershell
|
||||
continue-on-error: true
|
||||
run: |
|
||||
$path = "$Env:APPDATA\jan"
|
||||
if (Test-Path $path) {
|
||||
Remove-Item "\\?\$path" -Recurse -Force
|
||||
} else {
|
||||
Write-Output "Folder does not exist."
|
||||
}
|
||||
make clean
|
||||
|
||||
- name: Get Commit Message for PR
|
||||
if: github.event_name == 'pull_request'
|
||||
shell: bash
|
||||
run: |
|
||||
echo "REPORT_PORTAL_DESCRIPTION=${{github.event.after}}" >> $GITHUB_ENV
|
||||
|
||||
# - name: 'Config report portal'
|
||||
# shell: bash
|
||||
# run: |
|
||||
# make update-playwright-config REPORT_PORTAL_URL=${{ secrets.REPORT_PORTAL_URL }} REPORT_PORTAL_API_KEY=${{ secrets.REPORT_PORTAL_API_KEY }} REPORT_PORTAL_PROJECT_NAME=${{ secrets.REPORT_PORTAL_PROJECT_NAME }} REPORT_PORTAL_LAUNCH_NAME="Jan App Windows" REPORT_PORTAL_DESCRIPTION="${{env.REPORT_PORTAL_DESCRIPTION}}"
|
||||
|
||||
- name: Install Prerequisites
|
||||
shell: 'powershell'
|
||||
# https://github.com/actions/runner-images/issues/9538
|
||||
# https://github.com/microsoft/playwright/pull/30009/files
|
||||
# https://github.com/tauri-apps/wry/issues/1268
|
||||
# Evergreen Bootstrapper
|
||||
# The Bootstrapper is a tiny installer that downloads
|
||||
# the Evergreen Runtime matching device architecture
|
||||
# and installs it locally.
|
||||
# https://developer.microsoft.com/en-us/microsoft-edge/webview2/consumer/?form=MA13LH
|
||||
run: |
|
||||
Invoke-WebRequest -Uri 'https://go.microsoft.com/fwlink/p/?LinkId=2124703' -OutFile 'setup.exe'
|
||||
Start-Process -FilePath setup.exe -Verb RunAs -Wait
|
||||
|
||||
- name: Linter and test
|
||||
shell: powershell
|
||||
run: |
|
||||
make test
|
||||
|
||||
test-on-windows-pr-target:
|
||||
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Getting the repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Installing node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Install tauri-driver dependencies
|
||||
run: |
|
||||
cargo install tauri-driver --locked
|
||||
|
||||
# Clean cache, continue on error
|
||||
- name: 'Cleanup cache'
|
||||
shell: powershell
|
||||
continue-on-error: true
|
||||
run: |
|
||||
$path = "$Env:APPDATA\jan"
|
||||
if (Test-Path $path) {
|
||||
Remove-Item "\\?\$path" -Recurse -Force
|
||||
} else {
|
||||
Write-Output "Folder does not exist."
|
||||
}
|
||||
make clean
|
||||
|
||||
- name: Linter and test
|
||||
shell: powershell
|
||||
run: |
|
||||
make test
|
||||
|
||||
test-on-ubuntu:
|
||||
runs-on: ubuntu-latest
|
||||
if: (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || github.event_name == 'push' || github.event_name == 'workflow_dispatch'
|
||||
steps:
|
||||
- name: Getting the repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Installing node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Install Tauri dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y libglib2.0-dev libatk1.0-dev libpango1.0-dev libgtk-3-dev libsoup-3.0-dev libwebkit2gtk-4.1-dev librsvg2-dev libfuse2 webkit2gtk-driver
|
||||
|
||||
- name: Install tauri-driver dependencies
|
||||
run: |
|
||||
cargo install tauri-driver --locked
|
||||
|
||||
- name: 'Cleanup cache'
|
||||
continue-on-error: true
|
||||
run: |
|
||||
rm -rf ~/jan
|
||||
make clean
|
||||
|
||||
- name: Get Commit Message for PR
|
||||
if: github.event_name == 'pull_request'
|
||||
run: |
|
||||
echo "REPORT_PORTAL_DESCRIPTION=${{github.event.after}}" >> $GITHUB_ENV
|
||||
|
||||
- name: Get Commit Message for push event
|
||||
if: github.event_name == 'push'
|
||||
run: |
|
||||
echo "REPORT_PORTAL_DESCRIPTION=${{github.sha}}" >> $GITHUB_ENV
|
||||
|
||||
# - name: 'Config report portal'
|
||||
# shell: bash
|
||||
# run: |
|
||||
# make update-playwright-config REPORT_PORTAL_URL=${{ secrets.REPORT_PORTAL_URL }} REPORT_PORTAL_API_KEY=${{ secrets.REPORT_PORTAL_API_KEY }} REPORT_PORTAL_PROJECT_NAME=${{ secrets.REPORT_PORTAL_PROJECT_NAME }} REPORT_PORTAL_LAUNCH_NAME="Jan App Linux" REPORT_PORTAL_DESCRIPTION="${{env.REPORT_PORTAL_DESCRIPTION}}"
|
||||
|
||||
- name: Linter and test
|
||||
run: |
|
||||
export DISPLAY=$(w -h | awk 'NR==1 {print $2}')
|
||||
echo -e "Display ID: $DISPLAY"
|
||||
make test
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: playwright-report
|
||||
path: electron/playwright-report/
|
||||
retention-days: 2
|
||||
|
||||
# coverage-check:
|
||||
# runs-on: ubuntu-latest
|
||||
# needs: base_branch_cov
|
||||
# continue-on-error: true
|
||||
# if: (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || github.event_name == 'push' || github.event_name == 'workflow_dispatch'
|
||||
# steps:
|
||||
# - name: Getting the repo
|
||||
# uses: actions/checkout@v3
|
||||
# with:
|
||||
# fetch-depth: 0
|
||||
|
||||
# - name: Installing node
|
||||
# uses: actions/setup-node@v3
|
||||
# with:
|
||||
# node-version: 20
|
||||
|
||||
# - name: Install yarn
|
||||
# run: npm install -g yarn
|
||||
|
||||
# - name: 'Cleanup cache'
|
||||
# continue-on-error: true
|
||||
# run: |
|
||||
# rm -rf ~/jan
|
||||
# make clean
|
||||
|
||||
# - name: Download code coverage report from base branch
|
||||
# uses: actions/download-artifact@v4
|
||||
# with:
|
||||
# name: ref-lcov.info
|
||||
|
||||
# - name: Linter and test coverage
|
||||
# run: |
|
||||
# export DISPLAY=$(w -h | awk 'NR==1 {print $2}')
|
||||
# echo -e "Display ID: $DISPLAY"
|
||||
# make lint
|
||||
# yarn build:test
|
||||
# yarn test:coverage
|
||||
|
||||
# - name: Generate Code Coverage report
|
||||
# id: code-coverage
|
||||
# uses: barecheck/code-coverage-action@v1
|
||||
# with:
|
||||
# github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# lcov-file: './coverage/lcov.info'
|
||||
# base-lcov-file: './lcov.info'
|
||||
# send-summary-comment: true
|
||||
# show-annotations: 'warning'
|
||||
|
||||
test-on-ubuntu-pr-target:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository
|
||||
steps:
|
||||
- name: Getting the repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Installing node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Install Tauri dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y libglib2.0-dev libatk1.0-dev libpango1.0-dev libgtk-3-dev libsoup-3.0-dev libwebkit2gtk-4.1-dev librsvg2-dev libfuse2 webkit2gtk-driver
|
||||
|
||||
- name: Install tauri-driver dependencies
|
||||
run: |
|
||||
cargo install tauri-driver --locked
|
||||
|
||||
- name: 'Cleanup cache'
|
||||
continue-on-error: true
|
||||
run: |
|
||||
rm -rf ~/jan
|
||||
make clean
|
||||
|
||||
- name: Linter and test
|
||||
run: |
|
||||
export DISPLAY=$(w -h | awk 'NR==1 {print $2}')
|
||||
echo -e "Display ID: $DISPLAY"
|
||||
make test
|
||||
269
.github/workflows/jan-linter-and-test.yml
vendored
Normal file
269
.github/workflows/jan-linter-and-test.yml
vendored
Normal file
@ -0,0 +1,269 @@
|
||||
name: Test - Linter & Playwright
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- dev
|
||||
paths:
|
||||
- .github/workflows/jan-linter-and-test.yml
|
||||
- 'web/**'
|
||||
- 'joi/**'
|
||||
- 'package.json'
|
||||
- 'node_modules/**'
|
||||
- 'yarn.lock'
|
||||
- 'core/**'
|
||||
- 'extensions/**'
|
||||
- '!README.md'
|
||||
- 'Makefile'
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- dev
|
||||
- release/**
|
||||
paths:
|
||||
- .github/workflows/jan-linter-and-test.yml
|
||||
- 'web/**'
|
||||
- 'joi/**'
|
||||
- 'package.json'
|
||||
- 'node_modules/**'
|
||||
- 'yarn.lock'
|
||||
- 'Makefile'
|
||||
- 'extensions/**'
|
||||
- 'core/**'
|
||||
- 'src-tauri/**'
|
||||
- 'web-app/**'
|
||||
- '!README.md'
|
||||
|
||||
jobs:
|
||||
base_branch_cov:
|
||||
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.base_ref }}
|
||||
- name: Use Node.js 20.x
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: 'Cleanup cache'
|
||||
continue-on-error: true
|
||||
run: |
|
||||
rm -rf ~/jan
|
||||
make clean
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
make lint
|
||||
|
||||
- name: Run test coverage
|
||||
run: |
|
||||
yarn test:coverage
|
||||
|
||||
- name: Upload code coverage for ref branch
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ref-lcov.info
|
||||
path: coverage/merged/lcov.info
|
||||
|
||||
test-on-macos:
|
||||
runs-on: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) && 'macos-latest' || 'macos-selfhosted-12-arm64' }}
|
||||
if: github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'workflow_dispatch'
|
||||
steps:
|
||||
- name: Getting the repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Installing node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: 'Cleanup cache'
|
||||
continue-on-error: true
|
||||
run: |
|
||||
rm -rf ~/jan
|
||||
make clean
|
||||
|
||||
- name: Linter and test
|
||||
run: |
|
||||
make test
|
||||
env:
|
||||
CSC_IDENTITY_AUTO_DISCOVERY: 'false'
|
||||
|
||||
test-on-windows:
|
||||
if: github.event_name == 'push'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
antivirus-tools: ['mcafee', 'default-windows-security', 'bit-defender']
|
||||
runs-on: windows-desktop-${{ matrix.antivirus-tools }}
|
||||
steps:
|
||||
- name: Getting the repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Installing node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Install tauri-driver dependencies
|
||||
run: |
|
||||
cargo install tauri-driver --locked
|
||||
|
||||
# Clean cache, continue on error
|
||||
- name: 'Cleanup cache'
|
||||
shell: powershell
|
||||
continue-on-error: true
|
||||
run: |
|
||||
$path = "$Env:APPDATA\jan"
|
||||
if (Test-Path $path) {
|
||||
Remove-Item "\\?\$path" -Recurse -Force
|
||||
} else {
|
||||
Write-Output "Folder does not exist."
|
||||
}
|
||||
make clean
|
||||
|
||||
- name: Linter and test
|
||||
shell: powershell
|
||||
run: |
|
||||
make test
|
||||
|
||||
test-on-windows-pr:
|
||||
if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch'
|
||||
runs-on: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) && 'windows-latest' || 'WINDOWS-11' }}
|
||||
steps:
|
||||
- name: Getting the repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: install dependencies
|
||||
run: |
|
||||
choco install --yes --no-progress make
|
||||
|
||||
- name: Installing node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Install tauri-driver dependencies
|
||||
run: |
|
||||
cargo install tauri-driver --locked
|
||||
|
||||
- name: 'Cleanup cache'
|
||||
shell: powershell
|
||||
continue-on-error: true
|
||||
run: |
|
||||
$path = "$Env:APPDATA\jan"
|
||||
if (Test-Path $path) {
|
||||
Remove-Item "\\?\$path" -Recurse -Force
|
||||
} else {
|
||||
Write-Output "Folder does not exist."
|
||||
}
|
||||
make clean
|
||||
|
||||
- name: Install WebView2 Runtime (Bootstrapper)
|
||||
shell: powershell
|
||||
run: |
|
||||
Invoke-WebRequest -Uri 'https://go.microsoft.com/fwlink/p/?LinkId=2124703' -OutFile 'setup.exe'
|
||||
Start-Process -FilePath setup.exe -Verb RunAs -Wait
|
||||
|
||||
- name: Linter and test
|
||||
shell: powershell
|
||||
run: |
|
||||
make test
|
||||
env:
|
||||
NODE_OPTIONS: '--max-old-space-size=2048'
|
||||
|
||||
test-on-ubuntu:
|
||||
runs-on: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) && 'ubuntu-latest' || 'ubuntu-latest' }}
|
||||
if: github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'workflow_dispatch'
|
||||
steps:
|
||||
- name: Getting the repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Installing node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Install Tauri dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y libglib2.0-dev libatk1.0-dev libpango1.0-dev libgtk-3-dev libsoup-3.0-dev libwebkit2gtk-4.1-dev librsvg2-dev libfuse2 webkit2gtk-driver
|
||||
|
||||
- name: Install tauri-driver dependencies
|
||||
run: |
|
||||
cargo install tauri-driver --locked
|
||||
|
||||
- name: 'Cleanup cache'
|
||||
continue-on-error: true
|
||||
run: |
|
||||
rm -rf ~/jan
|
||||
make clean
|
||||
|
||||
- name: Linter and test
|
||||
run: |
|
||||
export DISPLAY=$(w -h | awk 'NR==1 {print $2}')
|
||||
echo -e "Display ID: $DISPLAY"
|
||||
make test
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: playwright-report
|
||||
path: electron/playwright-report/
|
||||
retention-days: 2
|
||||
|
||||
coverage-check:
|
||||
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
|
||||
runs-on: ubuntu-latest
|
||||
needs: base_branch_cov
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- name: Getting the repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Installing node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
- name: 'Cleanup cache'
|
||||
continue-on-error: true
|
||||
run: |
|
||||
rm -rf ~/jan
|
||||
make clean
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
make lint
|
||||
|
||||
- name: Run test coverage
|
||||
run: |
|
||||
yarn test:coverage
|
||||
|
||||
- name: Download code coverage report from base branch
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ref-lcov.info
|
||||
- name: Generate Code Coverage report
|
||||
id: code-coverage
|
||||
uses: barecheck/code-coverage-action@v1
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
lcov-file: './coverage/merged/lcov.info'
|
||||
base-lcov-file: './lcov.info'
|
||||
send-summary-comment: true
|
||||
show-annotations: 'warning'
|
||||
@ -1,186 +0,0 @@
|
||||
name: build-linux-x64
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
ref:
|
||||
required: true
|
||||
type: string
|
||||
default: 'refs/heads/main'
|
||||
public_provider:
|
||||
required: true
|
||||
type: string
|
||||
default: none
|
||||
description: 'none: build only, github: build and publish to github, aws s3: build and publish to aws s3'
|
||||
new_version:
|
||||
required: true
|
||||
type: string
|
||||
default: ''
|
||||
aws_s3_prefix:
|
||||
required: false
|
||||
type: string
|
||||
default: '/latest/'
|
||||
beta:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
nightly:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
cortex_api_port:
|
||||
required: false
|
||||
type: string
|
||||
default: null
|
||||
secrets:
|
||||
DELTA_AWS_S3_BUCKET_NAME:
|
||||
required: false
|
||||
DELTA_AWS_ACCESS_KEY_ID:
|
||||
required: false
|
||||
DELTA_AWS_SECRET_ACCESS_KEY:
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
build-linux-x64:
|
||||
if: inputs.public_provider == 'github' || inputs.public_provider == 'none'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Getting the repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ inputs.ref }}
|
||||
|
||||
- name: Replace Icons for Beta Build
|
||||
if: inputs.beta == true && inputs.nightly != true
|
||||
shell: bash
|
||||
run: |
|
||||
rm -rf electron/icons/*
|
||||
|
||||
cp electron/icons_dev/jan-beta-512x512.png electron/icons/512x512.png
|
||||
cp electron/icons_dev/jan-beta.ico electron/icons/icon.ico
|
||||
cp electron/icons_dev/jan-beta.png electron/icons/icon.png
|
||||
cp electron/icons_dev/jan-beta-tray@2x.png electron/icons/icon-tray@2x.png
|
||||
cp electron/icons_dev/jan-beta-tray.png electron/icons/icon-tray.png
|
||||
|
||||
- name: Replace Icons for Nightly Build
|
||||
if: inputs.nightly == true && inputs.beta != true
|
||||
shell: bash
|
||||
run: |
|
||||
rm -rf electron/icons/*
|
||||
|
||||
cp electron/icons_dev/jan-nightly-512x512.png electron/icons/512x512.png
|
||||
cp electron/icons_dev/jan-nightly.ico electron/icons/icon.ico
|
||||
cp electron/icons_dev/jan-nightly.png electron/icons/icon.png
|
||||
cp electron/icons_dev/jan-nightly-tray@2x.png electron/icons/icon-tray@2x.png
|
||||
cp electron/icons_dev/jan-nightly-tray.png electron/icons/icon-tray.png
|
||||
|
||||
- name: Installing node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Install jq
|
||||
uses: dcarbone/install-jq-action@v2.0.1
|
||||
|
||||
- name: Update app version base public_provider
|
||||
if: inputs.public_provider != 'github'
|
||||
run: |
|
||||
echo "Version: ${{ inputs.new_version }}"
|
||||
# Update the version in electron/package.json
|
||||
jq --arg version "${{ inputs.new_version }}" '.version = $version' electron/package.json > /tmp/package.json
|
||||
mv /tmp/package.json electron/package.json
|
||||
jq --arg version "${{ inputs.new_version }}" '.version = $version' web/package.json > /tmp/package.json
|
||||
mv /tmp/package.json web/package.json
|
||||
jq '.build.publish = [{"provider": "generic", "url": "https://delta.jan.ai/nightly", "channel": "latest"}, {"provider": "s3", "acl": null, "bucket": "${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}", "region": "${{ secrets.DELTA_AWS_REGION}}", "path": "temp-nightly", "channel": "latest"}]' electron/package.json > /tmp/package.json
|
||||
mv /tmp/package.json electron/package.json
|
||||
cat electron/package.json
|
||||
chmod +x .github/scripts/rename-app.sh
|
||||
.github/scripts/rename-app.sh ./electron/package.json nightly
|
||||
chmod +x .github/scripts/rename-workspace.sh
|
||||
.github/scripts/rename-workspace.sh ./package.json nightly
|
||||
echo "------------------------"
|
||||
cat ./electron/package.json
|
||||
echo "------------------------"
|
||||
|
||||
- name: Change App Name for beta version
|
||||
if: inputs.beta == true
|
||||
shell: bash
|
||||
run: |
|
||||
chmod +x .github/scripts/rename-app.sh
|
||||
.github/scripts/rename-app.sh ./electron/package.json beta
|
||||
chmod +x .github/scripts/rename-workspace.sh
|
||||
.github/scripts/rename-workspace.sh ./package.json beta
|
||||
echo "------------------------"
|
||||
cat ./electron/package.json
|
||||
echo "------------------------"
|
||||
cat ./package.json
|
||||
jq '.build.publish = [{"provider": "generic", "url": "https://delta.jan.ai/beta", "channel": "beta"}, {"provider": "s3", "acl": null, "bucket": "${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}", "region": "${{ secrets.DELTA_AWS_REGION}}", "path": "temp-beta", "channel": "beta"}]' electron/package.json > /tmp/package.json
|
||||
mv /tmp/package.json electron/package.json
|
||||
cat electron/package.json
|
||||
|
||||
- name: Update app version base on tag
|
||||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github'
|
||||
run: |
|
||||
jq --arg version "${VERSION_TAG#v}" '.version = $version' electron/package.json > /tmp/package.json
|
||||
mv /tmp/package.json electron/package.json
|
||||
jq --arg version "${VERSION_TAG#v}" '.version = $version' web/package.json > /tmp/package.json
|
||||
mv /tmp/package.json web/package.json
|
||||
env:
|
||||
VERSION_TAG: ${{ inputs.new_version }}
|
||||
|
||||
- name: Build and publish app to aws s3 r2 or github artifactory
|
||||
if: inputs.public_provider != 'github'
|
||||
run: |
|
||||
# check public_provider is true or not
|
||||
echo "public_provider is ${{ inputs.public_provider }}"
|
||||
if [ "${{ inputs.public_provider }}" == "none" ]; then
|
||||
make build
|
||||
else
|
||||
make build-and-publish
|
||||
fi
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.DELTA_AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.DELTA_AWS_SECRET_ACCESS_KEY }}
|
||||
AWS_EC2_METADATA_DISABLED: 'true'
|
||||
AWS_MAX_ATTEMPTS: '5'
|
||||
POSTHOG_KEY: ${{ secrets.POSTHOG_KEY }}
|
||||
POSTHOG_HOST: ${{ secrets.POSTHOG_HOST }}
|
||||
CORTEX_API_PORT: ${{ inputs.cortex_api_port }}
|
||||
|
||||
- name: Build and publish app to github
|
||||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github' && inputs.beta == false
|
||||
run: |
|
||||
make build-and-publish
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
POSTHOG_KEY: ${{ secrets.POSTHOG_KEY }}
|
||||
POSTHOG_HOST: ${{ secrets.POSTHOG_HOST }}
|
||||
|
||||
- name: Build and publish app to github
|
||||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github' && inputs.beta == true
|
||||
run: |
|
||||
make build-and-publish
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.DELTA_AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.DELTA_AWS_SECRET_ACCESS_KEY }}
|
||||
AWS_EC2_METADATA_DISABLED: 'true'
|
||||
AWS_MAX_ATTEMPTS: '5'
|
||||
POSTHOG_KEY: ${{ secrets.POSTHOG_KEY }}
|
||||
POSTHOG_HOST: ${{ secrets.POSTHOG_HOST }}
|
||||
|
||||
- name: Upload Artifact .deb file
|
||||
if: inputs.public_provider != 'github'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: jan-electron-linux-amd64-${{ inputs.new_version }}-deb
|
||||
path: ./electron/dist/*.deb
|
||||
|
||||
- name: Upload Artifact .AppImage file
|
||||
if: inputs.public_provider != 'github'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: jan-electron-linux-amd64-${{ inputs.new_version }}-AppImage
|
||||
path: ./electron/dist/*.AppImage
|
||||
233
.github/workflows/template-electron-build-macos.yml
vendored
233
.github/workflows/template-electron-build-macos.yml
vendored
@ -1,233 +0,0 @@
|
||||
name: build-macos
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
ref:
|
||||
required: true
|
||||
type: string
|
||||
default: 'refs/heads/main'
|
||||
public_provider:
|
||||
required: true
|
||||
type: string
|
||||
default: none
|
||||
description: 'none: build only, github: build and publish to github, aws s3: build and publish to aws s3'
|
||||
new_version:
|
||||
required: true
|
||||
type: string
|
||||
default: ''
|
||||
aws_s3_prefix:
|
||||
required: false
|
||||
type: string
|
||||
default: '/latest/'
|
||||
beta:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
nightly:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
cortex_api_port:
|
||||
required: false
|
||||
type: string
|
||||
default: null
|
||||
secrets:
|
||||
DELTA_AWS_S3_BUCKET_NAME:
|
||||
required: false
|
||||
DELTA_AWS_ACCESS_KEY_ID:
|
||||
required: false
|
||||
DELTA_AWS_SECRET_ACCESS_KEY:
|
||||
required: false
|
||||
CODE_SIGN_P12_BASE64:
|
||||
required: false
|
||||
CODE_SIGN_P12_PASSWORD:
|
||||
required: false
|
||||
APPLE_ID:
|
||||
required: false
|
||||
APPLE_APP_SPECIFIC_PASSWORD:
|
||||
required: false
|
||||
DEVELOPER_ID:
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
build-macos:
|
||||
if: inputs.public_provider == 'github' || inputs.public_provider == 'none'
|
||||
runs-on: macos-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Getting the repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ inputs.ref }}
|
||||
|
||||
- name: Replace Icons for Beta Build
|
||||
if: inputs.beta == true && inputs.nightly != true
|
||||
shell: bash
|
||||
run: |
|
||||
rm -rf electron/icons/*
|
||||
|
||||
cp electron/icons_dev/jan-beta-512x512.png electron/icons/512x512.png
|
||||
cp electron/icons_dev/jan-beta.ico electron/icons/icon.ico
|
||||
cp electron/icons_dev/jan-beta.png electron/icons/icon.png
|
||||
cp electron/icons_dev/jan-beta-tray@2x.png electron/icons/icon-tray@2x.png
|
||||
cp electron/icons_dev/jan-beta-tray.png electron/icons/icon-tray.png
|
||||
|
||||
- name: Replace Icons for Nightly Build
|
||||
if: inputs.nightly == true && inputs.beta != true
|
||||
shell: bash
|
||||
run: |
|
||||
rm -rf electron/icons/*
|
||||
|
||||
cp electron/icons_dev/jan-nightly-512x512.png electron/icons/512x512.png
|
||||
cp electron/icons_dev/jan-nightly.ico electron/icons/icon.ico
|
||||
cp electron/icons_dev/jan-nightly.png electron/icons/icon.png
|
||||
cp electron/icons_dev/jan-nightly-tray@2x.png electron/icons/icon-tray@2x.png
|
||||
cp electron/icons_dev/jan-nightly-tray.png electron/icons/icon-tray.png
|
||||
|
||||
- name: Installing node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Install jq
|
||||
uses: dcarbone/install-jq-action@v2.0.1
|
||||
|
||||
- name: Update app version based on latest release tag with build number
|
||||
if: inputs.public_provider != 'github'
|
||||
run: |
|
||||
echo "Version: ${{ inputs.new_version }}"
|
||||
# Update the version in electron/package.json
|
||||
jq --arg version "${{ inputs.new_version }}" '.version = $version' electron/package.json > /tmp/package.json
|
||||
mv /tmp/package.json electron/package.json
|
||||
|
||||
jq --arg version "${{ inputs.new_version }}" '.version = $version' web/package.json > /tmp/package.json
|
||||
mv /tmp/package.json web/package.json
|
||||
|
||||
jq '.build.publish = [{"provider": "generic", "url": "https://delta.jan.ai/nightly", "channel": "latest"}, {"provider": "s3", "acl": null, "bucket": "${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}", "region": "${{ secrets.DELTA_AWS_REGION}}", "path": "temp-nightly", "channel": "latest"}]' electron/package.json > /tmp/package.json
|
||||
mv /tmp/package.json electron/package.json
|
||||
|
||||
jq --arg teamid "${{ secrets.APPLE_TEAM_ID }}" '.build.mac.notarize.teamId = $teamid' electron/package.json > /tmp/package.json
|
||||
mv /tmp/package.json electron/package.json
|
||||
|
||||
# cat electron/package.json
|
||||
chmod +x .github/scripts/rename-app.sh
|
||||
.github/scripts/rename-app.sh ./electron/package.json nightly
|
||||
chmod +x .github/scripts/rename-workspace.sh
|
||||
.github/scripts/rename-workspace.sh ./package.json nightly
|
||||
echo "------------------------"
|
||||
cat ./electron/package.json
|
||||
echo "------------------------"
|
||||
|
||||
- name: Change App Name for beta version
|
||||
if: inputs.beta == true
|
||||
shell: bash
|
||||
run: |
|
||||
chmod +x .github/scripts/rename-app.sh
|
||||
.github/scripts/rename-app.sh ./electron/package.json beta
|
||||
chmod +x .github/scripts/rename-workspace.sh
|
||||
.github/scripts/rename-workspace.sh ./package.json beta
|
||||
echo "------------------------"
|
||||
cat ./electron/package.json
|
||||
echo "------------------------"
|
||||
cat ./package.json
|
||||
jq '.build.publish = [{"provider": "generic", "url": "https://delta.jan.ai/beta", "channel": "beta"}, {"provider": "s3", "acl": null, "bucket": "${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}", "region": "${{ secrets.DELTA_AWS_REGION}}", "path": "temp-beta", "channel": "beta"}]' electron/package.json > /tmp/package.json
|
||||
mv /tmp/package.json electron/package.json
|
||||
cat electron/package.json
|
||||
|
||||
- name: Update app version base on tag
|
||||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github'
|
||||
run: |
|
||||
jq --arg version "${VERSION_TAG#v}" '.version = $version' electron/package.json > /tmp/package.json
|
||||
mv /tmp/package.json electron/package.json
|
||||
jq --arg version "${VERSION_TAG#v}" '.version = $version' web/package.json > /tmp/package.json
|
||||
mv /tmp/package.json web/package.json
|
||||
jq --arg teamid "${{ secrets.APPLE_TEAM_ID }}" '.build.mac.notarize.teamId = $teamid' electron/package.json > /tmp/package.json
|
||||
mv /tmp/package.json electron/package.json
|
||||
cat electron/package.json
|
||||
env:
|
||||
VERSION_TAG: ${{ inputs.new_version }}
|
||||
|
||||
- name: Get Cer for code signing
|
||||
run: base64 -d <<< "$CODE_SIGN_P12_BASE64" > /tmp/codesign.p12
|
||||
shell: bash
|
||||
env:
|
||||
CODE_SIGN_P12_BASE64: ${{ secrets.CODE_SIGN_P12_BASE64 }}
|
||||
|
||||
- uses: apple-actions/import-codesign-certs@v2
|
||||
continue-on-error: true
|
||||
with:
|
||||
p12-file-base64: ${{ secrets.CODE_SIGN_P12_BASE64 }}
|
||||
p12-password: ${{ secrets.CODE_SIGN_P12_PASSWORD }}
|
||||
|
||||
- name: Build and publish app to aws s3 r2 or github artifactory
|
||||
if: inputs.public_provider != 'github'
|
||||
run: |
|
||||
# check public_provider is true or not
|
||||
echo "public_provider is ${{ inputs.public_provider }}"
|
||||
if [ "${{ inputs.public_provider }}" == "none" ]; then
|
||||
make build
|
||||
else
|
||||
make build-and-publish
|
||||
fi
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CSC_LINK: '/tmp/codesign.p12'
|
||||
CSC_KEY_PASSWORD: ${{ secrets.CODE_SIGN_P12_PASSWORD }}
|
||||
CSC_IDENTITY_AUTO_DISCOVERY: 'true'
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
||||
APP_PATH: '.'
|
||||
DEVELOPER_ID: ${{ secrets.DEVELOPER_ID }}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.DELTA_AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.DELTA_AWS_SECRET_ACCESS_KEY }}
|
||||
AWS_DEFAULT_REGION: auto
|
||||
AWS_EC2_METADATA_DISABLED: 'true'
|
||||
AWS_MAX_ATTEMPTS: '5'
|
||||
POSTHOG_KEY: ${{ secrets.POSTHOG_KEY }}
|
||||
POSTHOG_HOST: ${{ secrets.POSTHOG_HOST }}
|
||||
CORTEX_API_PORT: ${{ inputs.cortex_api_port }}
|
||||
|
||||
- name: Build and publish app to github
|
||||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github' && inputs.beta == false
|
||||
run: |
|
||||
make build-and-publish
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CSC_LINK: '/tmp/codesign.p12'
|
||||
CSC_KEY_PASSWORD: ${{ secrets.CODE_SIGN_P12_PASSWORD }}
|
||||
CSC_IDENTITY_AUTO_DISCOVERY: 'true'
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
||||
APP_PATH: '.'
|
||||
DEVELOPER_ID: ${{ secrets.DEVELOPER_ID }}
|
||||
POSTHOG_KEY: ${{ secrets.POSTHOG_KEY }}
|
||||
POSTHOG_HOST: ${{ secrets.POSTHOG_HOST }}
|
||||
|
||||
- name: Build and publish app to github
|
||||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github' && inputs.beta == true
|
||||
run: |
|
||||
make build-and-publish
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CSC_LINK: '/tmp/codesign.p12'
|
||||
CSC_KEY_PASSWORD: ${{ secrets.CODE_SIGN_P12_PASSWORD }}
|
||||
CSC_IDENTITY_AUTO_DISCOVERY: 'true'
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
||||
APP_PATH: '.'
|
||||
DEVELOPER_ID: ${{ secrets.DEVELOPER_ID }}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.DELTA_AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.DELTA_AWS_SECRET_ACCESS_KEY }}
|
||||
AWS_DEFAULT_REGION: auto
|
||||
AWS_EC2_METADATA_DISABLED: 'true'
|
||||
AWS_MAX_ATTEMPTS: '5'
|
||||
POSTHOG_KEY: ${{ secrets.POSTHOG_KEY }}
|
||||
POSTHOG_HOST: ${{ secrets.POSTHOG_HOST }}
|
||||
|
||||
- name: Upload Artifact
|
||||
if: inputs.public_provider != 'github'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: jan-electron-mac-universal-${{ inputs.new_version }}
|
||||
path: ./electron/dist/*.dmg
|
||||
@ -1,230 +0,0 @@
|
||||
name: build-windows-x64
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
ref:
|
||||
required: true
|
||||
type: string
|
||||
default: 'refs/heads/main'
|
||||
public_provider:
|
||||
required: true
|
||||
type: string
|
||||
default: none
|
||||
description: 'none: build only, github: build and publish to github, aws s3: build and publish to aws s3'
|
||||
new_version:
|
||||
required: true
|
||||
type: string
|
||||
default: ''
|
||||
aws_s3_prefix:
|
||||
required: false
|
||||
type: string
|
||||
default: '/latest/'
|
||||
beta:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
nightly:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
cortex_api_port:
|
||||
required: false
|
||||
type: string
|
||||
default: null
|
||||
secrets:
|
||||
DELTA_AWS_S3_BUCKET_NAME:
|
||||
required: false
|
||||
DELTA_AWS_ACCESS_KEY_ID:
|
||||
required: false
|
||||
DELTA_AWS_SECRET_ACCESS_KEY:
|
||||
required: false
|
||||
AZURE_KEY_VAULT_URI:
|
||||
required: false
|
||||
AZURE_CLIENT_ID:
|
||||
required: false
|
||||
AZURE_TENANT_ID:
|
||||
required: false
|
||||
AZURE_CLIENT_SECRET:
|
||||
required: false
|
||||
AZURE_CERT_NAME:
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
build-windows-x64:
|
||||
if: inputs.public_provider == 'github' || inputs.public_provider == 'none'
|
||||
runs-on: windows-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Getting the repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ inputs.ref }}
|
||||
|
||||
- name: Replace Icons for Beta Build
|
||||
if: inputs.beta == true && inputs.nightly != true
|
||||
shell: bash
|
||||
run: |
|
||||
rm -rf electron/icons/*
|
||||
|
||||
cp electron/icons_dev/jan-beta-512x512.png electron/icons/512x512.png
|
||||
cp electron/icons_dev/jan-beta.ico electron/icons/icon.ico
|
||||
cp electron/icons_dev/jan-beta.png electron/icons/icon.png
|
||||
cp electron/icons_dev/jan-beta-tray@2x.png electron/icons/icon-tray@2x.png
|
||||
cp electron/icons_dev/jan-beta-tray.png electron/icons/icon-tray.png
|
||||
|
||||
- name: Replace Icons for Nightly Build
|
||||
if: inputs.nightly == true && inputs.beta != true
|
||||
shell: bash
|
||||
run: |
|
||||
rm -rf electron/icons/*
|
||||
|
||||
cp electron/icons_dev/jan-nightly-512x512.png electron/icons/512x512.png
|
||||
cp electron/icons_dev/jan-nightly.ico electron/icons/icon.ico
|
||||
cp electron/icons_dev/jan-nightly.png electron/icons/icon.png
|
||||
cp electron/icons_dev/jan-nightly-tray@2x.png electron/icons/icon-tray@2x.png
|
||||
cp electron/icons_dev/jan-nightly-tray.png electron/icons/icon-tray.png
|
||||
|
||||
- name: Installing node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Install jq
|
||||
uses: dcarbone/install-jq-action@v2.0.1
|
||||
|
||||
- name: Update app version base on tag
|
||||
if: inputs.public_provider != 'github'
|
||||
id: version_update
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Version: ${{ inputs.new_version }}"
|
||||
# Update the version in electron/package.json
|
||||
jq --arg version "${{ inputs.new_version }}" '.version = $version' electron/package.json > /tmp/package.json
|
||||
mv /tmp/package.json electron/package.json
|
||||
|
||||
jq --arg version "${{ inputs.new_version }}" '.version = $version' web/package.json > /tmp/package.json
|
||||
mv /tmp/package.json web/package.json
|
||||
|
||||
jq '.build.publish = [{"provider": "generic", "url": "https://delta.jan.ai/nightly", "channel": "latest"}, {"provider": "s3", "acl": null, "bucket": "${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}", "region": "${{ secrets.DELTA_AWS_REGION}}", "path": "temp-nightly", "channel": "latest"}]' electron/package.json > /tmp/package.json
|
||||
mv /tmp/package.json electron/package.json
|
||||
|
||||
jq '.build.win.sign = "./sign.js"' electron/package.json > /tmp/package.json
|
||||
mv /tmp/package.json electron/package.json
|
||||
cat electron/package.json
|
||||
|
||||
chmod +x .github/scripts/rename-app.sh
|
||||
.github/scripts/rename-app.sh ./electron/package.json nightly
|
||||
chmod +x .github/scripts/rename-workspace.sh
|
||||
.github/scripts/rename-workspace.sh ./package.json nightly
|
||||
chmod +x .github/scripts/rename-uninstaller.sh
|
||||
.github/scripts/rename-uninstaller.sh nightly
|
||||
echo "------------------------"
|
||||
cat ./electron/package.json
|
||||
echo "------------------------"
|
||||
cat ./package.json
|
||||
echo "------------------------"
|
||||
|
||||
- name: Change App Name for beta version
|
||||
if: inputs.beta == true
|
||||
shell: bash
|
||||
run: |
|
||||
chmod +x .github/scripts/rename-app.sh
|
||||
.github/scripts/rename-app.sh ./electron/package.json beta
|
||||
chmod +x .github/scripts/rename-workspace.sh
|
||||
.github/scripts/rename-workspace.sh ./package.json beta
|
||||
chmod +x .github/scripts/rename-uninstaller.sh
|
||||
.github/scripts/rename-uninstaller.sh beta
|
||||
echo "------------------------"
|
||||
cat ./electron/package.json
|
||||
echo "------------------------"
|
||||
cat ./package.json
|
||||
echo "------------------------"
|
||||
cat ./electron/scripts/uninstaller.nsh
|
||||
jq '.build.publish = [{"provider": "generic", "url": "https://delta.jan.ai/beta", "channel": "beta"}, {"provider": "s3", "acl": null, "bucket": "${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}", "region": "${{ secrets.DELTA_AWS_REGION}}", "path": "temp-beta", "channel": "beta"}]' electron/package.json > /tmp/package.json
|
||||
mv /tmp/package.json electron/package.json
|
||||
cat electron/package.json
|
||||
|
||||
- name: Update app version base on tag
|
||||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github'
|
||||
shell: bash
|
||||
run: |
|
||||
jq --arg version "${VERSION_TAG#v}" '.version = $version' electron/package.json > /tmp/package.json
|
||||
mv /tmp/package.json electron/package.json
|
||||
jq --arg version "${VERSION_TAG#v}" '.version = $version' web/package.json > /tmp/package.json
|
||||
mv /tmp/package.json web/package.json
|
||||
jq '.build.win.sign = "./sign.js"' electron/package.json > /tmp/package.json
|
||||
mv /tmp/package.json electron/package.json
|
||||
env:
|
||||
VERSION_TAG: ${{ inputs.new_version }}
|
||||
|
||||
- name: Install AzureSignTool
|
||||
run: |
|
||||
dotnet tool install --global AzureSignTool
|
||||
|
||||
- name: Build and publish app to aws s3 r2 or github artifactory
|
||||
shell: bash
|
||||
if: inputs.public_provider != 'github'
|
||||
run: |
|
||||
# check public_provider is true or not
|
||||
echo "public_provider is ${{ inputs.public_provider }}"
|
||||
if [ "${{ inputs.public_provider }}" == "none" ]; then
|
||||
make build
|
||||
else
|
||||
make build-and-publish
|
||||
fi
|
||||
env:
|
||||
AZURE_KEY_VAULT_URI: ${{ secrets.AZURE_KEY_VAULT_URI }}
|
||||
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
|
||||
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
|
||||
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
|
||||
AZURE_CERT_NAME: homebrewltd
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.DELTA_AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.DELTA_AWS_SECRET_ACCESS_KEY }}
|
||||
AWS_DEFAULT_REGION: auto
|
||||
AWS_EC2_METADATA_DISABLED: 'true'
|
||||
AWS_MAX_ATTEMPTS: '5'
|
||||
POSTHOG_KEY: ${{ secrets.POSTHOG_KEY }}
|
||||
POSTHOG_HOST: ${{ secrets.POSTHOG_HOST }}
|
||||
CORTEX_API_PORT: ${{ inputs.cortex_api_port }}
|
||||
|
||||
- name: Build app and publish app to github
|
||||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github' && inputs.beta == false
|
||||
run: |
|
||||
make build-and-publish
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
AZURE_KEY_VAULT_URI: ${{ secrets.AZURE_KEY_VAULT_URI }}
|
||||
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
|
||||
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
|
||||
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
|
||||
AZURE_CERT_NAME: homebrewltd
|
||||
POSTHOG_KEY: ${{ secrets.POSTHOG_KEY }}
|
||||
POSTHOG_HOST: ${{ secrets.POSTHOG_HOST }}
|
||||
|
||||
- name: Build app and publish app to github
|
||||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github' && inputs.beta == true
|
||||
run: |
|
||||
make build-and-publish
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.DELTA_AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.DELTA_AWS_SECRET_ACCESS_KEY }}
|
||||
AWS_DEFAULT_REGION: auto
|
||||
AWS_EC2_METADATA_DISABLED: 'true'
|
||||
AWS_MAX_ATTEMPTS: '5'
|
||||
AZURE_KEY_VAULT_URI: ${{ secrets.AZURE_KEY_VAULT_URI }}
|
||||
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
|
||||
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
|
||||
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
|
||||
# AZURE_CERT_NAME: ${{ secrets.AZURE_CERT_NAME }}
|
||||
AZURE_CERT_NAME: homebrewltd
|
||||
POSTHOG_KEY: ${{ secrets.POSTHOG_KEY }}
|
||||
POSTHOG_HOST: ${{ secrets.POSTHOG_HOST }}
|
||||
|
||||
- name: Upload Artifact
|
||||
if: inputs.public_provider != 'github'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: jan-electron-win-x64-${{ inputs.new_version }}
|
||||
path: ./electron/dist/*.exe
|
||||
@ -104,20 +104,15 @@ jobs:
|
||||
run: |
|
||||
echo "Version: ${{ inputs.new_version }}"
|
||||
# Update tauri.conf.json
|
||||
jq --arg version "${{ inputs.new_version }}" '.version = $version | .bundle.createUpdaterArtifacts = true | .bundle.resources = ["resources/pre-install/**/*"] | .bundle.externalBin = ["binaries/cortex-server", "resources/bin/uv"]' ./src-tauri/tauri.conf.json > /tmp/tauri.conf.json
|
||||
jq --arg version "${{ inputs.new_version }}" '.version = $version | .bundle.createUpdaterArtifacts = true' ./src-tauri/tauri.conf.json > /tmp/tauri.conf.json
|
||||
mv /tmp/tauri.conf.json ./src-tauri/tauri.conf.json
|
||||
if [ "${{ inputs.channel }}" != "stable" ]; then
|
||||
jq '.bundle.linux.deb.files = {"usr/bin/bun": "resources/bin/bun",
|
||||
"usr/lib/Jan-${{ inputs.channel }}/binaries": "binaries/deps",
|
||||
"usr/lib/Jan-${{ inputs.channel }}/binaries/engines": "binaries/engines",
|
||||
"usr/lib/Jan-${{ inputs.channel }}/binaries/libvulkan.so": "binaries/libvulkan.so"}' ./src-tauri/tauri.conf.json > /tmp/tauri.conf.json
|
||||
else
|
||||
jq '.bundle.linux.deb.files = {"usr/bin/bun": "resources/bin/bun",
|
||||
"usr/lib/Jan/binaries": "binaries/deps",
|
||||
"usr/lib/Jan/binaries/engines": "binaries/engines",
|
||||
"usr/lib/Jan/binaries/libvulkan.so": "binaries/libvulkan.so"}' ./src-tauri/tauri.conf.json > /tmp/tauri.conf.json
|
||||
"usr/lib/Jan-${{ inputs.channel }}/binaries/libvulkan.so": "binaries/libvulkan.so"}' ./src-tauri/tauri.linux.conf.json > /tmp/tauri.linux.conf.json
|
||||
mv /tmp/tauri.linux.conf.json ./src-tauri/tauri.linux.conf.json
|
||||
fi
|
||||
mv /tmp/tauri.conf.json ./src-tauri/tauri.conf.json
|
||||
jq --arg version "${{ inputs.new_version }}" '.version = $version' web-app/package.json > /tmp/package.json
|
||||
mv /tmp/package.json web-app/package.json
|
||||
|
||||
@ -150,48 +145,16 @@ jobs:
|
||||
fi
|
||||
- name: Build app
|
||||
run: |
|
||||
# Pin linuxdeploy version to prevent @tauri-apps/cli-linux-x64-gnu from pulling in an outdated version
|
||||
TAURI_TOOLKIT_PATH="${XDG_CACHE_HOME:-$HOME/.cache}/tauri"
|
||||
mkdir -p "$TAURI_TOOLKIT_PATH"
|
||||
wget https://github.com/linuxdeploy/linuxdeploy/releases/download/1-alpha-20250213-2/linuxdeploy-x86_64.AppImage -O "$TAURI_TOOLKIT_PATH/linuxdeploy-x86_64.AppImage"
|
||||
chmod +x "$TAURI_TOOLKIT_PATH/linuxdeploy-x86_64.AppImage"
|
||||
|
||||
make build-tauri
|
||||
# Copy engines and bun to appimage
|
||||
wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O ./appimagetool
|
||||
chmod +x ./appimagetool
|
||||
if [ "${{ inputs.channel }}" != "stable" ]; then
|
||||
ls ./src-tauri/target/release/bundle/appimage/
|
||||
cp ./src-tauri/resources/bin/bun ./src-tauri/target/release/bundle/appimage/Jan-${{ inputs.channel }}.AppDir/usr/bin/bun
|
||||
mkdir -p ./src-tauri/target/release/bundle/appimage/Jan-${{ inputs.channel }}.AppDir/usr/lib/Jan-${{ inputs.channel }}/binaries/engines
|
||||
cp -f ./src-tauri/binaries/deps/*.so* ./src-tauri/target/release/bundle/appimage/Jan-${{ inputs.channel }}.AppDir/usr/lib/Jan-${{ inputs.channel }}/binaries/
|
||||
cp -f ./src-tauri/binaries/*.so* ./src-tauri/target/release/bundle/appimage/Jan-${{ inputs.channel }}.AppDir/usr/lib/Jan-${{ inputs.channel }}/binaries/
|
||||
cp -rf ./src-tauri/binaries/engines ./src-tauri/target/release/bundle/appimage/Jan-${{ inputs.channel }}.AppDir/usr/lib/Jan-${{ inputs.channel }}/binaries/
|
||||
APP_IMAGE=./src-tauri/target/release/bundle/appimage/$(ls ./src-tauri/target/release/bundle/appimage/ | grep .AppImage | head -1)
|
||||
echo $APP_IMAGE
|
||||
rm -f $APP_IMAGE
|
||||
./appimagetool ./src-tauri/target/release/bundle/appimage/Jan-${{ inputs.channel }}.AppDir $APP_IMAGE
|
||||
yarn tauri signer sign \
|
||||
--private-key "$TAURI_SIGNING_PRIVATE_KEY" \
|
||||
--password "$TAURI_SIGNING_PRIVATE_KEY_PASSWORD" \
|
||||
"$APP_IMAGE"
|
||||
else
|
||||
cp ./src-tauri/resources/bin/bun ./src-tauri/target/release/bundle/appimage/Jan.AppDir/usr/bin/bun
|
||||
mkdir -p ./src-tauri/target/release/bundle/appimage/Jan.AppDir/usr/lib/Jan/binaries/engines
|
||||
cp -f ./src-tauri/binaries/deps/*.so* ./src-tauri/target/release/bundle/appimage/Jan.AppDir/usr/lib/Jan/binaries/
|
||||
cp -f ./src-tauri/binaries/*.so* ./src-tauri/target/release/bundle/appimage/Jan.AppDir/usr/lib/Jan/binaries/
|
||||
cp -rf ./src-tauri/binaries/engines ./src-tauri/target/release/bundle/appimage/Jan.AppDir/usr/lib/Jan/binaries/
|
||||
APP_IMAGE=./src-tauri/target/release/bundle/appimage/$(ls ./src-tauri/target/release/bundle/appimage/ | grep AppImage | head -1)
|
||||
echo $APP_IMAGE
|
||||
rm -f $APP_IMAGE
|
||||
./appimagetool ./src-tauri/target/release/bundle/appimage/Jan.AppDir $APP_IMAGE
|
||||
yarn tauri signer sign \
|
||||
--private-key "$TAURI_SIGNING_PRIVATE_KEY" \
|
||||
--password "$TAURI_SIGNING_PRIVATE_KEY_PASSWORD" \
|
||||
"$APP_IMAGE"
|
||||
fi
|
||||
|
||||
APP_IMAGE=./src-tauri/target/release/bundle/appimage/$(ls ./src-tauri/target/release/bundle/appimage/ | grep AppImage | head -1)
|
||||
yarn tauri signer sign \
|
||||
--private-key "$TAURI_SIGNING_PRIVATE_KEY" \
|
||||
--password "$TAURI_SIGNING_PRIVATE_KEY_PASSWORD" \
|
||||
"$APP_IMAGE"
|
||||
|
||||
env:
|
||||
RELEASE_CHANNEL: "${{ inputs.channel }}"
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
POSTHOG_KEY: ${{ secrets.POSTHOG_KEY }}
|
||||
POSTHOG_HOST: ${{ secrets.POSTHOG_HOST }}
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -49,4 +49,5 @@ src-tauri/resources/bin
|
||||
# Helper tools
|
||||
.opencode
|
||||
OpenCode.md
|
||||
archive/
|
||||
archive/
|
||||
.cache/
|
||||
3
Makefile
3
Makefile
@ -22,6 +22,8 @@ config-yarn:
|
||||
install-and-build: config-yarn
|
||||
ifeq ($(OS),Windows_NT)
|
||||
echo "skip"
|
||||
else ifeq ($(shell uname -s),Linux)
|
||||
chmod +x src-tauri/build-utils/*
|
||||
endif
|
||||
yarn install
|
||||
yarn build:core
|
||||
@ -82,6 +84,7 @@ else ifeq ($(shell uname -s),Linux)
|
||||
rm -rf ./src-tauri/target
|
||||
rm -rf "~/jan/extensions"
|
||||
rm -rf "~/.cache/jan*"
|
||||
rm -rf "./.cache"
|
||||
else
|
||||
find . -name "node_modules" -type d -prune -exec rm -rf '{}' +
|
||||
find . -name ".next" -type d -exec rm -rf '{}' +
|
||||
|
||||
@ -7,8 +7,8 @@ module.exports = {
|
||||
},
|
||||
runner: './testRunner.js',
|
||||
transform: {
|
||||
"^.+\\.tsx?$": [
|
||||
"ts-jest",
|
||||
'^.+\\.tsx?$': [
|
||||
'ts-jest',
|
||||
{
|
||||
diagnostics: false,
|
||||
},
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
"eslint-plugin-jest": "^27.9.0",
|
||||
"jest": "^30.0.3",
|
||||
"jest-junit": "^16.0.0",
|
||||
"jest-runner": "^29.7.0",
|
||||
"jest-runner": "^30.0.3",
|
||||
"pacote": "^21.0.0",
|
||||
"request": "^2.88.2",
|
||||
"request-progress": "^3.0.0",
|
||||
|
||||
@ -43,41 +43,41 @@ describe('EngineManager', () => {
|
||||
})
|
||||
|
||||
describe('cortex engine migration', () => {
|
||||
test('should map nitro to cortex engine', () => {
|
||||
test.skip('should map nitro to cortex engine', () => {
|
||||
const cortexEngine = new MockAIEngine(InferenceEngine.cortex)
|
||||
// @ts-ignore
|
||||
engineManager.register(cortexEngine)
|
||||
|
||||
|
||||
// @ts-ignore
|
||||
const retrievedEngine = engineManager.get<MockAIEngine>(InferenceEngine.nitro)
|
||||
expect(retrievedEngine).toBe(cortexEngine)
|
||||
})
|
||||
|
||||
test('should map cortex_llamacpp to cortex engine', () => {
|
||||
test.skip('should map cortex_llamacpp to cortex engine', () => {
|
||||
const cortexEngine = new MockAIEngine(InferenceEngine.cortex)
|
||||
// @ts-ignore
|
||||
engineManager.register(cortexEngine)
|
||||
|
||||
|
||||
// @ts-ignore
|
||||
const retrievedEngine = engineManager.get<MockAIEngine>(InferenceEngine.cortex_llamacpp)
|
||||
expect(retrievedEngine).toBe(cortexEngine)
|
||||
})
|
||||
|
||||
test('should map cortex_onnx to cortex engine', () => {
|
||||
test.skip('should map cortex_onnx to cortex engine', () => {
|
||||
const cortexEngine = new MockAIEngine(InferenceEngine.cortex)
|
||||
// @ts-ignore
|
||||
engineManager.register(cortexEngine)
|
||||
|
||||
|
||||
// @ts-ignore
|
||||
const retrievedEngine = engineManager.get<MockAIEngine>(InferenceEngine.cortex_onnx)
|
||||
expect(retrievedEngine).toBe(cortexEngine)
|
||||
})
|
||||
|
||||
test('should map cortex_tensorrtllm to cortex engine', () => {
|
||||
test.skip('should map cortex_tensorrtllm to cortex engine', () => {
|
||||
const cortexEngine = new MockAIEngine(InferenceEngine.cortex)
|
||||
// @ts-ignore
|
||||
engineManager.register(cortexEngine)
|
||||
|
||||
|
||||
// @ts-ignore
|
||||
const retrievedEngine = engineManager.get<MockAIEngine>(InferenceEngine.cortex_tensorrtllm)
|
||||
expect(retrievedEngine).toBe(cortexEngine)
|
||||
@ -89,19 +89,19 @@ describe('EngineManager', () => {
|
||||
const mockEngineManager = new EngineManager()
|
||||
// @ts-ignore
|
||||
window.core = { engineManager: mockEngineManager }
|
||||
|
||||
|
||||
const instance = EngineManager.instance()
|
||||
expect(instance).toBe(mockEngineManager)
|
||||
|
||||
|
||||
// Clean up
|
||||
// @ts-ignore
|
||||
delete window.core
|
||||
})
|
||||
|
||||
|
||||
test('should create a new instance if window.core.engineManager is not available', () => {
|
||||
// @ts-ignore
|
||||
delete window.core
|
||||
|
||||
|
||||
const instance = EngineManager.instance()
|
||||
expect(instance).toBeInstanceOf(EngineManager)
|
||||
})
|
||||
|
||||
@ -23,7 +23,7 @@ describe('fs module', () => {
|
||||
it('should call writeFileSync with correct arguments', () => {
|
||||
const args = ['path/to/file', 'data']
|
||||
fs.writeFileSync(...args)
|
||||
expect(globalThis.core.api.writeFileSync).toHaveBeenCalledWith(...args)
|
||||
expect(globalThis.core.api.writeFileSync).toHaveBeenCalledWith({ args })
|
||||
})
|
||||
|
||||
it('should call writeBlob with correct arguments', async () => {
|
||||
@ -90,8 +90,7 @@ describe('fs module', () => {
|
||||
|
||||
it('should call fileStat with correct arguments', async () => {
|
||||
const path = 'path/to/file'
|
||||
const outsideJanDataFolder = true
|
||||
await fs.fileStat(path, outsideJanDataFolder)
|
||||
expect(globalThis.core.api.fileStat).toHaveBeenCalledWith(path, outsideJanDataFolder)
|
||||
await fs.fileStat(path)
|
||||
expect(globalThis.core.api.fileStat).toHaveBeenCalledWith({ args: path })
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { useExtensions } from './index'
|
||||
|
||||
|
||||
import { useExtensions } from './index'
|
||||
|
||||
test('testUseExtensionsMissingPath', () => {
|
||||
expect(() => useExtensions(undefined as any)).toThrowError('A path to the extensions folder is required to use extensions')
|
||||
})
|
||||
test('testUseExtensionsMissingPath', () => {
|
||||
expect(() => useExtensions(undefined as any)).toThrow(
|
||||
'A path to the extensions folder is required to use extensions'
|
||||
)
|
||||
})
|
||||
|
||||
@ -1,30 +1,29 @@
|
||||
import { Model, ModelSettingParams, ModelRuntimeParams } from '../model'
|
||||
import { InferenceEngine } from '../engine'
|
||||
|
||||
test.skip('testValidModelCreation', () => {
|
||||
const model: Model = {
|
||||
object: 'model',
|
||||
version: '1.0',
|
||||
format: 'format1',
|
||||
sources: [{ filename: 'model.bin', url: 'http://example.com/model.bin' }],
|
||||
id: 'model1',
|
||||
name: 'Test Model',
|
||||
created: Date.now(),
|
||||
description: 'A cool model from Huggingface',
|
||||
settings: { ctx_len: 100, ngl: 50, embedding: true },
|
||||
parameters: { temperature: 0.5, token_limit: 100, top_k: 10 },
|
||||
metadata: { author: 'Author', tags: ['tag1', 'tag2'], size: 100 },
|
||||
engine: InferenceEngine.anthropic,
|
||||
}
|
||||
|
||||
import { Model, ModelSettingParams, ModelRuntimeParams, InferenceEngine } from '../model'
|
||||
|
||||
test('testValidModelCreation', () => {
|
||||
const model: Model = {
|
||||
object: 'model',
|
||||
version: '1.0',
|
||||
format: 'format1',
|
||||
sources: [{ filename: 'model.bin', url: 'http://example.com/model.bin' }],
|
||||
id: 'model1',
|
||||
name: 'Test Model',
|
||||
created: Date.now(),
|
||||
description: 'A cool model from Huggingface',
|
||||
settings: { ctx_len: 100, ngl: 50, embedding: true },
|
||||
parameters: { temperature: 0.5, token_limit: 100, top_k: 10 },
|
||||
metadata: { author: 'Author', tags: ['tag1', 'tag2'], size: 100 },
|
||||
engine: InferenceEngine.anthropic
|
||||
};
|
||||
|
||||
expect(model).toBeDefined();
|
||||
expect(model.object).toBe('model');
|
||||
expect(model.version).toBe('1.0');
|
||||
expect(model.sources).toHaveLength(1);
|
||||
expect(model.sources[0].filename).toBe('model.bin');
|
||||
expect(model.settings).toBeDefined();
|
||||
expect(model.parameters).toBeDefined();
|
||||
expect(model.metadata).toBeDefined();
|
||||
expect(model.engine).toBe(InferenceEngine.anthropic);
|
||||
});
|
||||
expect(model).toBeDefined()
|
||||
expect(model.object).toBe('model')
|
||||
expect(model.version).toBe('1.0')
|
||||
expect(model.sources).toHaveLength(1)
|
||||
expect(model.sources[0].filename).toBe('model.bin')
|
||||
expect(model.settings).toBeDefined()
|
||||
expect(model.parameters).toBeDefined()
|
||||
expect(model.metadata).toBeDefined()
|
||||
expect(model.engine).toBe(InferenceEngine.anthropic)
|
||||
})
|
||||
|
||||
@ -1,19 +1,9 @@
|
||||
import * as SettingComponent from './settingComponent'
|
||||
|
||||
import { createSettingComponent } from './settingComponent';
|
||||
it('should not throw any errors when importing settingComponent', () => {
|
||||
expect(() => require('./settingComponent')).not.toThrow()
|
||||
})
|
||||
|
||||
it('should throw an error when creating a setting component with invalid controller type', () => {
|
||||
const props: SettingComponentProps = {
|
||||
key: 'invalidControllerKey',
|
||||
title: 'Invalid Controller Title',
|
||||
description: 'Invalid Controller Description',
|
||||
controllerType: 'invalid' as any,
|
||||
controllerProps: {
|
||||
placeholder: 'Enter text',
|
||||
value: 'Initial Value',
|
||||
type: 'text',
|
||||
textAlign: 'left',
|
||||
inputActions: ['unobscure'],
|
||||
},
|
||||
};
|
||||
expect(() => createSettingComponent(props)).toThrowError();
|
||||
});
|
||||
it('should export SettingComponentProps type', () => {
|
||||
expect(SettingComponent).toBeDefined()
|
||||
})
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.0 MiB After Width: | Height: | Size: 1.3 MiB |
@ -94,7 +94,7 @@ const Hero = () => {
|
||||
</p>
|
||||
<div className="w-4/5 mx-auto mt-10 relative">
|
||||
<ThemeImage
|
||||
className="absolute object-cover w-full object-center mx-auto h-full top-0 left-0 scale-150"
|
||||
className="absolute object-cover w-full object-center mx-auto h-full top-0 left-0 scale-125"
|
||||
source={{
|
||||
light: '/assets/images/homepage/glow.png',
|
||||
dark: '/assets/images/homepage/glow.png',
|
||||
|
||||
@ -587,6 +587,22 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@isaacs/balanced-match@npm:^4.0.1":
|
||||
version: 4.0.1
|
||||
resolution: "@isaacs/balanced-match@npm:4.0.1"
|
||||
checksum: 10c0/7da011805b259ec5c955f01cee903da72ad97c5e6f01ca96197267d3f33103d5b2f8a1af192140f3aa64526c593c8d098ae366c2b11f7f17645d12387c2fd420
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@isaacs/brace-expansion@npm:^5.0.0":
|
||||
version: 5.0.0
|
||||
resolution: "@isaacs/brace-expansion@npm:5.0.0"
|
||||
dependencies:
|
||||
"@isaacs/balanced-match": "npm:^4.0.1"
|
||||
checksum: 10c0/b4d4812f4be53afc2c5b6c545001ff7a4659af68d4484804e9d514e183d20269bb81def8682c01a22b17c4d6aed14292c8494f7d2ac664e547101c1a905aa977
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@isaacs/cliui@npm:^8.0.2":
|
||||
version: 8.0.2
|
||||
resolution: "@isaacs/cliui@npm:8.0.2"
|
||||
@ -636,7 +652,7 @@ __metadata:
|
||||
dependencies:
|
||||
"@janhq/core": ../../core/package.tgz
|
||||
cpx: "npm:^1.5.0"
|
||||
rimraf: "npm:^3.0.2"
|
||||
rimraf: "npm:^6.0.1"
|
||||
rolldown: "npm:1.0.0-beta.1"
|
||||
run-script-os: "npm:^1.1.6"
|
||||
ts-loader: "npm:^9.5.0"
|
||||
@ -650,7 +666,7 @@ __metadata:
|
||||
dependencies:
|
||||
"@janhq/core": ../../core/package.tgz
|
||||
cpx: "npm:^1.5.0"
|
||||
rimraf: "npm:^3.0.2"
|
||||
rimraf: "npm:^6.0.1"
|
||||
rolldown: "npm:1.0.0-beta.1"
|
||||
ts-loader: "npm:^9.5.0"
|
||||
typescript: "npm:^5.7.2"
|
||||
@ -659,64 +675,89 @@ __metadata:
|
||||
|
||||
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fassistant-extension%40workspace%3Aassistant-extension":
|
||||
version: 0.1.10
|
||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=5531aa&locator=%40janhq%2Fassistant-extension%40workspace%3Aassistant-extension"
|
||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=f2e0b5&locator=%40janhq%2Fassistant-extension%40workspace%3Aassistant-extension"
|
||||
dependencies:
|
||||
rxjs: "npm:^7.8.1"
|
||||
ulidx: "npm:^2.3.0"
|
||||
checksum: 10c0/ee7fe21267cf795dba890781d1e7807a6cb3ecb915ce9ecbd3a8386a2ebc916a8b70a775ce5d9d9f74d2ec29e20b65cea4ef6cdd0ea250a8ff2d5e6bd2237b1e
|
||||
checksum: 10c0/6f085adb6211c2d0735c2ebccf38c26b90c78a786d6d327fab3e1a9e10380a522429e19f9b9752f7c5a42eb6d80f37c7022c5146b2e4ca1fada609dccbea4194
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fconversational-extension%40workspace%3Aconversational-extension":
|
||||
version: 0.1.10
|
||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=5531aa&locator=%40janhq%2Fconversational-extension%40workspace%3Aconversational-extension"
|
||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=f2e0b5&locator=%40janhq%2Fconversational-extension%40workspace%3Aconversational-extension"
|
||||
dependencies:
|
||||
rxjs: "npm:^7.8.1"
|
||||
ulidx: "npm:^2.3.0"
|
||||
checksum: 10c0/ee7fe21267cf795dba890781d1e7807a6cb3ecb915ce9ecbd3a8386a2ebc916a8b70a775ce5d9d9f74d2ec29e20b65cea4ef6cdd0ea250a8ff2d5e6bd2237b1e
|
||||
checksum: 10c0/6f085adb6211c2d0735c2ebccf38c26b90c78a786d6d327fab3e1a9e10380a522429e19f9b9752f7c5a42eb6d80f37c7022c5146b2e4ca1fada609dccbea4194
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fdownload-extension%40workspace%3Adownload-extension":
|
||||
version: 0.1.10
|
||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=f2e0b5&locator=%40janhq%2Fdownload-extension%40workspace%3Adownload-extension"
|
||||
dependencies:
|
||||
rxjs: "npm:^7.8.1"
|
||||
ulidx: "npm:^2.3.0"
|
||||
checksum: 10c0/6f085adb6211c2d0735c2ebccf38c26b90c78a786d6d327fab3e1a9e10380a522429e19f9b9752f7c5a42eb6d80f37c7022c5146b2e4ca1fada609dccbea4194
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fengine-management-extension%40workspace%3Aengine-management-extension":
|
||||
version: 0.1.10
|
||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=5531aa&locator=%40janhq%2Fengine-management-extension%40workspace%3Aengine-management-extension"
|
||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=f2e0b5&locator=%40janhq%2Fengine-management-extension%40workspace%3Aengine-management-extension"
|
||||
dependencies:
|
||||
rxjs: "npm:^7.8.1"
|
||||
ulidx: "npm:^2.3.0"
|
||||
checksum: 10c0/ee7fe21267cf795dba890781d1e7807a6cb3ecb915ce9ecbd3a8386a2ebc916a8b70a775ce5d9d9f74d2ec29e20b65cea4ef6cdd0ea250a8ff2d5e6bd2237b1e
|
||||
checksum: 10c0/6f085adb6211c2d0735c2ebccf38c26b90c78a786d6d327fab3e1a9e10380a522429e19f9b9752f7c5a42eb6d80f37c7022c5146b2e4ca1fada609dccbea4194
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fhardware-management-extension%40workspace%3Ahardware-management-extension":
|
||||
version: 0.1.10
|
||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=5531aa&locator=%40janhq%2Fhardware-management-extension%40workspace%3Ahardware-management-extension"
|
||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=f2e0b5&locator=%40janhq%2Fhardware-management-extension%40workspace%3Ahardware-management-extension"
|
||||
dependencies:
|
||||
rxjs: "npm:^7.8.1"
|
||||
ulidx: "npm:^2.3.0"
|
||||
checksum: 10c0/ee7fe21267cf795dba890781d1e7807a6cb3ecb915ce9ecbd3a8386a2ebc916a8b70a775ce5d9d9f74d2ec29e20b65cea4ef6cdd0ea250a8ff2d5e6bd2237b1e
|
||||
checksum: 10c0/6f085adb6211c2d0735c2ebccf38c26b90c78a786d6d327fab3e1a9e10380a522429e19f9b9752f7c5a42eb6d80f37c7022c5146b2e4ca1fada609dccbea4194
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Finference-cortex-extension%40workspace%3Ainference-cortex-extension":
|
||||
version: 0.1.10
|
||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=5531aa&locator=%40janhq%2Finference-cortex-extension%40workspace%3Ainference-cortex-extension"
|
||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=f2e0b5&locator=%40janhq%2Finference-cortex-extension%40workspace%3Ainference-cortex-extension"
|
||||
dependencies:
|
||||
rxjs: "npm:^7.8.1"
|
||||
ulidx: "npm:^2.3.0"
|
||||
checksum: 10c0/ee7fe21267cf795dba890781d1e7807a6cb3ecb915ce9ecbd3a8386a2ebc916a8b70a775ce5d9d9f74d2ec29e20b65cea4ef6cdd0ea250a8ff2d5e6bd2237b1e
|
||||
checksum: 10c0/6f085adb6211c2d0735c2ebccf38c26b90c78a786d6d327fab3e1a9e10380a522429e19f9b9752f7c5a42eb6d80f37c7022c5146b2e4ca1fada609dccbea4194
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fmodel-extension%40workspace%3Amodel-extension":
|
||||
version: 0.1.10
|
||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=5531aa&locator=%40janhq%2Fmodel-extension%40workspace%3Amodel-extension"
|
||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=f2e0b5&locator=%40janhq%2Fmodel-extension%40workspace%3Amodel-extension"
|
||||
dependencies:
|
||||
rxjs: "npm:^7.8.1"
|
||||
ulidx: "npm:^2.3.0"
|
||||
checksum: 10c0/ee7fe21267cf795dba890781d1e7807a6cb3ecb915ce9ecbd3a8386a2ebc916a8b70a775ce5d9d9f74d2ec29e20b65cea4ef6cdd0ea250a8ff2d5e6bd2237b1e
|
||||
checksum: 10c0/6f085adb6211c2d0735c2ebccf38c26b90c78a786d6d327fab3e1a9e10380a522429e19f9b9752f7c5a42eb6d80f37c7022c5146b2e4ca1fada609dccbea4194
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@janhq/download-extension@workspace:download-extension":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@janhq/download-extension@workspace:download-extension"
|
||||
dependencies:
|
||||
"@janhq/core": ../../core/package.tgz
|
||||
"@tauri-apps/api": "npm:^2.5.0"
|
||||
cpx: "npm:^1.5.0"
|
||||
rimraf: "npm:^6.0.1"
|
||||
rolldown: "npm:1.0.0-beta.1"
|
||||
run-script-os: "npm:^1.1.6"
|
||||
typescript: "npm:5.8.3"
|
||||
vitest: "npm:^3.0.6"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@janhq/engine-management-extension@workspace:engine-management-extension":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@janhq/engine-management-extension@workspace:engine-management-extension"
|
||||
@ -1436,6 +1477,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@tauri-apps/api@npm:^2.5.0":
|
||||
version: 2.6.0
|
||||
resolution: "@tauri-apps/api@npm:2.6.0"
|
||||
checksum: 10c0/211353d951c7e3e5298f074ec762b5853ff0cdee261478c27db1e450fcf3d6f2c03a616483abbf9dfc79f13c6dfcfa7db0b790c1384c113951c0d694809f05ef
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@tybys/wasm-util@npm:^0.9.0":
|
||||
version: 0.9.0
|
||||
resolution: "@tybys/wasm-util@npm:0.9.0"
|
||||
@ -2587,7 +2635,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.3":
|
||||
"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6":
|
||||
version: 7.0.6
|
||||
resolution: "cross-spawn@npm:7.0.6"
|
||||
dependencies:
|
||||
@ -3392,6 +3440,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"foreground-child@npm:^3.3.1":
|
||||
version: 3.3.1
|
||||
resolution: "foreground-child@npm:3.3.1"
|
||||
dependencies:
|
||||
cross-spawn: "npm:^7.0.6"
|
||||
signal-exit: "npm:^4.0.1"
|
||||
checksum: 10c0/8986e4af2430896e65bc2788d6679067294d6aee9545daefc84923a0a4b399ad9c7a3ea7bd8c0b2b80fdf4a92de4c69df3f628233ff3224260e9c1541a9e9ed3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"fragment-cache@npm:^0.2.1":
|
||||
version: 0.2.1
|
||||
resolution: "fragment-cache@npm:0.2.1"
|
||||
@ -3583,6 +3641,22 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"glob@npm:^11.0.0":
|
||||
version: 11.0.3
|
||||
resolution: "glob@npm:11.0.3"
|
||||
dependencies:
|
||||
foreground-child: "npm:^3.3.1"
|
||||
jackspeak: "npm:^4.1.1"
|
||||
minimatch: "npm:^10.0.3"
|
||||
minipass: "npm:^7.1.2"
|
||||
package-json-from-dist: "npm:^1.0.0"
|
||||
path-scurry: "npm:^2.0.0"
|
||||
bin:
|
||||
glob: dist/esm/bin.mjs
|
||||
checksum: 10c0/7d24457549ec2903920dfa3d8e76850e7c02aa709122f0164b240c712f5455c0b457e6f2a1eee39344c6148e39895be8094ae8cfef7ccc3296ed30bce250c661
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"glob@npm:^7.0.5, glob@npm:^7.1.3, glob@npm:^7.1.4":
|
||||
version: 7.2.3
|
||||
resolution: "glob@npm:7.2.3"
|
||||
@ -4205,6 +4279,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jackspeak@npm:^4.1.1":
|
||||
version: 4.1.1
|
||||
resolution: "jackspeak@npm:4.1.1"
|
||||
dependencies:
|
||||
"@isaacs/cliui": "npm:^8.0.2"
|
||||
checksum: 10c0/84ec4f8e21d6514db24737d9caf65361511f75e5e424980eebca4199f400874f45e562ac20fa8aeb1dd20ca2f3f81f0788b6e9c3e64d216a5794fd6f30e0e042
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jake@npm:^10.8.5":
|
||||
version: 10.9.2
|
||||
resolution: "jake@npm:10.9.2"
|
||||
@ -4829,6 +4912,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lru-cache@npm:^11.0.0":
|
||||
version: 11.1.0
|
||||
resolution: "lru-cache@npm:11.1.0"
|
||||
checksum: 10c0/85c312f7113f65fae6a62de7985348649937eb34fb3d212811acbf6704dc322a421788aca253b62838f1f07049a84cc513d88f494e373d3756514ad263670a64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lru-cache@npm:^5.1.1":
|
||||
version: 5.1.1
|
||||
resolution: "lru-cache@npm:5.1.1"
|
||||
@ -5028,6 +5118,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"minimatch@npm:^10.0.3":
|
||||
version: 10.0.3
|
||||
resolution: "minimatch@npm:10.0.3"
|
||||
dependencies:
|
||||
"@isaacs/brace-expansion": "npm:^5.0.0"
|
||||
checksum: 10c0/e43e4a905c5d70ac4cec8530ceaeccb9c544b1ba8ac45238e2a78121a01c17ff0c373346472d221872563204eabe929ad02669bb575cb1f0cc30facab369f70f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"minimatch@npm:^3.0.2, minimatch@npm:^3.0.4, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2":
|
||||
version: 3.1.2
|
||||
resolution: "minimatch@npm:3.1.2"
|
||||
@ -5574,6 +5673,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"path-scurry@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "path-scurry@npm:2.0.0"
|
||||
dependencies:
|
||||
lru-cache: "npm:^11.0.0"
|
||||
minipass: "npm:^7.1.2"
|
||||
checksum: 10c0/3da4adedaa8e7ef8d6dc4f35a0ff8f05a9b4d8365f2b28047752b62d4c1ad73eec21e37b1579ef2d075920157856a3b52ae8309c480a6f1a8bbe06ff8e52b33c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"path-type@npm:^1.0.0":
|
||||
version: 1.1.0
|
||||
resolution: "path-type@npm:1.1.0"
|
||||
@ -5987,6 +6096,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"rimraf@npm:^6.0.1":
|
||||
version: 6.0.1
|
||||
resolution: "rimraf@npm:6.0.1"
|
||||
dependencies:
|
||||
glob: "npm:^11.0.0"
|
||||
package-json-from-dist: "npm:^1.0.0"
|
||||
bin:
|
||||
rimraf: dist/esm/bin.mjs
|
||||
checksum: 10c0/b30b6b072771f0d1e73b4ca5f37bb2944ee09375be9db5f558fcd3310000d29dfcfa93cf7734d75295ad5a7486dc8e40f63089ced1722a664539ffc0c3ece8c6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"rolldown@npm:1.0.0-beta.1":
|
||||
version: 1.0.0-beta.1
|
||||
resolution: "rolldown@npm:1.0.0-beta.1"
|
||||
@ -6979,6 +7100,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"typescript@npm:5.8.3":
|
||||
version: 5.8.3
|
||||
resolution: "typescript@npm:5.8.3"
|
||||
bin:
|
||||
tsc: bin/tsc
|
||||
tsserver: bin/tsserver
|
||||
checksum: 10c0/5f8bb01196e542e64d44db3d16ee0e4063ce4f3e3966df6005f2588e86d91c03e1fb131c2581baf0fb65ee79669eea6e161cd448178986587e9f6844446dbb48
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"typescript@npm:^5.3.3, typescript@npm:^5.7.2":
|
||||
version: 5.7.2
|
||||
resolution: "typescript@npm:5.7.2"
|
||||
@ -6999,6 +7130,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"typescript@patch:typescript@npm%3A5.8.3#optional!builtin<compat/typescript>":
|
||||
version: 5.8.3
|
||||
resolution: "typescript@patch:typescript@npm%3A5.8.3#optional!builtin<compat/typescript>::version=5.8.3&hash=5786d5"
|
||||
bin:
|
||||
tsc: bin/tsc
|
||||
tsserver: bin/tsserver
|
||||
checksum: 10c0/39117e346ff8ebd87ae1510b3a77d5d92dae5a89bde588c747d25da5c146603a99c8ee588c7ef80faaf123d89ed46f6dbd918d534d641083177d5fac38b8a1cb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"typescript@patch:typescript@npm%3A^5.3.3#optional!builtin<compat/typescript>, typescript@patch:typescript@npm%3A^5.7.2#optional!builtin<compat/typescript>":
|
||||
version: 5.7.2
|
||||
resolution: "typescript@patch:typescript@npm%3A5.7.2#optional!builtin<compat/typescript>::version=5.7.2&hash=5786d5"
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
module.exports = {
|
||||
projects: ['<rootDir>/core', '<rootDir>/web', '<rootDir>/joi'],
|
||||
projects: ['<rootDir>/core'],
|
||||
}
|
||||
|
||||
@ -164,6 +164,7 @@ elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||
rm -rf ./src-tauri/target 2>/dev/null || true
|
||||
rm -rf ~/jan/extensions 2>/dev/null || true
|
||||
rm -rf "~/.cache/jan*" 2>/dev/null || true
|
||||
rm -rf "./.cache" 2>/dev/null || true
|
||||
else
|
||||
# macOS cleanup (matches Makefile)
|
||||
find . -name "node_modules" -type d -prune -exec rm -rf '{}' + 2>/dev/null || true
|
||||
|
||||
19
package.json
19
package.json
@ -12,8 +12,11 @@
|
||||
"lint": "yarn workspace @janhq/web-app lint",
|
||||
"dev": "yarn dev:tauri",
|
||||
"build": "yarn build:web && yarn build:tauri",
|
||||
"test": "yarn workspace @janhq/web-app test",
|
||||
"test:coverage": "yarn workspace @janhq/web-app test",
|
||||
"test": "jest && yarn workspace @janhq/web-app test",
|
||||
"test:coverage": "yarn test:coverage:jest && yarn test:coverage:vitest && yarn merge:coverage",
|
||||
"test:coverage:jest": "jest --coverage --coverageDirectory=coverage/jest",
|
||||
"test:coverage:vitest": "yarn workspace @janhq/web-app test:coverage",
|
||||
"merge:coverage": "node scripts/merge-coverage.js",
|
||||
"test:prepare": "yarn build:icon && yarn copy:lib && yarn copy:assets:tauri && yarn build --no-bundle ",
|
||||
"test:e2e:linux": "yarn test:prepare && xvfb-run yarn workspace tests-e2-js test",
|
||||
"test:e2e:win32": "yarn test:prepare && yarn workspace tests-e2-js test",
|
||||
@ -30,9 +33,10 @@
|
||||
"copy:lib:win32": "cpx \"./lib/windows/*.dll\" \"./src-tauri/resources/lib/\"",
|
||||
"copy:lib:darwin": "mkdir -p \"./src-tauri/resources/lib/\"",
|
||||
"download:bin": "node ./scripts/download-bin.mjs",
|
||||
"build:tauri:linux:win32": "yarn download:bin && yarn install:cortex && yarn build:icon && yarn copy:assets:tauri && yarn tauri build",
|
||||
"build:tauri:darwin": "yarn install:cortex && yarn build:icon && yarn copy:assets:tauri && yarn tauri build --target universal-apple-darwin",
|
||||
"build:tauri": "run-script-os",
|
||||
"build:tauri:win32": "yarn download:bin && yarn tauri build",
|
||||
"build:tauri:linux": "yarn download:bin && ./src-tauri/build-utils/shim-linuxdeploy.sh yarn tauri build && ./src-tauri/build-utils/buildAppImage.sh",
|
||||
"build:tauri:darwin": "yarn tauri build --target universal-apple-darwin",
|
||||
"build:tauri": "yarn install:cortex && yarn build:icon && yarn copy:assets:tauri && run-script-os",
|
||||
"build:icon": "tauri icon ./src-tauri/icons/icon.png",
|
||||
"build:core": "cd core && yarn build && yarn pack",
|
||||
"build:web": "yarn workspace @janhq/web-app build",
|
||||
@ -45,8 +49,13 @@
|
||||
"cpx": "^1.5.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"husky": "^9.1.5",
|
||||
"istanbul-api": "^3.0.0",
|
||||
"istanbul-lib-coverage": "^3.2.2",
|
||||
"istanbul-lib-report": "^3.0.1",
|
||||
"istanbul-reports": "^3.1.7",
|
||||
"jest": "^30.0.3",
|
||||
"jest-environment-jsdom": "^29.7.0",
|
||||
"nyc": "^17.1.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"run-script-os": "^1.1.6",
|
||||
"tar": "^4.4.19",
|
||||
|
||||
145
scripts/merge-coverage.js
Normal file
145
scripts/merge-coverage.js
Normal file
@ -0,0 +1,145 @@
|
||||
const { createCoverageMap } = require('istanbul-lib-coverage')
|
||||
const { createReporter } = require('istanbul-api')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
const coverageDir = path.join(__dirname, '../coverage')
|
||||
const jestCoverage = path.join(coverageDir, 'jest/coverage-final.json')
|
||||
const vitestCoverage = path.join(coverageDir, 'vitest/coverage-final.json')
|
||||
const mergedDir = path.join(coverageDir, 'merged')
|
||||
|
||||
function normalizePath(filePath, workspace) {
|
||||
if (workspace === 'jest') {
|
||||
return `[CORE] ${filePath}`
|
||||
} else if (workspace === 'vitest') {
|
||||
return `[WEB-APP] ${filePath}`
|
||||
}
|
||||
return filePath
|
||||
}
|
||||
|
||||
async function mergeCoverage() {
|
||||
const map = createCoverageMap({})
|
||||
|
||||
console.log('🔍 Checking coverage files...')
|
||||
console.log('Jest coverage path:', jestCoverage)
|
||||
console.log('Vitest coverage path:', vitestCoverage)
|
||||
console.log('Jest file exists:', fs.existsSync(jestCoverage))
|
||||
console.log('Vitest file exists:', fs.existsSync(vitestCoverage))
|
||||
|
||||
// Load Jest coverage (core workspace)
|
||||
if (fs.existsSync(jestCoverage)) {
|
||||
const jestData = JSON.parse(fs.readFileSync(jestCoverage, 'utf8'))
|
||||
console.log('Jest data keys:', Object.keys(jestData).length)
|
||||
map.merge(jestData)
|
||||
console.log('✓ Merged Jest coverage (core workspace)')
|
||||
} else {
|
||||
console.log('❌ Jest coverage file not found')
|
||||
}
|
||||
|
||||
// Load Vitest coverage (web-app workspace)
|
||||
if (fs.existsSync(vitestCoverage)) {
|
||||
const vitestData = JSON.parse(fs.readFileSync(vitestCoverage, 'utf8'))
|
||||
console.log('Vitest data keys:', Object.keys(vitestData).length)
|
||||
map.merge(vitestData)
|
||||
console.log('✓ Merged Vitest coverage (web-app workspace)')
|
||||
} else {
|
||||
console.log('❌ Vitest coverage file not found')
|
||||
}
|
||||
|
||||
console.log('📊 Total files in coverage map:', map.files().length)
|
||||
|
||||
// Create merged directory
|
||||
if (!fs.existsSync(mergedDir)) {
|
||||
fs.mkdirSync(mergedDir, { recursive: true })
|
||||
console.log('✓ Created merged directory')
|
||||
}
|
||||
|
||||
try {
|
||||
console.log('🔄 Generating reports...')
|
||||
|
||||
const context = require('istanbul-lib-report').createContext({
|
||||
dir: mergedDir,
|
||||
coverageMap: map,
|
||||
})
|
||||
|
||||
const htmlReporter = require('istanbul-reports').create('html')
|
||||
const lcovReporter = require('istanbul-reports').create('lcov')
|
||||
const textReporter = require('istanbul-reports').create('text')
|
||||
|
||||
// Generate reports
|
||||
htmlReporter.execute(context)
|
||||
lcovReporter.execute(context)
|
||||
textReporter.execute(context)
|
||||
|
||||
console.log('\n📊 Coverage reports merged successfully!')
|
||||
console.log('📁 HTML report: coverage/merged/index.html')
|
||||
console.log('📁 LCOV report: coverage/merged/lcov.info')
|
||||
|
||||
// Check if files were created
|
||||
if (fs.existsSync(mergedDir)) {
|
||||
const mergedFiles = fs.readdirSync(mergedDir)
|
||||
console.log('📁 Files in merged directory:', mergedFiles)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Error generating reports:', error.message)
|
||||
console.error('Stack trace:', error.stack)
|
||||
throw error
|
||||
}
|
||||
|
||||
// Generate separate reports for each workspace
|
||||
await generateWorkspaceReports()
|
||||
}
|
||||
|
||||
async function generateWorkspaceReports() {
|
||||
// Generate separate core report
|
||||
if (fs.existsSync(jestCoverage)) {
|
||||
const coreMap = createCoverageMap({})
|
||||
const jestData = JSON.parse(fs.readFileSync(jestCoverage, 'utf8'))
|
||||
coreMap.merge(jestData)
|
||||
|
||||
const coreDir = path.join(coverageDir, 'core-only')
|
||||
if (!fs.existsSync(coreDir)) {
|
||||
fs.mkdirSync(coreDir, { recursive: true })
|
||||
}
|
||||
|
||||
const coreContext = require('istanbul-lib-report').createContext({
|
||||
dir: coreDir,
|
||||
coverageMap: coreMap,
|
||||
})
|
||||
|
||||
const htmlReporter = require('istanbul-reports').create('html')
|
||||
const textSummaryReporter =
|
||||
require('istanbul-reports').create('text-summary')
|
||||
|
||||
htmlReporter.execute(coreContext)
|
||||
textSummaryReporter.execute(coreContext)
|
||||
console.log('📁 Core-only report: coverage/core-only/index.html')
|
||||
}
|
||||
|
||||
// Generate separate web-app report
|
||||
if (fs.existsSync(vitestCoverage)) {
|
||||
const webAppMap = createCoverageMap({})
|
||||
const vitestData = JSON.parse(fs.readFileSync(vitestCoverage, 'utf8'))
|
||||
webAppMap.merge(vitestData)
|
||||
|
||||
const webAppDir = path.join(coverageDir, 'web-app-only')
|
||||
if (!fs.existsSync(webAppDir)) {
|
||||
fs.mkdirSync(webAppDir, { recursive: true })
|
||||
}
|
||||
|
||||
const webAppContext = require('istanbul-lib-report').createContext({
|
||||
dir: webAppDir,
|
||||
coverageMap: webAppMap,
|
||||
})
|
||||
|
||||
const htmlReporter = require('istanbul-reports').create('html')
|
||||
const textSummaryReporter =
|
||||
require('istanbul-reports').create('text-summary')
|
||||
|
||||
htmlReporter.execute(webAppContext)
|
||||
textSummaryReporter.execute(webAppContext)
|
||||
console.log('📁 Web-app-only report: coverage/web-app-only/index.html')
|
||||
}
|
||||
}
|
||||
|
||||
mergeCoverage().catch(console.error)
|
||||
33
src-tauri/build-utils/buildAppImage.sh
Executable file
33
src-tauri/build-utils/buildAppImage.sh
Executable file
@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
APPIMAGETOOL="./.cache/build-tools/appimagetool"
|
||||
RELEASE_CHANNEL=${RELEASE_CHANNEL:-"stable"}
|
||||
|
||||
# pull in AppImageTool if it's not pre cached
|
||||
mkdir -p ./.cache/build-tools
|
||||
if [ ! -f "${APPIMAGETOOL}" ]; then
|
||||
wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O "${APPIMAGETOOL}"
|
||||
chmod +x "${APPIMAGETOOL}"
|
||||
fi
|
||||
|
||||
if [ "${RELEASE_CHANNEL}" != "stable" ]; then
|
||||
APP_DIR=./src-tauri/target/release/bundle/appimage/Jan-${RELEASE_CHANNEL}.AppDir
|
||||
LIB_DIR=$APP_DIR/usr/lib/Jan-${RELEASE_CHANNEL}/binaries
|
||||
else
|
||||
APP_DIR=./src-tauri/target/release/bundle/appimage/Jan.AppDir
|
||||
LIB_DIR=$APP_DIR/usr/lib/Jan/binaries
|
||||
fi
|
||||
|
||||
# bundle additional resources in the AppDir without pulling in their dependencies
|
||||
cp ./src-tauri/resources/bin/bun $APP_DIR/usr/bin/bun
|
||||
mkdir -p $LIB_DIR/engines
|
||||
cp -f ./src-tauri/binaries/deps/*.so* $LIB_DIR/
|
||||
cp -f ./src-tauri/binaries/*.so* $LIB_DIR/
|
||||
cp -rf ./src-tauri/binaries/engines $LIB_DIR/
|
||||
|
||||
# remove appimage generated by tauri build
|
||||
APP_IMAGE=./src-tauri/target/release/bundle/appimage/$(ls ./src-tauri/target/release/bundle/appimage/ | grep AppImage | head -1)
|
||||
echo $APP_IMAGE
|
||||
rm -f $APP_IMAGE
|
||||
|
||||
# repackage appimage with additional resources
|
||||
"${APPIMAGETOOL}" $APP_DIR $APP_IMAGE
|
||||
30
src-tauri/build-utils/shim-linuxdeploy.sh
Executable file
30
src-tauri/build-utils/shim-linuxdeploy.sh
Executable file
@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# wrapper script to pin linuxdeploy version and inject environment variables into the
|
||||
# build process. While yarn supports injecting environment vairables via env files,
|
||||
# this applies to all yarn scripts. Using a wrapper allows granular control over
|
||||
# when environment variables are injected, and avoids tainting the system .cache
|
||||
|
||||
# avoid redownloading corepack if possible
|
||||
export COREPACK_HOME=${COREPACK_HOME:-${XDG_CACHE_HOME:-$HOME/.cache}/node/corepack}
|
||||
# move cache home to <project root>/.cache
|
||||
export XDG_CACHE_HOME=${PWD}/.cache
|
||||
|
||||
LINUXDEPLOY_VER="1-alpha-20250213-2"
|
||||
LINUXDEPLOY="$XDG_CACHE_HOME/tauri/linuxdeploy-$LINUXDEPLOY_VER-x86_64.AppImage"
|
||||
SYMLINK="$XDG_CACHE_HOME/tauri/linuxdeploy-x86_64.AppImage"
|
||||
|
||||
mkdir -p "$XDG_CACHE_HOME/tauri"
|
||||
|
||||
if [ ! -f "$LINUXDEPLOY" ]; then
|
||||
GLOB_PATTERN="$XDG_CACHE_HOME/tauri/linuxdeploy-*-x86_64.AppImage"
|
||||
rm -f $GLOB_PATTERN
|
||||
wget "https://github.com/linuxdeploy/linuxdeploy/releases/download/$LINUXDEPLOY_VER/linuxdeploy-x86_64.AppImage" -O "$LINUXDEPLOY"
|
||||
chmod a+x "$LINUXDEPLOY"
|
||||
fi
|
||||
|
||||
rm -f "$SYMLINK"
|
||||
ln -s "$LINUXDEPLOY" "$SYMLINK"
|
||||
|
||||
"$@"
|
||||
@ -76,7 +76,6 @@
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"targets": ["nsis", "app", "dmg", "deb", "appimage"],
|
||||
"createUpdaterArtifacts": false,
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
@ -84,32 +83,6 @@
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"resources": [
|
||||
"resources/pre-install/**/*",
|
||||
"resources/lib/",
|
||||
"binaries/**/*"
|
||||
],
|
||||
"externalBin": [
|
||||
"binaries/cortex-server",
|
||||
"resources/bin/bun",
|
||||
"resources/bin/uv"
|
||||
],
|
||||
"linux": {
|
||||
"appimage": {
|
||||
"bundleMediaFramework": false,
|
||||
"files": {}
|
||||
},
|
||||
"deb": {
|
||||
"files": {
|
||||
"usr/bin/bun": "resources/bin/bun",
|
||||
"usr/lib/Jan/binaries": "binaries/deps",
|
||||
"usr/lib/Jan/binaries/engines": "binaries/engines"
|
||||
}
|
||||
}
|
||||
},
|
||||
"windows": {
|
||||
"signCommand": "powershell -ExecutionPolicy Bypass -File ./sign.ps1 %1"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
26
src-tauri/tauri.linux.conf.json
Normal file
26
src-tauri/tauri.linux.conf.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"bundle": {
|
||||
"targets": ["deb", "appimage"],
|
||||
"resources": [
|
||||
"resources/pre-install/**/*"
|
||||
],
|
||||
"externalBin": [
|
||||
"binaries/cortex-server",
|
||||
"resources/bin/uv"
|
||||
],
|
||||
"linux": {
|
||||
"appimage": {
|
||||
"bundleMediaFramework": false,
|
||||
"files": {}
|
||||
},
|
||||
"deb": {
|
||||
"files": {
|
||||
"usr/bin/bun": "resources/bin/bun",
|
||||
"usr/lib/Jan/binaries": "binaries/deps",
|
||||
"usr/lib/Jan/binaries/engines": "binaries/engines",
|
||||
"usr/lib/Jan/binaries/libvulkan.so": "binaries/libvulkan.so"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
15
src-tauri/tauri.macos.conf.json
Normal file
15
src-tauri/tauri.macos.conf.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"bundle": {
|
||||
"targets": ["app", "dmg"],
|
||||
"resources": [
|
||||
"resources/pre-install/**/*",
|
||||
"resources/lib/",
|
||||
"binaries/**/*"
|
||||
],
|
||||
"externalBin": [
|
||||
"binaries/cortex-server",
|
||||
"resources/bin/bun",
|
||||
"resources/bin/uv"
|
||||
]
|
||||
}
|
||||
}
|
||||
18
src-tauri/tauri.windows.conf.json
Normal file
18
src-tauri/tauri.windows.conf.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"bundle": {
|
||||
"targets": ["nsis"],
|
||||
"resources": [
|
||||
"resources/pre-install/**/*",
|
||||
"resources/lib/",
|
||||
"binaries/**/*"
|
||||
],
|
||||
"externalBin": [
|
||||
"binaries/cortex-server",
|
||||
"resources/bin/bun",
|
||||
"resources/bin/uv"
|
||||
],
|
||||
"windows": {
|
||||
"signCommand": "powershell -ExecutionPolicy Bypass -File ./sign.ps1 %1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8,7 +8,8 @@
|
||||
"build": "tsc -b && vite build",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview",
|
||||
"test": "vitest"
|
||||
"test": "vitest --run",
|
||||
"test:coverage": "vitest --coverage --run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
@ -45,6 +46,7 @@
|
||||
"fzf": "^0.5.2",
|
||||
"i18next": "^25.0.1",
|
||||
"katex": "^0.16.22",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"lucide-react": "^0.522.0",
|
||||
"motion": "^12.10.5",
|
||||
@ -77,16 +79,24 @@
|
||||
"@eslint/js": "^9.22.0",
|
||||
"@tanstack/router-plugin": "^1.116.1",
|
||||
"@types/culori": "^2.1.1",
|
||||
"@types/istanbul-lib-report": "^3",
|
||||
"@types/istanbul-reports": "^3",
|
||||
"@types/lodash.clonedeep": "^4",
|
||||
"@types/lodash.debounce": "^4",
|
||||
"@types/node": "^22.14.1",
|
||||
"@types/react": "^19.0.10",
|
||||
"@types/react-dom": "^19.0.4",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"@vitest/coverage-v8": "3.2.4",
|
||||
"clsx": "^2.1.1",
|
||||
"eslint": "^9.22.0",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.19",
|
||||
"globals": "^16.0.0",
|
||||
"istanbul-api": "^3.0.0",
|
||||
"istanbul-lib-coverage": "^3.2.2",
|
||||
"istanbul-lib-report": "^3.0.1",
|
||||
"istanbul-reports": "^3.1.7",
|
||||
"tailwind-merge": "^3.2.0",
|
||||
"typescript": "~5.8.3",
|
||||
"typescript-eslint": "^8.26.1",
|
||||
|
||||
@ -14,6 +14,7 @@ const LANGUAGES = [
|
||||
{ value: 'vn', label: 'Tiếng Việt' },
|
||||
{ value: 'zh-CN', label: '简体中文' },
|
||||
{ value: 'zh-TW', label: '繁體中文' },
|
||||
{ value: 'de-DE', label: 'Deutsch' },
|
||||
]
|
||||
|
||||
export default function LanguageSwitcher() {
|
||||
|
||||
@ -12,27 +12,30 @@ interface Props {
|
||||
// Zustand store for thinking block state
|
||||
type ThinkingBlockState = {
|
||||
thinkingState: { [id: string]: boolean }
|
||||
toggleState: (id: string) => void
|
||||
setThinkingState: (id: string, expanded: boolean) => void
|
||||
}
|
||||
|
||||
const useThinkingStore = create<ThinkingBlockState>((set) => ({
|
||||
thinkingState: {},
|
||||
toggleState: (id) =>
|
||||
setThinkingState: (id, expanded) =>
|
||||
set((state) => ({
|
||||
thinkingState: {
|
||||
...state.thinkingState,
|
||||
[id]: !state.thinkingState[id],
|
||||
[id]: expanded,
|
||||
},
|
||||
})),
|
||||
}))
|
||||
|
||||
const ThinkingBlock = ({ id, text }: Props) => {
|
||||
const { thinkingState, toggleState } = useThinkingStore()
|
||||
const { thinkingState, setThinkingState } = useThinkingStore()
|
||||
const { streamingContent } = useAppState()
|
||||
const { t } = useTranslation()
|
||||
const loading = !text.includes('</think>') && streamingContent
|
||||
const isExpanded = thinkingState[id] ?? false
|
||||
const handleClick = () => toggleState(id)
|
||||
const isExpanded = thinkingState[id] ?? (loading ? true : false)
|
||||
const handleClick = () => {
|
||||
const newExpandedState = !isExpanded
|
||||
setThinkingState(id, newExpandedState)
|
||||
}
|
||||
|
||||
if (!text.replace(/<\/?think>/g, '').trim()) return null
|
||||
|
||||
|
||||
@ -26,7 +26,6 @@ import {
|
||||
} from '@/components/ui/dialog'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Textarea } from '@/components/ui/textarea'
|
||||
import { toast } from 'sonner'
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
@ -75,6 +74,69 @@ const CopyButton = ({ text }: { text: string }) => {
|
||||
)
|
||||
}
|
||||
|
||||
const EditDialog = ({
|
||||
message,
|
||||
setMessage,
|
||||
}: {
|
||||
message: string
|
||||
setMessage: (message: string) => void
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const [draft, setDraft] = useState(message)
|
||||
|
||||
const handleSave = () => {
|
||||
if (draft !== message) {
|
||||
setMessage(draft)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog>
|
||||
<DialogTrigger>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<div className="flex outline-0 items-center gap-1 hover:text-accent transition-colors cursor-pointer group relative">
|
||||
<IconPencil size={16} />
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{t('edit')}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="w-3/4 h-3/4">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{t('common:dialogs.editMessage.title')}</DialogTitle>
|
||||
<Textarea
|
||||
value={draft}
|
||||
onChange={(e) => setDraft(e.target.value)}
|
||||
className="mt-2 resize-none h-full w-full"
|
||||
onKeyDown={(e) => {
|
||||
// Prevent key from being captured by parent components
|
||||
e.stopPropagation()
|
||||
}}
|
||||
/>
|
||||
<DialogFooter className="mt-2 flex items-center">
|
||||
<DialogClose asChild>
|
||||
<Button variant="link" size="sm" className="hover:no-underline">
|
||||
Cancel
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<DialogClose asChild>
|
||||
<Button
|
||||
disabled={draft === message || !draft}
|
||||
onClick={handleSave}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</DialogClose>
|
||||
</DialogFooter>
|
||||
</DialogHeader>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
// Use memo to prevent unnecessary re-renders, but allow re-renders when props change
|
||||
export const ThreadContent = memo(
|
||||
(
|
||||
@ -85,9 +147,9 @@ export const ThreadContent = memo(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
streamTools?: any
|
||||
contextOverflowModal?: React.ReactNode | null
|
||||
updateMessage?: (item: ThreadMessage, message: string) => void
|
||||
}
|
||||
) => {
|
||||
const [message, setMessage] = useState(item.content?.[0]?.text?.value || '')
|
||||
const { t } = useTranslation()
|
||||
|
||||
// Use useMemo to stabilize the components prop
|
||||
@ -166,23 +228,6 @@ export const ThreadContent = memo(
|
||||
}
|
||||
}, [deleteMessage, getMessages, item])
|
||||
|
||||
const editMessage = useCallback(
|
||||
(messageId: string) => {
|
||||
const threadMessages = getMessages(item.thread_id)
|
||||
|
||||
const index = threadMessages.findIndex((msg) => msg.id === messageId)
|
||||
if (index === -1) return
|
||||
|
||||
// Delete all messages after the edited message
|
||||
for (let i = threadMessages.length - 1; i >= index; i--) {
|
||||
deleteMessage(threadMessages[i].thread_id, threadMessages[i].id)
|
||||
}
|
||||
|
||||
sendMessage(message)
|
||||
},
|
||||
[deleteMessage, getMessages, item.thread_id, message, sendMessage]
|
||||
)
|
||||
|
||||
const isToolCalls =
|
||||
item.metadata &&
|
||||
'tool_calls' in item.metadata &&
|
||||
@ -209,61 +254,14 @@ export const ThreadContent = memo(
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-end gap-2 text-main-view-fg/60 text-xs mt-2">
|
||||
<Dialog>
|
||||
<DialogTrigger>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<div className="flex outline-0 items-center gap-1 hover:text-accent transition-colors cursor-pointer group relative">
|
||||
<IconPencil size={16} />
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{t('edit')}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{t('common:dialogs.editMessage.title')}</DialogTitle>
|
||||
<Textarea
|
||||
value={message}
|
||||
onChange={(e) => {
|
||||
setMessage(e.target.value)
|
||||
}}
|
||||
className="mt-2 resize-none"
|
||||
onKeyDown={(e) => {
|
||||
// Prevent key from being captured by parent components
|
||||
e.stopPropagation()
|
||||
}}
|
||||
/>
|
||||
<DialogFooter className="mt-2 flex items-center">
|
||||
<DialogClose asChild>
|
||||
<Button
|
||||
variant="link"
|
||||
size="sm"
|
||||
className="hover:no-underline"
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<DialogClose asChild>
|
||||
<Button
|
||||
disabled={!message}
|
||||
onClick={() => {
|
||||
editMessage(item.id)
|
||||
toast.success(t('common:toast.editMessage.title'), {
|
||||
id: 'edit-message',
|
||||
description: t('common:toast.editMessage.description'),
|
||||
})
|
||||
}}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</DialogClose>
|
||||
</DialogFooter>
|
||||
</DialogHeader>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
<EditDialog
|
||||
message={item.content?.[0]?.text.value}
|
||||
setMessage={(message) => {
|
||||
if (item.updateMessage) {
|
||||
item.updateMessage(item, message)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<button
|
||||
@ -360,6 +358,12 @@ export const ThreadContent = memo(
|
||||
'hidden'
|
||||
)}
|
||||
>
|
||||
<EditDialog
|
||||
message={item.content?.[0]?.text.value}
|
||||
setMessage={(message) =>
|
||||
item.updateMessage && item.updateMessage(item, message)
|
||||
}
|
||||
/>
|
||||
<CopyButton text={item.content?.[0]?.text.value || ''} />
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
@ -391,7 +395,9 @@ export const ThreadContent = memo(
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{t('common:dialogs.messageMetadata.title')}</DialogTitle>
|
||||
<DialogTitle>
|
||||
{t('common:dialogs.messageMetadata.title')}
|
||||
</DialogTitle>
|
||||
<div className="space-y-2">
|
||||
<div className="border border-main-view-fg/10 rounded-md overflow-hidden">
|
||||
<CodeEditor
|
||||
|
||||
@ -138,6 +138,14 @@ export const sendCompletion = async (
|
||||
baseURL: provider.base_url,
|
||||
// Use Tauri's fetch to avoid CORS issues only for openai-compatible provider
|
||||
...(providerName === 'openai-compatible' && { fetch: fetchTauri }),
|
||||
// OpenRouter identification headers for Jan
|
||||
// ref: https://openrouter.ai/docs/api-reference/overview#headers
|
||||
...(provider.provider === 'openrouter' && {
|
||||
defaultHeaders: {
|
||||
'HTTP-Referer': 'https://jan.ai',
|
||||
'X-Title': 'Jan',
|
||||
},
|
||||
}),
|
||||
} as ExtendedConfigOptions)
|
||||
if (
|
||||
thread.model.id &&
|
||||
@ -286,10 +294,10 @@ export const extractToolCall = (
|
||||
* @param calls
|
||||
* @param builder
|
||||
* @param message
|
||||
* @param content
|
||||
* @param approvedTools - Record of approved tools per thread
|
||||
* @param showModal - Function to show approval modal, returns true if approved
|
||||
* @param allowAllMCPPermissions - Global setting to allow all MCP permissions without modal
|
||||
* @param abortController
|
||||
* @param approvedTools
|
||||
* @param showModal
|
||||
* @param allowAllMCPPermissions
|
||||
*/
|
||||
export const postMessageProcessing = async (
|
||||
calls: ChatCompletionMessageToolCall[],
|
||||
|
||||
32
web-app/src/locales/de-DE/assistants.json
Normal file
32
web-app/src/locales/de-DE/assistants.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"title": "Assistenten",
|
||||
"editAssistant": "Assistent bearbeiten",
|
||||
"deleteAssistant": "Assistenten löschen",
|
||||
"deleteConfirmation": "Assistenten löschen",
|
||||
"deleteConfirmationDesc": "Bist Du sicher, daß Du diesen Assistenten löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.",
|
||||
"cancel": "Abbrechen",
|
||||
"delete": "Löschen",
|
||||
"addAssistant": "Assistenten hinzufügen",
|
||||
"emoji": "Emoji",
|
||||
"name": "Name",
|
||||
"enterName": "Namen eingeben",
|
||||
"description": "Beschreibung (optional)",
|
||||
"enterDescription": "Beschreibung eingeben",
|
||||
"instructions": "Anweisungen",
|
||||
"enterInstructions": "Anweisungen eingeben",
|
||||
"predefinedParameters": "Vordefinierte Parameter",
|
||||
"parameters": "Parameter",
|
||||
"key": "Schlüssel",
|
||||
"value": "Wert",
|
||||
"stringValue": "String",
|
||||
"numberValue": "Number",
|
||||
"booleanValue": "Boolean",
|
||||
"jsonValue": "JSON",
|
||||
"trueValue": "True",
|
||||
"falseValue": "False",
|
||||
"jsonValuePlaceholder": "JSON Value",
|
||||
"save": "Speichern",
|
||||
"createNew": "Neuen Assistenten anlegen",
|
||||
"personality": "Persönlichkeit",
|
||||
"capabilities": "Fähigkeiten"
|
||||
}
|
||||
10
web-app/src/locales/de-DE/chat.json
Normal file
10
web-app/src/locales/de-DE/chat.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"welcome": "Hi, wie geht es Dir?",
|
||||
"description": "Wie kann ich Dir heute helfen?",
|
||||
"status": {
|
||||
"empty": "Keine Chats gefunden"
|
||||
},
|
||||
"sendMessage": "Nachricht senden",
|
||||
"newConversation": "Neue Konversation",
|
||||
"clearHistory": "Verlauf löschen"
|
||||
}
|
||||
267
web-app/src/locales/de-DE/common.json
Normal file
267
web-app/src/locales/de-DE/common.json
Normal file
@ -0,0 +1,267 @@
|
||||
{
|
||||
"assistants": "Assistenten",
|
||||
"hardware": "Hardware",
|
||||
"mcp-servers": "Mcp Server",
|
||||
"local_api_server": "Lokaler API Server",
|
||||
"https_proxy": "HTTPS Proxy",
|
||||
"extensions": "Erweiterungen",
|
||||
"general": "Allgemein",
|
||||
"settings": "Einstellungen",
|
||||
"modelProviders": "Modell Anbieter",
|
||||
"appearance": "Erscheinung",
|
||||
"privacy": "Privatsphäre",
|
||||
"keyboardShortcuts": "Shortcuts",
|
||||
"newChat": "Neuer Chat",
|
||||
"favorites": "Favoriten",
|
||||
"recents": "Kürzlich",
|
||||
"hub": "Hub",
|
||||
"helpSupport": "Hilfe & Support",
|
||||
"helpUsImproveJan": "Hilf uns Jan zu verbessern",
|
||||
"unstarAll": "Alle De-Favorisieren",
|
||||
"unstar": "De-Favorisieren",
|
||||
"deleteAll": "Alles löschen",
|
||||
"star": "Favorisieren",
|
||||
"rename": "Umbenennen",
|
||||
"delete": "Löschen",
|
||||
"copied": "Kopiert!",
|
||||
"dataFolder": "Daten Ordner",
|
||||
"others": "Andere",
|
||||
"language": "Sprache",
|
||||
"reset": "Zurücksetzen",
|
||||
"search": "Suchen",
|
||||
"name": "Name",
|
||||
"cancel": "Abbrechen",
|
||||
"create": "Anlegen",
|
||||
"save": "Speichern",
|
||||
"edit": "Editieren",
|
||||
"copy": "Kopieren",
|
||||
"back": "Zurück",
|
||||
"close": "Schließen",
|
||||
"next": "Nächster",
|
||||
"finish": "Abschließen",
|
||||
"skip": "Überspringen",
|
||||
"allow": "Erlauben",
|
||||
"deny": "Verbieten",
|
||||
"start": "Start",
|
||||
"stop": "Stop",
|
||||
"preview": "Vorschau",
|
||||
"compactWidth": "Kompakte Breite",
|
||||
"fullWidth": "Volle Breite",
|
||||
"dark": "Dunkel",
|
||||
"light": "Hell",
|
||||
"system": "System",
|
||||
"auto": "Automatisch",
|
||||
"english": "Englisch",
|
||||
"medium": "Medium",
|
||||
"newThread": "Neuer Thread",
|
||||
"noResultsFound": "Keine Ergebnisse gefunden",
|
||||
"noThreadsYet": "Keine Threads bisher",
|
||||
"noThreadsYetDesc": "Starte eine neue Unterhaltung, um deinen Threadverlauf hier anzuzeigen.",
|
||||
"downloads": "Downloads",
|
||||
"downloading": "Downloading",
|
||||
"cancelDownload": "Download abbrechen",
|
||||
"downloadCancelled": "Download wurde abgebrochen",
|
||||
"downloadComplete": "Download abgeschlossen",
|
||||
"thinking": "Denke nach...",
|
||||
"thought": "Gedanke",
|
||||
"callingTool": "Rufe Werkzeug auf",
|
||||
"completed": "Abgeschlossen",
|
||||
"image": "Bild",
|
||||
"vision": "Vision",
|
||||
"embeddings": "Einbettungen",
|
||||
"tools": "Werkzeuge",
|
||||
"webSearch": "Web Suche",
|
||||
"reasoning": "Argumentation",
|
||||
"selectAModel": "Wähle ein Modell",
|
||||
"noToolsAvailable": "Keine Werkzeuge verfügbar",
|
||||
"noModelsFoundFor": "Keine Modelle gefunden zu \"{{searchValue}}\"",
|
||||
"customAvatar": "Benutzerdefinierter Avatar",
|
||||
"editAssistant": "Assistenten bearbeiten",
|
||||
"jan": "Jan",
|
||||
"metadata": "Metadaten",
|
||||
"regenerate": "Neu generieren",
|
||||
"threadImage": "Thread Bild",
|
||||
"editMessage": "Nachricht bearbeiten",
|
||||
"deleteMessage": "Nachricht löschen",
|
||||
"deleteThread": "Thread löschen",
|
||||
"renameThread": "Thread umbenennen",
|
||||
"threadTitle": "Thread Titel",
|
||||
"deleteAllThreads": "Alle Threads löschen",
|
||||
"allThreadsUnfavorited": "Alle Threads defavorisieren",
|
||||
"deleteAllThreadsConfirm": "Bist Du sicher, daß Du alle Threads löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.",
|
||||
"addProvider": "Anbieter hinzufügen",
|
||||
"addOpenAIProvider": "OpenAI Anbieter hinzufügen",
|
||||
"enterNameForProvider": "Gib einen Namen ein für den Anbieter",
|
||||
"providerAlreadyExists": "Ein Anbieter mit dem Namen \"{{name}}\" existiert bereits. Bitte wähle einen anderen Namen.",
|
||||
"adjustFontSize": "Schriftgröße einstellen",
|
||||
"changeLanguage": "Sprache wechseln",
|
||||
"editTheme": " Vorlage bearbeiten",
|
||||
"editCodeBlockStyle": "Code Block Stil bearbeiten",
|
||||
"editServerHost": "Server Host bearbeiten",
|
||||
"pickColorWindowBackground": "Fensterhintergrundfarbe wählen",
|
||||
"pickColorAppMainView": "Farben wählen für das Hauptfenster",
|
||||
"pickColorAppPrimary": "Wähle primäre App-Farbe",
|
||||
"pickColorAppAccent": "Wähle hervorgehobene App-Farbe",
|
||||
"pickColorAppDestructive": "Wähle destruktive App-Farbe",
|
||||
"apiKeyRequired": "API Key ist erforderlich",
|
||||
"enterTrustedHosts": "Vertraute Hosts eingeben",
|
||||
"placeholder": {
|
||||
"chatInput": "Frage mich etwas..."
|
||||
},
|
||||
"confirm": "Bestätige",
|
||||
"loading": "Lade...",
|
||||
"error": "Fehler",
|
||||
"success": "Erfolg",
|
||||
"warning": "Warnung",
|
||||
"noResultsFoundDesc": "Wir konnten keinen Chat finden, welcher mit deiner Suche übereinstimmt. Versuche andere Schlüsselworte.",
|
||||
"searchModels": "Suche Modelle...",
|
||||
"searchStyles": "Suche Styles...",
|
||||
"createAssistant": "Assistenten anlegen",
|
||||
"enterApiKey": "API Key eingeben",
|
||||
"scrollToBottom": "Zum Ende scrollen",
|
||||
"addModel": {
|
||||
"title": "Modell hinzufügen",
|
||||
"modelId": "Modell ID",
|
||||
"enterModelId": "Modell ID eingeben",
|
||||
"addModel": "Modell hinzufügen",
|
||||
"description": "Neues Modell zum Anbieter hinzufügen",
|
||||
"exploreModels": "Modelle des Anbieters ansehen"
|
||||
},
|
||||
"mcpServers": {
|
||||
"editServer": "Server bearbeiten",
|
||||
"addServer": "Server hinzufügen",
|
||||
"serverName": "Server Name",
|
||||
"enterServerName": "Server Namen eingeben",
|
||||
"command": "Kommando",
|
||||
"enterCommand": "Kommando eingeben",
|
||||
"arguments": "Argumente",
|
||||
"argument": "Argument {{index}}",
|
||||
"envVars": "Umgebungs Variable",
|
||||
"key": "Schlüssel",
|
||||
"value": "Wert",
|
||||
"save": "Speichern"
|
||||
},
|
||||
"deleteServer": {
|
||||
"title": "Server löschen",
|
||||
"delete": "Löschen"
|
||||
},
|
||||
"editJson": {
|
||||
"errorParse": "Failed to parse JSON",
|
||||
"errorPaste": "Failed to paste JSON",
|
||||
"errorFormat": "Invalid JSON format",
|
||||
"titleAll": "Edit All Servers Configuration",
|
||||
"placeholder": "Enter JSON configuration...",
|
||||
"save": "Save"
|
||||
},
|
||||
"editModel": {
|
||||
"title": "Modell bearbeiten: {{modelId}}",
|
||||
"description": "Konfiguriere die Modelfähigkeiten durch Umschalten der untenstehenden Optionen.",
|
||||
"capabilities": "Modelfähigkeiten",
|
||||
"tools": "Werkzeuge",
|
||||
"vision": "Vision",
|
||||
"embeddings": "Einbettungen",
|
||||
"notAvailable": "Nicht verfügbar bisher"
|
||||
},
|
||||
"outOfContextError": {
|
||||
"truncateInput": "Input verkleinern",
|
||||
"title": "Out of context error",
|
||||
"description": "Dieser Chat erreicht das KI Speicher Limit. Wir können das Speicherfenster vergrößern (auch Kontextgröße genannt), so daß sich die KI an mehr erinnern kann, aber dies erfordert es mehr Speicher zu verwenden. Um Platz zu schaffen können wir auch den Input verkleinern, was bedeutet, daß die KI einen Teil seiner Chat-Historie vergisst.",
|
||||
"increaseContextSizeDescription": "Möchtest Du die Kontextgröße erhöhen?",
|
||||
"increaseContextSize": "Kontextgröße erhöhen"
|
||||
},
|
||||
"toolApproval": {
|
||||
"title": "Anfrage für Werkzeugnutzung",
|
||||
"description": "Der Assistant möchte <strong>{{toolName}}</strong> verwenden",
|
||||
"securityNotice": "Erlaube nur Werkzeuge zu nutzen denen Du vertraust. Werkzeuge können auf deine Daten oder System zugreifen.",
|
||||
"deny": "Ablehnen",
|
||||
"allowOnce": "Einmal erlauben",
|
||||
"alwaysAllow": "Immer erlauben"
|
||||
},
|
||||
"deleteModel": {
|
||||
"title": "Modell löschen: {{modelId}}",
|
||||
"description": "Bist Du sicher, daß Du dieses Modell löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.",
|
||||
"success": "Modell {{modelId}} wurde permanent gelöscht.",
|
||||
"cancel": "Abbrechen",
|
||||
"delete": "Löschen"
|
||||
},
|
||||
"deleteProvider": {
|
||||
"title": "Anbieter löschen",
|
||||
"description": "Lösche diesen Anbieter und alle seine Modelle. Diese Aktion kann nicht rückgängig gemacht werden.",
|
||||
"success": "Anbieter {{provider}} wurde permanent gelöscht.",
|
||||
"confirmTitle": "Anbieter löschen: {{provider}}",
|
||||
"confirmDescription": "Bist Du sicher, daß Du diesen Anbieter löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.",
|
||||
"cancel": "Abbrechen",
|
||||
"delete": "Löschen"
|
||||
},
|
||||
"modelSettings": {
|
||||
"title": "Modell Einstellungen - {{modelId}}",
|
||||
"description": "Modeleinstellungen konfigurieren, um die Leistung und das Verhalten zu optimieren."
|
||||
},
|
||||
"dialogs": {
|
||||
"changeDataFolder": {
|
||||
"title": "Speicherort des Datenordners ändern",
|
||||
"description": "Bist Du sicher den Speicherort des Datenordners zu ändern? Dies wird alle Daten zum neuen Speicherort verschieben und anschließend die Anwendung neu starten.",
|
||||
"currentLocation": "Aktueller Speicherort:",
|
||||
"newLocation": "Neuer Speicherort:",
|
||||
"cancel": "Abbrechen",
|
||||
"changeLocation": "Speicherort ändern"
|
||||
},
|
||||
"deleteAllThreads": {
|
||||
"title": "Alle Threads löschen",
|
||||
"description": "Alle Threads werden gelöscht. Diese Aktion kann nicht rückgängig gemacht werden."
|
||||
},
|
||||
"deleteThread": {
|
||||
"description": "Bist Du sicher, daß Du diesen Thread löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden."
|
||||
},
|
||||
"editMessage": {
|
||||
"title": "Nachricht bearbeiten"
|
||||
},
|
||||
"messageMetadata": {
|
||||
"title": "Nachricht Metadaten"
|
||||
}
|
||||
},
|
||||
"toast": {
|
||||
"allThreadsUnfavorited": {
|
||||
"title": "Alle Threads De-Favorisieren ",
|
||||
"description": "Alle deine Threads wurden defavorisiert."
|
||||
},
|
||||
"deleteAllThreads": {
|
||||
"title": "Alle Threads löschen",
|
||||
"description": "Alle deine Threads wurden permanent gelöscht."
|
||||
},
|
||||
"renameThread": {
|
||||
"title": "Thread umbenennen",
|
||||
"description": "Thread Titel wurde umbenannt zu '{{title}}'"
|
||||
},
|
||||
"deleteThread": {
|
||||
"title": "Thread löschen",
|
||||
"description": "This thread has been permanently deleted."
|
||||
},
|
||||
"editMessage": {
|
||||
"title": "Nachricht bearbeiten",
|
||||
"description": "Die Nachricht wurde erfolgreich bearbeitet. Bitte warte auf die Antwort des Models."
|
||||
},
|
||||
"appUpdateDownloaded": {
|
||||
"title": "App Update heruntergeladen",
|
||||
"description": "Das App-Update wurde erfolgreich heruntergeladen."
|
||||
},
|
||||
"appUpdateDownloadFailed": {
|
||||
"title": "App Update Download fehlgeschlagen",
|
||||
"description": "Das App-Update konnte nicht heruntergeladen werden. Bitte versuche es noch einmal."
|
||||
},
|
||||
"downloadComplete": {
|
||||
"title": "Download abgeschlossen",
|
||||
"description": "Das Modell {{modelId}} wurde heruntergeladen"
|
||||
},
|
||||
"downloadCancelled": {
|
||||
"title": "Download abgebrochen",
|
||||
"description": "Der Download-Prozess wurde abgebrochen"
|
||||
}
|
||||
},
|
||||
"cortexFailureDialog": {
|
||||
"title": "Problem mit der lokalen KI-Engine",
|
||||
"description": "Die Lokale KI-Engine (Cortex) konnte nach mehreren Versuchen nicht gestartet werden. Dies verhindert möglicherweise die korrekte Ausführung diverser Funktionalitäten.",
|
||||
"contactSupport": "Support kontaktieren",
|
||||
"restartJan": "Jan neu starten"
|
||||
}
|
||||
}
|
||||
31
web-app/src/locales/de-DE/hub.json
Normal file
31
web-app/src/locales/de-DE/hub.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"sortNewest": "Neueste",
|
||||
"sortMostDownloaded": "Meist heruntergeladen",
|
||||
"use": "Nutzen",
|
||||
"download": "Herunterladen",
|
||||
"downloaded": "Heruntergeladen",
|
||||
"loadingModels": "Lade Modelle...",
|
||||
"noModels": "Keine Modelle gefunden",
|
||||
"by": "Von",
|
||||
"downloads": "Downloads",
|
||||
"variants": "Varianten",
|
||||
"showVariants": "Zeige Varianten",
|
||||
"useModel": "Nutze dieses Modell",
|
||||
"downloadModel": "Modell herunterladen",
|
||||
"searchPlaceholder": "Suche nach Modellen auf Hugging Face...",
|
||||
"editTheme": "Bearbeite Erscheinungsbild",
|
||||
"joyride": {
|
||||
"recommendedModelTitle": "Empfohlenes Modell",
|
||||
"recommendedModelContent": "Durchsuche und lade leistungsstarke KI-Modelle verschiedener Anbieter an einem Ort herunter. Wir empfehlen mit Jan-Nano zu beginnen, einem Modell, das für Funktionsaufrufe, Werkzeug-Integration und Forschungsfunktionen optimiert ist. Es eignet sich ideal für die Entwicklung interaktiver KI-Agenten.",
|
||||
"downloadInProgressTitle": "Download läuft",
|
||||
"downloadInProgressContent": "Dein Modell wird jetzt heruntergeladen. Verfolge hier den Fortschritt. Sobald der Download abgeschlossen ist, ist es einsatzbereit.",
|
||||
"downloadModelTitle": "Modell herunterladen",
|
||||
"downloadModelContent": "Klicke auf den Download Button um das Herunterladen zu beginnen.",
|
||||
"back": "Zurück",
|
||||
"close": "Schließen",
|
||||
"lastWithDownload": "Download",
|
||||
"last": "Fertig",
|
||||
"next": "Nächstes",
|
||||
"skip": "Überspringen"
|
||||
}
|
||||
}
|
||||
3
web-app/src/locales/de-DE/logs.json
Normal file
3
web-app/src/locales/de-DE/logs.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"noLogs": "Keine Logs verfügbar"
|
||||
}
|
||||
43
web-app/src/locales/de-DE/mcp-servers.json
Normal file
43
web-app/src/locales/de-DE/mcp-servers.json
Normal file
@ -0,0 +1,43 @@
|
||||
{
|
||||
"editServer": "MCP Server bearbeiten",
|
||||
"addServer": "MCP Server hinzufügen",
|
||||
"serverName": "Server Name",
|
||||
"enterServerName": "Server Namen eingeben",
|
||||
"command": "Kommando",
|
||||
"enterCommand": "Kommando eingeben (uvx oder npx)",
|
||||
"arguments": "Argumente",
|
||||
"argument": "Argument {{index}}",
|
||||
"envVars": "Umgebungs Variablen",
|
||||
"key": "Schlüssel",
|
||||
"value": "Wert",
|
||||
"save": "Speichern",
|
||||
"status": "Status",
|
||||
"connected": "Verbunden",
|
||||
"disconnected": "Nicht verbunden",
|
||||
"deleteServer": {
|
||||
"title": "MCP Server löschen",
|
||||
"description": "Bist Du sicher, dass Du den MCP Server {{serverName}} löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.",
|
||||
"delete": ""
|
||||
},
|
||||
"editJson": {
|
||||
"title": "JSON für den MCP Server bearbeiten: {{serverName}}",
|
||||
"titleAll": "JSON für alle MCP Server bearbeiten",
|
||||
"placeholder": "JSON Konfiguration eingeben",
|
||||
"errorParse": "Fehler beim Parsen der initialen Daten",
|
||||
"errorPaste": "Ungültiges JSON Format in dem eingefügten Inhalt",
|
||||
"errorFormat": "Ungültiges JSON Format",
|
||||
"save": "Speichern"
|
||||
},
|
||||
"checkParams": "Bitte überprüfe die Parameter gemäß dem Tutorial.",
|
||||
"title": "MCP Server",
|
||||
"experimental": "Experimentell",
|
||||
"editAllJson": "JSON aller Server bearbeiten",
|
||||
"findMore": "Finde mehr MCP Server bei",
|
||||
"allowPermissions": "Erlaube allen MCP Werkzeugen den Zugriff",
|
||||
"allowPermissionsDesc": "Wenn aktiviert, werden alle MCP-Werkzeug-Aufrufe automatisch genehmigt, ohne dass Berechtigungsdialoge angezeigt werden.",
|
||||
"noServers": "Keine MCP Server gefunden",
|
||||
"args": "Argumente",
|
||||
"env": "Umgebung",
|
||||
"serverStatusActive": "Server {{serverKey}} erfolgreich aktiviert",
|
||||
"serverStatusInactive": "Server {{serverKey}} erfolgreich deaktiviert"
|
||||
}
|
||||
7
web-app/src/locales/de-DE/model-errors.json
Normal file
7
web-app/src/locales/de-DE/model-errors.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"title": "Out of context error",
|
||||
"description": "Dieser Chat erreicht das KI Speicher Limit. Wir können das Speicherfenster vergrößern (auch Kontextgröße genannt), so dass sich die KI an mehr erinnern kann, aber dies erfordert es mehr Speicher zu verwenden. Um Platz zu schaffen können wir auch den Input verkleinern, was bedeutet, dass die KI einen Teil seiner Chat-Historie vergisst.",
|
||||
"increaseContextSizeDescription": "Möchtest Du die Kontextgröße erhöhen?",
|
||||
"truncateInput": "Input verkleinern",
|
||||
"increaseContextSize": "Kontextgröße erhöhen"
|
||||
}
|
||||
5
web-app/src/locales/de-DE/provider.json
Normal file
5
web-app/src/locales/de-DE/provider.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"addProvider": "Anbieter hinzufügen",
|
||||
"addOpenAIProvider": "OpenAI Anbieter hinzufügen",
|
||||
"enterNameForProvider": "Namen für Anbieter eingeben"
|
||||
}
|
||||
68
web-app/src/locales/de-DE/providers.json
Normal file
68
web-app/src/locales/de-DE/providers.json
Normal file
@ -0,0 +1,68 @@
|
||||
{
|
||||
"joyride": {
|
||||
"chooseProviderTitle": "Wähle einen Anbieter",
|
||||
"chooseProviderContent": "Wähle den Anbieter aus, den Du verwenden möchtest, und stelle sicher, daß Du Zugriff auf einen API-Schlüssel dafür hast.",
|
||||
"getApiKeyTitle": "Hole Dir Deinen API-Schlüssel",
|
||||
"getApiKeyContent": "Melde Dich bei dem Anbieter an, um Deinen API-Schlüssel zu finden oder zu generieren.",
|
||||
"insertApiKeyTitle": "Gebe Deinen API-Schlüssel ein",
|
||||
"insertApiKeyContent": "Füge hier Deinen API-Schlüssel ein, um eine Verbindung zum Anbieter herzustellen und ihn zu aktivieren.",
|
||||
"back": "Zurück",
|
||||
"close": "Schließen",
|
||||
"last": "Abschließen",
|
||||
"next": "Nächster",
|
||||
"skip": "Überspringen"
|
||||
},
|
||||
"refreshModelsError": "Der Anbieter muss über eine Basis-URL und einen API-Schlüssel verfügen, um Modelle abzurufen.",
|
||||
"refreshModelsSuccess": "{{count}} neue(s) Modell(e) hinzugefügt von {{provider}}.",
|
||||
"noNewModels": "Keine neuen Modelle gefunden. Alle verfügbaren Modelle sind bereits hinzugefügt.",
|
||||
"refreshModelsFailed": "Das Abrufen der Modelle von {{provider}} ist fehlgeschlagen. Bitte überprüfe Deinen API-Schlüssel und die Basis-URL.",
|
||||
"models": "Modelle",
|
||||
"refreshing": "Aktualisiere...",
|
||||
"refresh": "Aktualisieren",
|
||||
"import": "Importieren",
|
||||
"importModelSuccess": "Modell von {{provider}} wurde erfolgreich importiert.",
|
||||
"importModelError": "Modellimport ist fehlgeschlagen:",
|
||||
"stop": "Stop",
|
||||
"start": "Start",
|
||||
"noModelFound": "Kein Modell gefunden",
|
||||
"noModelFoundDesc": "Verfügbare Modelle werden hier aufgelistet. Wenn Du noch keine Modelle hast, können diese im Hub heruntergeladen werden.",
|
||||
"configuration": "Konfiguration",
|
||||
"apiEndpoint": "API Endpunkt",
|
||||
"testConnection": "Teste Verbindung",
|
||||
"addModel": {
|
||||
"title": "Neues Modell hinzufügen",
|
||||
"description": "Neues Modell zu Anbieter {{provider}} hinzufügen.",
|
||||
"modelId": "Modell ID",
|
||||
"enterModelId": "Modell ID eingeben",
|
||||
"exploreModels": "Sehe Modellliste von {{provider}}",
|
||||
"addModel": "Modell hinzufügen"
|
||||
},
|
||||
"deleteModel": {
|
||||
"title": "Lösche Modell: {{modelId}}",
|
||||
"description": "Möchtest Du dieses Modell wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden.",
|
||||
"success": "Modell {{modelId}} wurde permanent gelöscht.",
|
||||
"cancel": "Abbrechen",
|
||||
"delete": "Löschen"
|
||||
},
|
||||
"deleteProvider": {
|
||||
"title": "Anbieter löschen",
|
||||
"description": "Lösche diesen Anbieter und alle seine Modelle. Diese Aktion kann nicht rückgängig gemacht werden.",
|
||||
"success": "Anbieter {{provider}} wurde permanent gelöscht.",
|
||||
"confirmTitle": "Lösche Anbieter: {{provider}}",
|
||||
"confirmDescription": "Möchtest Du diesen Anbieter wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden.",
|
||||
"cancel": "Abbrechen",
|
||||
"delete": "Löschen"
|
||||
},
|
||||
"editModel": {
|
||||
"title": "Modell bearbeiten: {{modelId}}",
|
||||
"description": "Konfiguriere die Modellfunktionen, indem Du die folgenden Optionen einstellst.",
|
||||
"capabilities": "Fähigkeiten",
|
||||
"tools": "Werkzeuge",
|
||||
"vision": "Vision",
|
||||
"embeddings": "Einbettungen",
|
||||
"notAvailable": "Noch nicht verfügbar"
|
||||
},
|
||||
"addProvider": "Anbieter hinzufügen",
|
||||
"addOpenAIProvider": "OpenAI Anbieter hinzufügen",
|
||||
"enterNameForProvider": "Namen für den Anbieter eingeben"
|
||||
}
|
||||
248
web-app/src/locales/de-DE/settings.json
Normal file
248
web-app/src/locales/de-DE/settings.json
Normal file
@ -0,0 +1,248 @@
|
||||
{
|
||||
"autoDownload": "Automatisch neue Updates herunterladen",
|
||||
"checkForUpdates": "Auf Updates prüfen",
|
||||
"checkForUpdatesDesc": "Prüfe, ob eine neuere Version von Jan verfügbar ist.",
|
||||
"checkingForUpdates": "Suche nach Updates...",
|
||||
"noUpdateAvailable": "Du verwendest die neueste Version",
|
||||
"devVersion": "Entwicklungsversion erkannt",
|
||||
"updateError": "Fehler beim Suchen nach Updates",
|
||||
"changeLocation": "Ort ändern",
|
||||
"copied": "Kopiert",
|
||||
"copyPath": "Pfad kopieren",
|
||||
"openLogs": "Logs öffnen",
|
||||
"revealLogs": "Logs aufzeigen",
|
||||
"showInFinder": "Zeige im Finder",
|
||||
"showInFileExplorer": "Zeige in Datei Explorer",
|
||||
"openContainingFolder": "Enthaltenen Ordner öffnen",
|
||||
"failedToRelocateDataFolder": "Datenordner konnte nicht verschoben werden",
|
||||
"failedToRelocateDataFolderDesc": "Der Datenordner konnte nicht verschoben werden. Bitte versuche es erneut.",
|
||||
"factoryResetTitle": "Auf Werkseinstellungen zurücksetzen",
|
||||
"factoryResetDesc": "Dadurch werden alle App-Einstellungen auf die Standardeinstellungen zurückgesetzt. Dieser Vorgang kann nicht rückgängig gemacht werden. Wir empfehlen dies nur, wenn die App beschädigt ist.",
|
||||
"cancel": "Abbrechen",
|
||||
"reset": "Zurücksetzen",
|
||||
"resources": "Ressourcen",
|
||||
"documentation": "Dokumentation",
|
||||
"documentationDesc": "Erfahre, wie Du Jan verwenden und seine Funktionen erkunden kannst.",
|
||||
"viewDocs": "Dokumentation ansehen",
|
||||
"releaseNotes": "Release Notes",
|
||||
"releaseNotesDesc": "Siehe, was es Neues in der neuesten Version von Jan gibt.",
|
||||
"viewReleases": "Releases ansehen",
|
||||
"community": "Community",
|
||||
"github": "GitHub",
|
||||
"githubDesc": "Beitragen zu Jan's Entwicklung.",
|
||||
"discord": "Discord",
|
||||
"discordDesc": "Trete unserer Community für Unterstützung und Diskussionen bei.",
|
||||
"support": "Support",
|
||||
"reportAnIssue": "Melde ein Problem",
|
||||
"reportAnIssueDesc": "Hast Du einen Bug gefunden? Hilf uns, indem Du ein Problem auf GitHub meldest.",
|
||||
"reportIssue": "Problem melden",
|
||||
"credits": "Credits",
|
||||
"creditsDesc1": "Jan wurde mit ❤️ gebaut vom Menlo Team.",
|
||||
"creditsDesc2": "Besonderer Dank gilt unseren Open-Source-Abhängigkeiten - insbesondere llama.cpp und Tauri - und unserer großartigen KI-Community.",
|
||||
"appVersion": "App Version",
|
||||
"dataFolder": {
|
||||
"appData": "App Daten",
|
||||
"appDataDesc": "Standardspeicherort für Nachrichten und andere Benutzerdaten.",
|
||||
"appLogs": "App Logs",
|
||||
"appLogsDesc": "Zeige detaillierte Logs der App an."
|
||||
},
|
||||
"others": {
|
||||
"spellCheck": "Rechtschreibprüfung",
|
||||
"spellCheckDesc": "Aktiviere die Rechtschreibprüfung für Deine Threads.",
|
||||
"resetFactory": "Auf Werkseinstellungen zurücksetzen",
|
||||
"resetFactoryDesc": "Setzt die Anwendung in den ursprünglichen Zustand zurück und löscht dabei alle Modelle und den Chatverlauf. Diese Aktion ist irreversibel und wird nur empfohlen, wenn die Anwendung beschädigt ist."
|
||||
},
|
||||
"shortcuts": {
|
||||
"application": "Anwendung",
|
||||
"newChat": "Neuer Chat",
|
||||
"newChatDesc": "Neuen Chat anlegen.",
|
||||
"toggleSidebar": "Seitenleiste umschalten",
|
||||
"toggleSidebarDesc": "Seitenleiste ein- oder ausblenden.",
|
||||
"zoomIn": "Vergrößern",
|
||||
"zoomInDesc": "Erhöhe die Zoomstufe.",
|
||||
"zoomOut": "Verkleinern",
|
||||
"zoomOutDesc": "Verringere die Zoomstufe.",
|
||||
"chat": "Chat",
|
||||
"sendMessage": "Nachricht senden",
|
||||
"sendMessageDesc": "Aktuelle Nachricht senden",
|
||||
"enter": "Eingabe",
|
||||
"newLine": "Neue Zeile",
|
||||
"newLineDesc": "Neue Zeile einfügen.",
|
||||
"shiftEnter": "Shift + Enter",
|
||||
"navigation": "Navigation",
|
||||
"goToSettings": "Gehe zu den Einstellungen",
|
||||
"goToSettingsDesc": "Einstellungen öffnen."
|
||||
},
|
||||
"appearance": {
|
||||
"title": "Erscheinungsbild",
|
||||
"theme": "Theme",
|
||||
"themeDesc": "Dem Betriebssystem anpassen.",
|
||||
"fontSize": "Schriftgröße",
|
||||
"fontSizeDesc": "Einstellen der App Schriftgröße",
|
||||
"windowBackground": "Fenster Hintergrund",
|
||||
"windowBackgroundDesc": "Lege die Hintergrundfarbe des App-Fensters fest.",
|
||||
"appMainView": "App-Hauptansicht",
|
||||
"appMainViewDesc": "Lege die Hintergrundfarbe des Hauptinhaltsbereichs fest.",
|
||||
"primary": "Primär",
|
||||
"primaryDesc": "Lege die Primärfarbe für UI-Komponenten fest.",
|
||||
"accent": "Akzent",
|
||||
"accentDesc": "Lege die Akzentfarbe für UI-Hervorhebungen fest.",
|
||||
"destructive": "Destruktiv",
|
||||
"destructiveDesc": "Lege die Farbe für destruktive Aktionen fest.",
|
||||
"resetToDefault": "Auf Werkseinstellungen zurücksetzen",
|
||||
"resetToDefaultDesc": "Setzt alle Darstellungseinstellungen auf die Standardeinstellungen zurück.",
|
||||
"resetAppearanceSuccess": "Erscheinungsbild erfolgreich zurückgesetzt",
|
||||
"resetAppearanceSuccessDesc": "Alle Darstellungseinstellungen wurden auf die Standardeinstellungen zurückgesetzt.",
|
||||
"chatWidth": "Chat Breite",
|
||||
"chatWidthDesc": "Passe die Breite der Chatansicht an.",
|
||||
"codeBlockTitle": "Code Block",
|
||||
"codeBlockDesc": "Wähle einen Stil zur Syntaxhervorhebung.",
|
||||
"showLineNumbers": "Zeilennummern anzeigen",
|
||||
"showLineNumbersDesc": "Zeilennummern in Codeblöcken anzeigen.",
|
||||
"resetCodeBlockStyle": "Codeblockstil zurücksetzen",
|
||||
"resetCodeBlockStyleDesc": "Codeblockstil auf Standard zurücksetzen.",
|
||||
"resetCodeBlockSuccess": "Codeblockstil erfolgreich zurückgesetzt",
|
||||
"resetCodeBlockSuccessDesc": "Der Codeblockstil wurde auf die Standardeinstellung zurückgesetzt."
|
||||
},
|
||||
"hardware": {
|
||||
"os": "Betriebssystem",
|
||||
"name": "Name",
|
||||
"version": "Version",
|
||||
"cpu": "CPU",
|
||||
"model": "Modell",
|
||||
"architecture": "Architektur",
|
||||
"cores": "Kerne",
|
||||
"instructions": "Instruktionen",
|
||||
"usage": "Nutzung",
|
||||
"memory": "Speicher",
|
||||
"totalRam": "RAM Total",
|
||||
"availableRam": "Verfügbarer RAM",
|
||||
"vulkan": "Vulkan",
|
||||
"enableVulkan": "Vulkan aktivieren",
|
||||
"enableVulkanDesc": "Verwende die Vulkan-API zur GPU-Beschleunigung. Aktiviere Vulkan nicht, wenn Du eine NVIDIA-GPU verwendest, da dies zu Kompatibilitätsproblemen führen kann.",
|
||||
"gpus": "GPUs",
|
||||
"noGpus": "Keine GPUs erkannt",
|
||||
"vram": "VRAM",
|
||||
"freeOf": "frei von",
|
||||
"driverVersion": "Treiber Version",
|
||||
"computeCapability": "Rechenfähigkeit",
|
||||
"systemMonitor": "System Monitor"
|
||||
},
|
||||
"httpsProxy": {
|
||||
"proxy": "Proxy",
|
||||
"proxyUrl": "Proxy URL",
|
||||
"proxyUrlDesc": "Die URL und der Port deines Proxyservers.",
|
||||
"proxyUrlPlaceholder": "http://proxy.example.com:8080",
|
||||
"authentication": "Authentifizierung",
|
||||
"authenticationDesc": "Anmeldeinformationen für den Proxyserver, falls erforderlich.",
|
||||
"username": "Username",
|
||||
"password": "Passwort",
|
||||
"noProxy": "Kein Proxy",
|
||||
"noProxyDesc": "Eine durch Kommas getrennte Liste von Hosts, um den Proxy zu umgehen.",
|
||||
"noProxyPlaceholder": "localhost,127.0.0.1,.local",
|
||||
"sslVerification": "SSL Verifikation",
|
||||
"ignoreSsl": "SSL Certificates ignorieren",
|
||||
"ignoreSslDesc": "Erlaube selbstsignierte oder nicht verifizierte Zertifikate. Dies kann für einige Proxys erforderlich sein, verringert aber die Sicherheit. Aktiviere diese Option nur, wenn Du Deinem Proxy vertraust.",
|
||||
"proxySsl": "Proxy SSL",
|
||||
"proxySslDesc": "Validieren des SSL-Zertifikats, wenn eine Verbindung mit dem Proxy hergestellt wird.",
|
||||
"proxyHostSsl": "Proxy Host SSL",
|
||||
"proxyHostSslDesc": "Validieren des SSL-Zertifikats des Proxy-Hosts.",
|
||||
"peerSsl": "Peer SSL",
|
||||
"peerSslDesc": "Validieren des SSL-Zertifikats von Peer-Verbindungen.",
|
||||
"hostSsl": "Host SSL",
|
||||
"hostSslDesc": "Validieren der SSL-Zertifikate der Zielhosts."
|
||||
},
|
||||
"localApiServer": {
|
||||
"title": "Lokaler API Server",
|
||||
"description": "Führe lokal einen OpenAI-kompatiblen Server aus.",
|
||||
"startServer": "Start Server",
|
||||
"stopServer": "Stop Server",
|
||||
"serverLogs": "Server Logs",
|
||||
"serverLogsDesc": "Zeige detaillierte Logs des lokalen API-Servers an.",
|
||||
"openLogs": "Logs öffnen",
|
||||
"serverConfiguration": "Server Konfiguration",
|
||||
"serverHost": "Server Host",
|
||||
"serverHostDesc": "Netzwerkadresse für den Server.",
|
||||
"serverPort": "Server Port",
|
||||
"serverPortDesc": "Portnummer für den API Server.",
|
||||
"apiPrefix": "API Prefix",
|
||||
"apiPrefixDesc": "Pfadprefix für den API Endpunkt.",
|
||||
"apiKey": "API Schlüssel",
|
||||
"apiKeyDesc": "Authentifiziere Anfragen mit einem API-Schlüssel.",
|
||||
"trustedHosts": "Vertrauenswürdige Hosts",
|
||||
"trustedHostsDesc": "Hosts, die auf den Server zugreifen dürfen, durch Kommas getrennt.",
|
||||
"advancedSettings": "Erweiterte Einstellungen",
|
||||
"cors": "Cross-Origin Resource Sharing (CORS)",
|
||||
"corsDesc": "Erlaube Cross-Origin-Anfragen an den API-Server.",
|
||||
"verboseLogs": "Ausführliche Server Logs",
|
||||
"verboseLogsDesc": "Aktiviere detaillierte Server Logs zum Debuggen"
|
||||
},
|
||||
"privacy": {
|
||||
"analytics": "Analytik",
|
||||
"helpUsImprove": "Hilf uns, uns zu verbessern",
|
||||
"helpUsImproveDesc": "Um uns bei der Verbesserung von Jan zu unterstützen, kannst Du uns anonyme Daten wie Funktionsnutzung und Benutzerzahlen mitteilen. Wir erfassen niemals Deine Chats oder persönlichen Daten.",
|
||||
"privacyPolicy": "Du hast die volle Kontrolle über Deine Daten. Erfahre mehr in unserer Datenschutzerklärung.",
|
||||
"analyticsDesc": "Um Jan zu verbessern, müssen wir verstehen, wie es genutzt wird - aber nur mit deiner Hilfe. Du kannst diese Einstellung jederzeit ändern.",
|
||||
"privacyPromises": "Deine Auswahl hier ändert nichts an unseren grundlegenden Datenschutzversprechen:",
|
||||
"promise1": "Deine Gespräche bleiben privat und auf deinem Gerät",
|
||||
"promise2": "Wir erfassen niemals Deine persönlichen Daten oder Chat-Inhalte",
|
||||
"promise3": "Der gesamte Datenaustausch erfolgt anonym und aggregiert",
|
||||
"promise4": "Du kannst dich jederzeit abmelden, ohne die Funktionalität zu verlieren",
|
||||
"promise5": "Wir sind transparent darüber, was wir sammeln und warum"
|
||||
},
|
||||
"general": {
|
||||
"showInFinder": "Im Finder zeigen",
|
||||
"showInFileExplorer": "Zeige im Datei Explorer",
|
||||
"openContainingFolder": "Enthaltenen Ordner öffnen",
|
||||
"failedToRelocateDataFolder": "Datenordner konnte nicht verschoben werden",
|
||||
"failedToRelocateDataFolderDesc": "Der Datenordner konnte nicht verschoben werden. Bitte versuche es erneut.",
|
||||
"devVersion": "Entwicklungsversion erkannt",
|
||||
"noUpdateAvailable": "Du verwendest die neueste Version",
|
||||
"updateError": "Fehler beim Suchen nach Updates",
|
||||
"appVersion": "App Version",
|
||||
"checkForUpdates": "Auf Updates prüfen",
|
||||
"checkForUpdatesDesc": "Prüfe, ob eine neuere Version von Jan verfügbar ist.",
|
||||
"checkingForUpdates": "Suche nach Updates...",
|
||||
"copied": "Kopiert",
|
||||
"copyPath": "Pfad kopieren",
|
||||
"changeLocation": "Ort ändern",
|
||||
"openLogs": "Logs öffnen",
|
||||
"revealLogs": "Logs anzeigen",
|
||||
"factoryResetTitle": "Auf Werkseinstellungen zurücksetzen",
|
||||
"factoryResetDesc": "Dadurch werden alle App-Einstellungen auf die Standardeinstellungen zurückgesetzt. Dieser Vorgang kann nicht rückgängig gemacht werden. Wir empfehlen dies nur, wenn die App beschädigt ist.",
|
||||
"cancel": "Abbrechen",
|
||||
"reset": "Zurücksetzen",
|
||||
"resources": "Ressourcen",
|
||||
"documentation": "Dokumentation",
|
||||
"documentationDesc": "Erfahre, wie Du Jan verwenden und seine Funktionen erkunden kannst.",
|
||||
"viewDocs": "Dokumentation ansehen",
|
||||
"releaseNotes": "Release Notes",
|
||||
"releaseNotesDesc": "Sehe, was es Neues in der neuesten Version von Jan gibt.",
|
||||
"viewReleases": "Releases anzeigen",
|
||||
"community": "Community",
|
||||
"github": "GitHub",
|
||||
"githubDesc": "Trage zu Jan's Entwicklung bei.",
|
||||
"discord": "Discord",
|
||||
"discordDesc": "Trete unserer Community für Unterstützung und Diskussionen bei.",
|
||||
"support": "Support",
|
||||
"reportAnIssue": "Melde ein Problem",
|
||||
"reportAnIssueDesc": "Hast Du einen Bug gefunden? Hilf uns, indem Du ein Problem auf GitHub meldest.",
|
||||
"reportIssue": "Problem melden",
|
||||
"credits": "Credits",
|
||||
"creditsDesc1": "Jan wurde mit ❤️ gebaut vom Menlo Team.",
|
||||
"creditsDesc2": "Besonderer Dank gilt unseren Open-Source-Abhängigkeiten - insbesondere llama.cpp und Tauri - und unserer großartigen KI-Community."
|
||||
},
|
||||
"extensions": {
|
||||
"title": "Erweiterungen"
|
||||
},
|
||||
"dialogs": {
|
||||
"changeDataFolder": {
|
||||
"title": "Speicherort des Datenordners ändern",
|
||||
"description": "Möchtest Du den Speicherort des Datenordners wirklich ändern? Dadurch werden alle Deine Daten an den neuen Speicherort verschoben und die Anwendung neu gestartet.",
|
||||
"currentLocation": "Aktueller Ort:",
|
||||
"newLocation": "Neuer Ort:",
|
||||
"cancel": "Abbrechen",
|
||||
"changeLocation": "Ort ändern"
|
||||
}
|
||||
}
|
||||
}
|
||||
6
web-app/src/locales/de-DE/setup.json
Normal file
6
web-app/src/locales/de-DE/setup.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"welcome": "Willkommen bei Jan",
|
||||
"description": "Um zu beginnen, musst Du entweder ein lokales KI-Modell herunterladen oder über einen API-Schlüssel eine Verbindung zu einem Cloud-Modell herstellen.",
|
||||
"localModel": "Lokales Modell einrichten",
|
||||
"remoteProvider": "Fernen Anbieter einrichten"
|
||||
}
|
||||
28
web-app/src/locales/de-DE/system-monitor.json
Normal file
28
web-app/src/locales/de-DE/system-monitor.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"title": "System Monitor",
|
||||
"cpuUsage": "CPU Nutzung",
|
||||
"model": "Modell",
|
||||
"cores": "Kerne",
|
||||
"architecture": "Architektur",
|
||||
"currentUsage": "Aktuelle Nutzung",
|
||||
"memoryUsage": "Speicher Nutzung",
|
||||
"totalRam": "RAM Total",
|
||||
"availableRam": "Verfügbarer RAM",
|
||||
"usedRam": "Genutzter RAM",
|
||||
"runningModels": "Laufende Modelle",
|
||||
"noRunningModels": "Momentan laufen keine Modelle",
|
||||
"provider": "Anbieter",
|
||||
"uptime": "Betriebszeit",
|
||||
"actions": "Aktionen",
|
||||
"stop": "Stop",
|
||||
"activeGpus": "Aktive GPUs",
|
||||
"noGpus": "Keine GPUs detektiert",
|
||||
"noActiveGpus": "Keine aktiven GPUs. Alle GPUs sind momentan deaktiviert.",
|
||||
"vramUsage": "VRAM Nutzung",
|
||||
"driverVersion": "Treiber Version:",
|
||||
"computeCapability": "Rechenfähigkeit:",
|
||||
"active": "Aktiv",
|
||||
"performance": "Leistung",
|
||||
"resources": "Ressourcen",
|
||||
"refresh": "Aktualisieren"
|
||||
}
|
||||
11
web-app/src/locales/de-DE/tool-approval.json
Normal file
11
web-app/src/locales/de-DE/tool-approval.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"title": "Werkzeugaufruf angefordert",
|
||||
"description": "Der Assistent möchte folgendes Werkzeug verwenden: <strong>{{toolName}}</strong>",
|
||||
"securityNotice": "<strong>Sicherheitshinweis:</strong> Schädliche Werkzeuge oder Konversationsinhalte könnten den Assistenten möglicherweise zu schädlichen Aktionen verleiten. Überprüfe jeden Werkzeug-Aufruf sorgfältig, bevor Du ihn genehmigst.",
|
||||
"deny": "Verweigern",
|
||||
"allowOnce": "Einmal erlauben",
|
||||
"alwaysAllow": "Immer erlauben",
|
||||
"permissions": "Berechtigungen",
|
||||
"approve": "Genehmigen",
|
||||
"reject": "Ablehnen"
|
||||
}
|
||||
10
web-app/src/locales/de-DE/tools.json
Normal file
10
web-app/src/locales/de-DE/tools.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"toolApproval": {
|
||||
"title": "Werkzeuggenehmigung erforderlich",
|
||||
"description": "Der Assistent möchte das Werkzeug <strong>{{toolName}}</strong> verwenden.",
|
||||
"securityNotice": "Dieses Werkzeug möchte eine Aktion ausführen. Bitte überprüfen und genehmigen oder Ablehnen.",
|
||||
"deny": "Ablehnen",
|
||||
"allowOnce": "Einmal erlauben",
|
||||
"alwaysAllow": "Immer erlauben"
|
||||
}
|
||||
}
|
||||
10
web-app/src/locales/de-DE/updater.json
Normal file
10
web-app/src/locales/de-DE/updater.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"newVersion": "Neue Version {{version}}",
|
||||
"updateAvailable": "Update Verfügbar",
|
||||
"nightlyBuild": "Nächtlicher Build",
|
||||
"showReleaseNotes": "Zeige Release Notes",
|
||||
"hideReleaseNotes": "Verstecke Release Notes",
|
||||
"remindMeLater": "Erinnere Mich Später",
|
||||
"downloading": "Lade herunter...",
|
||||
"updateNow": "Jetzt Aktualisieren"
|
||||
}
|
||||
@ -2,8 +2,10 @@ import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { createFileRoute, useParams } from '@tanstack/react-router'
|
||||
import { UIEventHandler } from 'react'
|
||||
import debounce from 'lodash.debounce'
|
||||
import cloneDeep from 'lodash.clonedeep'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { ArrowDown } from 'lucide-react'
|
||||
import { Play } from 'lucide-react'
|
||||
|
||||
import HeaderPage from '@/containers/HeaderPage'
|
||||
import { useThreads } from '@/hooks/useThreads'
|
||||
@ -18,7 +20,9 @@ import { useAppState } from '@/hooks/useAppState'
|
||||
import DropdownAssistant from '@/containers/DropdownAssistant'
|
||||
import { useAssistant } from '@/hooks/useAssistant'
|
||||
import { useAppearance } from '@/hooks/useAppearance'
|
||||
import { ContentType, ThreadMessage } from '@janhq/core'
|
||||
import { useTranslation } from '@/i18n/react-i18next-compat'
|
||||
import { useChat } from '@/hooks/useChat'
|
||||
import { useSmallScreen } from '@/hooks/useMediaQuery'
|
||||
|
||||
// as route.threadsDetail
|
||||
@ -38,6 +42,7 @@ function ThreadDetail() {
|
||||
const { setMessages } = useMessages()
|
||||
const { streamingContent } = useAppState()
|
||||
const { appMainViewBgColor, chatWidth } = useAppearance()
|
||||
const { sendMessage } = useChat()
|
||||
const isSmallScreen = useSmallScreen()
|
||||
|
||||
const { messages } = useMessages(
|
||||
@ -180,6 +185,26 @@ function ThreadDetail() {
|
||||
lastScrollTopRef.current = scrollTop
|
||||
}
|
||||
|
||||
const updateMessage = (item: ThreadMessage, message: string) => {
|
||||
const newMessages: ThreadMessage[] = messages.map((m) => {
|
||||
if (m.id === item.id) {
|
||||
const msg: ThreadMessage = cloneDeep(m)
|
||||
msg.content = [
|
||||
{
|
||||
type: ContentType.Text,
|
||||
text: {
|
||||
value: message,
|
||||
annotations: m.content[0].text?.annotations ?? [],
|
||||
},
|
||||
},
|
||||
]
|
||||
return msg
|
||||
}
|
||||
return m
|
||||
})
|
||||
setMessages(threadId, newMessages)
|
||||
}
|
||||
|
||||
// Use a shorter debounce time for more responsive scrolling
|
||||
const debouncedScroll = debounce(handleDOMScroll)
|
||||
|
||||
@ -193,10 +218,22 @@ function ThreadDetail() {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
// used when there is a sent/added user message and no assistant message (error or manual deletion)
|
||||
const generateAIResponse = () => {
|
||||
const latestUserMessage = messages[messages.length - 1]
|
||||
if (latestUserMessage?.content?.[0]?.text?.value) {
|
||||
sendMessage(latestUserMessage.content[0].text.value, false)
|
||||
}
|
||||
}
|
||||
|
||||
const threadModel = useMemo(() => thread?.model, [thread])
|
||||
|
||||
if (!messages || !threadModel) return null
|
||||
|
||||
const showScrollToBottomBtn = !isAtBottom && hasScrollbar
|
||||
const showGenerateAIResponseBtn =
|
||||
messages[messages.length - 1]?.role === 'user' && !streamingContent
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full">
|
||||
<HeaderPage>
|
||||
@ -243,6 +280,7 @@ function ThreadDetail() {
|
||||
))
|
||||
}
|
||||
index={index}
|
||||
updateMessage={updateMessage}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
@ -266,19 +304,31 @@ function ThreadDetail() {
|
||||
appMainViewBgColor.a === 1
|
||||
? 'from-main-view/20 bg-gradient-to-b to-main-view backdrop-blur'
|
||||
: 'bg-transparent',
|
||||
!isAtBottom && hasScrollbar && 'visibility-visible opacity-100'
|
||||
(showScrollToBottomBtn || showGenerateAIResponseBtn) &&
|
||||
'visibility-visible opacity-100'
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className="bg-main-view-fg/10 px-4 border border-main-view-fg/5 flex items-center justify-center rounded-xl gap-x-2 cursor-pointer pointer-events-auto"
|
||||
onClick={() => {
|
||||
scrollToBottom(true)
|
||||
setIsUserScrolling(false)
|
||||
}}
|
||||
>
|
||||
<p className="text-xs">{t('scrollToBottom')}</p>
|
||||
<ArrowDown size={12} />
|
||||
</div>
|
||||
{showScrollToBottomBtn && (
|
||||
<div
|
||||
className="bg-main-view-fg/10 px-4 border border-main-view-fg/5 flex items-center justify-center rounded-xl gap-x-2 cursor-pointer pointer-events-auto"
|
||||
onClick={() => {
|
||||
scrollToBottom(true)
|
||||
setIsUserScrolling(false)
|
||||
}}
|
||||
>
|
||||
<p className="text-xs">{t('scrollToBottom')}</p>
|
||||
<ArrowDown size={12} />
|
||||
</div>
|
||||
)}
|
||||
{showGenerateAIResponseBtn && (
|
||||
<div
|
||||
className="bg-main-view-fg/10 px-4 border border-main-view-fg/5 flex items-center justify-center rounded-xl gap-x-2 cursor-pointer pointer-events-auto"
|
||||
onClick={generateAIResponse}
|
||||
>
|
||||
<p className="text-xs">{t('Generate AI Response')}</p>
|
||||
<Play size={12} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<ChatInput model={threadModel} />
|
||||
</div>
|
||||
|
||||
@ -72,5 +72,13 @@ export default defineConfig(({ mode }) => {
|
||||
ignored: ['**/src-tauri/**'],
|
||||
},
|
||||
},
|
||||
test: {
|
||||
environment: 'jsdom',
|
||||
coverage: {
|
||||
provider: 'v8',
|
||||
reporter: ['json', 'lcov'],
|
||||
reportsDirectory: '../coverage/vitest',
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user