new snippet
This commit is contained in:
@ -25,7 +25,7 @@ SECRET_KEY = "django-insecure-o27968vc7m@z*=+$ykqo!b2v+ycc)r2^d8u=)ee)gi5bas-+wm
|
|||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
|
|
||||||
ALLOWED_HOSTS = ['ovz1.ollyhearn.gmzem.vps.myjino.ru']
|
ALLOWED_HOSTS = ['ovz1.ollyhearn.gmzem.vps.myjino.ru', 'localhost', '127.0.0.1']
|
||||||
|
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|||||||
@ -15,7 +15,7 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "3000"
|
- "3000"
|
||||||
environment:
|
environment:
|
||||||
- REACT_APP_DOMAIN=ovz1.ollyhearn.gmzem.vps.myjino.ru
|
- REACT_APP_DOMAIN=localhost
|
||||||
volumes:
|
volumes:
|
||||||
- ./react/app:/app:z
|
- ./react/app:/app:z
|
||||||
# - ./docker_cache/node_modules:/app/node_modules
|
# - ./docker_cache/node_modules:/app/node_modules
|
||||||
|
|||||||
@ -1,17 +1,21 @@
|
|||||||
# stage1 - build react app first
|
FROM node:20.1
|
||||||
FROM node:20-alpine as build
|
|
||||||
WORKDIR /app
|
|
||||||
ENV PATH /app/node_modules/.bin:$PATH
|
|
||||||
COPY ./app/package.json /app/
|
|
||||||
COPY ./app/yarn.lock /app/
|
|
||||||
RUN yarn
|
|
||||||
COPY /app /app
|
|
||||||
RUN yarn build
|
|
||||||
|
|
||||||
# stage 2 - build the final image and copy the react build files
|
ENV CI=true
|
||||||
FROM nginx:1.25.0-alpine
|
ENV PORT=3000
|
||||||
COPY --from=build /app/build /usr/share/nginx/html
|
ENV HOST=0.0.0.0
|
||||||
RUN rm /etc/nginx/conf.d/default.conf
|
ENV WDS_SOCKET_PORT=0
|
||||||
COPY nginx/nginx.conf /etc/nginx/conf.d
|
ENV REACT_APP_DOMAIN=127.0.0.1
|
||||||
EXPOSE 80
|
|
||||||
CMD ["nginx", "-g", "daemon off;"]
|
WORKDIR /app
|
||||||
|
COPY /app /app
|
||||||
|
# COPY package.json /app/package.json
|
||||||
|
# COPY package-lock.json /app/package-lock.json
|
||||||
|
|
||||||
|
# Same as npm install
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
# COPY . /app
|
||||||
|
#
|
||||||
|
|
||||||
|
RUN printenv
|
||||||
|
CMD [ "npm", "start" ]
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
|
|||||||
import { AuthProvider } from "./context/AuthContext";
|
import { AuthProvider } from "./context/AuthContext";
|
||||||
import AuthPage from './pages/AuthPage'
|
import AuthPage from './pages/AuthPage'
|
||||||
import SnippetPage from './pages/SnippetPage'
|
import SnippetPage from './pages/SnippetPage'
|
||||||
|
import NewSnippet from './pages/NewSnippetPage'
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
@ -19,6 +20,9 @@ function App() {
|
|||||||
<Route path="/snippet/:id" element={<div className="App">
|
<Route path="/snippet/:id" element={<div className="App">
|
||||||
<SnippetPage />
|
<SnippetPage />
|
||||||
</div>} />
|
</div>} />
|
||||||
|
<Route path="/new-snippet" element={<div className="App">
|
||||||
|
<NewSnippet />
|
||||||
|
</div>} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
</Router>
|
</Router>
|
||||||
|
|||||||
@ -17,10 +17,11 @@ import {
|
|||||||
} from 'mdb-react-ui-kit';
|
} from 'mdb-react-ui-kit';
|
||||||
import 'mdb-react-ui-kit/dist/css/mdb.min.css';
|
import 'mdb-react-ui-kit/dist/css/mdb.min.css';
|
||||||
import "@fortawesome/fontawesome-free/css/all.min.css";
|
import "@fortawesome/fontawesome-free/css/all.min.css";
|
||||||
import { Link } from 'react-router-dom';
|
import { Link, useLocation } from 'react-router-dom';
|
||||||
import AuthContext from "../context/AuthContext";
|
import AuthContext from "../context/AuthContext";
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
|
const location = useLocation();
|
||||||
const [showBasic, setShowBasic] = useState(false);
|
const [showBasic, setShowBasic] = useState(false);
|
||||||
const { user, logoutUser } = useContext(AuthContext);
|
const { user, logoutUser } = useContext(AuthContext);
|
||||||
|
|
||||||
@ -69,7 +70,7 @@ export default function App() {
|
|||||||
</MDBNavbarItem>
|
</MDBNavbarItem>
|
||||||
|
|
||||||
<MDBNavbarItem>
|
<MDBNavbarItem>
|
||||||
<MDBNavbarLink disabled={user && false} href='#' tabIndex={-1} aria-disabled='true' background='#3b71ca'>
|
<MDBNavbarLink disabled={user && false} href='/new-snippet' tabIndex={-1} aria-disabled='true' background='#3b71ca'>
|
||||||
New snippet
|
New snippet
|
||||||
</MDBNavbarLink>
|
</MDBNavbarLink>
|
||||||
</MDBNavbarItem>
|
</MDBNavbarItem>
|
||||||
|
|||||||
86
react/app/src/components/NewSnippet.jsx
Normal file
86
react/app/src/components/NewSnippet.jsx
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import React, { useContext, useState } from 'react';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import {
|
||||||
|
MDBCard,
|
||||||
|
MDBCardBody,
|
||||||
|
MDBCardTitle,
|
||||||
|
MDBCardText,
|
||||||
|
MDBBtn,
|
||||||
|
MDBInput,
|
||||||
|
} from 'mdb-react-ui-kit';
|
||||||
|
import 'mdb-react-ui-kit/dist/css/mdb.min.css';
|
||||||
|
import "@fortawesome/fontawesome-free/css/all.min.css";
|
||||||
|
import AuthContext from "../context/AuthContext";
|
||||||
|
import MonacoEditor from 'react-monaco-editor';
|
||||||
|
|
||||||
|
const NewSnippet = () => {
|
||||||
|
const { authTokens } = useContext(AuthContext);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const [ snippetContent, setSnippetContent ] = useState("");
|
||||||
|
const [ snippetTitle, setSnippetTitle ] = useState("");
|
||||||
|
|
||||||
|
const saveSnippet = async () => {
|
||||||
|
const response = await fetch(`http://${process.env.REACT_APP_DOMAIN}/api/snippets/`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Authorization": `Bearer ${authTokens.access}`,
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ "content": snippetContent, "title": snippetTitle })
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (response.status === 201) {
|
||||||
|
alert("Snippet created!")
|
||||||
|
navigate(`/snippet/${data?.id}`)
|
||||||
|
} else {
|
||||||
|
alert(`Error updating snippet: ${data?.detail}`)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
autoIndent: 'full',
|
||||||
|
contextmenu: true,
|
||||||
|
fontFamily: 'monospace',
|
||||||
|
fontSize: 13,
|
||||||
|
lineHeight: 24,
|
||||||
|
hideCursorInOverviewRuler: true,
|
||||||
|
matchBrackets: 'always',
|
||||||
|
minimap: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
scrollbar: {
|
||||||
|
horizontalSliderSize: 4,
|
||||||
|
verticalSliderSize: 18,
|
||||||
|
},
|
||||||
|
selectOnLineNumbers: true,
|
||||||
|
roundedSelection: false,
|
||||||
|
readOnly: false,
|
||||||
|
cursorStyle: 'line',
|
||||||
|
automaticLayout: true,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<MDBCard>
|
||||||
|
<MDBCardBody>
|
||||||
|
<MDBInput type="text" placeholder='Your snippet title..' value={snippetTitle} onChange={(e) => setSnippetTitle(e.target.value)}/>
|
||||||
|
</MDBCardBody>
|
||||||
|
</MDBCard>
|
||||||
|
<div style={{textAlign: "left", height: "80vh"}}>
|
||||||
|
<MonacoEditor
|
||||||
|
height="80vh"
|
||||||
|
options={options}
|
||||||
|
value={snippetContent}
|
||||||
|
onChange={setSnippetContent}
|
||||||
|
/>
|
||||||
|
<MDBBtn className="mb-4 w-100" onClick={saveSnippet}>Create</MDBBtn>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default NewSnippet;
|
||||||
@ -11,9 +11,10 @@ import "@fortawesome/fontawesome-free/css/all.min.css";
|
|||||||
import AuthContext from "../context/AuthContext";
|
import AuthContext from "../context/AuthContext";
|
||||||
import MonacoEditor from 'react-monaco-editor';
|
import MonacoEditor from 'react-monaco-editor';
|
||||||
|
|
||||||
const Snippet = ({ id }) => {
|
const Snippet = ({ id = 0 }) => {
|
||||||
const { authTokens } = useContext(AuthContext);
|
const { authTokens } = useContext(AuthContext);
|
||||||
const [ snippet, setSnippet ] = useState("");
|
const [ snippet, setSnippet ] = useState(null);
|
||||||
|
const [ snippetContent, setSnippetContent ] = useState("");
|
||||||
const getSnippet = async (id) => {
|
const getSnippet = async (id) => {
|
||||||
const response = await fetch(`http://${process.env.REACT_APP_DOMAIN}/api/snippets/${id}`, {
|
const response = await fetch(`http://${process.env.REACT_APP_DOMAIN}/api/snippets/${id}`, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
@ -26,18 +27,20 @@ const Snippet = ({ id }) => {
|
|||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
console.log(data)
|
console.log(data)
|
||||||
setSnippet(data)
|
setSnippet(data)
|
||||||
|
setSnippetContent(data?.content)
|
||||||
} else {
|
} else {
|
||||||
console.log(data, authTokens)
|
console.log(data, authTokens)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const updateSnippet = async (id, snippet) => {
|
const updateSnippet = async () => {
|
||||||
|
console.log(snippet, snippetContent);
|
||||||
const response = await fetch(`http://${process.env.REACT_APP_DOMAIN}/api/snippets/${id}`, {
|
const response = await fetch(`http://${process.env.REACT_APP_DOMAIN}/api/snippets/${id}`, {
|
||||||
method: "POST",
|
method: "PATCH",
|
||||||
headers: {
|
headers: {
|
||||||
"Authorization": `Bearer ${authTokens.access}`,
|
"Authorization": `Bearer ${authTokens.access}`,
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json"
|
||||||
},
|
},
|
||||||
body: snippet
|
body: JSON.stringify({...snippet, "content": snippetContent})
|
||||||
});
|
});
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
@ -75,7 +78,7 @@ const Snippet = ({ id }) => {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return snippet ? (
|
||||||
<>
|
<>
|
||||||
<MDBCard>
|
<MDBCard>
|
||||||
<MDBCardBody>
|
<MDBCardBody>
|
||||||
@ -86,11 +89,19 @@ const Snippet = ({ id }) => {
|
|||||||
<MonacoEditor
|
<MonacoEditor
|
||||||
height="80vh"
|
height="80vh"
|
||||||
options={options}
|
options={options}
|
||||||
value={snippet.content}
|
value={snippetContent}
|
||||||
|
onChange={setSnippetContent}
|
||||||
/>
|
/>
|
||||||
<MDBBtn className="mb-4 w-100" onClick={updateSnippet}>Save</MDBBtn>
|
<MDBBtn className="mb-4 w-100" onClick={updateSnippet}>Save</MDBBtn>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
) : (
|
||||||
|
<MDBCard>
|
||||||
|
<MDBCardBody>
|
||||||
|
<MDBCardTitle>Snippet not found!</MDBCardTitle>
|
||||||
|
<MDBCardText>Create your own at New Snippet </MDBCardText>
|
||||||
|
</MDBCardBody>
|
||||||
|
</MDBCard>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -40,8 +40,10 @@ export const AuthProvider = ({ children }) => {
|
|||||||
setUser(jwt_decode(data.access));
|
setUser(jwt_decode(data.access));
|
||||||
localStorage.setItem("authTokens", JSON.stringify(data));
|
localStorage.setItem("authTokens", JSON.stringify(data));
|
||||||
history("/");
|
history("/");
|
||||||
} else {
|
}
|
||||||
alert(response.data?.message);
|
|
||||||
|
if (response.status === 401) {
|
||||||
|
alert("Given credentials invalid!")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
12
react/app/src/pages/NewSnippetPage.jsx
Normal file
12
react/app/src/pages/NewSnippetPage.jsx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import BasicPage from './BasicPage'
|
||||||
|
import NewSnippet from '../components/NewSnippet'
|
||||||
|
|
||||||
|
const NewSnippetPage = () => {
|
||||||
|
return (
|
||||||
|
<BasicPage style={{margin: "20%"}}>
|
||||||
|
<NewSnippet />
|
||||||
|
</BasicPage>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NewSnippetPage;
|
||||||
Reference in New Issue
Block a user