adding skills to experiences, profiles, and projects
Some checks failed
Main / changes (push) Successful in 37s
Main / deploy (push) Has been cancelled
Main / build-and-test (push) Has been cancelled

This commit is contained in:
2026-07-20 19:28:37 -05:00
parent 9d9cdbaebc
commit e5219761c2
40 changed files with 15075 additions and 162 deletions

9
.gitignore vendored
View File

@@ -1,2 +1,9 @@
.vscode/*
node_modules
**/.env
**/.env.*
**/*.env
.DS_Store
*.auto.tfvars
.dapr
**/**/secrets.json
.prod

16
Dockerfile Normal file
View File

@@ -0,0 +1,16 @@
FROM node:24
WORKDIR app
COPY ./api/dist ./api/dist
COPY ./api/package.json package-lock.json ./api
COPY ./client/dist ./client/dist
WORKDIR api
RUN npm ci
WORKDIR /
EXPOSE 3000
CMD ["node", "./app/api/dist/main.js"]
# ENTRYPOINT ["tail", "-f", "/dev/null"]

View File

@@ -6,5 +6,11 @@ export default () => ({
clientSecret: process.env.CLIENT_SECRET,
issuer: process.env.ISSUER_URL,
jwksUri: process.env.JWKS_URI,
tenantId: process.env.TENANT_ID
tenantId: process.env.TENANT_ID,
db: {
sync: process.env.DB_SYNC,
migrationsRun: process.env.DB_MIGRATIONS_RUN,
path: process.env.DB_PATH
},
dbPath: process.env.DB_PATH
})

View File

@@ -12,7 +12,7 @@ export const dataSourceOptions: DataSourceOptions & SeederOptions = {
database: configService.get<string>('DB_PATH'),
entities: ['../**/*.entity.js'],
migrations: ['dist/database/migrations/**/*.js'],
migrationsRun: false,
migrationsRun: configService.get<boolean>('DB_MIGRATIONS_RUN'),
seeds: ['dist/database/seeds/**/*.ts'],
synchronize: configService.get<boolean>('DB_SYNC')
}

View File

@@ -1,56 +1,122 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class InitialMigration1782738482901 implements MigrationInterface {
name = 'InitialMigration1782738482901'
export class InitialMigration1784577734670 implements MigrationInterface {
name = 'InitialMigration1784577734670'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TABLE "statuses" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar NOT NULL)`);
await queryRunner.query(`CREATE TABLE "skill_categories" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar)`);
await queryRunner.query(`CREATE TABLE "skill_levels" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar)`);
await queryRunner.query(`CREATE TABLE "skill_ranks" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar NOT NULL, "weight" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar)`);
await queryRunner.query(`CREATE TABLE "skills" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "categoryId" varchar NOT NULL, "levelId" integer NOT NULL, "rankId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "REL_168133e3158020b53392549d3e" UNIQUE ("rankId"))`);
await queryRunner.query(`CREATE TABLE "projects" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "iconName" varchar NOT NULL, "order" integer NOT NULL, "summary" varchar NOT NULL, "repoUrl" varchar, "siteUrl" varchar, "statusId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "REL_5a833dfa646b99b852c67dd859" UNIQUE ("statusId"))`);
await queryRunner.query(`CREATE TABLE "experiences" ("id" varchar PRIMARY KEY NOT NULL, "profileId" varchar NOT NULL, "companyName" varchar NOT NULL, "companyGeneric" varchar NOT NULL, "title" varchar NOT NULL, "startDate" datetime NOT NULL, "endDate" datetime, "summary" varchar, "statusId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "REL_23dfcd8f2d1b6585b848f840d5" UNIQUE ("statusId"))`);
await queryRunner.query(`CREATE TABLE "profiles" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "headline" varchar NOT NULL, "summary" varchar NOT NULL, "statusId" integer NOT NULL, "userId" varchar NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "REL_a0e37cd676d13d116f73d494ee" UNIQUE ("statusId"))`);
await queryRunner.query(`CREATE TABLE "temporary_skills" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "categoryId" varchar NOT NULL, "levelId" integer NOT NULL, "rankId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "REL_168133e3158020b53392549d3e" UNIQUE ("rankId"), CONSTRAINT "FK_06d267f85858229c10a01a08ad7" FOREIGN KEY ("categoryId") REFERENCES "skill_categories" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_168133e3158020b53392549d3ee" FOREIGN KEY ("rankId") REFERENCES "skill_ranks" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_cad5a64685c1be599c10bb7fc7b" FOREIGN KEY ("levelId") REFERENCES "skill_levels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "temporary_skills"("id", "name", "categoryId", "levelId", "rankId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "name", "categoryId", "levelId", "rankId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "skills"`);
await queryRunner.query(`DROP TABLE "skills"`);
await queryRunner.query(`ALTER TABLE "temporary_skills" RENAME TO "skills"`);
await queryRunner.query(`CREATE TABLE "temporary_projects" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "iconName" varchar NOT NULL, "order" integer NOT NULL, "summary" varchar NOT NULL, "repoUrl" varchar, "siteUrl" varchar, "statusId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "REL_5a833dfa646b99b852c67dd859" UNIQUE ("statusId"), CONSTRAINT "FK_5a833dfa646b99b852c67dd8593" FOREIGN KEY ("statusId") REFERENCES "statuses" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "temporary_projects"("id", "name", "iconName", "order", "summary", "repoUrl", "siteUrl", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "name", "iconName", "order", "summary", "repoUrl", "siteUrl", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "projects"`);
await queryRunner.query(`DROP TABLE "projects"`);
await queryRunner.query(`ALTER TABLE "temporary_projects" RENAME TO "projects"`);
await queryRunner.query(`CREATE TABLE "temporary_experiences" ("id" varchar PRIMARY KEY NOT NULL, "profileId" varchar NOT NULL, "companyName" varchar NOT NULL, "companyGeneric" varchar NOT NULL, "title" varchar NOT NULL, "startDate" datetime NOT NULL, "endDate" datetime, "summary" varchar, "statusId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "REL_23dfcd8f2d1b6585b848f840d5" UNIQUE ("statusId"), CONSTRAINT "FK_be01c61f0c549f2187b5c05c349" FOREIGN KEY ("profileId") REFERENCES "profiles" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_23dfcd8f2d1b6585b848f840d5e" FOREIGN KEY ("statusId") REFERENCES "statuses" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "temporary_experiences"("id", "profileId", "companyName", "companyGeneric", "title", "startDate", "endDate", "summary", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "profileId", "companyName", "companyGeneric", "title", "startDate", "endDate", "summary", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "experiences"`);
await queryRunner.query(`DROP TABLE "experiences"`);
await queryRunner.query(`ALTER TABLE "temporary_experiences" RENAME TO "experiences"`);
await queryRunner.query(`CREATE TABLE "temporary_profiles" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "headline" varchar NOT NULL, "summary" varchar NOT NULL, "statusId" integer NOT NULL, "userId" varchar NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "REL_a0e37cd676d13d116f73d494ee" UNIQUE ("statusId"), CONSTRAINT "FK_a0e37cd676d13d116f73d494ee6" FOREIGN KEY ("statusId") REFERENCES "statuses" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`CREATE TABLE "profiles" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "headline" varchar NOT NULL, "summary" varchar NOT NULL, "statusId" integer NOT NULL, "userId" varchar NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar)`);
await queryRunner.query(`CREATE TABLE "experiences" ("id" varchar PRIMARY KEY NOT NULL, "profileId" varchar NOT NULL, "companyName" varchar NOT NULL, "companyGeneric" varchar NOT NULL, "title" varchar NOT NULL, "startDate" datetime NOT NULL, "endDate" datetime, "summary" varchar, "statusId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar)`);
await queryRunner.query(`CREATE TABLE "skills" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "categoryId" varchar NOT NULL, "levelId" integer NOT NULL, "rankId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar)`);
await queryRunner.query(`CREATE TABLE "projects" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "iconName" varchar NOT NULL, "order" integer NOT NULL, "summary" varchar NOT NULL, "repoUrl" varchar, "siteUrl" varchar, "statusId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar)`);
await queryRunner.query(`CREATE TABLE "profiles_skills_skills" ("profilesId" varchar NOT NULL, "skillsId" varchar NOT NULL, PRIMARY KEY ("profilesId", "skillsId"))`);
await queryRunner.query(`CREATE INDEX "IDX_8401800ec9c15b8f383ac8d9c0" ON "profiles_skills_skills" ("profilesId") `);
await queryRunner.query(`CREATE INDEX "IDX_36a9448df496235d81a7ceb089" ON "profiles_skills_skills" ("skillsId") `);
await queryRunner.query(`CREATE TABLE "experiences_skills_skills" ("experiencesId" varchar NOT NULL, "skillsId" varchar NOT NULL, PRIMARY KEY ("experiencesId", "skillsId"))`);
await queryRunner.query(`CREATE INDEX "IDX_54957c4ce34cebce0c6f152b87" ON "experiences_skills_skills" ("experiencesId") `);
await queryRunner.query(`CREATE INDEX "IDX_b39ff48a29419ea48077b619c4" ON "experiences_skills_skills" ("skillsId") `);
await queryRunner.query(`CREATE TABLE "projects_skills_skills" ("projectsId" varchar NOT NULL, "skillsId" varchar NOT NULL, PRIMARY KEY ("projectsId", "skillsId"))`);
await queryRunner.query(`CREATE INDEX "IDX_d8128e9b444108a09d81529ea0" ON "projects_skills_skills" ("projectsId") `);
await queryRunner.query(`CREATE INDEX "IDX_5291aa5a2295552d375007fefe" ON "projects_skills_skills" ("skillsId") `);
await queryRunner.query(`CREATE TABLE "temporary_profiles" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "headline" varchar NOT NULL, "summary" varchar NOT NULL, "statusId" integer NOT NULL, "userId" varchar NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "FK_a0e37cd676d13d116f73d494ee6" FOREIGN KEY ("statusId") REFERENCES "statuses" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "temporary_profiles"("id", "name", "headline", "summary", "statusId", "userId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "name", "headline", "summary", "statusId", "userId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "profiles"`);
await queryRunner.query(`DROP TABLE "profiles"`);
await queryRunner.query(`ALTER TABLE "temporary_profiles" RENAME TO "profiles"`);
await queryRunner.query(`CREATE TABLE "temporary_experiences" ("id" varchar PRIMARY KEY NOT NULL, "profileId" varchar NOT NULL, "companyName" varchar NOT NULL, "companyGeneric" varchar NOT NULL, "title" varchar NOT NULL, "startDate" datetime NOT NULL, "endDate" datetime, "summary" varchar, "statusId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "FK_23dfcd8f2d1b6585b848f840d5e" FOREIGN KEY ("statusId") REFERENCES "statuses" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_be01c61f0c549f2187b5c05c349" FOREIGN KEY ("profileId") REFERENCES "profiles" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "temporary_experiences"("id", "profileId", "companyName", "companyGeneric", "title", "startDate", "endDate", "summary", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "profileId", "companyName", "companyGeneric", "title", "startDate", "endDate", "summary", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "experiences"`);
await queryRunner.query(`DROP TABLE "experiences"`);
await queryRunner.query(`ALTER TABLE "temporary_experiences" RENAME TO "experiences"`);
await queryRunner.query(`CREATE TABLE "temporary_skills" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "categoryId" varchar NOT NULL, "levelId" integer NOT NULL, "rankId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "FK_06d267f85858229c10a01a08ad7" FOREIGN KEY ("categoryId") REFERENCES "skill_categories" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_168133e3158020b53392549d3ee" FOREIGN KEY ("rankId") REFERENCES "skill_ranks" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_cad5a64685c1be599c10bb7fc7b" FOREIGN KEY ("levelId") REFERENCES "skill_levels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "temporary_skills"("id", "name", "categoryId", "levelId", "rankId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "name", "categoryId", "levelId", "rankId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "skills"`);
await queryRunner.query(`DROP TABLE "skills"`);
await queryRunner.query(`ALTER TABLE "temporary_skills" RENAME TO "skills"`);
await queryRunner.query(`CREATE TABLE "temporary_projects" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "iconName" varchar NOT NULL, "order" integer NOT NULL, "summary" varchar NOT NULL, "repoUrl" varchar, "siteUrl" varchar, "statusId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "FK_5a833dfa646b99b852c67dd8593" FOREIGN KEY ("statusId") REFERENCES "statuses" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "temporary_projects"("id", "name", "iconName", "order", "summary", "repoUrl", "siteUrl", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "name", "iconName", "order", "summary", "repoUrl", "siteUrl", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "projects"`);
await queryRunner.query(`DROP TABLE "projects"`);
await queryRunner.query(`ALTER TABLE "temporary_projects" RENAME TO "projects"`);
await queryRunner.query(`DROP INDEX "IDX_8401800ec9c15b8f383ac8d9c0"`);
await queryRunner.query(`DROP INDEX "IDX_36a9448df496235d81a7ceb089"`);
await queryRunner.query(`CREATE TABLE "temporary_profiles_skills_skills" ("profilesId" varchar NOT NULL, "skillsId" varchar NOT NULL, CONSTRAINT "FK_8401800ec9c15b8f383ac8d9c0d" FOREIGN KEY ("profilesId") REFERENCES "profiles" ("id") ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT "FK_36a9448df496235d81a7ceb089d" FOREIGN KEY ("skillsId") REFERENCES "skills" ("id") ON DELETE CASCADE ON UPDATE CASCADE, PRIMARY KEY ("profilesId", "skillsId"))`);
await queryRunner.query(`INSERT INTO "temporary_profiles_skills_skills"("profilesId", "skillsId") SELECT "profilesId", "skillsId" FROM "profiles_skills_skills"`);
await queryRunner.query(`DROP TABLE "profiles_skills_skills"`);
await queryRunner.query(`ALTER TABLE "temporary_profiles_skills_skills" RENAME TO "profiles_skills_skills"`);
await queryRunner.query(`CREATE INDEX "IDX_8401800ec9c15b8f383ac8d9c0" ON "profiles_skills_skills" ("profilesId") `);
await queryRunner.query(`CREATE INDEX "IDX_36a9448df496235d81a7ceb089" ON "profiles_skills_skills" ("skillsId") `);
await queryRunner.query(`DROP INDEX "IDX_54957c4ce34cebce0c6f152b87"`);
await queryRunner.query(`DROP INDEX "IDX_b39ff48a29419ea48077b619c4"`);
await queryRunner.query(`CREATE TABLE "temporary_experiences_skills_skills" ("experiencesId" varchar NOT NULL, "skillsId" varchar NOT NULL, CONSTRAINT "FK_54957c4ce34cebce0c6f152b875" FOREIGN KEY ("experiencesId") REFERENCES "experiences" ("id") ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT "FK_b39ff48a29419ea48077b619c46" FOREIGN KEY ("skillsId") REFERENCES "skills" ("id") ON DELETE CASCADE ON UPDATE CASCADE, PRIMARY KEY ("experiencesId", "skillsId"))`);
await queryRunner.query(`INSERT INTO "temporary_experiences_skills_skills"("experiencesId", "skillsId") SELECT "experiencesId", "skillsId" FROM "experiences_skills_skills"`);
await queryRunner.query(`DROP TABLE "experiences_skills_skills"`);
await queryRunner.query(`ALTER TABLE "temporary_experiences_skills_skills" RENAME TO "experiences_skills_skills"`);
await queryRunner.query(`CREATE INDEX "IDX_54957c4ce34cebce0c6f152b87" ON "experiences_skills_skills" ("experiencesId") `);
await queryRunner.query(`CREATE INDEX "IDX_b39ff48a29419ea48077b619c4" ON "experiences_skills_skills" ("skillsId") `);
await queryRunner.query(`DROP INDEX "IDX_d8128e9b444108a09d81529ea0"`);
await queryRunner.query(`DROP INDEX "IDX_5291aa5a2295552d375007fefe"`);
await queryRunner.query(`CREATE TABLE "temporary_projects_skills_skills" ("projectsId" varchar NOT NULL, "skillsId" varchar NOT NULL, CONSTRAINT "FK_d8128e9b444108a09d81529ea06" FOREIGN KEY ("projectsId") REFERENCES "projects" ("id") ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT "FK_5291aa5a2295552d375007fefee" FOREIGN KEY ("skillsId") REFERENCES "skills" ("id") ON DELETE CASCADE ON UPDATE CASCADE, PRIMARY KEY ("projectsId", "skillsId"))`);
await queryRunner.query(`INSERT INTO "temporary_projects_skills_skills"("projectsId", "skillsId") SELECT "projectsId", "skillsId" FROM "projects_skills_skills"`);
await queryRunner.query(`DROP TABLE "projects_skills_skills"`);
await queryRunner.query(`ALTER TABLE "temporary_projects_skills_skills" RENAME TO "projects_skills_skills"`);
await queryRunner.query(`CREATE INDEX "IDX_d8128e9b444108a09d81529ea0" ON "projects_skills_skills" ("projectsId") `);
await queryRunner.query(`CREATE INDEX "IDX_5291aa5a2295552d375007fefe" ON "projects_skills_skills" ("skillsId") `);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "profiles" RENAME TO "temporary_profiles"`);
await queryRunner.query(`CREATE TABLE "profiles" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "headline" varchar NOT NULL, "summary" varchar NOT NULL, "statusId" integer NOT NULL, "userId" varchar NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "REL_a0e37cd676d13d116f73d494ee" UNIQUE ("statusId"))`);
await queryRunner.query(`INSERT INTO "profiles"("id", "name", "headline", "summary", "statusId", "userId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "name", "headline", "summary", "statusId", "userId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "temporary_profiles"`);
await queryRunner.query(`DROP TABLE "temporary_profiles"`);
await queryRunner.query(`ALTER TABLE "experiences" RENAME TO "temporary_experiences"`);
await queryRunner.query(`CREATE TABLE "experiences" ("id" varchar PRIMARY KEY NOT NULL, "profileId" varchar NOT NULL, "companyName" varchar NOT NULL, "companyGeneric" varchar NOT NULL, "title" varchar NOT NULL, "startDate" datetime NOT NULL, "endDate" datetime, "summary" varchar, "statusId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "REL_23dfcd8f2d1b6585b848f840d5" UNIQUE ("statusId"))`);
await queryRunner.query(`INSERT INTO "experiences"("id", "profileId", "companyName", "companyGeneric", "title", "startDate", "endDate", "summary", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "profileId", "companyName", "companyGeneric", "title", "startDate", "endDate", "summary", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "temporary_experiences"`);
await queryRunner.query(`DROP TABLE "temporary_experiences"`);
await queryRunner.query(`DROP INDEX "IDX_5291aa5a2295552d375007fefe"`);
await queryRunner.query(`DROP INDEX "IDX_d8128e9b444108a09d81529ea0"`);
await queryRunner.query(`ALTER TABLE "projects_skills_skills" RENAME TO "temporary_projects_skills_skills"`);
await queryRunner.query(`CREATE TABLE "projects_skills_skills" ("projectsId" varchar NOT NULL, "skillsId" varchar NOT NULL, PRIMARY KEY ("projectsId", "skillsId"))`);
await queryRunner.query(`INSERT INTO "projects_skills_skills"("projectsId", "skillsId") SELECT "projectsId", "skillsId" FROM "temporary_projects_skills_skills"`);
await queryRunner.query(`DROP TABLE "temporary_projects_skills_skills"`);
await queryRunner.query(`CREATE INDEX "IDX_5291aa5a2295552d375007fefe" ON "projects_skills_skills" ("skillsId") `);
await queryRunner.query(`CREATE INDEX "IDX_d8128e9b444108a09d81529ea0" ON "projects_skills_skills" ("projectsId") `);
await queryRunner.query(`DROP INDEX "IDX_b39ff48a29419ea48077b619c4"`);
await queryRunner.query(`DROP INDEX "IDX_54957c4ce34cebce0c6f152b87"`);
await queryRunner.query(`ALTER TABLE "experiences_skills_skills" RENAME TO "temporary_experiences_skills_skills"`);
await queryRunner.query(`CREATE TABLE "experiences_skills_skills" ("experiencesId" varchar NOT NULL, "skillsId" varchar NOT NULL, PRIMARY KEY ("experiencesId", "skillsId"))`);
await queryRunner.query(`INSERT INTO "experiences_skills_skills"("experiencesId", "skillsId") SELECT "experiencesId", "skillsId" FROM "temporary_experiences_skills_skills"`);
await queryRunner.query(`DROP TABLE "temporary_experiences_skills_skills"`);
await queryRunner.query(`CREATE INDEX "IDX_b39ff48a29419ea48077b619c4" ON "experiences_skills_skills" ("skillsId") `);
await queryRunner.query(`CREATE INDEX "IDX_54957c4ce34cebce0c6f152b87" ON "experiences_skills_skills" ("experiencesId") `);
await queryRunner.query(`DROP INDEX "IDX_36a9448df496235d81a7ceb089"`);
await queryRunner.query(`DROP INDEX "IDX_8401800ec9c15b8f383ac8d9c0"`);
await queryRunner.query(`ALTER TABLE "profiles_skills_skills" RENAME TO "temporary_profiles_skills_skills"`);
await queryRunner.query(`CREATE TABLE "profiles_skills_skills" ("profilesId" varchar NOT NULL, "skillsId" varchar NOT NULL, PRIMARY KEY ("profilesId", "skillsId"))`);
await queryRunner.query(`INSERT INTO "profiles_skills_skills"("profilesId", "skillsId") SELECT "profilesId", "skillsId" FROM "temporary_profiles_skills_skills"`);
await queryRunner.query(`DROP TABLE "temporary_profiles_skills_skills"`);
await queryRunner.query(`CREATE INDEX "IDX_36a9448df496235d81a7ceb089" ON "profiles_skills_skills" ("skillsId") `);
await queryRunner.query(`CREATE INDEX "IDX_8401800ec9c15b8f383ac8d9c0" ON "profiles_skills_skills" ("profilesId") `);
await queryRunner.query(`ALTER TABLE "projects" RENAME TO "temporary_projects"`);
await queryRunner.query(`CREATE TABLE "projects" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "iconName" varchar NOT NULL, "order" integer NOT NULL, "summary" varchar NOT NULL, "repoUrl" varchar, "siteUrl" varchar, "statusId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "REL_5a833dfa646b99b852c67dd859" UNIQUE ("statusId"))`);
await queryRunner.query(`CREATE TABLE "projects" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "iconName" varchar NOT NULL, "order" integer NOT NULL, "summary" varchar NOT NULL, "repoUrl" varchar, "siteUrl" varchar, "statusId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar)`);
await queryRunner.query(`INSERT INTO "projects"("id", "name", "iconName", "order", "summary", "repoUrl", "siteUrl", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "name", "iconName", "order", "summary", "repoUrl", "siteUrl", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "temporary_projects"`);
await queryRunner.query(`DROP TABLE "temporary_projects"`);
await queryRunner.query(`ALTER TABLE "skills" RENAME TO "temporary_skills"`);
await queryRunner.query(`CREATE TABLE "skills" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "categoryId" varchar NOT NULL, "levelId" integer NOT NULL, "rankId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "REL_168133e3158020b53392549d3e" UNIQUE ("rankId"))`);
await queryRunner.query(`CREATE TABLE "skills" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "categoryId" varchar NOT NULL, "levelId" integer NOT NULL, "rankId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar)`);
await queryRunner.query(`INSERT INTO "skills"("id", "name", "categoryId", "levelId", "rankId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "name", "categoryId", "levelId", "rankId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "temporary_skills"`);
await queryRunner.query(`DROP TABLE "temporary_skills"`);
await queryRunner.query(`DROP TABLE "profiles"`);
await queryRunner.query(`DROP TABLE "experiences"`);
await queryRunner.query(`ALTER TABLE "experiences" RENAME TO "temporary_experiences"`);
await queryRunner.query(`CREATE TABLE "experiences" ("id" varchar PRIMARY KEY NOT NULL, "profileId" varchar NOT NULL, "companyName" varchar NOT NULL, "companyGeneric" varchar NOT NULL, "title" varchar NOT NULL, "startDate" datetime NOT NULL, "endDate" datetime, "summary" varchar, "statusId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar)`);
await queryRunner.query(`INSERT INTO "experiences"("id", "profileId", "companyName", "companyGeneric", "title", "startDate", "endDate", "summary", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "profileId", "companyName", "companyGeneric", "title", "startDate", "endDate", "summary", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "temporary_experiences"`);
await queryRunner.query(`DROP TABLE "temporary_experiences"`);
await queryRunner.query(`ALTER TABLE "profiles" RENAME TO "temporary_profiles"`);
await queryRunner.query(`CREATE TABLE "profiles" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "headline" varchar NOT NULL, "summary" varchar NOT NULL, "statusId" integer NOT NULL, "userId" varchar NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar)`);
await queryRunner.query(`INSERT INTO "profiles"("id", "name", "headline", "summary", "statusId", "userId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "name", "headline", "summary", "statusId", "userId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "temporary_profiles"`);
await queryRunner.query(`DROP TABLE "temporary_profiles"`);
await queryRunner.query(`DROP INDEX "IDX_5291aa5a2295552d375007fefe"`);
await queryRunner.query(`DROP INDEX "IDX_d8128e9b444108a09d81529ea0"`);
await queryRunner.query(`DROP TABLE "projects_skills_skills"`);
await queryRunner.query(`DROP INDEX "IDX_b39ff48a29419ea48077b619c4"`);
await queryRunner.query(`DROP INDEX "IDX_54957c4ce34cebce0c6f152b87"`);
await queryRunner.query(`DROP TABLE "experiences_skills_skills"`);
await queryRunner.query(`DROP INDEX "IDX_36a9448df496235d81a7ceb089"`);
await queryRunner.query(`DROP INDEX "IDX_8401800ec9c15b8f383ac8d9c0"`);
await queryRunner.query(`DROP TABLE "profiles_skills_skills"`);
await queryRunner.query(`DROP TABLE "projects"`);
await queryRunner.query(`DROP TABLE "skills"`);
await queryRunner.query(`DROP TABLE "experiences"`);
await queryRunner.query(`DROP TABLE "profiles"`);
await queryRunner.query(`DROP TABLE "skill_ranks"`);
await queryRunner.query(`DROP TABLE "skill_levels"`);
await queryRunner.query(`DROP TABLE "skill_categories"`);

View File

@@ -31,6 +31,7 @@ export class ExperienceController {
@Post()
async create(@Body() experienceDto: ExperienceDto): Promise<ExperienceDto> {
console.log(experienceDto)
try {
return await this.experienceService.create(experienceDto);
} catch (error) {
@@ -45,6 +46,7 @@ export class ExperienceController {
@Param('id') id: string,
@Body() ExperienceDto: ExperienceDto
) {
console.log(ExperienceDto)
try {
return await this.experienceService.update(id, ExperienceDto);
} catch (error) {

View File

@@ -1,3 +1,5 @@
import { SkillEntity } from "src/skill/skill.entity";
export class ExperienceDto {
companyName: string;
companyNameGeneric: string;
@@ -6,7 +8,7 @@ export class ExperienceDto {
startDate: Date;
endDate?: Date;
summary: string;
skills?: [];
skills?: SkillEntity[];
createdBy?: string;
updatedBy?: string;
deletedBy?: string;

View File

@@ -1,7 +1,7 @@
import { ProfileEntity } from '../profile/profile.entity'
import { SkillEntity } from 'src/skill/skill.entity';
import { StatusEntity } from 'src/status/status.entity';
import { Entity, PrimaryGeneratedColumn, Column, JoinColumn, ManyToOne, OneToMany, OneToOne, CreateDateColumn, UpdateDateColumn, DeleteDateColumn } from 'typeorm';
import { Entity, PrimaryGeneratedColumn, Column, JoinColumn, ManyToOne, OneToMany, OneToOne, CreateDateColumn, UpdateDateColumn, DeleteDateColumn, ManyToMany, JoinTable } from 'typeorm';
@Entity({ name: 'experiences' })
export class ExperienceEntity {
@@ -50,14 +50,15 @@ export class ExperienceEntity {
@Column({ nullable: true })
deletedBy: string;
@OneToMany(() => SkillEntity, (skill: SkillEntity) => skill.name )
skills: SkillEntity[];
@ManyToOne(() => StatusEntity, (status: StatusEntity) => status.name )
@JoinColumn({ name: 'statusId' })
status: StatusEntity;
@ManyToOne(() => ProfileEntity, (profile: ProfileEntity) => profile.experiences)
@JoinColumn({ name: 'profileId' })
profile: ProfileEntity;
@OneToOne(() => StatusEntity, (status: StatusEntity) => status.name )
@JoinColumn({ name: 'statusId' })
status: StatusEntity;
@ManyToMany(() => SkillEntity, (skill: SkillEntity) => skill.name )
@JoinTable()
skills: SkillEntity[];
}

View File

@@ -13,13 +13,13 @@ export class ExperienceService {
async find(id: string): Promise<ExperienceEntity> {
return await this.experienceRepository.findOne({
where: { id: id },
relations: ['profile', 'status']
relations: ['profile', 'skills', 'status']
})
}
async findAll(): Promise<ExperienceEntity[]> {
return await this.experienceRepository.find({
relations: ['profile', 'status']
relations: ['profile', 'skills', 'status']
});
}

View File

@@ -1,3 +0,0 @@
body {
background-color: #f2f2f2;
}

View File

@@ -38,7 +38,7 @@ export class ProfileController {
return await this.profileService.findAll();
} catch (error) {
const customError = error as CustomError;
console.log(error)
throw new HttpException(customError.message, customError.statusCode);
}
}

View File

@@ -1,9 +1,12 @@
import { SkillEntity } from "src/skill/skill.entity";
export class ProfileDto {
name: string;
headline: string;
skills: SkillEntity[];
statusId: number;
summary: string;
userId: string;
statusId: number;
createdBy?: string;
updatedBy?: string;
deletedBy?: string;

View File

@@ -1,7 +1,7 @@
import { ExperienceEntity } from 'src/experience/experience.entity';
import { SkillEntity } from 'src/skill/skill.entity';
import { StatusEntity } from 'src/status/status.entity';
import { Entity, PrimaryGeneratedColumn, Column, OneToMany, CreateDateColumn, UpdateDateColumn, DeleteDateColumn, OneToOne, JoinColumn } from 'typeorm';
import { Entity, PrimaryGeneratedColumn, Column, OneToMany, CreateDateColumn, UpdateDateColumn, DeleteDateColumn, OneToOne, JoinColumn, ManyToOne, ManyToMany, JoinTable } from 'typeorm';
@Entity({ name: 'profiles' })
export class ProfileEntity {
@@ -44,10 +44,11 @@ export class ProfileEntity {
@OneToMany(() => ExperienceEntity, (experience: ExperienceEntity) => experience.profile)
experiences: ExperienceEntity[]
@OneToMany(() => SkillEntity, (skill: SkillEntity) => skill.name )
skills: SkillEntity[];
@OneToOne(() => StatusEntity, (status: StatusEntity) => status.name )
@ManyToOne(() => StatusEntity, (status: StatusEntity) => status.name )
@JoinColumn({ name: 'statusId' })
status: StatusEntity;
@ManyToMany(() => SkillEntity, (skill: SkillEntity) => skill.name )
@JoinTable()
skills: SkillEntity[];
}

View File

@@ -13,7 +13,7 @@ export class ProfileService {
async find(id: string): Promise<ProfileEntity> {
const profile = await this.profileRepository.findOne({
where: { id: id },
relations: ['status']
relations: ['skills', 'status']
});
console.log(profile);
@@ -22,7 +22,7 @@ export class ProfileService {
async findAll(): Promise<ProfileEntity[]> {
return await this.profileRepository.find({
relations: ['status']
relations: ['skills', 'status']
});
}

View File

@@ -1,3 +1,5 @@
import { SkillEntity } from "src/skill/skill.entity";
export class ProjectDto {
id: string;
name: string;
@@ -6,7 +8,7 @@ export class ProjectDto {
summary: string;
repoUrl?: string;
siteUrl?: string;
skills?: [];
skills?: SkillEntity[];
createdBy?: string;
updatedBy?: string;
deletedBy?: string;

View File

@@ -1,6 +1,6 @@
import { SkillEntity } from 'src/skill/skill.entity';
import { StatusEntity } from 'src/status/status.entity';
import { Entity, PrimaryGeneratedColumn, Column, OneToMany, OneToOne, JoinColumn, CreateDateColumn, UpdateDateColumn, DeleteDateColumn } from 'typeorm';
import { Entity, PrimaryGeneratedColumn, Column, OneToMany, OneToOne, JoinColumn, CreateDateColumn, UpdateDateColumn, DeleteDateColumn, ManyToOne, ManyToMany, JoinTable } from 'typeorm';
@Entity({ name: 'projects' })
export class ProjectEntity {
@@ -46,10 +46,11 @@ export class ProjectEntity {
@Column({ nullable: true })
deletedBy: string
@OneToMany(() => SkillEntity, (skill: SkillEntity) => skill.name )
skills: SkillEntity[];
@OneToOne(() => StatusEntity, (status: StatusEntity) => status.name )
@ManyToOne(() => StatusEntity, (status: StatusEntity) => status.name )
@JoinColumn({ name: 'statusId' })
status: StatusEntity;
@ManyToMany(() => SkillEntity, (skill: SkillEntity) => skill.name )
@JoinTable()
skills: SkillEntity[];
}

View File

@@ -13,16 +13,15 @@ export class ProjectService {
async find(id: string): Promise<ProjectEntity> {
const project = await this.projectRepository.findOne({
where: { id: id },
relations: ['status']
relations: ['skills', 'status']
});
console.log(project);
return project;
}
async findAll(): Promise<ProjectEntity[]> {
return await this.projectRepository.find({
relations: ['status']
relations: ['skills', 'status']
});
}

View File

@@ -26,8 +26,5 @@ export class SkillLevelEntity {
@Column({ nullable: true })
deletedBy: string;
@OneToMany(() => SkillEntity, (skill: SkillEntity) => skill.name)
skills: SkillEntity[];
}

View File

@@ -2,6 +2,7 @@ import { SkillCategoryEntity } from 'src/skill/skill-category.entity';
import { Entity, PrimaryGeneratedColumn, Column, JoinColumn, ManyToOne, ManyToMany, OneToOne, CreateDateColumn, UpdateDateColumn, DeleteDateColumn } from 'typeorm';
import { SkillLevelEntity } from './skill-level.entity';
import { SkillRankEntity } from './skill-rank.entity';
import { ExperienceEntity } from 'src/experience/experience.entity';
@Entity({ name: 'skills' })
export class SkillEntity {
@@ -42,11 +43,14 @@ export class SkillEntity {
@JoinColumn({ name: 'categoryId' })
category: SkillCategoryEntity;
@OneToOne(() => SkillRankEntity, (rank: SkillRankEntity) => rank.name)
@ManyToOne(() => SkillRankEntity, (rank: SkillRankEntity) => rank.name)
@JoinColumn({ name: 'rankId' })
rank: SkillRankEntity;
@ManyToOne(() => SkillLevelEntity, (level: SkillLevelEntity) => level.name)
@JoinColumn({ name: 'levelId' })
level: SkillLevelEntity;
@ManyToMany(() => ExperienceEntity, (experience: ExperienceEntity) => experience.skills)
experiences: ExperienceEntity[]
}

View File

@@ -9,11 +9,15 @@ import { AxiosError, AxiosResponse } from "axios";
import { ScreenSize } from "../../enums/screenSize";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faSave, faXmark } from "@fortawesome/free-solid-svg-icons";
import { useAppContext } from "../../hooks/appContext/UseAppContext";
const SkillCategoryForm = ({ isDrawerOpen, mode, onOpenClose, categoryId }: SkillCategoryFormProps) => {
const [state, dispatch] = useReducer(reducer, initialState);
const appContext = useAppContext();
const defaultValues = {
name: ''
name: '',
createdBy: '',
updatedBy: ''
}
const methods = useForm({
defaultValues: defaultValues
@@ -26,14 +30,25 @@ const SkillCategoryForm = ({ isDrawerOpen, mode, onOpenClose, categoryId }: Skil
onOpenClose(FormMode.CANCEL)
}
const onSubmit = async (data: unknown) => {
const onSubmit = async (data: any) => {
try {
dispatch({ type: 'SET_IS_LOADING', payload: true })
if (!categoryId) {
await httpClient.post(`api/skill-categories`, data);
const newData = {
...data,
createdBy: appContext.state.userProfile.userPrincipalName,
updatedBy: appContext.state.userProfile.userPrincipalName
}
await httpClient.post(`api/skill-categories`, newData);
} else {
await httpClient.put(`api/skill-categories`)
const newData = {
...data,
updatedBy: appContext.state.userProfile.userPrincipalName
}
await httpClient.put(`api/skill-categories`, newData)
}
methods.reset(defaultValues);

View File

@@ -9,14 +9,18 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faSave, faXmark } from '@fortawesome/free-solid-svg-icons';
import { ScreenSize } from '../../enums/screenSize';
import { useBreakpoints } from '../../hooks/breakpoints/UseBreakpoints';
import { useAppContext } from '../../hooks/appContext/UseAppContext';
const SkillForm = ({ isDrawerOpen, mode, onOpenClose, skillId }: SkillFormProps) => {
const [state, dispatch] = useReducer(reducer, initialState);
const appContext = useAppContext();
const defaultValues = {
name: '',
categoryId: '',
levelId: '',
rankId: ''
rankId: '',
createdBy: '',
updatedBy: ''
}
const methods = useForm({
defaultValues: defaultValues
@@ -29,14 +33,25 @@ const SkillForm = ({ isDrawerOpen, mode, onOpenClose, skillId }: SkillFormProps)
onOpenClose(FormMode.CANCEL);
};
const onSubmit = async (data: unknown) => {
const onSubmit = async (data: any) => {
try {
dispatch({ type: 'SET_IS_LOADING', payload: true });
console.log(data)
if (!skillId) {
await httpClient.post(`api/skills`, data);
const newData = {
...data,
createdBy: appContext.state.userProfile.userPrincipalName,
updatedBy: appContext.state.userProfile.userPrincipalName
}
await httpClient.post(`api/skills`, newData);
} else {
await httpClient.put(`api/skills/skill/${skillId}`, data);
const newData = {
...data,
updatedBy: appContext.state.userProfile.userPrincipalName
}
await httpClient.put(`api/skills/skill/${skillId}`, newData);
}
methods.reset(defaultValues);

View File

@@ -12,14 +12,17 @@ import { useBreakpoints } from '../../hooks/breakpoints/UseBreakpoints';
import { Profile } from '../profiles/Profile.interface';
import { useProfiles } from '../../hooks/profiles/UseProfiles';
import { useAppContext } from '../../hooks/appContext/UseAppContext';
import { Listbox, ListboxButton, ListboxOption, ListboxOptions } from '@headlessui/react';
import { useSkills } from '../../hooks/skills/UseSkills';
import MultiSelectDropdown from '../multiSelectDropdown/MultiSelectDropdown';
import { Skill } from '../skills/Skill.interface';
import { Experience } from '../experiences/Experience.interface';
const ExperienceForm = ({ isDrawerOpen, mode, onOpenClose, experienceId }: ExperienceFormProps) => {
const [state, dispatch] = useReducer(reducer, initialState);
const appContext = useAppContext();
const { profiles } = useProfiles();
const { skills } = useSkills();
const experienceSkills: Skill[] = []
const defaultValues = {
profileId: '',
companyName: '',
@@ -27,7 +30,7 @@ const ExperienceForm = ({ isDrawerOpen, mode, onOpenClose, experienceId }: Exper
title: '',
startDate: '',
endDate: '',
skills: [],
skills: experienceSkills,
summary: '',
statusId: 1,
createdBy: '',
@@ -36,9 +39,23 @@ const ExperienceForm = ({ isDrawerOpen, mode, onOpenClose, experienceId }: Exper
const methods = useForm({
defaultValues: defaultValues
});
// const watchRepoName = methods.watch(['repoName'])
const { screenSize } = useBreakpoints();
const onSetSelectedSkills = (selectedSkill: Skill) => {
const selectedSkillExists = state.selectedSkills.find((skill) => skill.id === selectedSkill.id)
let newSelectedSkills: Skill[];
if (selectedSkillExists) {
newSelectedSkills = state.selectedSkills.filter((skill) => skill.id !== selectedSkillExists.id)
} else {
newSelectedSkills = [...state.selectedSkills, selectedSkill]
}
dispatch({ type: 'SET_SELECTED_SKILLS', payload: newSelectedSkills })
methods.setValue('skills', newSelectedSkills)
}
const onCancel = () => {
methods.reset(defaultValues);
dispatch({ type: 'SET_IS_DISABLED', payload: false });
@@ -92,6 +109,10 @@ const ExperienceForm = ({ isDrawerOpen, mode, onOpenClose, experienceId }: Exper
);
const experience = response.data;
if (experience.skills) {
dispatch({ type: 'SET_SELECTED_SKILLS', payload: experience.skills })
}
methods.reset(experience);
} catch (error) {
const axiosError = error as AxiosError;
@@ -127,7 +148,9 @@ const ExperienceForm = ({ isDrawerOpen, mode, onOpenClose, experienceId }: Exper
}, [profiles]);
useEffect(() => {
dispatch({ type: 'SET_SKILL_OPTIONS', payload: skills })
if (skills) {
dispatch({ type: 'SET_SKILL_OPTIONS', payload: skills })
}
}, [skills])
return (
@@ -296,23 +319,12 @@ const ExperienceForm = ({ isDrawerOpen, mode, onOpenClose, experienceId }: Exper
<Controller
name="skills"
control={methods.control}
render={({ field: { onChange, value } }) => (
// <input
// type='text'
// className='input w-full'
// disabled={state.isDisabled}
// onChange={onChange}
// value={value}
// />
<Listbox value={value} onChange={onChange}>
<ListboxOptions anchor='bottom'>
{state.skillOptions?.map((skill) => (
<ListboxOption key={skill.id} value={skill.id}>
{skill.name}
</ListboxOption>
))}
</ListboxOptions>
</Listbox>
render={() => (
<MultiSelectDropdown
skills={state.skillOptions}
onChange={onSetSelectedSkills}
selectedSkills={state.selectedSkills}
/>
)}
/>
</div>

View File

@@ -6,5 +6,6 @@ export interface ExperienceFormState {
isDisabled: boolean;
isLoading: boolean;
profileOptions: Profile[];
skillOptions: Skill[] | undefined;
selectedSkills: Skill[];
skillOptions: Skill[];
}

View File

@@ -7,13 +7,15 @@ type Action =
| { type: 'SET_IS_DISABLED'; payload: boolean }
| { type: 'SET_IS_LOADING'; payload: boolean }
| { type: 'SET_PROFILE_OPTIONS'; payload: Profile[] }
| { type: 'SET_SKILL_OPTIONS'; payload: Skill[] | undefined };
| { type: 'SET_SELECTED_SKILLS'; payload: Skill[] }
| { type: 'SET_SKILL_OPTIONS'; payload: Skill[] };
export const initialState: ExperienceFormState = {
error: undefined,
isDisabled: false,
isLoading: true,
profileOptions: [],
selectedSkills: [],
skillOptions: []
};
@@ -46,6 +48,12 @@ export const reducer = (
profileOptions: action.payload
}
}
case 'SET_SELECTED_SKILLS': {
return {
...state,
selectedSkills: action.payload
}
}
case 'SET_SKILL_OPTIONS': {
return {
...state,

View File

@@ -12,7 +12,7 @@ export interface Experience {
startDate: Date;
endDate?: Date;
summary?: string;
skills: Skill[];
skills?: Skill[];
profile: Profile;
status: Status;
}

View File

@@ -17,6 +17,7 @@ import { useUserRole } from '../../hooks/userRole/UseUserRole';
import Alert from '../../alert/Alert';
import { CellContext, ColumnDef, flexRender, getCoreRowModel, getPaginationRowModel, useReactTable } from '@tanstack/react-table';
import { Profile } from '../profiles/Profile.interface';
import { Skill } from '../skills/Skill.interface';
interface ActionsProps {
id: string;
@@ -166,6 +167,17 @@ const Experiences = () => {
accessorKey: 'summary',
header: 'Summary'
},
{
id: 'skills',
accessorKey: 'skills',
header: 'Skills',
cell: (info: CellContext<Experience, unknown>) => {
const skills = info.getValue() as Skill[];
const skillsString: string = skills.map((skill) => skill.name).join(', ')
return skillsString
}
},
{
id: 'status',
accessorKey: 'status',

View File

@@ -1,32 +1,33 @@
import { useEffect, useRef, useState } from "react";
import { MultiSelectDropdownProps } from "./MultiSelectDropdownProps";
import { Skill } from "../skills/Skill.interface";
const MultiSelectDropdown = ({ options }: MultiSelectDropdownProps) => {
const MultiSelectDropdown = ({ onChange, skills, selectedSkills }: MultiSelectDropdownProps) => {
const [isOpen, setIsOpen] = useState(false);
const [selectedValues, setSelectedValues] = useState([])
// const [selectedValues, setSelectedValues] = useState([])
const dropdownRef = useRef(null)
const handleToggleOption = (value: any) => {
let updated;
// let updated;
if (selectedValues.includes(value)) {
updated = selectedValues.filter((item) => item !== value);
} else {
updated = [...selectedValues, value];
}
// if (selectedValues.includes(value)) {
// updated = selectedValues.filter((item) => item !== value);
// } else {
// updated = [...selectedValues, value];
// }
setSelectedValues(updated);
if (onChange) onChange(updated)
// setSelectedValues(updated);
// if (onChange) onChange(updated)
}
const handleRemoveBadge = (event, value) => {
event.stopPropagation();
// event.stopPropagation();
const updated = selectedValues.filter((item) => item !== value);
// const updated = selectedValues.filter((item) => item !== value);
setSelectedValues(updated)
// setSelectedValues(updated)
if (onChange) onchange(updated)
// if (onChange) onchange(updated)
}
useEffect(() => {
@@ -50,21 +51,15 @@ const MultiSelectDropdown = ({ options }: MultiSelectDropdownProps) => {
className="select select-bordered w-full h-auto min-h-12 flex flex-wrap items-center gap-1 p-2 bg-base-100 text-left cursor-pointer"
onClick={() => setIsOpen(!isOpen)}
>
{selectedValues.length === 0 ? (
{selectedSkills.length === 0 ? (
<span className="text-base-content/50"></span>
) : (
<div className="flex flex-wrap gap-1">
{selectedValues.map((val) => {
const option = options.find((o: any) => o.value === val);
{selectedSkills.map((selectedSkill: Skill) => {
const option = skills.find((skill: Skill) => skill.id === selectedSkill.id);
return (
<div key={val} className="badge badge-primary gap-1 py-3 px-2">
{option?.label || val}
<button
onClick={(event) => handleRemoveBadge(event, val)}
className="btn btn-ghost btn-xs p-0 min-h-0 h-auto text-primary-content hover:bg-transparent"
>
</button>
<div key={selectedSkill.id} className="badge badge-primary gap-1 py-3 px-2">
{option?.name || selectedSkill.name}
</div>
);
})}
@@ -75,16 +70,16 @@ const MultiSelectDropdown = ({ options }: MultiSelectDropdownProps) => {
tabIndex={0}
className="dropdown-content menu p-2 shadow-lg bg-base-100 rounded-box w-full max-h-60 overflow-y-auto z-[1] border border-base-200"
>
{options.map((option) => (
<li key={option.value} className="p-0">
{skills.map((skill) => (
<li key={skill.id} className="p-0">
<label className="label cursor-pointer justify-start gap-3 px-4 py-2 hover:bg-base-200 rounded-lg w-full">
<input
type="checkbox"
className="checkbox checkbox-primary checkbox-sm"
checked={selectedValues.includes(option.value)}
onChange={() => handleToggleOption(option.value)}
checked={selectedSkills.includes(skill)}
onChange={() => onChange(skill)}
/>
<span className="label-text text-base-content">{option.label}</span>
<span className="label-text text-base-content">{skill.name}</span>
</label>
</li>
))}

View File

@@ -1,3 +1,7 @@
import { Skill } from "../skills/Skill.interface";
export interface MultiSelectDropdownProps {
options: { label: string; value: string }[];
onChange: (selectedSkill: Skill) => void;
skills: Skill[];
selectedSkills: Skill[];
}

View File

@@ -10,15 +10,21 @@ import { faSave, faXmark } from '@fortawesome/free-solid-svg-icons';
import { ScreenSize } from '../../enums/screenSize';
import { useBreakpoints } from '../../hooks/breakpoints/UseBreakpoints';
import { useAppContext } from '../../hooks/appContext/UseAppContext';
import { Skill } from '../skills/Skill.interface';
import { useSkills } from '../../hooks/skills/UseSkills';
import MultiSelectDropdown from '../multiSelectDropdown/MultiSelectDropdown';
const ProfileForm = ({ isDrawerOpen, mode, onOpenClose, profileId }: ProfileFormProps) => {
const [state, dispatch] = useReducer(reducer, initialState);
const appContext = useAppContext();
const { skills } = useSkills();
const projectSkills: Skill[] = []
const defaultValues = {
name: '',
headline: '',
summary: '',
userId: '',
skills: projectSkills,
statusId: 1
}
const methods = useForm({
@@ -27,6 +33,20 @@ const ProfileForm = ({ isDrawerOpen, mode, onOpenClose, profileId }: ProfileForm
// const watchRepoName = methods.watch(['repoName'])
const { screenSize } = useBreakpoints();
const onSetSelectedSkills = (selectedSkill: Skill) => {
const selectedSkillExists = state.selectedSkills.find((skill) => skill.id === selectedSkill.id)
let newSelectedSkills: Skill[];
if (selectedSkillExists) {
newSelectedSkills = state.selectedSkills.filter((skill) => skill.id !== selectedSkillExists.id)
} else {
newSelectedSkills = [...state.selectedSkills, selectedSkill]
}
dispatch({ type: 'SET_SELECTED_SKILLS', payload: newSelectedSkills })
methods.setValue('skills', newSelectedSkills)
}
const onCancel = () => {
methods.reset(defaultValues);
dispatch({ type: 'SET_IS_DISABLED', payload: false });
@@ -80,9 +100,13 @@ const ProfileForm = ({ isDrawerOpen, mode, onOpenClose, profileId }: ProfileForm
const response: AxiosResponse = await httpClient.get(
`api/profiles/${profileId}`
);
const entry = response.data;
const profile = response.data;
methods.reset(entry);
if (profile.skills) {
dispatch({ type: 'SET_SELECTED_SKILLS', payload: profile.skills })
}
methods.reset(profile);
} catch (error) {
const axiosError = error as AxiosError;
console.log(axiosError)
@@ -97,6 +121,12 @@ const ProfileForm = ({ isDrawerOpen, mode, onOpenClose, profileId }: ProfileForm
}
}, [profileId]);
useEffect(() => {
if (skills) {
dispatch({ type: 'SET_SKILL_OPTIONS', payload: skills })
}
}, [skills])
return (
<div className='drawer drawer-end'>
<input type='checkbox' className='drawer-toggle' onChange={() => {}} checked={isDrawerOpen} />
@@ -175,6 +205,22 @@ const ProfileForm = ({ isDrawerOpen, mode, onOpenClose, profileId }: ProfileForm
)}
/>
</div>
<div className={`col-span-3 self-center after:content-['*'] after:ms-0.5`}>
<span>Skills</span>
</div>
<div className='col-span-9'>
<Controller
name="skills"
control={methods.control}
render={() => (
<MultiSelectDropdown
skills={state.skillOptions}
onChange={onSetSelectedSkills}
selectedSkills={state.selectedSkills}
/>
)}
/>
</div>
<div className='col-span-12 justify-self-end self-center'>
<button
className='btn'

View File

@@ -1,5 +1,9 @@
import { Skill } from "../skills/Skill.interface";
export interface ProfileFormState {
error: string | undefined;
isDisabled: boolean;
isLoading: boolean;
selectedSkills: Skill[];
skillOptions: Skill[];
}

View File

@@ -1,15 +1,20 @@
import { Profile } from "../profiles/Profile.interface";
import { Skill } from "../skills/Skill.interface";
import { ProfileFormState } from "./ProfileFormState.interface"
type Action =
| { type: 'SET_ERROR'; payload: string | undefined }
| { type: 'SET_IS_DISABLED'; payload: boolean }
| { type: 'SET_IS_LOADING'; payload: boolean };
| { type: 'SET_IS_LOADING'; payload: boolean }
| { type: 'SET_SELECTED_SKILLS'; payload: Skill[] }
| { type: 'SET_SKILL_OPTIONS'; payload: Skill[] };
export const initialState: ProfileFormState = {
error: undefined,
isDisabled: false,
isLoading: true
isLoading: true,
selectedSkills: [],
skillOptions: []
};
export const reducer = (
@@ -34,6 +39,18 @@ export const reducer = (
...state,
isLoading: action.payload
};
}
case 'SET_SELECTED_SKILLS': {
return {
...state,
selectedSkills: action.payload
}
}
case 'SET_SKILL_OPTIONS': {
return {
...state,
skillOptions: action.payload
}
}
default: {
return state;

View File

@@ -16,6 +16,7 @@ import { UserRole } from '../../enums/userRole';
import { useUserRole } from '../../hooks/userRole/UseUserRole';
import Alert from '../../alert/Alert';
import { CellContext, ColumnDef, flexRender, getCoreRowModel, getPaginationRowModel, useReactTable } from '@tanstack/react-table';
import { Skill } from '../skills/Skill.interface';
interface ActionsProps {
id: string;
@@ -144,6 +145,17 @@ const Profiles = () => {
accessorKey: 'summary',
header: 'Summary'
},
{
id: 'skills',
accessorKey: 'skills',
header: 'Skills',
cell: (info: CellContext<Profile, unknown>) => {
const skills = info.getValue() as Skill[];
const skillsString: string = skills.map((skill) => skill.name).join(', ')
return skillsString
}
},
{
id: 'status',
accessorKey: 'status',

View File

@@ -11,10 +11,15 @@ import { ScreenSize } from '../../enums/screenSize';
import { useBreakpoints } from '../../hooks/breakpoints/UseBreakpoints';
import { useProfiles } from '../../hooks/profiles/UseProfiles';
import { Profile } from '../profiles/Profile.interface';
import { Skill } from '../skills/Skill.interface';
import { useSkills } from '../../hooks/skills/UseSkills';
import MultiSelectDropdown from '../multiSelectDropdown/MultiSelectDropdown';
const ProjectForm = ({ isDrawerOpen, mode, onOpenClose, projectId }: ProjectFormProps) => {
const [state, dispatch] = useReducer(reducer, initialState);
const { profiles } = useProfiles()
const { profiles } = useProfiles();
const { skills } = useSkills();
const projectSkills: Skill[] = []
const defaultValues = {
profileId: '',
name: '',
@@ -23,6 +28,7 @@ const ProjectForm = ({ isDrawerOpen, mode, onOpenClose, projectId }: ProjectForm
repoUrl: '',
siteUrl: '',
order: '',
skills: projectSkills,
statusId: 1
}
const methods = useForm({
@@ -31,6 +37,20 @@ const ProjectForm = ({ isDrawerOpen, mode, onOpenClose, projectId }: ProjectForm
// const watchRepoName = methods.watch(['repoName'])
const { screenSize } = useBreakpoints();
const onSetSelectedSkills = (selectedSkill: Skill) => {
const selectedSkillExists = state.selectedSkills.find((skill) => skill.id === selectedSkill.id)
let newSelectedSkills: Skill[];
if (selectedSkillExists) {
newSelectedSkills = state.selectedSkills.filter((skill) => skill.id !== selectedSkillExists.id)
} else {
newSelectedSkills = [...state.selectedSkills, selectedSkill]
}
dispatch({ type: 'SET_SELECTED_SKILLS', payload: newSelectedSkills })
methods.setValue('skills', newSelectedSkills)
}
const onCancel = () => {
methods.reset(defaultValues);
dispatch({ type: 'SET_IS_DISABLED', payload: false });
@@ -44,7 +64,7 @@ const ProjectForm = ({ isDrawerOpen, mode, onOpenClose, projectId }: ProjectForm
if (!projectId) {
await httpClient.post(`api/projects`, data);
} else {
await httpClient.put(`api/projects/project/${projectId}`, data);
await httpClient.put(`api/projects/${projectId}`, data);
}
methods.reset(defaultValues);
@@ -77,11 +97,15 @@ const ProjectForm = ({ isDrawerOpen, mode, onOpenClose, projectId }: ProjectForm
dispatch({ type: 'SET_IS_LOADING', payload: true });
const response: AxiosResponse = await httpClient.get(
`api/projects/project/${projectId}`
`api/projects/${projectId}`
);
const entry = response.data;
const project = response.data;
methods.reset(entry);
if (project.skills) {
dispatch({ type: 'SET_SELECTED_SKILLS', payload: project.skills })
}
methods.reset(project);
} catch (error) {
const axiosError = error as AxiosError;
console.log(axiosError)
@@ -107,13 +131,20 @@ const ProjectForm = ({ isDrawerOpen, mode, onOpenClose, projectId }: ProjectForm
summary: '',
userId: '',
experiences: [],
skills: []
skills: [],
status: null
})
dispatch({ type: 'SET_PROFILE_OPTIONS', payload: newProfileOptions });
}
}, [profiles]);
useEffect(() => {
if (skills) {
dispatch({ type: 'SET_SKILL_OPTIONS', payload: skills })
}
}, [skills])
return (
<div className='drawer drawer-end'>
<input type='checkbox' className='drawer-toggle' onChange={() => {}} checked={isDrawerOpen} />
@@ -272,6 +303,22 @@ const ProjectForm = ({ isDrawerOpen, mode, onOpenClose, projectId }: ProjectForm
)}
/>
</div>
<div className={`col-span-3 self-center after:content-['*'] after:ms-0.5`}>
<span>Skills</span>
</div>
<div className='col-span-9'>
<Controller
name="skills"
control={methods.control}
render={() => (
<MultiSelectDropdown
skills={state.skillOptions}
onChange={onSetSelectedSkills}
selectedSkills={state.selectedSkills}
/>
)}
/>
</div>
<div className='col-span-12 justify-self-end self-center'>
<button
className='btn'

View File

@@ -1,8 +1,11 @@
import { Profile } from "../profiles/Profile.interface";
import { Skill } from "../skills/Skill.interface";
export interface ProjectFormState {
error: string | undefined;
isDisabled: boolean;
isLoading: boolean;
profileOptions: Profile[];
selectedSkills: Skill[];
skillOptions: Skill[];
}

View File

@@ -1,17 +1,22 @@
import { Profile } from "../profiles/Profile.interface";
import { Skill } from "../skills/Skill.interface";
import { ProjectFormState } from "./ProjectFormState.interface"
type Action =
| { type: 'SET_ERROR'; payload: string | undefined }
| { type: 'SET_IS_DISABLED'; payload: boolean }
| { type: 'SET_IS_LOADING'; payload: boolean }
| { type: 'SET_PROFILE_OPTIONS'; payload: Profile[] };
| { type: 'SET_PROFILE_OPTIONS'; payload: Profile[] }
| { type: 'SET_SELECTED_SKILLS'; payload: Skill[] }
| { type: 'SET_SKILL_OPTIONS'; payload: Skill[] };
export const initialState: ProjectFormState = {
error: undefined,
isDisabled: false,
isLoading: true,
profileOptions: []
profileOptions: [],
selectedSkills: [],
skillOptions: []
};
export const reducer = (
@@ -43,6 +48,18 @@ export const reducer = (
profileOptions: action.payload
}
}
case 'SET_SELECTED_SKILLS': {
return {
...state,
selectedSkills: action.payload
}
}
case 'SET_SKILL_OPTIONS': {
return {
...state,
skillOptions: action.payload
}
}
default: {
return state;
}

View File

@@ -1,20 +1,4 @@
import { Project } from './Project.interface';
// import {
// Alert,
// Box,
// Button,
// Card,
// CardActions,
// CardContent,
// CardHeader,
// Container,
// Grid,
// Icon,
// IconName,
// Skeleton,
// Stack,
// Typography
// } from '@noahspan/noahspan-components';
import { FormMode } from '../../enums/formMode';
import { useEffect, useReducer } from 'react';
import { initialState, reducer } from './reducer';
@@ -32,6 +16,7 @@ import { UserRole } from '../../enums/userRole';
import { useUserRole } from '../../hooks/userRole/UseUserRole';
import Alert from '../../alert/Alert';
import { CellContext, ColumnDef, flexRender, getCoreRowModel, getPaginationRowModel, useReactTable } from '@tanstack/react-table';
import { Skill } from '../skills/Skill.interface';
interface ActionsProps {
id: string;
@@ -169,6 +154,17 @@ const Projects = () => {
accessorKey: 'summary',
header: 'Summary'
},
{
id: 'skills',
accessorKey: 'skills',
header: 'Skills',
cell: (info: CellContext<Project, unknown>) => {
const skills = info.getValue() as Skill[];
const skillsString: string = skills.map((skill) => skill.name).join(', ')
return skillsString
}
},
{
id: 'status',
accessorKey: 'status',

BIN
database/portfolio.db Normal file

Binary file not shown.

70
docker-compose.yaml Normal file
View File

@@ -0,0 +1,70 @@
services:
azurite:
container_name: azurite-portfolio
image: mcr.microsoft.com/azure-storage/azurite
ports:
- '10000:10000'
- '10001:10001'
- '10002:10002'
command: 'azurite --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost 0.0.0.0 --loose --skipApiVersionCheck'
healthcheck:
test: ["CMD", "nc", "-z", "127.0.0.1", "10000"]
volumes:
- ./azurite-data:/data
# seed:
# image: mcr.microsoft.com/azure-cli
# depends_on:
# azurite:
# condition: service_healthy
# volumes:
# - ./seed-data:/data
# entrypoint: >
# sh -c "
# az storage container create --name mycontainer --connection-string 'DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://azurite:10000/devstoreaccount1;' &&
# az storage blob upload-batch --destination mycontainer --source /data --connection-string 'DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://azurite:10000/devstoreaccount1;'
# "
restore:
container_name: restore
image: litestream/litestream:0.5.2
volumes:
- ./database/portfolio.db:/mnt/data/portfolio.db
- ./database/litestream/litestream.yml:/mnt/litestream/litestream.yml
- backup:/mnt/data/backup
- data:/mnt/data
command: restore -config /mnt/litestream/litestream.yml -if-db-not-exists -if-replica-exists /mnt/data/portfolio.db
app:
container_name: portfolio
build:
context: .
ports:
- '3000:3000'
env_file:
- ./api/.env
environment:
- DB_PATH=../../mnt/data/portfolio.db
volumes:
- data:/mnt/data
depends_on:
restore:
condition: service_completed_successfully
replicate:
container_name: replicate
image: litestream/litestream:0.5.2
volumes:
- ./database/litestream/litestream.yml:/mnt/litestream/litestream.yml
- backup:/mnt
- data:/mnt/data
command: replicate -config /mnt/litestream/litestream.yml
depends_on:
app:
condition: service_started
volumes:
azurite-data:
backup:
data:
# seed-data:

14535
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@
},
"workspaces": [
"api",
"cms",
"client",
"static-wfe"
]
}