Skip to content

Commit

Permalink
Enable document upload feature for native mode
Browse files Browse the repository at this point in the history
In Native mode, taxonomy-knowledge-docs repo is cloned
in the $HOME/.instructlab-ui/ directory and the docs are
committed to the main branch. Commit sha of that branch is
used in the knowledge contribution.

In knowledge yaml, document url points to the filepath
location of the taxonomy-knowledge-docs.

Signed-off-by: Anil Vishnoi <[email protected]>
  • Loading branch information
vishnoianil committed Dec 12, 2024
1 parent d71c733 commit 1bf55ca
Show file tree
Hide file tree
Showing 52 changed files with 619 additions and 204 deletions.
9 changes: 5 additions & 4 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@ IL_GRANITE_API=<GRANITE_HOST>
IL_GRANITE_MODEL_NAME=<GRANITE_MODEL_NAME>
IL_MERLINITE_API=<MERLINITE_HOST>
IL_MERLINITE_MODEL_NAME=<MERLINITE_MODEL_NAME>
IL_UI_DEPLOYMENT=dev ## Comment it out if it's not a dev deployment

IL_UI_DEPLOYMENT=native # Two deployment modes are available: github and native
IL_ENABLE_DEV_MODE=true #Enable this option if you want to enable UI features that helps in development, such as form Auto-Fill feature.

GITHUB_TOKEN=<TOKEN FOR OAUTH INSTRUCTLAB MEMBER LOOKUP>
TAXONOMY_DOCUMENTS_REPO=github.com/instructlab-public/taxonomy-knowledge-docs
NEXT_PUBLIC_AUTHENTICATION_ORG=<AUTHENTICATION_ORG>
NEXT_PUBLIC_TAXONOMY_REPO_OWNER=<GITHUB_ACCOUNT>
NEXT_PUBLIC_TAXONOMY_REPO=<REPO_NAME>

NEXT_PUBLIC_TAXONOMY_REPO_DIR=

NEXT_PUBLIC_EXPERIMENTAL_FEATURES=false
# The following requires experimental and dev mode to be enabled
# NEXT_PUBLIC_BASE_CLONE_DIRECTORY=/base/path/
# NEXT_PUBLIC_LOCAL_REPO_PATH=/base/path/cloned_dir_name
2 changes: 1 addition & 1 deletion src/app/api/native/clone-repo/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import fs from 'fs';
import path from 'path';

// Retrieve the base directory from the environment variable
const LOCAL_TAXONOMY_ROOT_DIR = process.env.NEXT_PUBLIC_LOCAL_TAXONOMY_ROOT_DIR || './.instructlab-ui';
const LOCAL_TAXONOMY_ROOT_DIR = process.env.NEXT_PUBLIC_LOCAL_TAXONOMY_ROOT_DIR || `${process.env.HOME}/.instructlab-ui`;
const TAXONOMY_REPO_URL = process.env.NEXT_PUBLIC_TAXONOMY_REPO_URL || 'https://github.com/instructlab/taxonomy.git';

export async function POST() {
Expand Down
98 changes: 98 additions & 0 deletions src/app/api/native/upload/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// src/app/api/native/upload/route.ts
import { NextResponse } from 'next/server';
import { NextRequest } from 'next/server';
import * as git from 'isomorphic-git';
import http from 'isomorphic-git/http/node';
import path from 'path';
import fs from 'fs';

const LOCAL_TAXONOMY_DOCS_ROOT_DIR = process.env.NEXT_PUBLIC_LOCAL_TAXONOMY_ROOT_DIR || `${process.env.HOME}/.instructlab-ui`;
const TAXONOMY_KNOWLEDGE_DOCS_REPO_URL = 'https://github.com/instructlab-public/taxonomy-knowledge-docs.git';

export async function POST(req: NextRequest) {
try {
const body = await req.json();
const { files } = body;
const docsRepoUrl = await cloneTaxonomyDocsRepo();

// If the repository was not cloned, return an error
if (!docsRepoUrl) {
return NextResponse.json({ error: 'Failed to clone taxonomy knowledge docs repository' }, { status: 500 });
}

const timestamp = new Date().toISOString().replace(/[-:.]/g, '').replace('T', 'T').slice(0, -1);
const filesWithTimestamp = files.map((file: { fileName: string; fileContent: string }) => {
const [name, extension] = file.fileName.split(/\.(?=[^.]+$)/);
return {
fileName: `${name}-${timestamp}.${extension}`,
fileContent: file.fileContent
};
});

// Write the files to the repository
for (const file of filesWithTimestamp) {
const filePath = path.join(docsRepoUrl, file.fileName);
fs.writeFileSync(filePath, file.fileContent);
}

// Checkout the main branch
await git.checkout({ fs, dir: docsRepoUrl, ref: 'main' });

// Stage the files
await git.add({ fs, dir: docsRepoUrl, filepath: '.' });

// Commit the files
const commitSha = await git.commit({
fs,
dir: docsRepoUrl,
author: { name: 'instructlab-ui', email: '[email protected]' },
message: `Add files: ${files
.map((file: { fileName: string; fileContent: string }) => file.fileName)
.join(', ')}\n\nSigned-off-by: [email protected]`
});

return NextResponse.json(
{
repoUrl: docsRepoUrl,
commitSha,
documentNames: filesWithTimestamp.map((file: { fileName: string }) => file.fileName),
prUrl: ''
},
{ status: 201 }
);
} catch (error) {
console.error('Failed to upload documents:', error);
return NextResponse.json({ error: 'Failed to upload documents' }, { status: 500 });
}
}

async function cloneTaxonomyDocsRepo() {
const taxonomyDocsDirectoryPath = path.join(LOCAL_TAXONOMY_DOCS_ROOT_DIR, '/taxonomy-knowledge-docs');
console.log(`Cloning taxonomy docs repository to ${taxonomyDocsDirectoryPath}...`);

if (fs.existsSync(taxonomyDocsDirectoryPath)) {
console.log(`Using existing taxonomy knowledge docs repository at ${taxonomyDocsDirectoryPath}.`);
return taxonomyDocsDirectoryPath;
} else {
console.log(`Taxonomy knowledge docs repository not found at ${taxonomyDocsDirectoryPath}. Cloning...`);
}

try {
await git.clone({
fs,
http,
dir: taxonomyDocsDirectoryPath,
url: TAXONOMY_KNOWLEDGE_DOCS_REPO_URL,
singleBranch: true,
depth: 1
});

// Include the full path in the response for client display
console.log(`Repository cloned successfully to ${taxonomyDocsDirectoryPath}.`);
return taxonomyDocsDirectoryPath;
} catch (error: unknown) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
console.error(`Failed to clone taxonomy docs repository: ${errorMessage}`);
return null;
}
}
4 changes: 2 additions & 2 deletions src/app/contribute/knowledge/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// src/app/contribute/knowledge/page.tsx
import KnowledgeFormNative from '@/components/Contribute/Native/Knowledge';
import KnowledgeFormNative from '@/components/Contribute/Knowledge/Native';
import * as React from 'react';
import { AppLayout } from '../../../components/AppLayout';
import { KnowledgeFormGithub } from '../../../components/Contribute/Github/Knowledge';
import { KnowledgeFormGithub } from '../../../components/Contribute/Knowledge/Github';

const KnowledgeFormPage: React.FC = () => {
return <AppLayout>{process.env.IL_UI_DEPLOYMENT === 'native' ? <KnowledgeFormNative /> : <KnowledgeFormGithub />}</AppLayout>;
Expand Down
4 changes: 2 additions & 2 deletions src/app/contribute/skill/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// src/app/contribute/skill/page.tsx
import SkillFormNative from '@/components/Contribute/Native/Skill';
import SkillFormNative from '@/components/Contribute/Skill/Native';
import * as React from 'react';
import { AppLayout } from '../../../components/AppLayout';
import { SkillFormGithub } from '../../../components/Contribute/Github/Skill';
import { SkillFormGithub } from '../../../components/Contribute/Skill/Github';

const SkillFormPage: React.FC = () => {
return <AppLayout>{process.env.IL_UI_DEPLOYMENT === 'native' ? <SkillFormNative /> : <SkillFormGithub />}</AppLayout>;
Expand Down
2 changes: 1 addition & 1 deletion src/app/edit-submission/knowledge/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// src/app/edit-submission/knowledge/[id]/page.tsx
import * as React from 'react';
import { AppLayout } from '@/components/AppLayout';
import EditKnowledge from '@/components/Contribute/Github/EditKnowledge/EditKnowledge';
import EditKnowledge from '@/components/Contribute/EditKnowledge/EditKnowledge';

type PageProps = {
params: Promise<{ id: string }>;
Expand Down
2 changes: 1 addition & 1 deletion src/app/edit-submission/skill/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// src/app/edit-submission/skill/[id]/page.tsx
import * as React from 'react';
import { AppLayout } from '@/components/AppLayout';
import EditSkill from '@/components/Contribute/Github/EditSkill/EditSkill';
import EditSkill from '@/components/Contribute/EditSkill/EditSkill';

type PageProps = {
params: Promise<{ id: string }>;
Expand Down
4 changes: 2 additions & 2 deletions src/components/Contribute/AuthorInformation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { HelperText } from '@patternfly/react-core/dist/dynamic/components/Helpe
import { HelperTextItem } from '@patternfly/react-core/dist/dynamic/components/HelperText';
import ExclamationCircleIcon from '@patternfly/react-icons/dist/dynamic/icons/exclamation-circle-icon';
import { ValidatedOptions } from '@patternfly/react-core/dist/esm/helpers/constants';
import { checkSkillFormCompletion } from './Github/Skill/validation';
import { checkKnowledgeFormCompletion } from './Github/Knowledge/validation';
import { checkSkillFormCompletion } from './Skill/validation';
import { checkKnowledgeFormCompletion } from './Knowledge/validation';

export enum FormType {
Knowledge,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import KnowledgeFormGithub, {
KnowledgeFormData,
QuestionAndAnswerPair,
SeedExample
} from '@/components/Contribute/Github/Knowledge';
} from '@/components/Contribute/Knowledge/Github';
import { ValidatedOptions } from '@patternfly/react-core/dist/esm/helpers/constants';
import { useEffect, useState } from 'react';
import { Modal, ModalVariant } from '@patternfly/react-core/dist/esm/deprecated/components/Modal/Modal';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import { useEffect, useState } from 'react';
import { ValidatedOptions } from '@patternfly/react-core/dist/esm/helpers/constants';
import { Modal, ModalVariant } from '@patternfly/react-core/dist/esm/deprecated/components/Modal/Modal';
import { useRouter } from 'next/navigation';
import SkillFormGithub, { SkillEditFormData, SkillFormData, SeedExample } from '@/components/Contribute/Github/Skill';
import SkillFormGithub, { SkillEditFormData } from '@/components/Contribute/Skill/Github';
import { fetchPullRequest, fetchFileContent, fetchPullRequestFiles } from '@/utils/github';
import yaml from 'js-yaml';
import axios from 'axios';
import { SkillYamlData, AttributionData, PullRequestFile } from '@/types';
import { SkillYamlData, AttributionData, PullRequestFile, SkillFormData, SkillSeedExample } from '@/types';
import { SkillSchemaVersion } from '@/types/const';

interface EditSkillClientComponentProps {
Expand Down Expand Up @@ -72,9 +72,9 @@ const EditSkill: React.FC<EditSkillClientComponentProps> = ({ prNumber }) => {
// Populate the form fields with YAML data
skillExistingFormData.documentOutline = yamlData.task_description;

const seedExamples: SeedExample[] = [];
const seedExamples: SkillSeedExample[] = [];
yamlData.seed_examples.forEach((seed, index) => {
const example: SeedExample = {
const example: SkillSeedExample = {
immutable: index < 5 ? true : false,
isExpanded: true,
context: seed.context || '',
Expand Down
31 changes: 0 additions & 31 deletions src/components/Contribute/Github/Knowledge/knowledge.css

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { HelperText } from '@patternfly/react-core/dist/dynamic/components/Helpe
import { HelperTextItem } from '@patternfly/react-core/dist/dynamic/components/HelperText';
import ExclamationCircleIcon from '@patternfly/react-icons/dist/dynamic/icons/exclamation-circle-icon';
import { ValidatedOptions } from '@patternfly/react-core/dist/esm/helpers/constants';
import { KnowledgeFormData } from '..';
import { KnowledgeFormData } from '../Github';
import { checkKnowledgeFormCompletion } from '../validation';

interface Props {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { KnowledgeFormData, QuestionAndAnswerPair, SeedExample } from '.';
import { KnowledgeFormData, QuestionAndAnswerPair, SeedExample } from './Github';
import { ValidatedOptions } from '@patternfly/react-core/dist/esm/helpers/constants';

const questionAndAnswerPairs1: QuestionAndAnswerPair[] = [
Expand Down Expand Up @@ -238,12 +238,12 @@ const seedExamples: SeedExample[] = [
{
immutable: true,
isExpanded: true,
context: `Phoenix is the radiant of two annual meteor showers. The Phoenicids,
also known as the December Phoenicids, were first observed on 3 December 1887.
The shower was particularly intense in December 1956, and is thought related
to the breakup of the short-period comet 289P/Blanpain. It peaks around 4–5
December, though is not seen every year.[58] A very minor meteor shower peaks
around July 14 with around one meteor an hour, though meteors can be seen
context: `Phoenix is the radiant of two annual meteor showers. The Phoenicids,
also known as the December Phoenicids, were first observed on 3 December 1887.
The shower was particularly intense in December 1956, and is thought related
to the breakup of the short-period comet 289P/Blanpain. It peaks around 4–5
December, though is not seen every year.[58] A very minor meteor shower peaks
around July 14 with around one meteor an hour, though meteors can be seen
anytime from July 3 to 18; this shower is referred to as the July Phoenicids.[59]`,
isContextValid: ValidatedOptions.success,
questionAndAnswers: questionAndAnswerPairs5
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { KnowledgeFormData } from '..';
import { KnowledgeFormData } from '../Github';
import { DropdownItem } from '@patternfly/react-core/dist/esm/components/Dropdown/DropdownItem';
import FileIcon from '@patternfly/react-icons/dist/esm/icons/file-icon';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { DropdownList } from '@patternfly/react-core/dist/dynamic/components/Dro
import { MenuToggle, MenuToggleElement } from '@patternfly/react-core/dist/dynamic/components/MenuToggle';
import DownloadYaml from '../DownloadYaml/DownloadYaml';
import DownloadAttribution from '../DownloadAttribution/DownloadAttribution';
import { KnowledgeFormData } from '..';
import { KnowledgeFormData } from '../Github';
import DownloadIcon from '@patternfly/react-icons/dist/esm/icons/download-icon';

interface Props {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { KnowledgeFormData } from '..';
import { KnowledgeFormData } from '../Github';
import { KnowledgeYamlData } from '@/types';
import { KnowledgeSchemaVersion } from '@/types/const';
import { dumpYaml } from '@/utils/yamlConfig';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import React, { useEffect, useState } from 'react';
import { FormFieldGroupHeader, FormGroup, FormHelperText } from '@patternfly/react-core/dist/dynamic/components/Form';
import { Button } from '@patternfly/react-core/dist/dynamic/components/Button';
import { TextInput } from '@patternfly/react-core/dist/dynamic/components/TextInput';
import { UploadFile } from '../UploadFile';
import { UploadFile } from '../../UploadFile';
import { Alert, AlertActionLink, AlertActionCloseButton } from '@patternfly/react-core/dist/dynamic/components/Alert';
import { HelperText } from '@patternfly/react-core/dist/dynamic/components/HelperText';
import { HelperTextItem } from '@patternfly/react-core/dist/dynamic/components/HelperText';
import ExclamationCircleIcon from '@patternfly/react-icons/dist/dynamic/icons/exclamation-circle-icon';
import { ValidatedOptions } from '@patternfly/react-core/dist/esm/helpers/constants';
import { KnowledgeFormData } from '..';
import { checkKnowledgeFormCompletion } from '../validation';
import { checkKnowledgeFormCompletion } from '../../validation';
import { Modal, ModalVariant } from '@patternfly/react-core/dist/esm/deprecated/components/Modal/Modal';

interface Props {
Expand Down Expand Up @@ -158,7 +158,9 @@ const DocumentInformation: React.FC<Props> = ({
console.log('Files uploaded:', result.documentNames);
setSuccessAlertTitle('Document uploaded successfully!');
setSuccessAlertMessage('Documents have been uploaded to your repo to be referenced in the knowledge submission.');
setSuccessAlertLink(result.prUrl);
if (result.prUrl !== '') {
setSuccessAlertLink(result.prUrl);
}
}
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ActionGroupAlertContent, KnowledgeFormData } from '..';
import { AttributionData, KnowledgeYamlData } from '@/types';
import { KnowledgeSchemaVersion } from '@/types/const';
import { dumpYaml } from '@/utils/yamlConfig';
import { validateFields } from '../validation';
import { validateFields } from '../../validation';

interface Props {
disableAction: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ActionGroupAlertContent, KnowledgeFormData } from '..';
import { AttributionData, KnowledgeYamlData, PullRequestFile } from '@/types';
import { KnowledgeSchemaVersion } from '@/types/const';
import { dumpYaml } from '@/utils/yamlConfig';
import { validateFields } from '../validation';
import { validateFields } from '../../validation';
import { amendCommit, getGitHubUsername, updatePullRequest } from '@/utils/github';
import { useSession } from 'next-auth/react';
import { useRouter } from 'next/navigation';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
// src/components/Contribute/Knowledge/index.tsx
'use client';
import React, { useEffect, useState } from 'react';
import './knowledge.css';
import '../knowledge.css';
import { Alert, AlertActionCloseButton } from '@patternfly/react-core/dist/dynamic/components/Alert';
import { ActionGroup } from '@patternfly/react-core/dist/dynamic/components/Form';
import { Form } from '@patternfly/react-core/dist/dynamic/components/Form';
import { getGitHubUsername } from '../../../../utils/github';
import { useSession } from 'next-auth/react';
import AuthorInformation from '../../AuthorInformation';
import { FormType } from '../../AuthorInformation';
import KnowledgeInformation from './KnowledgeInformation/KnowledgeInformation';
import FilePathInformation from './FilePathInformation/FilePathInformation';
import KnowledgeInformation from '../KnowledgeInformation/KnowledgeInformation';
import FilePathInformation from '../FilePathInformation/FilePathInformation';
import DocumentInformation from './DocumentInformation/DocumentInformation';
import AttributionInformation from './AttributionInformation/AttributionInformation';
import AttributionInformation from '../AttributionInformation/AttributionInformation';
import Submit from './Submit/Submit';
import { Breadcrumb } from '@patternfly/react-core/dist/dynamic/components/Breadcrumb';
import { BreadcrumbItem } from '@patternfly/react-core/dist/dynamic/components/Breadcrumb';
Expand All @@ -22,17 +22,17 @@ import { PageSection } from '@patternfly/react-core/dist/dynamic/components/Page
import { Content } from '@patternfly/react-core/dist/dynamic/components/Content';
import { Title } from '@patternfly/react-core/dist/dynamic/components/Title';
import { Flex, FlexItem } from '@patternfly/react-core/dist/dynamic/layouts/Flex';
import KnowledgeDescriptionContent from './KnowledgeDescription/KnowledgeDescriptionContent';
import KnowledgeSeedExample from './KnowledgeSeedExample/KnowledgeSeedExample';
import { checkKnowledgeFormCompletion } from './validation';
import KnowledgeDescriptionContent from '../KnowledgeDescription/KnowledgeDescriptionContent';
import KnowledgeSeedExample from '../KnowledgeSeedExample/KnowledgeSeedExample';
import { checkKnowledgeFormCompletion } from '../validation';
import { ValidatedOptions } from '@patternfly/react-core/dist/esm/helpers/constants';
import { DownloadDropdown } from './DownloadDropdown/DownloadDropdown';
import { ViewDropdown } from './ViewDropdown/ViewDropdown';
import { DownloadDropdown } from '../DownloadDropdown/DownloadDropdown';
import { ViewDropdown } from '../ViewDropdown/ViewDropdown';
import Update from './Update/Update';
import { KnowledgeYamlData, PullRequestFile } from '@/types';
import { Button } from '@patternfly/react-core/dist/esm/components/Button/Button';
import { useRouter } from 'next/navigation';
import { autoFillKnowledgeFields } from './AutoFill';
import { autoFillKnowledgeFields } from '../AutoFill';
import { Spinner } from '@patternfly/react-core/dist/esm/components/Spinner';
import { YamlFileUploadModal } from '../../YamlFileUploadModal';

Expand Down
Loading

0 comments on commit 1bf55ca

Please sign in to comment.