Introduction
The following is a collection of commands for various languages and tools.
This book is generated with mdBook and hosted by GitLab Pages.
See Also
Windows
Search Files.bat
REM From https://stackoverflow.com/a/13799990/11912
findstr /s "<term>" *.item
Battery reporting
# Generate a battery report.
powercfg /batteryreport /output "C:\battery-report.html"
# Sleep study.
powercfg /sleepstudy /output "C:\sleep-study.html"
Setup SSH Key
ssh-keygen -t ed25519 -C "[email protected]"
# Copy public key in Windows Terminal.
cat ~/.ssh/id_ed25519.pub | clip
# Copy to a Linux server.
type ~\.ssh\id_ed25519.pub | ssh user@host "cat >> .ssh/authorized_keys"
Linux
Specifically using Ubuntu.
SSH
Type exit
to exit out of a SSH session.
# SSH into a server with Raspberry Pi's default user.
ssh pi@<ip_address>
# SSH into a server as a particular user.
ssh <user_name>@<ip_address>
# Output current user's name.
whoami
# View last hour of SSH logs.
sudo journalctl -u ssh --since "1 hour ago"
# Determine shell being used.
ps -p "$$"
# Find process having a process id (PID).
ps -p <pid>
# Create a key.
ssh-keygen -b 4096
# View the public key.
cat ~/.ssh/id_rsa.pub
System information
# View OS information.
cat /etc/os-release
# View system information on Ubuntu, which is displayed on SSH login:
landscape-sysinfo
# System monitoring.
top
# Prettier version of top.
htop
# Memory usage.
free
# Human readable.
free -h
# Show in MBs.
free -m
# IP address
ip a
hostname -I
# Server uptime.
uptime
# View path variable.
echo $PATH
# Find path of binary.
which cd
Package management
# Show manually installed packages.
apt-mark showmanual
apt list --manual-installed
# List installed packages.
apt list --installed
dpkg --list
sudo dpkg --audit
sudo dpkg --get-selections
Service logs
# View logs for a particular service.
sudo journalctl -fu mycustom.service
sudo journalctl -fu mycustom.service --since "1 hour ago"
Copy files
# Copy a file to a directory.
scp file-name.ext <user>@<server>:~/path/to/directory/
# Copy the contents of a folder to a remote folder.
scp -r .\path\to\directory\* <user>@<server>:/path/to/remove/directory
Sudo
# Start a root shell. `exit` when done.
sudo -s
# Temporarily run as super user to do stuff.
sudo su
# do stuff
exit
Firewall (ufw)
# Show status of firewall. If active, also lists rules.
sudo ufw status
# Show rules even when ufw is inactive.
sudo ufw show added
# Allow by service.
sudo ufw allow ssh
# Allows 80 and 443.
sudo ufw allow 'Nginx Full'
# Allow port-number.
sudo ufw allow <port-number>
sudo ufw allow 8080
# Remove allowed port-number.
sudo ufw delete allow <port-number>
sudo ufw delete allow 9041
Linux system management
# Reboot/restart.
sudo reboot
sudo shutdown -r now
# Reboot in 5 minutes.
sudo shutdown -r 5
# Shutdown
sudo poweroff
# Get machine and kernel information.
uname -mrs
# Get distribution-specific information.
lsb_release -a
# Get computer name.
hostname
# Get Debian version.
cat /etc/debian_version
Updates
# Get a list of current packages.
sudo apt update
# Get a list of upgradable packages.
apt list --upgradable
apt list --upgradable -a
# Upgrade all packages.
sudo apt upgrade
# Install or update specificed package.
sudo apt install <package-name>
File system
Information
# View disk space.
df
df -h
# Count number of files and folders in home directory.
ls ~ | wc -l
# List block devices. Helps with seeing partition information.
sudo lsblk -f -m
# View the total size of a directory.
sudo du -sh /path/to/directory
# Show by child directory size.
sudo du -h /path/to/directory --max-depth=1
# Show largest directories first.
sudo du -h /path/to/directory --max-depth=1 | sort -hr
# Sort by directory name.
sudo du -h /path/to/directory --max-depth=1 | sort -k2
# Largest directories.
sudo du --separate-dirs -h /path/to/directory | sort -hr | head
sudo du --separate-dirs -h /path/to/directory | sort -hr | head -n 2
# List file sizes (in MB) in a directory.
sudo ls -l --block-size=MB /var/log/nginx/
sudo ls -l --block-size=1MB /var/log/nginx/
# Human readable file sizes.
sudo ls -lh /var/log/nginx/
# Get all .mp4 files sorted by date and showing date, folder name, file name, and size.
# Excludes ._ and .DS_Store files (macOS).
find . -type f -name "*.mp4" ! -name "._*" ! -name ".DS_Store" -printf "%CY-%Cm-%Cd %CT %h %f %s\n" | sort -n
Navigation
# Print working directory (current directory).
pwd
# By itself, move to the current user's home directory. Tilde is short for home directory.
cd
cd ~
Modification
# Make a new directory.
mkdir name
mkdir name1 name2 name3
# Make a new directory and sub-directory/ies.
mkdir -p path/to/directory
# Move file(s)/directories to an existing directory.
mv file.txt dir1
mv file1.txt file2.txt dir1
mv file1.txt file2.txt new-dir dir1
# Rename a file.
mv file.txt new-name.txt
# Rename a directory.
mv dir-name new-dir-name
# Copy a file
cp path/to/file.txt .
cp file.txt copy-file.txt
# Remove/delete a file.
rm file.txt
# Remove/delete an empty directory.
rmdir path/to/directory
# Remove/delete a directory, even if it has files. (Only macOS?)
rmdir -r path/to/directory
# Works on Ubuntu.
rm -r path/to/directory
File viewing and creation
# Look at a file or multiple files.
cat file.txt
cat file1.txt file2.txt
cat file?.txt
cat file*
# Write to a file.
echo "Some text" > file.txt
echo "Some more text" >> file.txt
# File viewer. Press q to quit.
less file.txt
# List all files in a directory, with full paths, into a text file.
find wwwroot -type f > files.txt
# The above with directory, file name, file date, and size, into a tab-separated file.
find . -type f ! -name "._*" ! -name ".DS_Store" -printf "%h\t%f\t%CY-%Cm-%Cd %CT\t%s\n" > files.tsv
# Get full path to a file.
readlink -f relative/path/to/file
# Read lines of a file
sudo head -n 10 /var/log/nginx/access.log
sudo tail -n 10 /var/log/nginx/access.log
Hidden content
# Make a hidden directory.
mkdir .dir1
# Make a hidden file.
mkdir .hide.txt
# List all hidden files/folders.
ls -a
Users and permissions
User management
# Show who's logged in.
w
# Show the last logged in users.
last
# Show the last bad login attempts.
lastb
# Set the password for a user.
passwd <user>
# List user information, including groups.
id <user>
# List all users.
cat /etc/passwd
# List all users across multiple sources.
getent passwd
# Install sudo on Debian or the like (that don't have it by default).
apt update
apt install sudo
# Grant a user sudo.
usermod -aG sudo <username>
# Add the current user to a group (<group-name>).
sudo usermod -aG <group-name> ${USER}
Permissions
# List all users.
compgen -u
getent passwd
# List all groups.
compgen -g
getent group
# List all groups current user is in.
groups
# List all groups a user (username) is in.
groups username
# Add write access to group.
chmod g+w file-or-directory
# Remove write and execute from group.
chmod g-wx file-or-directory
# Remove read, write, and execute from others.
chmod o-rwx file-or-directory
# Users, groups, and others have read, write, and execute.
chmod ugo+rwx file-or-directory
# Grant all users read-only access to a file or directory.
chmod a=r file-or-directory
# View permissions.
ls -l
ls -ld
nginx
Configuration
# Test/verify configuration.
sudo nginx -t
# View base configuration.
sudo cat /etc/nginx/nginx.conf
# View default site configuration.
sudo cat /etc/nginx/sites-enabled/default
# List enabled sites.
ls -l /etc/nginx/sites-enabled/
# List available sites.
ls /etc/nginx/sites-available/
# Enable site via a symbolic link.
sudo ln -s /etc/nginx/sites-available/SITE_CONFIG_FILE_NAME /etc/nginx/sites-enabled/
# Remove symbolic link/enabled site.
sudo rm SITE_CONFIG_FILE_NAME
sudo unlink SITE_CONFIG_FILE_NAME
# Remove with confirmation.
sudo rm -i SITE_CONFIG_FILE_NAME
Logging
# View access logs.
sudo cat /var/log/nginx/access.log
# Get top 20 most used user agents.
sudo cat /var/log/nginx/access.log | awk -F\" '{print $6}' | sort | uniq -c | sort -nr | head -20
Management
# Restart nginx.
sudo systemctl restart nginx
Raspberry Pi Commands
Note to self: Information about Pis I own can be found at https://strivinglife.gitlab.io/book-raspberry-pi/.
Current Uptime
uptime
Restarting
sudo reboot
Shutdown
sudo shutdown -h now
Internet Configuration
ifconfig
# Try to bring a network interface up.
sudo ifup wlan0
Samba
# Restart Samba services.
sudo /etc/init.d/samba restart
# Backup copy of Samba configuration.
sudo cp /etc/samba/smb.conf /etc/samba/smb.conf.old
# Edit Samba configuration. Restart (see above) for changes to be picked up.
sudo nano /etc/samba/smb.conf
# Check Samba services.
systemctl status smbd
SSH
# Check SSH service status.
systemctl status sshd
# SSH into a server with Raspberry Pi's default user.
# Enter `exit` and press enter to quit the session.
ssh pi@<ip_address>
Terminal
# View past commands.
history
# View process information
top
Drive Information
# List device information.
sudo fdisk -l
# List mounts.
sudo mount -l
# Example: cd into a mounted USB device.
cd /media/usbhdd1
USB/Port Information
# Basic list of each port.
lsusb
# Lists out each port, with Product if there's a connected device.
usb-devices
Display Information
# List information about the connected display.
tvservice -s
Hardware Information
See https://elinux.org/RPi_HardwareHistory#Board_Revision_History for more information.
# Includes Hardware and Revision information.
cat /proc/cpuinfo
OS Information
cat /etc/os-release
RetroPie audio issues
- Make sure the correct audio output device is selected in the RetroPie configuration.
sudo nano /boot/config.txt
and uncomment#hdmi_drive=2
. ctrl+o, enter, ctrl+x,sudo reboot
.
Start GUI
startx
Linux directories overview
From root (cd /
):
/bin
essential executables, always available/sbin
essential super user executables/lib
shared common libraries (forbin
andsbin
)/etc
(editable text configuration)/usr
/usr/local
/usr/local/bin
locally compiled binaries
/usr/bin
installed binaries for users
/home
user data/home/___
individual user directory (also~
)
/boot
required to boot the system (like Linux kernel)/dev
devices/hardware/drivers/opt
optional/add-on software, rarely will be used/var
variable files that change as the system is used (like log and cache files)/tmp
temporary files/proc
running processes
Detailed in the Filesystem Hierarchy Standard.
macOS
Homebrew
brew update
# Install example.
brew install git
# List outdated formulae.
brew outdated
brew upgrade
Angular
This content had previously been migrated to Angular Framework Notes but has been added back here.
Basics
Written as of Angular 12+.
Install the Angular CLI
npm install -g @angular/cli
Help/available commands
ng help
ng ___ --help
Create a new site/project
ng new new-project-name
# Use SCSS stylesheet format.
ng new new-project-name --style scss
# This option can be used if there's an issue during npm install.
ng new new-project-name --skip-install
# Use a custom prefix for selector names.
ng new new-project-name --prefix ___
# Create with a specific Angular version.
npx @angular/cli@12 new new-project-name
Start a development server
Runs on port 4200 by default.
ng serve
# Opens the site in the default browser.
ng serve --open
ng serve -o
Code scaffolding
See ng generate.
# Create a new component.
ng generate component heroes
ng generate component hero-detail
ng g c input-button-unit
ng g c products/product-detail
# Create a component in the current directory, without creating a directory.
ng g c product-detail --flat
ng g c products/product-detail --flat
# Preview creating a new component.
ng g c messages --dry-run
ng g c messages -d
# Create a new service.
ng generate service hero
ng generate service message
ng g s services/todo-list
# Create an interface
ng g i interfaces/todo-item
# Create a new module, putting it into AppModule.
ng g m products/product --flat -m app
# Create a new module, with routing.
ng g m admin-stuff --flat --routing
Build the project
# Puts in dist/ by default.
ng build
Add an in-memory web API
For mocking up a backend.
npm install angular-in-memory-web-api --save
# Generate a module in src/app (flat) and register it in AppModule imports (module=app)
ng generate module app-routing --flat --module=app
ng generate component dashboard
# In-memory Web API
npm install angular-in-memory-web-api --save
ng generate service InMemoryData
ng generate component hero-search
Angular Material
- Searchable Material Symbols
- Use the Android name.
ng add @angular/material
Add ESLint
See angular-eslint for current information.
Note that eslint-plugin-jsdoc
has been added to the install process.
ng add @angular-eslint/schematics
# Or alpha version for early Angular v13 support (as of 11/5/2021).
ng add @angular-eslint/schematics@next
npm install --save-dev eslint-plugin-jsdoc
New script in package.json:
"eslint": "eslint ./src --ext .js,.jsx,.ts,.tsx || (exit 0)",
Update *.ts overrides (plugins
is completely new) in .eslintrc.json:
"plugins": [
"jsdoc"
],
"extends": [
"plugin:@angular-eslint/recommended",
"plugin:@angular-eslint/template/process-inline-templates",
"plugin:jsdoc/recommended"
],
"rules": {
"@angular-eslint/directive-selector": [
"error",
{
"type": "attribute",
"prefix": "app",
"style": "camelCase"
}
],
"@angular-eslint/component-selector": [
"error",
{
"type": "element",
"prefix": "app",
"style": "kebab-case"
}
],
"jsdoc/require-jsdoc": [1, {
"contexts": ["ArrowFunctionExpression", "ClassDeclaration", "ClassExpression", "ClassProperty", "FunctionDeclaration", "MethodDefinition", "TSInterfaceDeclaration", "TSEnumDeclaration", "TSEnumMember"]
}],
"jsdoc/require-description": [1, {
"contexts": ["ArrowFunctionExpression", "ClassDeclaration", "ClassExpression", "ClassProperty", "FunctionDeclaration", "MethodDefinition", "TSInterfaceDeclaration", "TSEnumDeclaration", "TSEnumMember"]
}],
"jsdoc/require-param-type": "off",
"jsdoc/require-returns-type": "off"
}
Test
npm run eslint
Configure for GitLab Pages
New script in package.json:
"buildProd": "ng build --base-href=/project-name/ --output-path=public",
Add new .gitlab-ci.yml in root directory:
image: node:14.17.6
pages:
cache:
paths:
- node_modules/
script:
- npm install -g @angular/[email protected]
- npm install
- npm run buildProd
artifacts:
paths:
- public
only:
- main
- pages
Add Jest
npm install --save-dev jest jest-preset-angular @types/jest
# For Angular v13.
npm install --save-dev jest-preset-angular@next
New scripts in package.json:
"jest": "jest",
"jest:coverage": "jest --coverage",
"jest:coverageWatch": "jest --coverage --watchAll"
New setup-jest.ts file in the root directory:
import 'jest-preset-angular/setup-jest';
New jest.config.js file in the root directory:
// jest.config.js
module.exports = {
preset: 'jest-preset-angular',
setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'],
testPathIgnorePatterns: [
'/node_modules/',
'<rootDir>/src/test.ts'
],
// An array of glob patterns indicating a set of files for which coverage information should be collected
collectCoverageFrom: [
"<rootDir>/src/**/*.ts",
// Exclude main Angular files.
"!<rootDir>/src/main.ts",
"!<rootDir>/src/polyfills.ts",
"!<rootDir>/src/environments/**",
// Exclude Karma file.
"!<rootDir>/src/test.ts",
"!<rootDir>/src/**/*.d.ts",
'!<rootDir>/node_modules/**',
],
coverageReporters: [
//"json",
"text", // Command line output
"text-summary", // Command line output of the summary
"lcov",
//"clover"
],
};
You may need to add the following in module.exports
if it can't find your imports:
modulePaths: [ "<rootDir>" ]
New ignore in .gitignore:
# Jest
/coverage
Update tsconfig.spec.json in root directory:
"types": [
"jasmine",
"jest"
]
Test
npm run jest
Add Stylelint
npm init stylelint
npm install --save-dev stylelint-config-standard-scss
New script in package.json:
"stylelint": "stylelint \"src/**/*.scss\" --cache --formatter verbose --output-file stylelint.log || (exit 0)"
New .stylelintrc.js file in the root directory:
{
"extends": ["stylelint-config-standard", "stylelint-config-standard-scss"]
}
New ignore in .gitignore:
# Stylelint
.stylelintcache
stylelint.log
Test
npm run stylelint
VS Code
- Install Stylelint official extension.
- Update settings to include
scss
files.
Updating
See the Angular Update Guide for version-specific steps.
Angular
ng update @angular/cli @angular/core
# If using Angular Material (also updates cdk package):
ng update @angular/material
Updating to latest patch version
ng update @angular/cli@^<major_version> @angular/core@^<major_version> @angular/material@^<major_version>
# Update, ignoring pending changes
ng update @angular/cli@^<major_version> @angular/core@^<major_version> @angular/material@^<major_version> --allow-dirty
ESLint
ng update @angular-eslint/schematics
npm run eslint
Jest
npm install @types/jest jest jest-preset-angular
npm run jest
Stylelint
npm install --save-dev stylelint stylelint-config-sass-guidelines stylelint-config-standard
npm run stylelint
Testing
Run unit tests
By default uses Karma/Jasmine.
ng test
Add ESLint
See angular-eslint on GitHub for current information. As of 9/5/2021:
ng add @angular-eslint/schematics
Fixing Broken Tests
Basics
ng test
.- If you want to generate a code coverage report, run
ng test --no-watch --code-coverage
.
- If you want to generate a code coverage report, run
- You can also limit tests to a directory:
ng test --include='src/app/path/**/*.spec.ts'
.- It also supports patterns:
ng test --include='src/app/[n-z]*/**/*.spec.ts'
ng test --include='src/app/admin/[d,g-i]*/**/*.spec.ts'
- It also supports patterns:
Disabling Tests
If you would like to skip a test, you can either change describe()
to xdescribe()
or it()
to xit()
.
Skipped tests will display in the Karma report in a yellow-green color, and as a pending spec.
Fixing Common Errors
Error: Found the synthetic property @slideInAnimation. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.
Import NoopAnimationsModule
, unless you need the other:
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ AppComponent ],
imports: [ NoopAnimationsModule ]
}).compileComponents();
}));
Error: NG0302: The pipe 'stringArray' could not be found!
Error: NG0302: The pipe 'yesNoIndicator' could not be found!
Error: NG0302: The pipe 'yesNoUnknownIndicator' could not be found!
Required pipes need to be added to declarations
:
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ProviderViewComponent, StringArrayPipe, YesNoIndicatorPipe, YesNoUnknownIndicatorPipe ]
})
.compileComponents();
});
NullInjectorError: No provider for ActivatedRoute!
Import RouterTestingModule
:
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ AdminFacilityComponent ],
imports: [ RouterTestingModule ]
})
.compileComponents();
}));
NullInjectorError: No provider for FormBuilder!
Import ReactiveFormsModule
:
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ AdminCredentialUpsertComponent ],
imports: [ ReactiveFormsModule ]
})
.compileComponents();
});
NullInjectorError: No provider for HttpClient!
Import HttpClientTestingModule
:
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ FileUploadComponent ],
imports: [ HttpClientTestingModule ]
})
.compileComponents();
}));
NullInjectorError: No provider for MatDialog!
Import MatDialogModule
:
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ AdminCredentialTableComponent ],
imports: [ MatDialogModule ]
})
.compileComponents();
});
NullInjectorError: No provider for MatDialogRef!
NullInjectorError: No provider for InjectionToken MatDialogData!
Update providers
to provide MatDialogRef
and MAT_DIALOG_DATA
:
describe('AdminProviderEmploymentsInsertDialogComponent', () => {
let component: AdminProviderEmploymentsInsertDialogComponent;
let fixture: ComponentFixture<AdminProviderEmploymentsInsertDialogComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ AdminProviderEmploymentsInsertDialogComponent ],
providers: [
{ provide: MatDialogRef, useValue: {} },
{ provide: MAT_DIALOG_DATA, useValue: { } }
]
})
.compileComponents();
});
});
You may pass an object via useValue
if needed, such as { provide: MAT_DIALOG_DATA, useValue: { credentialId: 0 } }
.
NullInjectorError: No provider for MatSnackBar!
Import MatSnackBarModule
:
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ AdminCredentialComponent ],
imports: [ MatSnackBarModule ]
})
.compileComponents();
});
NullInjectorError: No provider for Router!
Import RouterTestingModule
:
beforeEach(() => {
TestBed.configureTestingModule({
providers: [AdminImportPreprocessGuard],
imports: [ RouterTestingModule ]
});
});
TypeError: Cannot read properties of null (reading 'paramMap')
The component likely has some code like the following:
this.facilityId = +this.route.snapshot.parent.paramMap.get('id');
(The order of these may vary; you'll want to make note of the order and make sure that the following fix has the same order.)
You'll want to configure the route in the providers
of your test, like the following example:
beforeEach(async () => {
await TestBed.configureTestingModule({
providers: [
{ provide: ActivatedRoute, useValue: { snapshot: { parent: { paramMap: convertToParamMap({ id: -1 }) } } } }
]
})
.compileComponents();
});
This isn't specific to paramMap
. For example:
//this.vendor = this.route.snapshot.data.vendor;
{ provide: ActivatedRoute, useValue: { snapshot: { data: { vendor: TEST_VENDOR } } } }
Error: No value accessor for form control with name: '...'
If this references a ng-select
if your template HTML, import NgSelectModule
(and likely NoopAnimationsModule
if you haven't already) and add the declaration NgSelectFormFieldControlDirective
:
await TestBed.configureTestingModule({
declarations: [ AdminSpecialtiesGroupSpecialtyUpsertComponent, NgSelectFormFieldControlDirective ],
imports: [ NgSelectModule, NoopAnimationsModule ]
})
.compileComponents();
If using mat-checkbox
, import MatCheckboxModule
, etcetera.
Fixing Common Console-Only Errors
These errors typically don't show in the browser, but will show in the console that ran ng test
.
ERROR: 'NG0303: Can't bind to 'routerLink' since it isn't a known property of 'a'.'
ERROR: 'NG0304: 'router-outlet' is not a known element:
Import RouterTestingModule
:
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ AdminSpecialtiesComponent ],
imports: [ RouterTestingModule ]
})
.compileComponents();
});
ERROR: 'NG0303: Can't bind to 'ngModel' since it isn't a known property of 'input'.'
Import FormsModule
:
await TestBed.configureTestingModule({
declarations: [ CommonListCrudTableComponent ],
imports: [ FormsModule ]
})
.compileComponents();
ERROR: 'NG0303: Can't bind to 'formGroup' since it isn't a known property of 'form'.'
ERROR: 'NG0303: Can't bind to 'formControl' since it isn't a known property of 'form'.'
Import ReactiveFormsModule
:
await TestBed.configureTestingModule({
declarations: [ SpecialtyUpsertComponent ],
imports: [ ReactiveFormsModule ]
})
.compileComponents();
ERROR: 'NG0304: 'mat-card' is not a known element:
ERROR: 'NG0304: 'mat-card-title' is not a known element:
ERROR: 'NG0304: 'mat-card-content' is not a known element:
ERROR: 'NG0304: 'mat-card-actions' is not a known element:
Import MatCardModule
:
await TestBed.configureTestingModule({
declarations: [ AdminSpecialtiesGroupUpsertComponent ],
imports: [ MatCardModule, MatSnackBarModule, ReactiveFormsModule ],
providers: [
{ provide: SpecialtyClient, useValue: mockSpecialtyClient }
]
})
.compileComponents();
ERROR: 'NG0304: 'mat-form-field' is not a known element:
ERROR: 'NG0304: 'mat-label' is not a known element:
ERROR: 'NG0304: 'mat-error' is not a known element:
Import MatFormFieldModule
, MatInputModule
, and NoopAnimationsModule
:
await TestBed.configureTestingModule({
declarations: [ AdminSpecialtiesGroupUpsertComponent ],
imports: [ MatFormFieldModule, MatInputModule, NoopAnimationsModule, ReactiveFormsModule ],
providers: [
{ provide: SpecialtyClient, useValue: mockSpecialtyClient }
]
})
.compileComponents();
ERROR: 'NG0303: Can't bind to 'dataSource' since it isn't a known property of 'table'.'
ERROR: 'NG0303: Can't bind to 'matHeaderRowDef' since it isn't a known property of 'tr'.'
ERROR: 'NG0303: Can't bind to 'matRowDefColumns' since it isn't a known property of 'tr'.'
Import MatTableModule
:
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ AdminSpecialtiesGroupTableComponent ],
imports: [ MatCardModule, MatDialogModule, MatTableModule ]
})
.compileComponents();
});
ERROR: 'NG0304: 'mat-datepicker' is not a known element:
Import MatDatepickerModule
and MatMomentDateModule
(unless using a different DateAdapter
):
await TestBed.configureTestingModule({
declarations: [ AdminSpecialtiesGroupSpecialtyUpsertComponent ],
imports: [ MatDatepickerModule, MatMomentDateModule ]
})
.compileComponents();
ERROR: 'NG0304: 'mat-icon' is not a known element:
Import MatIconModule
:
await TestBed.configureTestingModule({
declarations: [ AdminSpecialtiesGroupComponent ],
imports: [ MatIconModule, MatSnackBarModule ],
providers: [
{ provide: SpecialtyClient, useValue: mockSpecialtyClient }
]
})
.compileComponents();
ERROR: 'NG0304: 'mat-nav-list' is not a known element:
MatListModule
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ AdminSpecialtiesComponent ],
imports: [ MatListModule, RouterTestingModule ]
})
.compileComponents();
});
ERROR: 'NG0304: 'mat-paginator' is not a known element:
Import MatPaginatorModule
:
TestBed.configureTestingModule({
declarations: [ ProviderSearchComponent ],
imports: [ MatPaginatorModule, MatTableModule ],
providers: [
{ provide: ProviderClient, useValue: mockProviderClient }
]
})
.compileComponents();
ERROR: 'NG0304: 'app-...' is not a known element:
Where 'app-...'
is the name of a custom component, create and declare a fake component, including any @Input()
s:
describe('DemographicsGenderComponent', () => {
let component: DemographicsGenderComponent;
let fixture: ComponentFixture<DemographicsGenderComponent>;
@Component({
selector: 'app-demographics-gender-table',
template: ''
})
class FakeDemographicsGenderTableComponent {
@Input() genders;
}
beforeEach(async () => {
// ...
await TestBed.configureTestingModule({
declarations: [ DemographicsGenderComponent, FakeDemographicsGenderTableComponent ],
imports: [ MatIconModule, MatSnackBarModule ],
providers: [{ provide: DemographicsClient, useValue: mockDemographicsClient }]
})
.compileComponents();
});
// ...
});
TypeError: Cannot read properties of undefined (reading 'something')
Where something
is an @Input()
, set it when creating the component before running tests:
describe('AddressViewComponent', () => {
let component: AddressViewComponent;
let fixture: ComponentFixture<AddressViewComponent>;
// Addition 1.
const TEST_ADDRESS: IAddressViewModel = {
addressType: new AddressTypeViewModel()
};
beforeEach(async () => {
// ...
});
beforeEach(() => {
fixture = TestBed.createComponent(AddressViewComponent);
component = fixture.componentInstance;
// Addition 2.
component.address = TEST_ADDRESS;
fixture.detectChanges();
});
// ...
});
TinyMCE
For components that use TinyMCE, it's best to fake it for testing. If you do not, you'll end up with random errors mentioning length
and open
.
@Component({
selector: 'editor',
template: '',
providers: [
{ provide: NG_VALUE_ACCESSOR, useValue: { writeValue: () => {}, registerOnChange: () => {}, registerOnTouched: () => {} }, multi: true }
]
})
class FakeEditorComponent {
@Input() init;
}
// ...
await TestBed.configureTestingModule({
declarations: [ FakeEditorComponent ]
// ...
})
.compileComponents();
// ...
.NET API Swagger Clients
NullInjectorError: No provider for AdminClient!
NullInjectorError: No provider for AuthClient!
NullInjectorError: No provider for CommonClient!
Start by creating a simple mock client that has no methods that should be spied upon.
- Define a variable for the mock client.
- Set it to
jasmine.createSpy()
in thebeforeEach()
. - Add the new mock client in
providers
.
describe('AppAuthService', () => {
// Addition 1.
let mockAuthClient;
beforeEach(() => {
mockAuthClient = jasmine.createSpy();
TestBed.configureTestingModule({
providers: [ { provide: AuthClient, useValue: mockAuthClient } ]
})
});
// ...
});
Once it starts throwing an error, such as TypeError: this.adminClient.adminProviderCredentialsView is not a function
then you can modify your test.
- Swap in
jasmine.createSpyObj()
, passing in any methods that will need to be spied upon. - Try using
.and.returnValue(of(true))
initially, and then tweak it based upon what the component is doing.
describe('AdminFacilityComponent', () => {
let component: AdminFacilityComponent;
let fixture: ComponentFixture<AdminFacilityComponent>;
// Previous addition 1.
let mockFacilityClient;
beforeEach(waitForAsync(() => {
// Change to addition 2.
mockFacilityClient = jasmine.createSpyObj(['getFacilityAdminView']);
mockFacilityClient.getFacilityAdminView.and.returnValue(of(true));
TestBed.configureTestingModule({
declarations: [ AdminFacilityComponent ],
providers: [
// Previous addition 3.
{ provide: FacilityClient, useValue: mockFacilityClient }
]
})
.compileComponents();
}));
// ...
});
Angular: Getting Started
My notes from Deborah Kurata's Angular: Getting Started.
My repo with pull request with training notes.
Angular Component Communication
My notes from Deborah Kurata's excellent Angular Component Communication.
Module 3
Binding and structural directives
Interpolation
// Component
pageTitle: string = 'Product List';
<!-- Template -->
<div>{{pageTitle}}</div>
Can also use functions ({{ getPageTitle() }}
) but may run into performance issues due to how Angular checks for changes.
Property binding
// Component
imageWidth: number = 50;
<!-- Template -->
<img [style.width.px]="imageWidth" />
Event binding
// Component
toggleImage(): void {
this.showImage = !this.showImage;
}
<!-- Template -->
<button (click)="toggleImage()">Toggle Image</button>
Two-way binding
// Component
listFilter: string;
<!-- Template -->
<input type="text" [(ngModel)]="listFilter" />
*ngIf
// Component
showImage: boolean = false;
<!-- Template -->
<img *ngIf="showImage" [src]="product.imageUrl" />
*ngFor
// Component
products: IProduct[];
<!-- Template -->
<tr *ngFor="let product of products">
Two-way binding, long way
[(ngModel)]="listFilter"
is shorthand for [ngModel]="listFilter" (ngModelChange)="listFilter=$event"
.
So you could do [ngModel]="listFilter" (ngModelChange)="onFilterChange($event)"
, where onFilterChange
updates listFilter
.
Getters and setters
// Component
listFilter: string;
// Component
private _listFilter: string;
get listFilter(): string {
return this._listFilter;
}
set listFilter(value: string) {
this._listFilter = value;
}
Module 4
In my opinion, using these has more downsides than benefits.
ViewChild
// Angular Directive
@ViewChild(NgModel) filterInput: NgModel; // <input type="text" [(ngModel)]="listFilter" />
// Custom Directive or Child Component
@ViewChild(StarComponent) star: StarComponent;
// Template Reference Variable
@ViewChild('divElementVar') divElementRef: ElementRef; // <div #divElementVar>{{pageTitle}}</div>
// Above is available during/after ngAfterViewInit(), which is after constructor() and ngOnInit().
// However, if within a *ngIf you may run into an issue.
// ElementRef has a nativeElement which allows for access to any HTML element properties or methods.
@ViewChild(NgForm) editForm: NgForm; // if using template-driven forms.
With NgModel
we can for example:
@ViewChild(NgModel) filterInput: NgModel;
this.filterInput.valueChanges.subscribe(() => this.performFilter(this.listFilter));
Otherwise, NgModel
and NgForm
are read-only.
ViewChildren
@ViewChildren(NgModel) inputs: QueryList<NgModel>;
// Above would support checking for status.
@ViewChildren(StarComponent) stars: QueryList<StarComponent>;
@ViewChildren('divElementVar' divElementRefs: QueryList<ElementRef>;
@ViewChildren('filterElement, nameElement' divElementRefs: QueryList<ElementRef>;
// Tracks changes in the DOM.
this.divElementRefs.changes.subscribe(() => { /* act */ });
Module 5
Parent to child component communication
- Child:
@Input
, getters/setters,OnChanges
- Parent: Template reference variable,
@ViewChild
- Use a service
@Input()
Child:
@Input() propertyName: string;
Parent:
<app-child propertyName="binding source"></app-child>
Or:
parentProperty: string;
<app-child [propertyName]="parentProperty"></app-child>
Getter and setter
Child component:
private _propertyName: string;
get propertyName(): string {
rerturn this._propertyName;
}
@Input() set propertyName(value: string) {
this._propertyName = value;
}
OnChanges
Child component:
@Input() propertyName: string;
ngOnChanges(changes: SimpleChanges): void {
// Note: values start at undefined.
if (changes['propertyName']) {
changes['propertyName'].currentValue
}
}
Template reference value
<app-child #childReference [propertyName]="parentProperty"></app-child>
{{ childReference.propertyName }}
{{ childReference.methodName() }}
@ViewChild
<app-child #childReference [propertyName]="parentProperty"></app-child>
@ViewChild('childReference') childComponent: ChildComponent;
or
<app-child [propertyName]="parentProperty"></app-child>
@ViewChild(ChildComponent) childComponent: ChildComponent;
parentPropertyName: string;
ngAfterViewInit(): void {
this.parentVariable = this.childComponent.propertyName;
}
Summary
- Use a child component when:
- for a specific task
- complex
- reusable
@Input
, getter/setter, andOnChanges
are easier for parent to child- Favor getter/setter if you only need to react to changes to specific properties
- Favor
OnChanges
if you want to react to any input property changes, or if you need current/previous values- The key here is that it's
@Input()
property changes.
- The key here is that it's
- Template reference variable if you want to use it in the parent's template
ViewChild
if you want to use it in the class- but it won't receive notification of changes
Module 6
Child to parent component communication
- Event notification:
@Output
- Provide information: Template reference variable,
@ViewChild
- Service
@Output
Child:
@Output() valueChange = new EventEmitter<string>(); // in @angular/core
this.valueChange.emit(value);
Parent:
<app-child (valueChange)="onValueChange($event)"></app-child>
onValueChange(value: string): void {
// ...
}
Module 7 - Services
Managing state options
From simple to complex:
- Property bag
- Basic state management
- State management with notifications
- ngrx (inspired by Redux)
Property bag
Service that just contains properties.
Service:
@Injectable()
export class ThingService {
propertyName1: string;
propertyName2: boolean;
}
Component:
get propertyName1(): string {
return this.thingService.propertyName1;
}
set propertyName1(value: string) {
this.thingService.propertyName1 = value;
}
constructor(private thingService: ThingService) {
}
Great for 'stashing away properties for itself or other components.'
Service scope
Register the service based upon what you want to be able to use it (scope), and how long it is retained for (lifetime).
- Register in the component -
@Component({ providers: [ ThingService ]})
- for that component and children (template or via router).- Good if you need multiple instances of the service for different component instances.
- Register in a module -
@NgModule({ providers: [ ThingService ] })
- no matter which module it's registered in (unless lazy-loaded) it will be available to all components.- Lazy-loaded module services are only available to components declared in that module, but is then available for the entire application lifetime.
ngOnDestroy(): void { }
if you want to see the lifetime of a service.
Guidelines
Property bag for:
- Retaining view state
- Retaining user selections
- Sharing data or other state
- Communicating state changes
- Okay if any component can read or change the values
- Components are only notified of state changes if they use template binding
Module 8
Basic state management
Essentially store data on the service in a private property, and populate it from the server only when needed.
- Provide state values
- Maintain and update state
- Observe state changes
@Injectable()
export class ThingService {
private things: IThing[];
getThings(): Observable<IThing[]> {
if (this.things) {
return of(this.things);
}
// get things from the data store and save to this.things
}
getThing(id: number): Observable<IThing> {
if (this.things) {
const foundThing = this.things.find(item => item.id === id);
if (foundThing) {
return of(foundThing);
}
}
// get thing from the server and return it
}
}
For create/update/delete either post to the server and update the item in the property list, or pull fresh content from the server, depending upon need.
May want to always pull fresh data when doing an edit.
You may also want to store a pull or expiration date so that you don't have stale data.
Concurrent components
Could put a public property in a property bag or state management service that could be read/updated.
In the component that reads the property, use a getter to return this.thingService.currentThing;
if you want it to update every time currentThing
is changed.
- Define a property in the service
- Bind that property in a template
- Use a getter in the component class
Note that you'll either need to use binding in the template to have Angular pick up changes or have a timer (import { timer } from 'rxjs/observable/timer';
has one) in ngOnInit
that polls for changes. Timers are not ideal.
ngOnInit() {
timer(0, 1000).subscribe(t => console.log(this.thing));
// unsubscribe on destroy
}
Module 9
Service notifications
Can add notifications to any service, not just a state management service.
EventEmitter
only works child to parent, and you don't want to force it for service notifications.
Use Subject
or a variant like BehaviorSubject
instead. Subject
is a type of Observable
, and an Observer
. Don't necessarily need, if you can use binding.
Service:
@Injectable()
export class ThingService {
private selectedThingSource = new Subject<IThing | null>();
// source = source of knowledge about selected thing
selectedThingChanges$ = this.selectedThingSource.asObservable();
// $ convention = observable (that can be subscribed to)
// could make the source public but then anyone could push to it
// instead the asObservable makes it read-only externally
changeSelectedThing(selectedThing: IThing | null): void {
this.selectedThingSource.next(selectedThing);
}
}
Component, updating:
// ...
this.thingService.changeSelectedThing(thing);
// ...
Component, subscribing:
export class ThingDetailComponent implements OnInit, OnDestroy {
thing: IThing | null;
thingSub: Subscription;
constructor(private thingService: ThingService) { }
ngOnInit(): void {
this.thingSub = this.thingService.selectedThingChanges$.subscribe(
selectedThing => this.thing = selectedThing
);
}
ngOnDestroy(): void {
this.thingSub.unsubscribe();
}
}
BehaviorSubject
Many variants of subject, but this one:
- requires an initial value
- provides the current value on a new subscription
Service:
//private selectedThingSource = new Subject<IThing | null>();
private selectedThingSource = new BehaviorSubject<IThing | null>(null);
Works even when components are destroyed. However, will want to make sure the component that updates also subscribes, if it needs to.
Summary
Don't need to use Subject
if notifications are not required, or the only notifications are for changes to bound properties.
Subjects can also be used to sync multiple observables (advanced, not covered by this course).
There is a Subject
variant that can provide all previous messages.
Module 10
Route parameters
- Required
- Optional
- Query
Required parameters
Define:
{ path: 'products/:id', component: ProductDetailComponent }
Activate:
<a [routerLink]="['/products', product.id]">...</a>
this.router.navigate(['/products', this.product.id]);
Read:
this.route.snapshot.paramMap.get('id');
Optional parameters
In the URL, uses ;
as the delimiter. Can be lost during navigation (versus standard query parameters).
Define:
{ path: 'products', component: ProductListComponent }
Activate:
<a [routerLink]="['/products', { name: cart, code: g }]">...</a>
this.router.navigate(['/products', { name: 'cart', code: 'g' }]);
Read:
this.route.snapshot.paramMap.get('name');
Query parameters
In the URL, uses standard ?
and &
. Can be retained across routes.
Define:
{ path: 'products', component: ProductListComponent }
Activate:
<a [routerLink]="['/products']" [queryParams]="{ name: cart, code: g }">...</a>
this.router.navigate(['/products'], { queryParams: { name: 'cart', code: 'g' }});
Read:
this.route.snapshot.queryParamMap.get('name');
Summary
- Simple
- Bookmarkable and sharable
- Good for small amounts of data
Related: Creating Layouts with CSS Grid
Playing around while following Matt Henry's course on Pluralsight.
Notes
Basics
- grid-column-start
- grid-column-end
- grid-template-columns
- grid-template-rows
html, body {
height: 100%;
}
body {
/* Changes all direct children into grid items. */
/* By default 1 column 1 row grid. */
display: grid;
/* Number of columns and width. */
grid-template-columns: 15em auto 15em;
/* Number of rows and heights. */
/* min-content is minimum amount to fit content, and no more. */
/* auto only works here because of 100% height on html and body. */
grid-template-rows: min-content auto min-content;
/* Above is the same as the following. rows / columns. */
/*
grid-template: min-content auto min-content / 15em auto 15em;
*/
/* Can also use the more powerful grid, with just what we want. */
/* grid is also recommended, while grid-template is not. */
/*
grid: min-content auto min-content / 15em auto 15em;
*/
}
header, footer {
/* Grid line to start at. */
grid-column-start: 1;
/* Grid line to end at. */
grid-column-end: 4;
}
Sizing
Viewport-responsive:
- Percentage
- fr
- These will be min-content until all other tracks reach their growth limit (for example,
minmax()
).
- These will be min-content until all other tracks reach their growth limit (for example,
- auto
- Growth limit is
max-content
. - This means if a
1fr
is used it won't get any larger thanmax-content
.
- Growth limit is
Content-responsive:
-
min-content
-
max-content
-
fit-content()
-
fr
fractional unit. -
minmax(max-content, 50%)
define minimum and maximum values for a track. -
fit-content(30em)
try to fit the content, but don't go any larger than an amount. -
repeat(3, 20em)
repeats x times a track size of a certain amount.repeat(6, 1fr 2fr)
-
repeat(auto-fill, 10em)
fills up available space with tracks of set size.repeat(auto-fill, minmax(15em, 1fr))
is an example of combining for a responsive design.
-
auto-fit
tries to fill empty columns, versusauto-fill
. /* Default. Fills it row-by-row. */ -
grid-auto-flow: row;
is the default and tries to fill the grid row-by-row.grid-auto-flow: column;
fills column-by-column instead.- Alternative is to put it in the
grid
definition. For examplegrid: auto-flow 10em / 10em 10em
.
-
writing-mode: vertical-rl;
andwriting-mode: horizontal-tb
are examples of ways to getgrid-auto-flow
to start a certain way, but may also make columns look like rows. -
grid-auto-rows
can impact implicit rows created if the grid definition doesn't account for all grid items.- Supports more than one size, in which case it will alternate.
grid-auto-columns
is the other.- Depends upon
grid-auto-flow
definition.
Determing track size (slide)
- All tracks start at their base size.
- Extra space is allocated evenly to tracks which haven't reached their growth limit.
- Additional remaining space is given to fractional unit (
fr
) tracks. - If there are no fractional unit tracks, additional space is given to
auto
tracks.
Gaps
column-gap
,row-gap
, andgap
(shorthand) are the recommended properties.- Makes it consistent with CSS Grid, Flexbox, and Multi-column Layout.
grid-
prefix is also acceptable.
margin
on grid container for outer margin.
Positioning
- Can use -1 for end position (or any negative numbers) instead of a positive number. Negative numbers count from the end of the row to the start.
- However, avoid micromanaging.
- On a grid item, can use span x to span a certain number of tracks.
grid-column-end: span 2;
grid-column: start / end;
grid-column: 3 / 5;
grid-column: 3 / span 2;
grid-column: span 2;
grid-row
grid-area: 2 / 1 / 5 / 6;
is grid row start, column start, row end, column end.- May want to just use
grid-column
andgrid-row
for readability.
- May want to just use
Alignment
- Can align a grid on a web page or the content within a grid cell, and there must be extra space to align within.
- Properties:
justify-content
default is start.- Other options are center, end, space-around, space-between, and space-evenly. Controls entire grid.
align-content
default is start.- Other options are center, end, space-around, space-between, and space-evenly. Controls entire grid.
justify-items
default is stretch.- Other options (for this and next three properties) are start, center, and end. Controls content within grid item.
align-items
default is stretch. Controls content within grid item.justify-self
default is stretch. Controls an individual item.align-self
default is stretch. Controls an individual item.
- Justify = left to right.
- Align = top to bottom.
Accessibility
- Can use
dense
ingrid-auto-flow
and it will try to fill in empty gaps (in the case of spanning grid items). - Can also use
order
to force items before/after items. Default isorder: 0;
. - However, try to keep the source order = display order.
- Can also overlaps grid items by overlapping row/column placements. Combine with
z-index
as needed.
Naming
- When defining track sizes, you can name them.
grid-template-columns: [left-edge] 1fr 1fr [midpoint] 1fr 1fr [right-edge];
- Then use like
grid-column: left-edge / right-edge;
.
- Something like
body { display: grid; grid-template-rows: [header-start] 2em 5em [header-end body-start] 10em 10em [body-end]; }
is a bit more conventional. - Can also use names within
repeat()
which can cause multiple named lines.- When used for grid items, this will cause them to jump to the closest named line.
- Can put a number afte the name to use that instance.
- Can also use
span x
before to span over multiple, but be careful when repeating.
Simple layouts
body {
display: grid;
grid-template-areas: "header header header"
"nav main aside"
"footer footer footer";
grid-template-rows: min-content auto min-content;
grid-template-columns: 15em 1fr 1fr;
}
header { grid-area: header; }
nav { grid-area: nav; }
main { grid-area: main; }
aside { grid-area: aside; }
footer { grid-area: footer; }
Good for simple layouts.
- Must be rectangular shape.
- Must have same number of cells.
...
to define empty areas.- Lines automatically get names based upon area names.
- Named lines automatically create named areas.
Shorter version of the above:
body {
display: grid;
grid: "header header header" min-content "nav main aside" auto "footer footer footer" min-content / 15em 1fr 1fr;
}
Or to improve readability:
body {
display: grid;
grid: "header header header" min-content
"nav main aside" auto
"footer footer footer" min-content /
15em 1fr 1fr;
}
Responsive design
- Start small.
- Use media queries. :|
Subgrids
- May not be well supported (as of me typing this, still only Firefox supported).
- You can of course put a grid within a grid.
.NET
- dotnet new
dotnet new list
dotnet new gitignore
adds a .gitignore to the current directory.dotnet new mvc --auth Individual -o ProjectName
create a new MVC web app with authentication using SQLitedotnet new sln
dotnet sln add ProjectName
(don't include.\
from PowerShell)
# View .NET installed versions and information.
dotnet --info
# Restore packages.
dotnet restore
dotnet watch run
Environment variables
# launchSettings.json can typically set these.
# See https://learn.microsoft.com/en-us/aspnet/core/fundamentals/environments?view=aspnetcore-7.0#development-and-launchsettingsjson
$Env:ASPNETCORE_ENVIRONMENT = "Development"
$Env:NETCORE_ENVIRONMENT = "Development"
The ASPNETCORE_ENVIRONMENT
value overrides DOTNET_ENVIRONMENT
.
Entity Framework Core Tools
# Install a tool globally.
dotnet tool install --global dotnet-ef
# Update a tool to the latest version.
dotnet tool update --global dotnet-ef
# Install a specific version.
dotnet tool install --global dotnet-ef --version 8.0.10
dotnet tool install --global dotnet-ef --version 8.0.10 --allow-downgrade
# List installed tools.
dotnet tool list -g
# Search for tools matching `searchTerm`.
dotnet tool search searchTerm
dotnet tool search dotnet-ef --detail --take 1
Add SQLite
dotnet add package Microsoft.EntityFrameworkCore.Sqlite
dotnet add package Microsoft.EntityFrameworkCore.Design
appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Data source=./Database/name.db"
}
}
Data/DataContext.cs
using API.Models;
using Microsoft.EntityFrameworkCore;
namespace API.Data
{
public class DataContext : DbContext
{
public DbSet<Thing> Things { get; set; }
public DataContext(DbContextOptions options) : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
}
Program.cs
// Add near the top.
builder.Services.AddDbContext<DataContext>(options =>
{
options.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection"));
});
// Optional: apply migrations on startup. Add after builder.Build().
using (var scope = app.Services.CreateScope()) {
var db = scope.ServiceProvider.GetRequiredService<DataContext>();
db.Database.Migrate();
}
Create Initial Migration
dotnet ef migrations add InitialCreate -o Data/Migrations
dotnet ef database update
# List the last 5 migrations.
dotnet ef migrations list --no-build | Select-Object -last 5
# Create a migration for a specific context.
dotnet ef migrations add AddXEntity -o Data/Migrations/Application -c ApplicationDbContext
dotnet ef database update -c ApplicationDbContext
.NET Examples
Example: .NET API with Angular Frontend and XUnit Testing
This example sets up a new .NET webapi project with XUnit testing and an Angular frontend.
# From repo root:
dotnet new sln
dotnet new webapi -o API
dotnet sln add API
dotnet new gitignore
git init
git add .
git commit -m "Add new .NET webapi project and solution"
# XUnit project.
dotnet new xunit -o API.Tests
dotnet add .\API.Tests\API.Tests.csproj reference .\API\API.csproj
dotnet sln add API.Tests
git add .
git commit -m "Add new XUnit project"
# Create Angular application.
ng new client
git add .
git commit -m "Add new Angular application"
Project Workspace via Windows Terminal
wt -d .\ --title 'Repo Root' `; nt -d .\client\ --title 'ng serve' `; split-pane -H -d .\API\ --title 'dotnet watch run' `; nt -d .\client\src\app\ --title 'ng g ...'`; nt -d .\client\ --title 'ng test' `; split-pane -H -d .\ --title 'dotnet test'
Alternatively
# From repo root:
cd .\API\
dotnet run
# From repo root:
dotnet test
# From repo root:
cd .\client\
ng serve
# From repo root:
cd .\client\
ng test
GDScript Basics
Go
# Initialize a new module.
go mod init example.com/hello
# Run the current directory.
go run .
# Update and cleanup go.mod.
go mod tidy
# Run tests (in files that end with _test.go).
go test
go test -v
# testing.Short() returns true. Useful for t.Skip()ing long/integration tests.
go test -short
# Generate a platform-specific application.
go build
# Install the current application to the Go path.
go install
Information
# Get Go's version.
go version
# Find where the current module would be installed to.
go list -f '{{.Target}}'
# List environment information, including where packages are installed via go get.
go env
Requirements
# Update go.mod to point a module to a local directory.
go mod edit -replace example.com/greetings=../greetings
# Get an external module and add to go.mod require.
go get golang.org/x/example
# Get dependencies for code in the current directory (already added as an import).
go get .
Workspaces
# Initialize a workspace with an existing module.
go work init ./hello
# Add a child module directory to the workspace.
go work use ./example
Utilities
# Generate a TLS/SSL cert. Get GOPATH from `go env`.
go run 'C:\Program Files\Go\src\crypto\tls\generate_cert.go' --rsa-bits=2048 --host=localhost
Testing
# Get basic test coverage, per file.
go test -cover ./...
# Generate a coverage report by method and function.
go test -coverprofile='profile.out' ./...
# Read the report and output to the command line.
go tool cover -func='profile.out'
# Read the report and output to HTML.
go tool cover -func='profile.out'
# Generate a coverage report with number of times each statement is executed during testing.
# Use -covermode=atomic if running any tests in parallel.
go test -covermode=count -coverprofile='profile.out' ./...
T-SQL
Get all tables in a database.
SELECT TABLE_SCHEMA, TABLE_NAME
FROM <database_name>.INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
ORDER BY TABLE_SCHEMA, TABLE_NAME
Get all views in a database.
SELECT TABLE_SCHEMA, TABLE_NAME
FROM <database_name>.INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'VIEW'
ORDER BY TABLE_SCHEMA, TABLE_NAME
Get all stored procedures in a database.
SELECT SPECIFIC_SCHEMA, SPECIFIC_NAME
FROM <database_name>.INFORMATION_SCHEMA.ROUTINES
WHERE ROUTINE_TYPE = 'PROCEDURE'
ORDER BY SPECIFIC_SCHEMA, SPECIFIC_NAME
Table altering, in T-SQL
Change table schema
Change the schema on an existing table.
ALTER SCHEMA projectManagement
TRANSFER dbo.RequestPriority
Change column
Alter a column in an existing table.
ALTER TABLE [projectManagement].[Task]
ALTER COLUMN Name varchar(250) not null
Add identity and primary key
Add a new identity column to an existing table.
-- See http://stackoverflow.com/a/3698824/11912
ALTER TABLE JobSupplies add Id INT IDENTITY
ALTER TABLE JobSupplies add constraint PK_JobSupplies primary KEY(Id)
PostgreSQL
Unless otherwise noted, non-SQL commands are running under Ubuntu.
# On Ubuntu, run psql as default postgres user.
sudo -u postgres psql
# List all databases.
sudo -u postgres psql -l
-- List all databases.
\l
-- Quit psql.
\q
Configuration
# Show the full path to the PostgreSQL configuration file.
sudo -u postgres psql -c 'SHOW config_file'
# Example: /etc/postgresql/12/main/postgresql.conf
# Show the full path to the HBA configuration file.
sudo -u postgres psql -c 'SHOW hba_file'
# Example: /etc/postgresql/12/main/pg_hba.conf
-- Locate the HBA configuration file.
SHOW hba_file;
-- Example: /etc/postgresql/12/main/pg_hba.conf
-- Or just query the file for rules.
select * from pg_hba_file_rules();
User management
-- List all users.
\du
-- Create a new user.
CREATE USER <name>;
Database management
# Create a new database.
sudo -u postgres createdb <name>
# Verify it was created.
sudo -u postgres psql -l
# Create a new database, echoing out the commands run.
sudo -u postgres createdb <name> -e
# Drop a database.
sudo -u postgres dropdb <name>
SQLite
For a CLI on Windows, download sqlite-tools-win32-x86-___.zip
Import a tsv file into a new database.
This assumes the tsv has a header row.
.open files.sqlite3
.mode tabs
.import files.tsv files
Node
Upgrade npm
npm install npm@latest -g
View versions of a package
npm view package-name versions
Global Packages
Find all globally installed packages
npm ls -g --depth 0
Install/update a package globally
npm install http-server -g
Find outdated global packages
npm outdated -g --depth=0
Auditing
Find any production packages with vulnerabilities. Id est, ignore any development packages.
npm audit --production
Determine why a package is required.
npm explain package-name
npm why package-name
npm ls package-name
My Node Globals
The following is a list of globals I tend to install with Node. Items are listed in order of relative importance, and then alphabetically.
npm install ___ -g
npm install -g ___
Again, you can run npm ls -g --depth 0
to view any packages that have been installed globally.
Node Utilities
- npm-check-updates
General Utilities
- http-server
TypeScript
- typescript
- eslint
- typedoc
- dts-gen
Frameworks
- @angular/cli
- @ionic/cli
- @vue/cli
- create-react-app
- gulp-cli
Visual Studio Code Extension Development
- yo
- generator-code
PowerShell
List all files with a particular extension in the current directory and its children, with results sorted by full file name.
Get-ChildItem -Path .\ -Filter *.sln -Recurse -File | Select Fullname | Sort-Object Fullname
List the 10 largest files in the current directory and subdirectories.
gci -r | sort Length -desc | select @{n="Length";e={$_.length}}, fullname -f 10
Search Files.ps1
Get-ChildItem -Recurse -Include *.item | select-string "<term>"
gci -r -i *.item | select-string "<term>"
gci -r -i *.* -exclude *.dll,*.xml | select-string "<term>"
Search with Git Grep.ps1
# Can only be run within a Git repository, but this will also search untracked files, as well as those that are tracked.
git grep --untracked '<term>'
View a file's contents
Get-Content .\path\to\file.ext
Find path of a binary.
where.exe git.exe
Run git push
on all child folders of the current directory.
gci -Directory | % { Push-Location $_.FullName; git push; Pop-Location }
Get-ChildItem -Directory | foreach { Push-Location $_.FullName; git push; Pop-Location }
Environment variables
Get all environment variables.
dir Env:
Get environment variables at a certain scope.
[System.Environment]::GetEnvironmentVariables('User')
[System.Environment]::GetEnvironmentVariables('Machine')
Get a particular environment variable.
[Environment]::GetEnvironmentVariable("NAME_OF_VARIABLE")
[Environment]::GetEnvironmentVariable("NAME_OF_VARIABLE", "Machine")
[Environment]::GetEnvironmentVariable("NAME_OF_VARIABLE", "User")
Set an environment variable
$Env:NAME_OF_VARIABLE = "value"
Remove an environment variable
Remove-Item Env:\NAME_OF_VARIABLE
History
View where PSReadLine's history is saved to.
(Get-PSReadlineOption).HistorySavePath
Search PSReadLine's history
Get-Content (Get-PSReadlineOption).HistorySavePath | ? { $_ -like '*searchterm*' }
View session error information
Get-Error -newest 2
Get-Error -last 2
# Names only
$Error
Clear last command from history
Clear-History -Newest -Count 1
PowerShell Profile
Refresh PowerShell Profile
. $profile
My Windows PowerShell Profile
Import-Module Terminal-Icons
Import-Module PSReadLine
Set-PSReadLineOption -PredictionSource History
oh-my-posh init pwsh --config ~/OneDrive/Apps/oh-my-posh/aritraroy.omp.json | Invoke-Expression
$env:POSH_GIT_ENABLED = $true
function Set-Title {
<#
.Description
Set-Title sets the window/tab title, such as for Windows Terminal.
#>
param(
[Parameter(Mandatory = $true)]
[string]
$title
)
$Host.UI.RawUI.WindowTitle = $title
}
function Set-Title-Folder {
<#
.Description
Set-Title-Folder sets the window/tab title, such as for Windows Terminal, based on the current folder.
#>
$Host.UI.RawUI.WindowTitle = Split-Path -Path (Get-Location) -Leaf
}
function Start-ExtensionOpen {
<#
.Description
Start-ExtensionOpen opens a single file with a matching extension, if possible.
#>
param(
[string]
$FileExtension
)
$matchingFiles = Get-ChildItem . -Filter *.$FileExtension
$matchCount = ($matchingFiles | Measure-Object).Count
if ($matchCount -eq 1) {
Write-Output "Opening $($matchingFiles.Name)"
Invoke-Item $matchingFiles[0]
} elseif ($matchCount -eq 0) {
Write-Error "No matching files for $($FileExtension)"
} else {
Write-Output $matchingFiles.Name
}
}
Docker
Unless otherwise noted, commands run on Ubuntu 22.
Setup
# Add the current user to the docker group so docker can be run without sudo.
sudo usermod -aG docker ${USER}
su - ${USER}
exit
Basics
# Get installed version.
docker -v
# Verify Docker is setup / run the Hello World image.
sudo docker run hello-world
# Check whether Docker is running.
sudo systemctl status docker
sudo systemctl is-active docker
# Search Docker Hub for all images matching a search term (<term>).
docker search <term>
# Show all downloaded images.
docker images
# Remove an image.
docker rmi <image-id>
# View information about an image.
docker inspect <image-name>
# Get the size of an image from the above.
docker inspect -f "{{ .Size }}" <image-name>
Image Tags
# Give an image/tag an additional tag.
docker tag <image-name>:<tag-name> <image-name>:<another-tag-name>
# These extra tags can then be removed, while keeping the image.
docker tag <image-name>:<another-tag-name>
Containers
# List running containers.
docker ps
# List all containers.
docker ps -a
# Start a container with <container-id> or <container-name>.
docker start <container-id>
docker start <container-name>
# Stop a container.
docker stop <container>
# Restart a container.
docker restart <container>
# Remove/delete a container.
docker rm <container>
# View container's logs.
docker logs <container>
Working with Running Containers
docker cp path/to/file <container>:./destination/path/
# Run bash on the container, if installed.
docker exec -it <container> bash
Volumes
# List volumes.
docker volume ls
# View information about volume.
docker volume inspect <volume-name>
# Delete a volume.
docker volume rm <volume-name>
Volume content listing
From How to list the content of a named volume in docker 1.9+?.
# View a specific volume.
ls -las $(docker volume inspect <volume-name> | grep Mountpoint | cut -d\" -f 4)
# View all volumes.
for i in `docker volume ls -q`; do echo volume: ${i}; \
ls -las $(docker volume inspect $i | grep Mountpoint | cut -d\" -f 4); \
done
System
# Show disk usage.
docker system df
docker system df --verbose
# Show active container stats.
docker stats
# View and prune images.
docker image ls --filter dangling=true
docker image prune
Compose
# Stop based upon docker-compose.yml in directory.
docker compose stop
# Start services based upon docker-compose.yml.
docker compose up -d
# View the config of a docker-compose.yml in current directory.
docker compose config
Install on Ubuntu
On Ubuntu, from https://docs.docker.com/engine/install/ubuntu/:
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# Test.
sudo docker run hello-world
Windows Terminal
Open a new Windows Terminal window.
wt
Open a new tab in the current window.
wt -w 0
Visual Studio
Install particular NuGet package.ps1
# Installs a particular version of a package.
# See http://stackoverflow.com/q/16126338/11912
Install-Package jQuery -Version 1.10.2
Team Foundation Server
Last reviewed around November 2013.
Delete workspace for user.bat
REM Run from VS developer command prompt
tf workspace /delete _workspace_;_domain_\_user_ /server:http://_server_:8080/tfs
PAUSE
List all workspaces.bat
REM Run from VS developer command prompt
tf workspaces /server:http://_server_:8080/tfs /owner:*
PAUSE