mirror of
https://github.com/pawelmalak/snippet-box.git
synced 2025-12-21 13:23:05 +01:00
Create/update snippet with tags. DB migration to support tags
This commit is contained in:
@@ -77,7 +77,7 @@ docker run -p 5000:5000 -v /path/to/data:/app/data snippet-box
|
||||
|
||||

|
||||
|
||||
- Edditor
|
||||
- Editor
|
||||
- Create and edit your snippets from simple and easy to use editor
|
||||
|
||||

|
||||
|
||||
@@ -25,7 +25,8 @@ export const SnippetForm = (props: Props): JSX.Element => {
|
||||
language: '',
|
||||
code: '',
|
||||
docs: '',
|
||||
isPinned: false
|
||||
isPinned: false,
|
||||
tags: ''
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
@@ -109,11 +110,31 @@ export const SnippetForm = (props: Props): JSX.Element => {
|
||||
id='language'
|
||||
name='language'
|
||||
value={formData.language}
|
||||
placeholder='bash'
|
||||
placeholder='python'
|
||||
required
|
||||
onChange={e => inputHandler(e)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* TAGS */}
|
||||
<div className='mb-3'>
|
||||
<label htmlFor='tags' className='form-label'>
|
||||
Tags
|
||||
</label>
|
||||
<input
|
||||
type='text'
|
||||
className='form-control'
|
||||
id='tags'
|
||||
name='tags'
|
||||
value={formData.tags}
|
||||
placeholder='automation, files, loop'
|
||||
required
|
||||
onChange={e => inputHandler(e)}
|
||||
/>
|
||||
<div className='form-text'>
|
||||
Language tag will be added automatically
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
{/* CODE SECTION */}
|
||||
|
||||
@@ -7,6 +7,7 @@ export interface NewSnippet {
|
||||
code: string;
|
||||
docs?: string;
|
||||
isPinned: boolean;
|
||||
tags: string;
|
||||
}
|
||||
|
||||
export interface Snippet extends Model, NewSnippet {}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"dev:client": "npm start --prefix=client",
|
||||
"dev:server": "nodemon",
|
||||
"dev": "npm-run-all -n --parallel dev:**",
|
||||
"build:client": "npm run build prefix=client",
|
||||
"build:clear": "rm -rf build",
|
||||
"build:tsc": "tsc",
|
||||
"build": "npm-run-all -n build:**"
|
||||
|
||||
@@ -3,7 +3,7 @@ import { QueryTypes } from 'sequelize';
|
||||
import { sequelize } from '../db';
|
||||
import { asyncWrapper } from '../middleware';
|
||||
import { SnippetModel } from '../models';
|
||||
import { ErrorResponse } from '../utils';
|
||||
import { ErrorResponse, tagsParser } from '../utils';
|
||||
|
||||
/**
|
||||
* @description Create new snippet
|
||||
@@ -12,7 +12,17 @@ import { ErrorResponse } from '../utils';
|
||||
*/
|
||||
export const createSnippet = asyncWrapper(
|
||||
async (req: Request, res: Response, next: NextFunction): Promise<void> => {
|
||||
const snippet = await SnippetModel.create(req.body);
|
||||
const { language, tags } = <{ language: string; tags: string }>req.body;
|
||||
const parsedTags = tagsParser(tags);
|
||||
|
||||
if (!parsedTags.includes(language.toLowerCase())) {
|
||||
parsedTags.push(language.toLowerCase());
|
||||
}
|
||||
|
||||
const snippet = await SnippetModel.create({
|
||||
...req.body,
|
||||
tags: parsedTags.join(',')
|
||||
});
|
||||
|
||||
res.status(201).json({
|
||||
data: snippet
|
||||
@@ -81,7 +91,23 @@ export const updateSnippet = asyncWrapper(
|
||||
);
|
||||
}
|
||||
|
||||
snippet = await snippet.update(req.body);
|
||||
// Check if language was changed. Edit tags if so
|
||||
const { language: oldLanguage } = snippet;
|
||||
const { language, tags } = <{ language: string; tags: string }>req.body;
|
||||
let parsedTags = tagsParser(tags);
|
||||
|
||||
if (oldLanguage != language) {
|
||||
parsedTags = parsedTags.filter(tag => tag != oldLanguage);
|
||||
|
||||
if (!parsedTags.includes(language)) {
|
||||
parsedTags.push(language.toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
snippet = await snippet.update({
|
||||
...req.body,
|
||||
tags: parsedTags.join(',')
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
data: snippet
|
||||
|
||||
19
src/db/migrations/02_tags.ts
Normal file
19
src/db/migrations/02_tags.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { DataTypes, QueryInterface, QueryTypes } from 'sequelize';
|
||||
import { sequelize } from '../';
|
||||
const { STRING } = DataTypes;
|
||||
|
||||
export const up = async (queryInterface: QueryInterface): Promise<void> => {
|
||||
await queryInterface.addColumn('snippets', 'tags', {
|
||||
type: STRING,
|
||||
allowNull: true,
|
||||
defaultValue: ''
|
||||
});
|
||||
|
||||
await sequelize.query(`UPDATE snippets SET tags = language`, {
|
||||
type: QueryTypes.UPDATE
|
||||
});
|
||||
};
|
||||
|
||||
export const down = async (queryInterface: QueryInterface): Promise<void> => {
|
||||
await queryInterface.removeColumn('snippets', 'tags');
|
||||
};
|
||||
@@ -41,6 +41,11 @@ export const SnippetModel = sequelize.define<SnippetInstance>('Snippet', {
|
||||
allowNull: true,
|
||||
defaultValue: 0
|
||||
},
|
||||
tags: {
|
||||
type: STRING,
|
||||
allowNull: true,
|
||||
defaultValue: ''
|
||||
},
|
||||
createdAt: {
|
||||
type: DATE
|
||||
},
|
||||
|
||||
@@ -8,6 +8,7 @@ export interface Snippet extends Model {
|
||||
code: string;
|
||||
docs: string;
|
||||
isPinned: number;
|
||||
tags: string;
|
||||
}
|
||||
|
||||
export interface SnippetCreationAttributes
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from './Logger';
|
||||
export * from './ErrorResponse';
|
||||
export * from './tagsParser';
|
||||
|
||||
8
src/utils/tagsParser.ts
Normal file
8
src/utils/tagsParser.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export const tagsParser = (tags: string): string[] => {
|
||||
const parsedTags = tags
|
||||
.split(',')
|
||||
.map(tag => tag.trim().toLowerCase())
|
||||
.filter(String);
|
||||
|
||||
return parsedTags;
|
||||
};
|
||||
Reference in New Issue
Block a user