feat: Initial clean release of CHM
一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
这个提交包含在:
158
packages/lib/WelcomeUtils.ts
普通文件
158
packages/lib/WelcomeUtils.ts
普通文件
@@ -0,0 +1,158 @@
|
||||
const welcomeAssetsAny = require('./welcomeAssets');
|
||||
import Note from './models/Note';
|
||||
import { Dispatch } from 'redux';
|
||||
import Setting from './models/Setting';
|
||||
import Folder from './models/Folder';
|
||||
import shim, { MobilePlatform } from './shim';
|
||||
import uuid from './uuid';
|
||||
import { fileExtension, basename } from './path-utils';
|
||||
import { _ } from './locale';
|
||||
import { pregQuote } from './string-utils';
|
||||
import { FolderIconType } from './services/database/types';
|
||||
|
||||
export enum WelcomeAssetPlatform {
|
||||
Desktop = 'desktop',
|
||||
Cli = 'cli',
|
||||
Mobile = 'mobile',
|
||||
Web = 'web',
|
||||
}
|
||||
|
||||
export interface ItemMetadatum {
|
||||
id: string;
|
||||
platform?: WelcomeAssetPlatform;
|
||||
}
|
||||
|
||||
export type ItemMetadata = Record<string, ItemMetadatum>;
|
||||
|
||||
export interface CreateWelcomeItemsResult {
|
||||
defaultFolderId: string;
|
||||
}
|
||||
|
||||
export interface WelcomeAssetResource {
|
||||
id: string;
|
||||
body: string;
|
||||
}
|
||||
|
||||
export interface WelcomeAssetNote {
|
||||
id: string;
|
||||
parent_id: string;
|
||||
title: string;
|
||||
body: string;
|
||||
resources: Record<string, WelcomeAssetResource>;
|
||||
platform?: WelcomeAssetPlatform;
|
||||
}
|
||||
|
||||
export interface WelcomeAssetFolder {
|
||||
id: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export interface AssetContent {
|
||||
notes: WelcomeAssetNote[];
|
||||
folders: WelcomeAssetFolder[];
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
export type WelcomeAssets = Record<string, AssetContent>;
|
||||
|
||||
class WelcomeUtils {
|
||||
|
||||
public static async createWelcomeItems(locale: string, platform: WelcomeAssetPlatform): Promise<CreateWelcomeItemsResult> {
|
||||
const output: CreateWelcomeItemsResult = {
|
||||
defaultFolderId: null,
|
||||
};
|
||||
|
||||
const allWelcomeAssets = welcomeAssetsAny as WelcomeAssets;
|
||||
const welcomeAssets = locale in allWelcomeAssets ? allWelcomeAssets[locale] : allWelcomeAssets['en_GB'];
|
||||
const enGbWelcomeAssets = allWelcomeAssets['en_GB'];
|
||||
|
||||
const folderAssets = welcomeAssets.folders;
|
||||
const tempDir = Setting.value('resourceDir');
|
||||
|
||||
// Actually we don't really support multiple folders at this point, because not needed
|
||||
for (let i = 0; i < folderAssets.length; i++) {
|
||||
const folderIcon = {
|
||||
emoji: '👋',
|
||||
name: '',
|
||||
dataUrl: '',
|
||||
type: FolderIconType.Emoji,
|
||||
};
|
||||
const folder = await Folder.save({
|
||||
title: _('Welcome!'),
|
||||
icon: Folder.serializeIcon(folderIcon),
|
||||
});
|
||||
if (!output.defaultFolderId) output.defaultFolderId = folder.id;
|
||||
}
|
||||
|
||||
const noteAssets = welcomeAssets.notes;
|
||||
|
||||
for (let i = noteAssets.length - 1; i >= 0; i--) {
|
||||
const noteAsset = noteAssets[i];
|
||||
const enGbNoteAsset = enGbWelcomeAssets.notes[i];
|
||||
|
||||
if (noteAsset.platform && noteAsset.platform !== platform) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let noteBody = noteAsset.body;
|
||||
|
||||
for (const resourceUrl in enGbNoteAsset.resources) {
|
||||
if (!enGbNoteAsset.resources.hasOwnProperty(resourceUrl)) continue;
|
||||
const resourceAsset = enGbNoteAsset.resources[resourceUrl];
|
||||
const ext = fileExtension(resourceUrl);
|
||||
const tempFilePath = `${tempDir}/${uuid.create()}.tmp.${ext}`;
|
||||
await shim.fsDriver().writeFile(tempFilePath, resourceAsset.body, 'base64');
|
||||
const resource = await shim.createResourceFromPath(tempFilePath, {
|
||||
title: basename(resourceUrl),
|
||||
});
|
||||
await shim.fsDriver().remove(tempFilePath);
|
||||
|
||||
const regex = new RegExp(pregQuote(`(${resourceUrl})`), 'g');
|
||||
noteBody = noteBody.replace(regex, `(:/${resource.id})`);
|
||||
}
|
||||
|
||||
await Note.save({
|
||||
parent_id: output.defaultFolderId,
|
||||
title: noteAsset.title,
|
||||
body: noteBody,
|
||||
});
|
||||
|
||||
// if (noteAsset.tags) await Tag.setNoteTagsByTitles(note.id, noteAsset.tags);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
private static detectPlatform_() {
|
||||
if (shim.mobilePlatform() === MobilePlatform.Web) {
|
||||
return WelcomeAssetPlatform.Web;
|
||||
} else if (shim.mobilePlatform()) {
|
||||
return WelcomeAssetPlatform.Mobile;
|
||||
} else if (shim.isElectron()) {
|
||||
return WelcomeAssetPlatform.Desktop;
|
||||
} else {
|
||||
return WelcomeAssetPlatform.Cli;
|
||||
}
|
||||
}
|
||||
|
||||
public static async install(locale: string, dispatch: Dispatch) {
|
||||
if (!Setting.value('welcome.enabled')) {
|
||||
Setting.setValue('welcome.wasBuilt', true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Setting.value('welcome.wasBuilt')) {
|
||||
const result = await WelcomeUtils.createWelcomeItems(locale, this.detectPlatform_());
|
||||
Setting.setValue('welcome.wasBuilt', true);
|
||||
|
||||
dispatch({
|
||||
type: 'FOLDER_SELECT',
|
||||
id: result.defaultFolderId,
|
||||
});
|
||||
|
||||
Setting.setValue('activeFolderId', result.defaultFolderId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default WelcomeUtils;
|
||||
在新工单中引用
屏蔽一个用户