diff --git a/components/Form/CascadeSelect.tsx b/components/Form/CascadeSelect.tsx
deleted file mode 100644
index 4bd662b..0000000
--- a/components/Form/CascadeSelect.tsx
+++ /dev/null
@@ -1,92 +0,0 @@
-import { debounce } from 'lodash';
-import { Component } from 'react';
-import { uniqueID } from 'web-utility';
-
-import { SelectInput } from './SelectInput';
-
-export interface CascadeProps {
- required: boolean;
-}
-
-interface LevelItem {
- label?: string;
- list: string[];
-}
-
-export abstract class CascadeSelect<
- P extends CascadeProps,
-> extends Component
{
- UID = uniqueID();
-
- innerPath: string[] = [];
-
- list: LevelItem[] = [];
-
- get path() {
- return this.innerPath.filter(Boolean).slice(0, -1).join('/');
- }
-
- get name() {
- return this.innerPath.slice(-1)[0];
- }
-
- get pathName() {
- return this.innerPath.filter(Boolean).join('/');
- }
-
- reset() {
- const { innerPath, list } = this;
-
- this.innerPath = [innerPath[0]];
- this.list = [list[0]];
- }
-
- componentDidMount() {
- this.changeLevel(-1, '');
- }
-
- abstract getNextLevel(): Promise;
-
- changeLevel = debounce(async (index: number, value: string) => {
- const { innerPath, list } = this;
-
- innerPath.splice(index, Infinity, value);
-
- const level = await this.getNextLevel();
-
- if (level != null) list.splice(++index, Infinity, level);
- else list.length = ++index;
-
- this.list = list;
- });
-
- render() {
- const { UID, list } = this,
- { required } = this.props;
-
- return (
- <>
- {list.map(({ label, list }, index) => {
- const IID = `input-${UID}-${index}`,
- LID = `list-${UID}-${index}`;
-
- return (
-
-
- (value = value.trim()) && this.changeLevel(index, value)
- }
- required={!index && required}
- />
-
-
- );
- })}
- >
- );
- }
-}
diff --git a/components/Form/JSONEditor/AddBar.tsx b/components/Form/JSONEditor/AddBar.tsx
index 99ec4d0..5d169df 100644
--- a/components/Form/JSONEditor/AddBar.tsx
+++ b/components/Form/JSONEditor/AddBar.tsx
@@ -1,8 +1,10 @@
+import { Icon } from 'idea-react';
import { FC } from 'react';
+import { Button } from 'react-bootstrap';
const type_map = {
- string: { title: 'Inline text', icon: 'grip-lines' },
- text: { title: 'Rows text', icon: 'align-left' },
+ string: { title: 'Inline text', icon: 'input-cursor' },
+ text: { title: 'Rows text', icon: 'text-left' },
object: { title: 'Key-value list', icon: 'list-ul' },
array: { title: 'Ordered list', icon: 'list-ol' },
};
@@ -12,15 +14,17 @@ export interface AddBarProps {
}
export const AddBar: FC = ({ onSelect }) => (
-
+
)}
-
-
-
+
+
+
+
-
+
);
}
}
diff --git a/components/Git/RepositorySelect.tsx b/components/Git/RepositorySelect.tsx
index 43a9ce0..e8aec03 100644
--- a/components/Git/RepositorySelect.tsx
+++ b/components/Git/RepositorySelect.tsx
@@ -4,8 +4,8 @@ import { observer } from 'mobx-react';
import { Component } from 'react';
import { Col, Row } from 'react-bootstrap';
-import { OrganizationModel } from '../../models/Organization';
import { RepositoryModel } from '../../models/Repository';
+import userStore from '../../models/User';
import { SelectInput } from '../Form/SelectInput';
export type RepositoryIdentity = Record<'owner' | 'name', string>;
@@ -16,18 +16,18 @@ export interface RepositorySelectProps {
@observer
export class RepositorySelect extends Component {
- organizationStore = new OrganizationModel();
-
@observable
accessor owner = '';
@computed
get repositoryStore() {
- return new RepositoryModel(this.owner);
+ const { owner } = this;
+
+ return new RepositoryModel(owner === userStore.session?.login ? '' : owner);
}
componentDidMount() {
- this.organizationStore.getAll();
+ userStore.getSession();
}
#disposer = reaction(
@@ -40,10 +40,9 @@ export class RepositorySelect extends Component {
}
render() {
- const organizations = this.organizationStore.allItems,
+ const { namespaces } = userStore,
repositories = this.repositoryStore.allItems,
- downloading =
- this.organizationStore.downloading || this.repositoryStore.downloading;
+ downloading = userStore.downloading || this.repositoryStore.downloading;
return (
@@ -51,8 +50,10 @@ export class RepositorySelect extends Component {
login)}
- onBlur={({ currentTarget: { value } }) => (this.owner = value)}
+ options={namespaces}
+ onBlur={({ currentTarget: { value } }) =>
+ value.trim() && (this.owner = value)
+ }
/>
@@ -60,6 +61,7 @@ export class RepositorySelect extends Component {
className="form-control"
options={repositories.map(({ name }) => name!)}
onBlur={({ currentTarget: { value } }) =>
+ value.trim() &&
this.props.onChange({ owner: this.owner, name: value })
}
/>
diff --git a/models/Organization.ts b/models/Organization.ts
index 6b6f36c..2042cac 100644
--- a/models/Organization.ts
+++ b/models/Organization.ts
@@ -1,5 +1,5 @@
import { components } from '@octokit/openapi-types';
-import { ListModel, Stream } from 'mobx-restful';
+import { ListModel, Stream, toggle } from 'mobx-restful';
import { buildURLData } from 'web-utility';
import { githubClient } from './Base';
@@ -8,7 +8,7 @@ export type Organization = components['schemas']['organization'];
export class OrganizationModel extends Stream(ListModel) {
client = githubClient;
- baseURI = 'user/orgs';
+ baseURI = 'orgs';
async *openStream() {
var per_page = this.pageSize,
@@ -17,7 +17,7 @@ export class OrganizationModel extends Stream(ListModel) {
while (true) {
const { body } = await this.client.get(
- `${this.baseURI}?${buildURLData({ per_page, since })}`,
+ `user/${this.baseURI}?${buildURLData({ per_page, since })}`,
);
if (!body![0]) break;
@@ -29,6 +29,13 @@ export class OrganizationModel extends Stream(ListModel) {
}
this.totalCount = count;
}
+
+ @toggle('downloading')
+ async getOne(name: string) {
+ return this.currentOne.login === name
+ ? this.currentOne
+ : super.getOne(name);
+ }
}
export default new OrganizationModel();
diff --git a/models/Repository.ts b/models/Repository.ts
index 17bc9d0..6e6effb 100644
--- a/models/Repository.ts
+++ b/models/Repository.ts
@@ -1,9 +1,12 @@
import { components } from '@octokit/openapi-types';
+import { encodeBase64 } from 'koajax';
import { memoize } from 'lodash';
import { Filter, ListModel, toggle } from 'mobx-restful';
import { averageOf, buildURLData, makeArray,PickSingle } from 'web-utility';
import { githubClient } from './Base';
+import { OrganizationModel } from './Organization';
+import userStore from './User';
type Repository = components['schemas']['minimal-repository'];
export type Organization = components['schemas']['organization-full'];
@@ -36,11 +39,13 @@ export class RepositoryModel extends ListModel<
baseURI = '';
indexKey = 'full_name' as const;
- constructor(public owner = 'kaiyuanshe') {
+ constructor(public owner = '') {
super();
- this.baseURI = `orgs/${owner}/repos`;
+ this.baseURI = owner ? `orgs/${owner}/repos` : 'user/repos';
}
+ organizationStore = new OrganizationModel();
+
relation = {
issues: memoize(async (URI: string) => {
const { body: issuesList } = await this.client.get(
@@ -93,9 +98,12 @@ export class RepositoryModel extends ListModel<
per_page: number,
{ relation }: RepositoryFilter,
) {
+ const [kind, namespace] = this.baseURI.split('/'),
+ isUser = kind === 'user';
+
const { body: list } = await this.client.get(
`${this.baseURI}?${buildURLData({
- type: 'public',
+ type: isUser ? 'owner' : 'public',
sort: 'pushed',
page,
per_page,
@@ -107,12 +115,17 @@ export class RepositoryModel extends ListModel<
...(await this.getOneRelation(item.full_name, relation)),
})),
);
- const [_, organization] = this.baseURI.split('/');
+ if (!isUser) {
+ const { public_repos } = await this.organizationStore.getOne(namespace);
- const { body } = await this.client.get(
- `orgs/${organization}`,
- );
- return { pageData, totalCount: body!.public_repos };
+ return { pageData, totalCount: public_repos };
+ }
+ const { public_repos, total_private_repos } = await userStore.getSession();
+
+ return {
+ pageData,
+ totalCount: public_repos + (total_private_repos || 0),
+ };
}
@toggle('downloading')
@@ -123,6 +136,29 @@ export class RepositoryModel extends ListModel<
return makeArray(body);
}
+ @toggle('uploading')
+ async updateContent(
+ path: string,
+ content: string | Blob,
+ message = `[update] ${path}`,
+ repository = this.currentOne.name,
+ ) {
+ try {
+ var [{ sha }] = await this.getContents(repository, path);
+ } catch {}
+
+ const { body } = await this.client.put<{
+ content: GitContent;
+ commit: components['schemas']['commit'];
+ }>(`repos/${this.owner}/${repository}/contents/${path}`, {
+ message,
+ content: await encodeBase64(content),
+ // @ts-ignore
+ sha,
+ });
+ return body!.content;
+ }
+
@toggle('downloading')
async downloadRaw(
path: string,
@@ -145,4 +181,4 @@ export class RepositoryModel extends ListModel<
}
}
-export default new RepositoryModel();
+export default new RepositoryModel('kaiyuanshe');
diff --git a/models/User.ts b/models/User.ts
new file mode 100644
index 0000000..53f7fdb
--- /dev/null
+++ b/models/User.ts
@@ -0,0 +1,38 @@
+import { components } from '@octokit/openapi-types';
+import { computed, observable } from 'mobx';
+import { BaseModel, toggle } from 'mobx-restful';
+
+import { githubClient } from './Base';
+import { OrganizationModel } from './Organization';
+
+export type User = components['schemas']['public-user'];
+
+export class UserModel extends BaseModel {
+ client = githubClient;
+
+ @observable
+ accessor session: User | undefined;
+
+ organizationStore = new OrganizationModel();
+
+ @computed
+ get namespaces() {
+ return [
+ this.session?.login,
+ ...this.organizationStore.allItems.map(({ login }) => login),
+ ].filter(Boolean) as string[];
+ }
+
+ @toggle('downloading')
+ async getSession() {
+ if (this.session) return this.session;
+
+ const { body } = await this.client.get('user');
+
+ await this.organizationStore.getAll();
+
+ return (this.session = body!);
+ }
+}
+
+export default new UserModel();
diff --git a/package.json b/package.json
index e2b47cb..99facf4 100644
--- a/package.json
+++ b/package.json
@@ -15,7 +15,7 @@
"copy-webpack-plugin": "^12.0.2",
"file-type": "^19.0.0",
"idea-react": "^2.0.0-rc.2",
- "koajax": "^1.1.1",
+ "koajax": "^1.1.2",
"less": "^4.2.0",
"less-loader": "^12.2.0",
"license-filter": "^0.2.4",
@@ -43,7 +43,7 @@
"turndown-plugin-gfm": "^1.0.2",
"web-utility": "^4.4.0",
"webpack": "^5.91.0",
- "yaml": "^2.4.2"
+ "yaml": "^2.4.3"
},
"devDependencies": {
"@babel/plugin-proposal-decorators": "^7.24.6",
@@ -51,7 +51,7 @@
"@babel/preset-react": "^7.24.6",
"@octokit/openapi-types": "^22.2.0",
"@types/lodash": "^4.17.4",
- "@types/node": "^18.19.33",
+ "@types/node": "^18.19.34",
"@types/react": "^18.3.3",
"@types/turndown": "^5.0.4",
"eslint": "^8.57.0",
@@ -60,7 +60,7 @@
"eslint-plugin-simple-import-sort": "^12.1.0",
"husky": "^9.0.11",
"lint-staged": "^15.2.5",
- "prettier": "^3.2.5",
+ "prettier": "^3.3.0",
"typescript": "~5.4.5"
},
"prettier": {
diff --git a/pages/api/GitHub/raw/[...slug].ts b/pages/api/GitHub/raw/[...slug].ts
index 41e3ff2..a7f9ac3 100644
--- a/pages/api/GitHub/raw/[...slug].ts
+++ b/pages/api/GitHub/raw/[...slug].ts
@@ -29,6 +29,6 @@ export default safeAPI(async ({ method, url, headers, body }, response) => {
const { mime } = (await fileTypeFromBuffer(buffer)) || {};
response.status(status);
- response.setHeader('Content-Type', mime || 'text/plain');
+ response.setHeader('Content-Type', mime || 'application/octet-stream');
response.send(buffer);
});
diff --git a/pages/index.tsx b/pages/index.tsx
index f0a2d0b..2187c60 100644
--- a/pages/index.tsx
+++ b/pages/index.tsx
@@ -18,7 +18,7 @@ export const getServerSideProps = compose(
errorLogger,
translator(i18n),
async () => {
- const list = await new RepositoryModel().getList({
+ const list = await new RepositoryModel('kaiyuanshe').getList({
relation: ['languages'],
});
return { props: { list } };
diff --git a/pages/issue.tsx b/pages/issue.tsx
index 759b913..20c1cfe 100644
--- a/pages/issue.tsx
+++ b/pages/issue.tsx
@@ -12,8 +12,9 @@ import repositoryStore, { RepositoryModel } from '../models/Repository';
import { i18n } from '../models/Translation';
export const getServerSideProps = compose(translator(i18n), async () => {
- const list = await new RepositoryModel().getList({ relation: ['issues'] });
-
+ const list = await new RepositoryModel('kaiyuanshe').getList({
+ relation: ['issues'],
+ });
return { props: { list } };
});
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1cd1a05..8de8ef1 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -33,8 +33,8 @@ importers:
specifier: ^2.0.0-rc.2
version: 2.0.0-rc.2(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
koajax:
- specifier: ^1.1.1
- version: 1.1.1(typescript@5.4.5)
+ specifier: ^1.1.2
+ version: 1.1.2(typescript@5.4.5)
less:
specifier: ^4.2.0
version: 4.2.0
@@ -117,8 +117,8 @@ importers:
specifier: ^5.91.0
version: 5.91.0
yaml:
- specifier: ^2.4.2
- version: 2.4.2
+ specifier: ^2.4.3
+ version: 2.4.3
devDependencies:
'@babel/plugin-proposal-decorators':
specifier: ^7.24.6
@@ -136,8 +136,8 @@ importers:
specifier: ^4.17.4
version: 4.17.4
'@types/node':
- specifier: ^18.19.33
- version: 18.19.33
+ specifier: ^18.19.34
+ version: 18.19.34
'@types/react':
specifier: ^18.3.3
version: 18.3.3
@@ -163,8 +163,8 @@ importers:
specifier: ^15.2.5
version: 15.2.5
prettier:
- specifier: ^3.2.5
- version: 3.2.5
+ specifier: ^3.3.0
+ version: 3.3.0
typescript:
specifier: ~5.4.5
version: 5.4.5
@@ -1472,8 +1472,8 @@ packages:
'@types/mysql@2.15.22':
resolution: {integrity: sha512-wK1pzsJVVAjYCSZWQoWHziQZbNggXFDUEIGf54g4ZM/ERuP86uGdWeKZWMYlqTPMZfHJJvLPyogXGvCOg87yLQ==}
- '@types/node@18.19.33':
- resolution: {integrity: sha512-NR9+KrpSajr2qBVp/Yt5TU/rp+b5Mayi3+OlMlcg2cVCfRmcG5PWZ7S4+MG9PZ5gWBoc9Pd0BKSRViuBCRPu0A==}
+ '@types/node@18.19.34':
+ resolution: {integrity: sha512-eXF4pfBNV5DAMKGbI02NnDtWrQ40hAN558/2vvS4gMpMIxaf6JmD7YjnZbq0Q9TDSSkKBamime8ewRoomHdt4g==}
'@types/pg-pool@2.0.4':
resolution: {integrity: sha512-qZAvkv1K3QbmHHFYSNRYPkRjOWRLBYrL4B9c+wG0GSVGBw0NtJwPcgx/DSddeDJvRGMHCEQ4VMEVfuJ/0gZ3XQ==}
@@ -2883,8 +2883,8 @@ packages:
peerDependencies:
jsdom: '>=21'
- koajax@1.1.1:
- resolution: {integrity: sha512-ALT3qAv4LaNEU6g3Y1pbMGhf3VRMxxaFXQtw9yW6fqYSFlXL2qWlsQVdSAha0FCyCbrp59dj7SzzKdiWN98zxA==}
+ koajax@1.1.2:
+ resolution: {integrity: sha512-TGWJhGpojfSYdqGIKK8CWwMhUY1LYDyvodt6LywHVYEH6qq38/3DgW+FKTCV88O59G0J4W2XFbBTF8nvZ/J/nw==}
peerDependencies:
jsdom: '>=21'
@@ -3594,8 +3594,8 @@ packages:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
- prettier@3.2.5:
- resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==}
+ prettier@3.3.0:
+ resolution: {integrity: sha512-J9odKxERhCQ10OC2yb93583f6UnYutOeiV5i0zEDS7UGTdUt0u+y8erxl3lBKvwo/JHyyoEdXjwp4dke9oyZ/g==}
engines: {node: '>=14'}
hasBin: true
@@ -4432,8 +4432,8 @@ packages:
yallist@3.1.1:
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
- yaml@2.4.2:
- resolution: {integrity: sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==}
+ yaml@2.4.3:
+ resolution: {integrity: sha512-sntgmxj8o7DE7g/Qi60cqpLBA3HG3STcDA0kO+WfB05jEKhZMbY7umNm2rBpQvsmZ16/lPXCJGW2672dgOUkrg==}
engines: {node: '>= 14'}
hasBin: true
@@ -5932,7 +5932,7 @@ snapshots:
'@types/accepts@1.3.7':
dependencies:
- '@types/node': 18.19.33
+ '@types/node': 18.19.34
'@types/acorn@4.0.6':
dependencies:
@@ -5941,15 +5941,15 @@ snapshots:
'@types/body-parser@1.19.5':
dependencies:
'@types/connect': 3.4.38
- '@types/node': 18.19.33
+ '@types/node': 18.19.34
'@types/connect@3.4.36':
dependencies:
- '@types/node': 18.19.33
+ '@types/node': 18.19.34
'@types/connect@3.4.38':
dependencies:
- '@types/node': 18.19.33
+ '@types/node': 18.19.34
'@types/content-disposition@0.5.8': {}
@@ -5958,7 +5958,7 @@ snapshots:
'@types/connect': 3.4.38
'@types/express': 4.17.21
'@types/keygrip': 1.0.6
- '@types/node': 18.19.33
+ '@types/node': 18.19.34
'@types/debug@4.1.12':
dependencies:
@@ -5984,7 +5984,7 @@ snapshots:
'@types/express-serve-static-core@4.19.3':
dependencies:
- '@types/node': 18.19.33
+ '@types/node': 18.19.34
'@types/qs': 6.9.15
'@types/range-parser': 1.2.7
'@types/send': 0.17.4
@@ -5999,7 +5999,7 @@ snapshots:
'@types/glob@7.2.0':
dependencies:
'@types/minimatch': 5.1.2
- '@types/node': 18.19.33
+ '@types/node': 18.19.34
'@types/hast@3.0.4':
dependencies:
@@ -6028,7 +6028,7 @@ snapshots:
'@types/http-errors': 2.0.4
'@types/keygrip': 1.0.6
'@types/koa-compose': 3.2.8
- '@types/node': 18.19.33
+ '@types/node': 18.19.34
'@types/koa__router@12.0.3':
dependencies:
@@ -6050,9 +6050,9 @@ snapshots:
'@types/mysql@2.15.22':
dependencies:
- '@types/node': 18.19.33
+ '@types/node': 18.19.34
- '@types/node@18.19.33':
+ '@types/node@18.19.34':
dependencies:
undici-types: 5.26.5
@@ -6062,7 +6062,7 @@ snapshots:
'@types/pg@8.6.1':
dependencies:
- '@types/node': 18.19.33
+ '@types/node': 18.19.34
pg-protocol: 1.6.1
pg-types: 2.2.0
@@ -6083,17 +6083,17 @@ snapshots:
'@types/resolve@1.17.1':
dependencies:
- '@types/node': 18.19.33
+ '@types/node': 18.19.34
'@types/send@0.17.4':
dependencies:
'@types/mime': 1.3.5
- '@types/node': 18.19.33
+ '@types/node': 18.19.34
'@types/serve-static@1.15.7':
dependencies:
'@types/http-errors': 2.0.4
- '@types/node': 18.19.33
+ '@types/node': 18.19.34
'@types/send': 0.17.4
'@types/shimmer@1.0.5': {}
@@ -7668,13 +7668,13 @@ snapshots:
jest-worker@26.6.2:
dependencies:
- '@types/node': 18.19.33
+ '@types/node': 18.19.34
merge-stream: 2.0.0
supports-color: 7.2.0
jest-worker@27.5.1:
dependencies:
- '@types/node': 18.19.33
+ '@types/node': 18.19.34
merge-stream: 2.0.0
supports-color: 8.1.1
@@ -7760,7 +7760,7 @@ snapshots:
transitivePeerDependencies:
- typescript
- koajax@1.1.1(typescript@5.4.5):
+ koajax@1.1.2(typescript@5.4.5):
dependencies:
'@swc/helpers': 0.5.11
iterable-observer: 1.0.1
@@ -7819,7 +7819,7 @@ snapshots:
micromatch: 4.0.7
pidtree: 0.6.0
string-argv: 0.3.2
- yaml: 2.4.2
+ yaml: 2.4.3
transitivePeerDependencies:
- supports-color
@@ -8756,7 +8756,7 @@ snapshots:
prelude-ls@1.2.1: {}
- prettier@3.2.5: {}
+ prettier@3.3.0: {}
pretty-bytes@5.6.0: {}
@@ -8945,7 +8945,7 @@ snapshots:
estree-util-value-to-estree: 3.1.1
toml: 3.0.0
unified: 11.0.4
- yaml: 2.4.2
+ yaml: 2.4.3
remark-mdx@3.0.1:
dependencies:
@@ -9805,7 +9805,7 @@ snapshots:
yallist@3.1.1: {}
- yaml@2.4.2: {}
+ yaml@2.4.3: {}
yocto-queue@0.1.0: {}