I want to use vue3-cookies in my custom plugin, but whatever I do I keep getting undefined.
MyPlugin.js
export default {
install: (app, options) => {
app.config.globalProperties.$MyPlugin= {
someFunction() {
console.log(app.cookie);
console.log(app.cookies);
console.log(app.$cookies);
}
}
},
};
app.js
import {createApp} from 'vue';
import VueCookies from 'vue3-cookies'
import MyPlugin from "./plugins/MyPlugin";
const app = createApp({});
app.use(VueCookies)
app.use(MyPlugin)
const mountedApp = app.mount('#app');
What am I missing or doing wrong?
OK, I clearly missed a piece while reading the documentation.
This did the trick.
https://github.com/KanHarI/vue3-cookies#usage---via-composition-api-recommended
import {useCookies} from "vue3-cookies";
export default {
install: (app, options) => {
app.config.globalProperties.$MyPlugin = {
someFunction() {
const {cookies} = useCookies();
console.log(cookies.get('cookie_name'));
}
}
},
};
Related
I am trying to rearrange my MainHeader in Twilio. Trying to get rid of the Menu icon and the logo. Not sure if that is possible or not for the Menu icon but I tried hiding a Logo.
I tried following to hide the logo but it did not work.
import { VERSION } from '#twilio/flex-ui';
import { FlexPlugin } from '#twilio/flex-plugin';
import { ConnectorHelper } from './helpers/ConnectorHelper';
import ConnectorColorTheme from './theme/ConnectorColorTheme';
import reducers, { namespace } from './states';
import { StylesProvider, createGenerateClassName } from '#material-ui/core/styles';
import { FlexState } from '#twilio/flex-ui';
const PLUGIN_NAME = 'ConnectorPlugin';
const hideHeaderLogo = () => {
console.log("Hiding logo");
FlexState.ready().then(() => {
const { MainHeader } = FlexState;
MainHeader.setState({
showLogo: false
});
});
};
export default class ConnectorPlugin extends FlexPlugin {
constructor() {
super(PLUGIN_NAME);
}
async init(flex, manager) {
hideHeaderLogo();
const configuration = {
colorTheme: ConnectorColorTheme
};
apply theme
manager.updateConfig(configuration);
this.registerReducers(manager);
}
}
I'm new to Vue 3 (cli) and I'm not at all comfortable with front-end technology, so I'm having a hard time understanding the information I'm reading.
I succeeded in creating a registration/login interface with an api and JWT. The user information needs to be persisted everywhere in the project I'm doing to train myself, so I configured axios in my store.
store/index.js
import { createStore } from 'vuex'
import axios from 'axios';
const api = axios.create({
baseURL: 'http://127.0.0.1:7000'
});
let user = localStorage.getItem('user');
if(null === user) {
user = {uuid: '', token: ''};
} else {
try {
user = JSON.parse(user);
api.defaults.headers.common['Authorization'] = 'Bearer ' + user.token;
} catch (e) {
user = {uuid: '', token: ''};
}
}
export default createStore({
state: {
status: '',
user: user,
userInfos: {},
},
mutations: {
[...]
},
getters: {
},
actions: {
[...]
},
modules: {
}
})
I would like to be able to use api from my components. I have had several approaches:
1 - I have imported axios into my component, but this is not correct at all, as I will need axios in all my components.
2 - I've looked at different documentations that explain how to configure axios globally, but no two are the same and I couldn't get anything to work.
3 - I've tried calling api through strangenesses like this.$store.api in my methods, but obviously this is abused.
Can anyone help me understand what is the right way to use axios from my components and from the store with only one configuration? Knowing that I need to be able to keep my headers up to date for authentication with the Bearer Token (a mutation updates it in the store at user login).
main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap/dist/js/bootstrap.js'
import { library } from '#fortawesome/fontawesome-svg-core'
import { FontAwesomeIcon } from '#fortawesome/vue-fontawesome'
import { faMedal } from '#fortawesome/free-solid-svg-icons'
import { faLaptopMedical } from '#fortawesome/free-solid-svg-icons'
import { faCookieBite } from '#fortawesome/free-solid-svg-icons'
import { faCoins } from '#fortawesome/free-solid-svg-icons'
import { faHourglassStart } from '#fortawesome/free-solid-svg-icons'
import { faUpRightFromSquare } from '#fortawesome/free-solid-svg-icons'
import { faInfo } from '#fortawesome/free-solid-svg-icons'
import { faGears } from '#fortawesome/free-solid-svg-icons'
library.add(
faMedal,
faCoins,
faLaptopMedical,
faCookieBite,
faHourglassStart,
faUpRightFromSquare,
faInfo,
faGears
);
createApp(App)
.component('font-awesome-icon', FontAwesomeIcon)
.use(store)
.use(router)
.mount('#app')
Thank you very much for your help.
If you're creating a new app, I would use Pinia, which is really the next version of VueX. Don't put the user in localStorage, but in a store that you can access from all views and components.
So Axios setup in composables/myaxiosfile.js
// src/stores/oneStore.js
import { defineStore } from "pinia";
// Possibly import and deconstruct functions from #/api.js and use
// those functions in the "actions" section of the store,
// updating the state according to the answer of the api call.
export const useOneStore = defineStore("oneStore", {
state: () => {
return {
user: true
}
}
// actions
// getters
})
and in a component :
import { useOneStore } from '../stores/oneStore';
const oneStore = useOneStore()
I don't know if this is the right way, but by doing so, it allows me to use the store api in my components.
store/index.js
state: {
api: {},
[...]
},
mutations: {
setApi: function (state, api) {
state.api = api;
},
connexionUser: function (state, user) {
state.user = user;
api.defaults.headers.common['Authorization'] = 'Bearer ' + user.token;
state.api = api;
},
[...]
},
actions: {
setApi: ({commit}) => {
commit('setApi', api);
},
[...]
},
App.vue
mounted() {
this.$store.dispatch('setApi');
[...]
}
Like this, offline, it loads api which is set at the top of my store (see in my question) and when I log in, I update api in state to have JWT authentication.
I am having an issue with the following tech-stack:
Angular v8,
ionic Angular v5,
ngrx v8,
jasmine-marbles v0.8.3.
I am writing a unit test for "ngrx", in particular the "effects" part.
Following is my code snippet:
import { TestBed } from '#angular/core/testing';
import { provideMockActions } from '#ngrx/effects/testing';
import { Observable } from 'rxjs';
import { InformationEffects } from './information.effects';
import { HttpClientTestingModule, HttpTestingController } from '#angular/common/http/testing';
import { Storage } from '#ionic/storage';
import { DataService } from 'src/app/shared/services/data.service';
import { RouterTestingModule } from '#angular/router/testing';
import { cold, hot } from 'jasmine-marbles';
import { MockStore, provideMockStore } from '#ngrx/store/testing';
import {
InformationRequested,
InformationSuccess,
} from './information.actions';
describe('Information Effects', () => {
let information = {} as any;
const initialState = { information: information};
let actions$: Observable<any>;
let effects: InformationEffects;
let store: MockStore<any>;
let dataService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule, RouterTestingModule],
providers: [
{
provide: Storage,
},
InformationEffects,
MockStore,
provideMockStore({ initialState }),
provideMockActions(() => actions$),
{
provide: DataService,
useValue: jasmine.createSpyObj('DataService', ['getInformation'])
}
]
});
effects = TestBed.get(InformationEffects);
store = TestBed.get(MockStore);
dataService = TestBed.get(DataService);
});
it('should be created', () => {
expect(effects).toBeTruthy();
});
describe('INFORMATION_REQUESTED', () => {
it('should return an InformationSucess action, with the user, on success', () => {
let language = {} as any;
const action = new InformationRequested(language);
const outcome = new InformationSuccess(information);
actions$ = hot('-a-', { a: action });
const response = cold('-a|', { a: information });
const expected = cold('--b', { b: outcome });
dataService.getInformation.and.returnValue(response);
expect(effects.informationAction$).toBeObservable(expected);
});
});
});
When I run the test using "npm test", it failed at the "Received" part showing "?".
It says:
Expected: --b,
Received: --?,
Expected:
[{"frame":20,"notification":{"kind":"N","value":{"payload":{},"type":"[Information]
INFORMATION Success"},"hasValue":true}}]
Received:
[{"frame":20,"notification":{"kind":"N","value":{"payload":{},"type":"[Information]
INFORMATION Success"},"hasValue":true}}],
Please refer below figure:
enter image description here
I had searched the internet for this question mark in the "Received:" section, to no avail. I had also researched on each jasmine-marbles syntaxes, as well the (hot & cold) observable, to understand why & how to use it. Still no solution to get rid of the '?' question mark to have the unit-test being "Success". As such please help me.
I'm writing a Babel plugin that manipulates the AST node related to a specific decorator. I'm traversing the AST but for some reason, my plugin doesn't detect the method decorator - node.decorators is always null when the visitor visits a node.
This is the plugin:
import { ClassMethod, Decorator } from '#babel/types';
import { get } from 'lodash';
import { NodePath, PluginObj } from '#babel/core';
const providerArgumentsTransformer = (): PluginObj => ({
visitor: {
ClassMethod({ node, parent }: NodePath<ClassMethod>) {
const decorator = getProviderDecorator(node.decorators); // <- node.decorators is always null
if (getDecoratorName(decorator) === 'Provides') {
console.log('Success');
}
},
},
});
function getProviderDecorator(decorators: Array<Decorator> | undefined | null): Decorator | undefined {
return decorators?.find((decorator) => get(decorator, 'expression.callee.name') === 'Provides');
}
function getDecoratorName(decorator?: Decorator): string | undefined {
return get(decorator, 'expression.callee.name');
}
export default providerArgumentsTransformer;
I'm testing the decorator as follows:
import { PluginObj } from '#babel/core';
import * as babel from '#babel/core';
import providerArgumentsTransformer from './providerArgumentsTransformer';
const code = `class MainGraph {
Provides(clazz, propertyKey, descriptor) { }
#Provides()
someString(stringProvider) {
return stringProvider.theString;
}
}`;
describe('Provider Arguments Transformer', () => {
const uut: PluginObj = providerArgumentsTransformer();
it('Exposes transformer', () => {
babel.transformSync(code, {
plugins: [
['#babel/plugin-proposal-decorators', { legacy: true }],
['#babel/plugin-proposal-class-properties', { legacy: true }],
[uut, { legacy: true }],
],
configFile: false,
});
});
});
I wonder if the issue is related to how babel.transformSync is used or perhaps the visitor is not configured properly.
Turns out the decorators were missing because #babel/plugin-proposal-decorators clears the decorators when it traverses the AST.
In order to visit the node before #babel/plugin-proposal-decorators I had to modify my visitor a bit. This approach should probably be optimized by visiting ClassBody or ClassExpression instead of Program.
const providerArgumentsTransformer: PluginObj = {
visitor: {
Program(path: NodePath<Program>) {
path.traverse(internalVisitor);
},
},
};
const internalVisitor = {
ClassMethod: {
enter({ node }: NodePath<ClassMethod>) {
// node.decorators are not null anymore
},
},
};
We are using NestJS with mongoose and want to seed mongoDB.
Wondering what is the proper way to seed the database, and use the db schemas already defined to ensure the data seeded is valid and properly maintained.
Seeding at the module level (just before the definition of the Module) feels hacky and ends in threadpool being destroyed, and therefore all following mongo operations fail
I've done using the nestjs-command library like that.
1. Install the library:
https://www.npmjs.com/package/nestjs-command
2. Then I've created a command to seed my userService like:
src/modules/user/seeds/user.seed.ts
import { Command, Positional } from 'nestjs-command';
import { Injectable } from '#nestjs/common';
import { UserService } from '../../../shared/services/user.service';
#Injectable()
export class UserSeed {
constructor(
private readonly userService: UserService,
) { }
#Command({ command: 'create:user', describe: 'create a user', autoExit: true })
async create() {
const user = await this.userService.create({
firstName: 'First name',
lastName: 'Last name',
mobile: 999999999,
email: 'test#test.com',
password: 'foo_b#r',
});
console.log(user);
}
}
3. Add that seed command into your module. I've created a SeedsModule in a shared folder to add more seeds in future
src/shared/seeds.module.ts
import { Module } from '#nestjs/common';
import { CommandModule } from 'nestjs-command';
import { UserSeed } from '../modules/user/seeds/user.seed';
import { SharedModule } from './shared.module';
#Module({
imports: [CommandModule, SharedModule],
providers: [UserSeed],
exports: [UserSeed],
})
export class SeedsModule {}
Btw I'm importing my userService into my SharedModule
4. Add the SeedsModule into your AppModule
On your AppModule usually at src/app.module.ts add the SeedsModule into imports
Final
If you followed the steps in the nestjs-command repo you should be able to run
npx nestjs-command create:user
That will bootstrap a new application and run that command and then seed to your mongo/mongoose
Hope that help others too.
actually you can do it easily with onModuleInit(), here i'm using Mongoose ORM. This all done with zero dependencies, hope it helps
import { Injectable, OnModuleInit } from '#nestjs/common';
import { UserRepository } from './repositories/user.repository';
#Injectable()
export class UserService implements OnModuleInit {
constructor(private readonly userRepository: UserRepository) {}
// onModuleInit() is executed before the app bootstraped
async onModuleInit() {
try {
const res = await this.userRepository.findAll(); // this method returns user data exist in database (if any)
// checks if any user data exist
if (res['data'] == 0) {
const newUser = {
name: 'yourname',
email: 'youremail#gmail.com',
username: 'yourusername',
};
const user = await this.userRepository.create(newUser); // this method creates new user in database
console.log(user);
}
} catch (error) {
throw error;
}
}
// your other methods
}
For my case, I needed to insert seed during the tests, the best I could find is to create a seed service, imported and used only during tests.
Here is my base class using the schema model, all is needed is to extend and pass the model.
// # base.seed.service.ts
import { Model, Document } from 'mongoose';
import { forceArray, toJson } from 'src/utils/code';
export abstract class BaseSeedService<D extends Document> {
constructor(protected entityModel: Model<D>) {}
async insert<T = any>(data: T | T[]): Promise<any[]> {
const docs = await this.entityModel.insertMany(forceArray(data));
return toJson(docs);
}
}
// # utils
const toJson = (arg: any) => JSON.parse(JSON.stringify(arg));
function forceArray<T = any>(instance: T | T[]): T[] {
if (instance instanceof Array) return instance;
return [instance];
}
// # dummy.seed.service.ts
import { Injectable } from '#nestjs/common';
import { InjectModel } from '#nestjs/mongoose';
import { Model } from 'mongoose';
import { DummyDocument } from './dummy.schema';
#Injectable()
export class DummySeedService extends BaseSeedService<DummyDocument> {
constructor(
#InjectModel(Dummy.name)
protected model: Model<DummyDocument>,
) {
super(model);
}
}
Then inside the tests
describe('Dymmy Seeds', () => {
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [DummySeedService],
imports: [
MongooseModule.forRoot(__connect_to_your_mongodb_test_db__),
MongooseModule.forFeature([
{
name: Dummy.name,
schema: DummySchema,
},
]),
],
}).compile();
const seeder = module.get<DummySeedService>(DummySeedService);
const initData = [__seed_data_here__];
const entities: Dummy[] = await seeder.insert(initData);
expect(entities.length > 0).toBeTruthy();
});
});